diff --git a/adapter/jdbc/src/test/java/org/apache/arrow/adapter/jdbc/ResultSetUtilityTest.java b/adapter/jdbc/src/test/java/org/apache/arrow/adapter/jdbc/ResultSetUtilityTest.java index c7dc9b2791..833a199be2 100644 --- a/adapter/jdbc/src/test/java/org/apache/arrow/adapter/jdbc/ResultSetUtilityTest.java +++ b/adapter/jdbc/src/test/java/org/apache/arrow/adapter/jdbc/ResultSetUtilityTest.java @@ -43,15 +43,21 @@ public void testZeroRowResultSet() throws Exception { .setReuseVectorSchemaRoot(reuseVectorSchemaRoot) .build(); - ArrowVectorIterator iter = JdbcToArrow.sqlToArrowVectorIterator(rs, config); - assertTrue(iter.hasNext(), "Iterator on zero row ResultSet should haveNext() before use"); - VectorSchemaRoot root = iter.next(); - assertNotNull(root, "VectorSchemaRoot from first next() result should never be null"); - assertEquals( - 0, root.getRowCount(), "VectorSchemaRoot from empty ResultSet should have zero rows"); - assertFalse( - iter.hasNext(), - "hasNext() should return false on empty ResultSets after initial next() call"); + try (ArrowVectorIterator iter = JdbcToArrow.sqlToArrowVectorIterator(rs, config)) { + assertTrue(iter.hasNext(), "Iterator on zero row ResultSet should haveNext() before use"); + VectorSchemaRoot root = iter.next(); + assertNotNull(root, "VectorSchemaRoot from first next() result should never be null"); + assertEquals( + 0, + root.getRowCount(), + "VectorSchemaRoot from empty ResultSet should have zero rows"); + assertFalse( + iter.hasNext(), + "hasNext() should return false on empty ResultSets after initial next() call"); + if (!reuseVectorSchemaRoot) { + root.close(); + } + } } } } diff --git a/vector/src/main/java/org/apache/arrow/vector/BaseLargeVariableWidthVector.java b/vector/src/main/java/org/apache/arrow/vector/BaseLargeVariableWidthVector.java index 6c451f10a7..3bb6842b4b 100644 --- a/vector/src/main/java/org/apache/arrow/vector/BaseLargeVariableWidthVector.java +++ b/vector/src/main/java/org/apache/arrow/vector/BaseLargeVariableWidthVector.java @@ -71,7 +71,9 @@ public BaseLargeVariableWidthVector(Field field, final BufferAllocator allocator lastValueCapacity = INITIAL_VALUE_ALLOCATION - 1; valueCount = 0; lastSet = -1; - offsetBuffer = allocator.getEmpty(); + // Allocate offset buffer with at least OFFSET_WIDTH capacity to ensure + // offset[0] is always available according to Arrow spec. + offsetBuffer = allocateOffsetBuffer(OFFSET_WIDTH); validityBuffer = allocator.getEmpty(); valueBuffer = allocator.getEmpty(); } @@ -373,7 +375,6 @@ private void setReaderAndWriterIndex() { valueBuffer.readerIndex(0); if (valueCount == 0) { validityBuffer.writerIndex(0); - offsetBuffer.writerIndex(0); valueBuffer.writerIndex(0); } else { final long lastDataOffset = getStartOffset(valueCount); @@ -381,6 +382,23 @@ private void setReaderAndWriterIndex() { offsetBuffer.writerIndex((long) (valueCount + 1) * OFFSET_WIDTH); valueBuffer.writerIndex(lastDataOffset); } + // IPC serializer will determine readable bytes based on `readerIndex` and `writerIndex`. + // Both are set to 0 means 0 bytes are written to the IPC stream which will crash IPC readers + // in other libraries. According to Arrow spec, we should still output the offset buffer which + // is [0]. + final long requiredOffsetBufferSize = (long) (valueCount + 1) * OFFSET_WIDTH; + if (offsetBuffer.capacity() < requiredOffsetBufferSize) { + // Allocate a new buffer with sufficient capacity. This can happen when vector + // was loaded via loadFieldBuffers() with an empty offset buffer. + ArrowBuf newOffsetBuffer = allocateOffsetBuffer(requiredOffsetBufferSize); + // Copy existing data if any + if (offsetBuffer.capacity() > 0) { + newOffsetBuffer.setBytes(0, offsetBuffer, 0, offsetBuffer.capacity()); + } + offsetBuffer.getReferenceManager().release(); + offsetBuffer = newOffsetBuffer; + } + offsetBuffer.writerIndex(requiredOffsetBufferSize); } /** Same as {@link #allocateNewSafe()}. */ @@ -492,7 +510,9 @@ private void allocateBytes(final long valueBufferSize, final int valueCount) { /* allocate offset buffer */ private ArrowBuf allocateOffsetBuffer(final long size) { - ArrowBuf offsetBuffer = allocator.buffer(size); + // Ensure at least OFFSET_WIDTH capacity according to Arrow spec + final long curSize = Math.max(size, OFFSET_WIDTH); + ArrowBuf offsetBuffer = allocator.buffer(curSize); offsetBuffer.readerIndex(0); offsetBuffer.setZero(0, offsetBuffer.capacity()); return offsetBuffer; diff --git a/vector/src/main/java/org/apache/arrow/vector/BaseVariableWidthVector.java b/vector/src/main/java/org/apache/arrow/vector/BaseVariableWidthVector.java index 96e2afbd29..58b5dd11aa 100644 --- a/vector/src/main/java/org/apache/arrow/vector/BaseVariableWidthVector.java +++ b/vector/src/main/java/org/apache/arrow/vector/BaseVariableWidthVector.java @@ -69,7 +69,9 @@ public BaseVariableWidthVector(Field field, final BufferAllocator allocator) { lastValueCapacity = INITIAL_VALUE_ALLOCATION - 1; valueCount = 0; lastSet = -1; - offsetBuffer = allocator.getEmpty(); + // Allocate offset buffer with at least OFFSET_WIDTH capacity to ensure + // offset[0] is always available according to Arrow spec. + offsetBuffer = allocateOffsetBuffer(OFFSET_WIDTH); validityBuffer = allocator.getEmpty(); valueBuffer = allocator.getEmpty(); } @@ -389,14 +391,29 @@ private void setReaderAndWriterIndex() { valueBuffer.readerIndex(0); if (valueCount == 0) { validityBuffer.writerIndex(0); - offsetBuffer.writerIndex(0); valueBuffer.writerIndex(0); } else { final int lastDataOffset = getStartOffset(valueCount); validityBuffer.writerIndex(BitVectorHelper.getValidityBufferSizeFromCount(valueCount)); - offsetBuffer.writerIndex((long) (valueCount + 1) * OFFSET_WIDTH); valueBuffer.writerIndex(lastDataOffset); } + // IPC serializer will determine readable bytes based on `readerIndex` and `writerIndex`. + // Both are set to 0 means 0 bytes are written to the IPC stream which will crash IPC readers + // in other libraries. According to Arrow spec, we should still output the offset buffer which + // is [0]. + final long requiredOffsetBufferSize = (long) (valueCount + 1) * OFFSET_WIDTH; + if (offsetBuffer.capacity() < requiredOffsetBufferSize) { + // Allocate a new buffer with sufficient capacity. This can happen when vector + // was loaded via loadFieldBuffers() with an empty offset buffer. + ArrowBuf newOffsetBuffer = allocateOffsetBuffer(requiredOffsetBufferSize); + // Copy existing data if any + if (offsetBuffer.capacity() > 0) { + newOffsetBuffer.setBytes(0, offsetBuffer, 0, offsetBuffer.capacity()); + } + offsetBuffer.getReferenceManager().release(); + offsetBuffer = newOffsetBuffer; + } + offsetBuffer.writerIndex(requiredOffsetBufferSize); } /** Same as {@link #allocateNewSafe()}. */ @@ -509,7 +526,8 @@ private void allocateBytes(final long valueBufferSize, final int valueCount) { /* allocate offset buffer */ private ArrowBuf allocateOffsetBuffer(final long size) { - final int curSize = (int) size; + // Ensure at least OFFSET_WIDTH capacity according to Arrow spec + final int curSize = (int) Math.max(size, OFFSET_WIDTH); ArrowBuf offsetBuffer = allocator.buffer(curSize); offsetBuffer.readerIndex(0); offsetBuffer.setZero(0, offsetBuffer.capacity()); diff --git a/vector/src/main/java/org/apache/arrow/vector/complex/NonNullableStructVector.java b/vector/src/main/java/org/apache/arrow/vector/complex/NonNullableStructVector.java index 5a215608ef..edb9b30fef 100644 --- a/vector/src/main/java/org/apache/arrow/vector/complex/NonNullableStructVector.java +++ b/vector/src/main/java/org/apache/arrow/vector/complex/NonNullableStructVector.java @@ -509,7 +509,11 @@ public void close() { /** Initializes the struct's members from the given Fields. */ public void initializeChildrenFromFields(List children) { for (Field field : children) { + FieldVector oldVector = getChild(field.getName()); FieldVector vector = (FieldVector) this.add(field.getName(), field.getFieldType()); + if (oldVector != null && oldVector != vector) { + oldVector.close(); + } vector.initializeChildrenFromFields(field.getChildren()); } } diff --git a/vector/src/test/java/org/apache/arrow/vector/TestDenseUnionVector.java b/vector/src/test/java/org/apache/arrow/vector/TestDenseUnionVector.java index 9ac30730c4..7cba7f3f75 100644 --- a/vector/src/test/java/org/apache/arrow/vector/TestDenseUnionVector.java +++ b/vector/src/test/java/org/apache/arrow/vector/TestDenseUnionVector.java @@ -412,23 +412,25 @@ public void testGetFieldTypeInfo() throws Exception { final Field field = new Field("union", fieldType, children); MinorType minorType = MinorType.DENSEUNION; - DenseUnionVector vector = (DenseUnionVector) minorType.getNewVector(field, allocator, null); - vector.initializeChildrenFromFields(children); + try (DenseUnionVector vector = + (DenseUnionVector) minorType.getNewVector(field, allocator, null)) { + vector.initializeChildrenFromFields(children); - assertEquals(vector.getField(), field); + assertEquals(vector.getField(), field); - // Union has 2 child vectors - assertEquals(2, vector.size()); + // Union has 2 child vectors + assertEquals(2, vector.size()); - // Check child field 0 - VectorWithOrdinal intChild = vector.getChildVectorWithOrdinal("int"); - assertEquals(0, intChild.ordinal); - assertEquals(intChild.vector.getField(), children.get(0)); + // Check child field 0 + VectorWithOrdinal intChild = vector.getChildVectorWithOrdinal("int"); + assertEquals(0, intChild.ordinal); + assertEquals(intChild.vector.getField(), children.get(0)); - // Check child field 1 - VectorWithOrdinal varcharChild = vector.getChildVectorWithOrdinal("varchar"); - assertEquals(1, varcharChild.ordinal); - assertEquals(varcharChild.vector.getField(), children.get(1)); + // Check child field 1 + VectorWithOrdinal varcharChild = vector.getChildVectorWithOrdinal("varchar"); + assertEquals(1, varcharChild.ordinal); + assertEquals(varcharChild.vector.getField(), children.get(1)); + } } @Test diff --git a/vector/src/test/java/org/apache/arrow/vector/TestSplitAndTransfer.java b/vector/src/test/java/org/apache/arrow/vector/TestSplitAndTransfer.java index adf4eba10c..b30d8e13a6 100644 --- a/vector/src/test/java/org/apache/arrow/vector/TestSplitAndTransfer.java +++ b/vector/src/test/java/org/apache/arrow/vector/TestSplitAndTransfer.java @@ -111,60 +111,83 @@ private void populateDenseUnionVector(final DenseUnionVector vector, int valueCo @Test public void testWithEmptyVector() { // MapVector use TransferImpl from ListVector - ListVector listVector = ListVector.empty("", allocator); - TransferPair transferPair = listVector.getTransferPair(allocator); - transferPair.splitAndTransfer(0, 0); - assertEquals(0, transferPair.getTo().getValueCount()); + try (ListVector listVector = ListVector.empty("", allocator)) { + TransferPair transferPair = listVector.getTransferPair(allocator); + transferPair.splitAndTransfer(0, 0); + assertEquals(0, transferPair.getTo().getValueCount()); + transferPair.getTo().close(); + } // BaseFixedWidthVector - IntVector intVector = new IntVector("", allocator); - transferPair = intVector.getTransferPair(allocator); - transferPair.splitAndTransfer(0, 0); - assertEquals(0, transferPair.getTo().getValueCount()); + try (IntVector intVector = new IntVector("", allocator)) { + TransferPair transferPair = intVector.getTransferPair(allocator); + transferPair.splitAndTransfer(0, 0); + assertEquals(0, transferPair.getTo().getValueCount()); + transferPair.getTo().close(); + } // BaseVariableWidthVector - VarCharVector varCharVector = new VarCharVector("", allocator); - transferPair = varCharVector.getTransferPair(allocator); - transferPair.splitAndTransfer(0, 0); - assertEquals(0, transferPair.getTo().getValueCount()); + try (VarCharVector varCharVector = new VarCharVector("", allocator)) { + TransferPair transferPair = varCharVector.getTransferPair(allocator); + transferPair.splitAndTransfer(0, 0); + assertEquals(0, transferPair.getTo().getValueCount()); + transferPair.getTo().close(); + } // BaseVariableWidthViewVector: ViewVarCharVector - ViewVarCharVector viewVarCharVector = new ViewVarCharVector("", allocator); - transferPair = viewVarCharVector.getTransferPair(allocator); - transferPair.splitAndTransfer(0, 0); - assertEquals(0, transferPair.getTo().getValueCount()); + try (ViewVarCharVector viewVarCharVector = new ViewVarCharVector("", allocator)) { + TransferPair transferPair = viewVarCharVector.getTransferPair(allocator); + transferPair.splitAndTransfer(0, 0); + assertEquals(0, transferPair.getTo().getValueCount()); + transferPair.getTo().close(); + } // BaseVariableWidthVector: ViewVarBinaryVector - ViewVarBinaryVector viewVarBinaryVector = new ViewVarBinaryVector("", allocator); - transferPair = viewVarBinaryVector.getTransferPair(allocator); - transferPair.splitAndTransfer(0, 0); - assertEquals(0, transferPair.getTo().getValueCount()); + try (ViewVarBinaryVector viewVarBinaryVector = new ViewVarBinaryVector("", allocator)) { + TransferPair transferPair = viewVarBinaryVector.getTransferPair(allocator); + transferPair.splitAndTransfer(0, 0); + assertEquals(0, transferPair.getTo().getValueCount()); + transferPair.getTo().close(); + } // BaseLargeVariableWidthVector - LargeVarCharVector largeVarCharVector = new LargeVarCharVector("", allocator); - transferPair = largeVarCharVector.getTransferPair(allocator); - transferPair.splitAndTransfer(0, 0); - assertEquals(0, transferPair.getTo().getValueCount()); + try (LargeVarCharVector largeVarCharVector = new LargeVarCharVector("", allocator)) { + TransferPair transferPair = largeVarCharVector.getTransferPair(allocator); + transferPair.splitAndTransfer(0, 0); + assertEquals(0, transferPair.getTo().getValueCount()); + transferPair.getTo().close(); + } // StructVector - StructVector structVector = StructVector.empty("", allocator); - transferPair = structVector.getTransferPair(allocator); - transferPair.splitAndTransfer(0, 0); - assertEquals(0, transferPair.getTo().getValueCount()); + try (StructVector structVector = StructVector.empty("", allocator)) { + TransferPair transferPair = structVector.getTransferPair(allocator); + transferPair.splitAndTransfer(0, 0); + assertEquals(0, transferPair.getTo().getValueCount()); + transferPair.getTo().close(); + } // FixedSizeListVector - FixedSizeListVector fixedSizeListVector = FixedSizeListVector.empty("", 0, allocator); - transferPair = fixedSizeListVector.getTransferPair(allocator); - transferPair.splitAndTransfer(0, 0); - assertEquals(0, transferPair.getTo().getValueCount()); + try (FixedSizeListVector fixedSizeListVector = FixedSizeListVector.empty("", 0, allocator)) { + TransferPair transferPair = fixedSizeListVector.getTransferPair(allocator); + transferPair.splitAndTransfer(0, 0); + assertEquals(0, transferPair.getTo().getValueCount()); + transferPair.getTo().close(); + } // FixedSizeBinaryVector - FixedSizeBinaryVector fixedSizeBinaryVector = new FixedSizeBinaryVector("", allocator, 4); - transferPair = fixedSizeBinaryVector.getTransferPair(allocator); - transferPair.splitAndTransfer(0, 0); - assertEquals(0, transferPair.getTo().getValueCount()); + try (FixedSizeBinaryVector fixedSizeBinaryVector = + new FixedSizeBinaryVector("", allocator, 4)) { + TransferPair transferPair = fixedSizeBinaryVector.getTransferPair(allocator); + transferPair.splitAndTransfer(0, 0); + assertEquals(0, transferPair.getTo().getValueCount()); + transferPair.getTo().close(); + } // UnionVector - UnionVector unionVector = UnionVector.empty("", allocator); - transferPair = unionVector.getTransferPair(allocator); - transferPair.splitAndTransfer(0, 0); - assertEquals(0, transferPair.getTo().getValueCount()); + try (UnionVector unionVector = UnionVector.empty("", allocator)) { + TransferPair transferPair = unionVector.getTransferPair(allocator); + transferPair.splitAndTransfer(0, 0); + assertEquals(0, transferPair.getTo().getValueCount()); + transferPair.getTo().close(); + } // DenseUnionVector - DenseUnionVector duv = DenseUnionVector.empty("", allocator); - transferPair = duv.getTransferPair(allocator); - transferPair.splitAndTransfer(0, 0); - assertEquals(0, transferPair.getTo().getValueCount()); + try (DenseUnionVector duv = DenseUnionVector.empty("", allocator)) { + TransferPair transferPair = duv.getTransferPair(allocator); + transferPair.splitAndTransfer(0, 0); + assertEquals(0, transferPair.getTo().getValueCount()); + transferPair.getTo().close(); + } // non empty from vector @@ -172,7 +195,7 @@ public void testWithEmptyVector() { IntVector fromIntVector = new IntVector("", allocator); fromIntVector.allocateNew(100); populateIntVector(fromIntVector, 100); - transferPair = fromIntVector.getTransferPair(allocator); + TransferPair transferPair = fromIntVector.getTransferPair(allocator); IntVector toIntVector = (IntVector) transferPair.getTo(); transferPair.splitAndTransfer(0, 0); assertEquals(0, toIntVector.getValueCount()); diff --git a/vector/src/test/java/org/apache/arrow/vector/TestUnionVector.java b/vector/src/test/java/org/apache/arrow/vector/TestUnionVector.java index 40c05f9b11..b485c7bce7 100644 --- a/vector/src/test/java/org/apache/arrow/vector/TestUnionVector.java +++ b/vector/src/test/java/org/apache/arrow/vector/TestUnionVector.java @@ -402,23 +402,24 @@ public void testGetFieldTypeInfo() throws Exception { final Field field = new Field("union", fieldType, children); MinorType minorType = MinorType.UNION; - UnionVector vector = (UnionVector) minorType.getNewVector(field, allocator, null); - vector.initializeChildrenFromFields(children); + try (UnionVector vector = (UnionVector) minorType.getNewVector(field, allocator, null)) { + vector.initializeChildrenFromFields(children); - assertTrue(vector.getField().equals(field)); + assertTrue(vector.getField().equals(field)); - // Union has 2 child vectors - assertEquals(2, vector.size()); + // Union has 2 child vectors + assertEquals(2, vector.size()); - // Check child field 0 - VectorWithOrdinal intChild = vector.getChildVectorWithOrdinal("int"); - assertEquals(0, intChild.ordinal); - assertEquals(intChild.vector.getField(), children.get(0)); + // Check child field 0 + VectorWithOrdinal intChild = vector.getChildVectorWithOrdinal("int"); + assertEquals(0, intChild.ordinal); + assertEquals(intChild.vector.getField(), children.get(0)); - // Check child field 1 - VectorWithOrdinal varcharChild = vector.getChildVectorWithOrdinal("varchar"); - assertEquals(1, varcharChild.ordinal); - assertEquals(varcharChild.vector.getField(), children.get(1)); + // Check child field 1 + VectorWithOrdinal varcharChild = vector.getChildVectorWithOrdinal("varchar"); + assertEquals(1, varcharChild.ordinal); + assertEquals(varcharChild.vector.getField(), children.get(1)); + } } @Test diff --git a/vector/src/test/java/org/apache/arrow/vector/TestValueVector.java b/vector/src/test/java/org/apache/arrow/vector/TestValueVector.java index df42d04e60..1999a4463a 100644 --- a/vector/src/test/java/org/apache/arrow/vector/TestValueVector.java +++ b/vector/src/test/java/org/apache/arrow/vector/TestValueVector.java @@ -1154,9 +1154,9 @@ public void testSplitAndTransfer1() { final int dataRefCnt = sourceVector.getDataBuffer().refCnt(); // split and transfer with slice starting at the beginning: this should not allocate - // anything new + // anything new. The target vector's initial offset buffer (4 bytes) is freed during transfer. sourceVector.splitAndTransferTo(0, 2, targetVector); - assertEquals(allocatedMem, allocator.getAllocatedMemory()); + assertEquals(allocatedMem - 4, allocator.getAllocatedMemory()); // The validity and offset buffers are sliced from a same buffer.See // BaseFixedWidthVector#allocateBytes. // Therefore, the refcnt of the validity buffer is increased once since the startIndex is 0. @@ -1192,9 +1192,9 @@ public void testSplitAndTransfer2() { final int dataRefCnt = sourceVector.getDataBuffer().refCnt(); // split and transfer with slice starting at the beginning: this should not allocate - // anything new + // anything new. The target vector's initial offset buffer (4 bytes) is freed during transfer. sourceVector.splitAndTransferTo(0, 2, targetVector); - assertEquals(allocatedMem, allocator.getAllocatedMemory()); + assertEquals(allocatedMem - 4, allocator.getAllocatedMemory()); // The validity and offset buffers are sliced from a same buffer.See // BaseFixedWidthVector#allocateBytes. // Therefore, the refcnt of the validity buffer is increased once since the startIndex is 0. @@ -1239,7 +1239,8 @@ public void testSplitAndTransfer3() { final long validitySize = DefaultRoundingPolicy.DEFAULT_ROUNDING_POLICY.getRoundedSize( getValidityBufferSizeFromCount(2)); - assertEquals(allocatedMem + validitySize, allocator.getAllocatedMemory()); + // The target vector's initial offset buffer (4 bytes) is freed during transfer. + assertEquals(allocatedMem + validitySize - 4, allocator.getAllocatedMemory()); // The validity and offset buffers are sliced from a same buffer.See // BaseFixedWidthVector#allocateBytes. // Since values up to the startIndex are empty/null, the offset buffer doesn't need to be @@ -3701,7 +3702,7 @@ public void testEmptyBufBehavior() { assertEquals(1, vector.getOffsetBuffer().refCnt()); assertEquals(0, vector.getDataBuffer().capacity()); assertEquals(0, vector.getValidityBuffer().capacity()); - assertEquals(0, vector.getOffsetBuffer().capacity()); + assertEquals(4, vector.getOffsetBuffer().capacity()); vector.allocateNew(valueCount); assertEquals(1, vector.getDataBuffer().refCnt()); @@ -3940,4 +3941,42 @@ public void testVectorLoadUnloadOnNonVariadicVectors() { } } } + + @Test + public void testEmptyVarCharOffsetBuffer() { + // Validates that offset buffer has at least OFFSET_WIDTH bytes (for offset[0]=0) + // even when valueCount is 0, per Arrow specification. + try (VarCharVector vector = newVarCharVector("varchar", allocator)) { + vector.allocateNew(); + vector.setValueCount(0); + + List buffers = vector.getFieldBuffers(); + // buffers: [validity, offset, data] + assertTrue( + buffers.get(1).readableBytes() >= BaseVariableWidthVector.OFFSET_WIDTH, + "Offset buffer should have at least " + + BaseVariableWidthVector.OFFSET_WIDTH + + " bytes for offset[0]"); + assertEquals(0, vector.getOffsetBuffer().getInt(0)); + } + } + + @Test + public void testEmptyLargeVarCharOffsetBuffer() { + // Validates that offset buffer has at least OFFSET_WIDTH bytes (for offset[0]=0) + // even when valueCount is 0, per Arrow specification. + try (LargeVarCharVector vector = new LargeVarCharVector("largevarchar", allocator)) { + vector.allocateNew(); + vector.setValueCount(0); + + List buffers = vector.getFieldBuffers(); + // buffers: [validity, offset, data] + assertTrue( + buffers.get(1).readableBytes() >= BaseLargeVariableWidthVector.OFFSET_WIDTH, + "Offset buffer should have at least " + + BaseLargeVariableWidthVector.OFFSET_WIDTH + + " bytes for offset[0]"); + assertEquals(0, vector.getOffsetBuffer().getLong(0)); + } + } }