-
Notifications
You must be signed in to change notification settings - Fork 159
GH-471: Fix ListView reader iteration bounds #1310
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 void setPosition(int index) { | |
| 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 int size() { | |
|
|
||
| @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) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With the bound in place,
boolean found = true;
for (int i = -1; i < index && found; i++) {
found = next();
}
holder.reader = data.getReader();
holder.isSet = found && data.getReader().isSet() ? 1 : 0;Either way, a test for the out-of-range and empty-view cases would be good: |
||
| data.getReader().setPosition(currentOffset++); | ||
| remaining--; | ||
| return true; | ||
| } else { | ||
| return false; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,6 +29,7 @@ | |
| 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 void testRangeChildVector2() { | |
| } | ||
| } | ||
|
|
||
| @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); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The reader has to be built by hand here because While you are in |
||
| 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) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,9 +32,11 @@ | |
| 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 void testBasicListViewVector() { | |
| } | ||
| } | ||
|
|
||
| @Test | ||
| public void testCopyFromNonEmptyListView() { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you extend the coverage a bit here? Two cases would pin down #471:
|
||
| 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); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This passes because the reader is first obtained inside This predates your changes, but it is a one-line fix and the easiest way to still get wrong data out of a flat Would you mind including it here with a test? Otherwise I'm fine with a follow-up issue. |
||
| 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)) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: #471 points out that the approach differs from
UnionListReader. Mirroring itscurrentOffset/maxOffsetpair would keep the readers aligned and drop the extra decrement:Same in
UnionLargeListViewReader, wherecheckedCastToiInt(currentOffset++)and its import could also go, sincecurrentOffsetis already anint.