This is an automated email from the ASF dual-hosted git repository.
jbonofre pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-java.git
The following commit(s) were added to refs/heads/main by this push:
new 1d8dc54ba GH-471: Fix ListView reader iteration bounds (#1310)
1d8dc54ba is described below
commit 1d8dc54ba0c80513adddf3f16508e4154f64e8e1
Author: Dang Pham <[email protected]>
AuthorDate: Sat Oct 3 12:38:11 2026 +0700
GH-471: Fix ListView reader iteration bounds (#1310)
## What's Changed
Fix `UnionListViewReader` and `UnionLargeListViewReader` iteration so
non-empty
ListView values terminate after exactly the declared number of elements.
Closes #471.
---
.../complex/impl/UnionLargeListViewReader.java | 11 ++--
.../vector/complex/impl/UnionListViewReader.java | 11 ++--
.../arrow/vector/TestLargeListViewVector.java | 33 +++++++++++
.../apache/arrow/vector/TestListViewVector.java | 65 ++++++++++++++++++++++
4 files changed, 110 insertions(+), 10 deletions(-)
diff --git
a/vector/src/main/java/org/apache/arrow/vector/complex/impl/UnionLargeListViewReader.java
b/vector/src/main/java/org/apache/arrow/vector/complex/impl/UnionLargeListViewReader.java
index 4bcd028de..cd4a0c17d 100644
---
a/vector/src/main/java/org/apache/arrow/vector/complex/impl/UnionLargeListViewReader.java
+++
b/vector/src/main/java/org/apache/arrow/vector/complex/impl/UnionLargeListViewReader.java
@@ -33,6 +33,7 @@ public class UnionLargeListViewReader extends
AbstractFieldReader {
private final ValueVector data;
private int currentOffset;
private int size;
+ private int remaining;
/**
* Constructor for UnionLargeListViewReader.
@@ -60,6 +61,7 @@ public class UnionLargeListViewReader extends
AbstractFieldReader {
if (vector.getOffsetBuffer().capacity() == 0) {
currentOffset = 0;
size = 0;
+ remaining = 0;
} else {
currentOffset =
vector
@@ -67,6 +69,7 @@ public class UnionLargeListViewReader extends
AbstractFieldReader {
.getInt(index * (long)
BaseLargeRepeatedValueViewVector.OFFSET_WIDTH);
size =
vector.getSizeBuffer().getInt(index * (long)
BaseLargeRepeatedValueViewVector.SIZE_WIDTH);
+ remaining = size;
}
}
@@ -102,12 +105,10 @@ public class UnionLargeListViewReader extends
AbstractFieldReader {
@Override
public boolean next() {
- // Here, the currentOffSet keeps track of the current position in the
vector inside the list at
- // set position.
- // And, size keeps track of the elements count in the list, so to make
sure we traverse
- // the full list, we need to check if the currentOffset is less than the
currentOffset + size
- if (currentOffset < currentOffset + size) {
+ // Yield exactly the element count stored with this list view, beginning
at its stored offset.
+ if (remaining > 0) {
data.getReader().setPosition(checkedCastToInt(currentOffset++));
+ remaining--;
return true;
} else {
return false;
diff --git
a/vector/src/main/java/org/apache/arrow/vector/complex/impl/UnionListViewReader.java
b/vector/src/main/java/org/apache/arrow/vector/complex/impl/UnionListViewReader.java
index 17ac1150f..c4bc2b501 100644
---
a/vector/src/main/java/org/apache/arrow/vector/complex/impl/UnionListViewReader.java
+++
b/vector/src/main/java/org/apache/arrow/vector/complex/impl/UnionListViewReader.java
@@ -31,6 +31,7 @@ public class UnionListViewReader extends AbstractFieldReader {
private final ValueVector data;
private int currentOffset;
private int size;
+ private int remaining;
/**
* Constructor for UnionListViewReader.
@@ -58,10 +59,12 @@ public class UnionListViewReader extends
AbstractFieldReader {
if (vector.getOffsetBuffer().capacity() == 0) {
currentOffset = 0;
size = 0;
+ remaining = 0;
} else {
currentOffset =
vector.getOffsetBuffer().getInt(index * (long)
BaseRepeatedValueViewVector.OFFSET_WIDTH);
size = vector.getSizeBuffer().getInt(index * (long)
BaseRepeatedValueViewVector.SIZE_WIDTH);
+ remaining = size;
}
}
@@ -97,12 +100,10 @@ public class UnionListViewReader extends
AbstractFieldReader {
@Override
public boolean next() {
- // Here, the currentOffSet keeps track of the current position in the
vector inside the list at
- // set position.
- // And, size keeps track of the elements count in the list, so to make
sure we traverse
- // the full list, we need to check if the currentOffset is less than the
currentOffset + size
- if (currentOffset < currentOffset + size) {
+ // Yield exactly the element count stored with this list view, beginning
at its stored offset.
+ if (remaining > 0) {
data.getReader().setPosition(currentOffset++);
+ remaining--;
return true;
} else {
return false;
diff --git
a/vector/src/test/java/org/apache/arrow/vector/TestLargeListViewVector.java
b/vector/src/test/java/org/apache/arrow/vector/TestLargeListViewVector.java
index 256aa9968..1cdf10308 100644
--- a/vector/src/test/java/org/apache/arrow/vector/TestLargeListViewVector.java
+++ b/vector/src/test/java/org/apache/arrow/vector/TestLargeListViewVector.java
@@ -29,6 +29,7 @@ import org.apache.arrow.memory.ArrowBuf;
import org.apache.arrow.memory.BufferAllocator;
import org.apache.arrow.vector.complex.BaseLargeRepeatedValueViewVector;
import org.apache.arrow.vector.complex.LargeListViewVector;
+import org.apache.arrow.vector.complex.impl.UnionLargeListViewReader;
import org.apache.arrow.vector.complex.impl.UnionLargeListViewWriter;
import org.apache.arrow.vector.types.Types.MinorType;
import org.apache.arrow.vector.types.pojo.ArrowType;
@@ -2230,6 +2231,38 @@ public class TestLargeListViewVector {
}
}
+ @Test
+ public void testDirectReaderIteratesLargeListViewRange() {
+ try (LargeListViewVector largeListViewVector =
+ LargeListViewVector.empty("largelistview", allocator)) {
+ largeListViewVector.allocateNew();
+ FieldType fieldType = new FieldType(true, new ArrowType.Int(32, true),
null, null);
+ largeListViewVector.initializeChildrenFromFields(
+ Collections.singletonList(new Field("child-vector", fieldType,
null)));
+ IntVector childVector = (IntVector) largeListViewVector.getDataVector();
+ childVector.allocateNew(5);
+ for (int i = 0; i < 5; i++) {
+ childVector.set(i, 10 + i);
+ }
+ childVector.setValueCount(5);
+ largeListViewVector.setValidity(0, 1);
+ largeListViewVector.setOffset(0, 2);
+ largeListViewVector.setSize(0, 3);
+ largeListViewVector.setValueCount(1);
+
+ UnionLargeListViewReader reader = new
UnionLargeListViewReader(largeListViewVector);
+ reader.setPosition(0);
+ assertTrue(reader.next());
+ assertEquals(12, ((Number) reader.reader().readObject()).intValue());
+ assertTrue(reader.next());
+ assertEquals(13, ((Number) reader.reader().readObject()).intValue());
+ assertTrue(reader.next());
+ assertEquals(14, ((Number) reader.reader().readObject()).intValue());
+ assertFalse(reader.next());
+ assertFalse(reader.next());
+ }
+ }
+
private void writeIntValues(UnionLargeListViewWriter writer, int[] values) {
writer.startListView();
for (int v : values) {
diff --git
a/vector/src/test/java/org/apache/arrow/vector/TestListViewVector.java
b/vector/src/test/java/org/apache/arrow/vector/TestListViewVector.java
index 8ab0edb14..96403f7ee 100644
--- a/vector/src/test/java/org/apache/arrow/vector/TestListViewVector.java
+++ b/vector/src/test/java/org/apache/arrow/vector/TestListViewVector.java
@@ -32,9 +32,11 @@ import
org.apache.arrow.vector.complex.BaseRepeatedValueVector;
import org.apache.arrow.vector.complex.BaseRepeatedValueViewVector;
import org.apache.arrow.vector.complex.ListVector;
import org.apache.arrow.vector.complex.ListViewVector;
+import org.apache.arrow.vector.complex.impl.UnionListViewReader;
import org.apache.arrow.vector.complex.impl.UnionListViewWriter;
import org.apache.arrow.vector.holders.DurationHolder;
import org.apache.arrow.vector.holders.TimeStampMilliTZHolder;
+import org.apache.arrow.vector.holders.UnionHolder;
import org.apache.arrow.vector.types.TimeUnit;
import org.apache.arrow.vector.types.Types.MinorType;
import org.apache.arrow.vector.types.pojo.ArrowType;
@@ -142,6 +144,69 @@ public class TestListViewVector {
}
}
+ @Test
+ public void testCopyFromNonEmptyListView() {
+ try (ListViewVector inVector = ListViewVector.empty("input", allocator);
+ ListViewVector outVector = ListViewVector.empty("output", allocator)) {
+ UnionListViewWriter writer = inVector.getWriter();
+ writer.allocate();
+ writer.setPosition(0);
+ writeIntValues(writer, new int[] {10, 20});
+ writer.setValueCount(1);
+
+ outVector.allocateNew();
+ outVector.copyFrom(0, 0, inVector);
+ outVector.setValueCount(1);
+
+ assertEquals(Arrays.asList(10, 20), outVector.getObject(0));
+ }
+ }
+
+ @Test
+ public void testReaderIteratesListViewRangeAndResets() {
+ try (ListViewVector listViewVector = ListViewVector.empty("listview",
allocator)) {
+ initializeListViewVector(
+ listViewVector,
+ List.of(10, 11, 20, 21, 22),
+ List.of(1, 1, 1),
+ List.of(0, 2, 5),
+ List.of(2, 3, 0));
+ UnionListViewReader reader = listViewVector.getReader();
+
+ reader.setPosition(0);
+ assertTrue(reader.next());
+ assertEquals(10, ((Number) reader.reader().readObject()).intValue());
+ assertTrue(reader.next());
+ assertEquals(11, ((Number) reader.reader().readObject()).intValue());
+ assertFalse(reader.next());
+ assertFalse(reader.next());
+
+ reader.setPosition(1);
+ assertTrue(reader.next());
+ assertEquals(20, ((Number) reader.reader().readObject()).intValue());
+ assertTrue(reader.next());
+ assertEquals(21, ((Number) reader.reader().readObject()).intValue());
+ assertTrue(reader.next());
+ assertEquals(22, ((Number) reader.reader().readObject()).intValue());
+ assertFalse(reader.next());
+ assertFalse(reader.next());
+
+ reader.setPosition(1);
+ assertTrue(reader.next());
+ assertEquals(20, ((Number) reader.reader().readObject()).intValue());
+
+ reader.setPosition(2);
+ assertFalse(reader.next());
+ assertFalse(reader.next());
+
+ reader.setPosition(1);
+ UnionHolder holder = new UnionHolder();
+ reader.read(2, holder);
+ assertEquals(22, ((Number) holder.reader.readObject()).intValue());
+ assertFalse(reader.next());
+ }
+ }
+
@Test
public void testImplicitNullVectors() {
try (ListViewVector listViewVector = ListViewVector.empty("sourceVector",
allocator)) {