2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 package org
.apache
.arrow
.vector
;
20 import static org
.apache
.arrow
.vector
.NullCheckingForGet
.NULL_CHECKING_ENABLED
;
22 import java
.math
.BigDecimal
;
23 import java
.nio
.ByteOrder
;
25 import org
.apache
.arrow
.memory
.ArrowBuf
;
26 import org
.apache
.arrow
.memory
.BufferAllocator
;
27 import org
.apache
.arrow
.vector
.complex
.impl
.Decimal256ReaderImpl
;
28 import org
.apache
.arrow
.vector
.complex
.reader
.FieldReader
;
29 import org
.apache
.arrow
.vector
.holders
.Decimal256Holder
;
30 import org
.apache
.arrow
.vector
.holders
.NullableDecimal256Holder
;
31 import org
.apache
.arrow
.vector
.types
.Types
.MinorType
;
32 import org
.apache
.arrow
.vector
.types
.pojo
.ArrowType
;
33 import org
.apache
.arrow
.vector
.types
.pojo
.Field
;
34 import org
.apache
.arrow
.vector
.types
.pojo
.FieldType
;
35 import org
.apache
.arrow
.vector
.util
.DecimalUtility
;
36 import org
.apache
.arrow
.vector
.util
.TransferPair
;
38 import io
.netty
.util
.internal
.PlatformDependent
;
41 * Decimal256Vector implements a fixed width vector (32 bytes) of
42 * decimal values which could be null. A validity buffer (bit vector) is
43 * maintained to track which elements in the vector are null.
45 public final class Decimal256Vector
extends BaseFixedWidthVector
{
46 public static final byte TYPE_WIDTH
= 32;
47 private static final boolean LITTLE_ENDIAN
= ByteOrder
.nativeOrder() == ByteOrder
.LITTLE_ENDIAN
;
48 private final FieldReader reader
;
50 private final int precision
;
51 private final int scale
;
54 * Instantiate a Decimal256Vector. This doesn't allocate any memory for
57 * @param name name of the vector
58 * @param allocator allocator for memory management.
60 public Decimal256Vector(String name
, BufferAllocator allocator
,
61 int precision
, int scale
) {
62 this(name
, FieldType
.nullable(new ArrowType
.Decimal(precision
, scale
, /*bitWidth=*/TYPE_WIDTH
* 8)), allocator
);
66 * Instantiate a Decimal256Vector. This doesn't allocate any memory for
69 * @param name name of the vector
70 * @param fieldType type of Field materialized by this vector
71 * @param allocator allocator for memory management.
73 public Decimal256Vector(String name
, FieldType fieldType
, BufferAllocator allocator
) {
74 this(new Field(name
, fieldType
, null), allocator
);
78 * Instantiate a Decimal256Vector. This doesn't allocate any memory for
81 * @param field field materialized by this vector
82 * @param allocator allocator for memory management.
84 public Decimal256Vector(Field field
, BufferAllocator allocator
) {
85 super(field
, allocator
, TYPE_WIDTH
);
86 ArrowType
.Decimal arrowType
= (ArrowType
.Decimal
) field
.getFieldType().getType();
87 reader
= new Decimal256ReaderImpl(Decimal256Vector
.this);
88 this.precision
= arrowType
.getPrecision();
89 this.scale
= arrowType
.getScale();
93 * Get a reader that supports reading values from this vector.
95 * @return Field Reader for this vector
98 public FieldReader
getReader() {
103 * Get minor type for this vector. The vector holds values belonging
104 * to a particular type.
106 * @return {@link org.apache.arrow.vector.types.Types.MinorType}
109 public MinorType
getMinorType() {
110 return MinorType
.DECIMAL256
;
114 /*----------------------------------------------------------------*
116 | vector value retrieval methods |
118 *----------------------------------------------------------------*/
122 * Get the element at the given index from the vector.
124 * @param index position of element
125 * @return element at given index
127 public ArrowBuf
get(int index
) throws IllegalStateException
{
128 if (NULL_CHECKING_ENABLED
&& isSet(index
) == 0) {
129 throw new IllegalStateException("Value at index is null");
131 return valueBuffer
.slice((long) index
* TYPE_WIDTH
, TYPE_WIDTH
);
135 * Get the element at the given index from the vector and
136 * sets the state in holder. If element at given index
137 * is null, holder.isSet will be zero.
139 * @param index position of element
141 public void get(int index
, NullableDecimal256Holder holder
) {
142 if (isSet(index
) == 0) {
147 holder
.buffer
= valueBuffer
;
148 holder
.precision
= precision
;
149 holder
.scale
= scale
;
150 holder
.start
= ((long) index
) * TYPE_WIDTH
;
154 * Same as {@link #get(int)}.
156 * @param index position of element
157 * @return element at given index
159 public BigDecimal
getObject(int index
) {
160 if (isSet(index
) == 0) {
163 return DecimalUtility
.getBigDecimalFromArrowBuf(valueBuffer
, index
, scale
, TYPE_WIDTH
);
168 * Return precision for the decimal value.
170 public int getPrecision() {
175 * Return scale for the decimal value.
177 public int getScale() {
182 /*----------------------------------------------------------------*
184 | vector value setter methods |
186 *----------------------------------------------------------------*/
190 * Set the element at the given index to the given value.
192 * @param index position of element
193 * @param buffer ArrowBuf containing decimal value.
195 public void set(int index
, ArrowBuf buffer
) {
196 BitVectorHelper
.setBit(validityBuffer
, index
);
197 valueBuffer
.setBytes((long) index
* TYPE_WIDTH
, buffer
, 0, TYPE_WIDTH
);
201 * Set the decimal element at given index to the provided array of bytes.
202 * Decimal256 is now implemented as Native Endian. This API allows the user
203 * to pass a decimal value in the form of byte array in BE byte order.
205 * <p>Consumers of Arrow code can use this API instead of first swapping
206 * the source bytes (doing a write and read) and then finally writing to
207 * ArrowBuf of decimal vector.
209 * <p>This method takes care of adding the necessary padding if the length
210 * of byte array is less then 32 (length of decimal type).
212 * @param index position of element
213 * @param value array of bytes containing decimal in big endian byte order.
215 public void setBigEndian(int index
, byte[] value
) {
216 BitVectorHelper
.setBit(validityBuffer
, index
);
217 final int length
= value
.length
;
219 // do the bound check.
220 valueBuffer
.checkBytes((long) index
* TYPE_WIDTH
, (long) (index
+ 1) * TYPE_WIDTH
);
222 long outAddress
= valueBuffer
.memoryAddress() + (long) index
* TYPE_WIDTH
;
224 PlatformDependent
.setMemory(outAddress
, Decimal256Vector
.TYPE_WIDTH
, (byte) 0);
228 // swap bytes to convert BE to LE
229 for (int byteIdx
= 0; byteIdx
< length
; ++byteIdx
) {
230 PlatformDependent
.putByte(outAddress
+ byteIdx
, value
[length
- 1 - byteIdx
]);
233 if (length
== TYPE_WIDTH
) {
237 if (length
< TYPE_WIDTH
) {
239 final byte pad
= (byte) (value
[0] < 0 ?
0xFF : 0x00);
240 PlatformDependent
.setMemory(outAddress
+ length
, Decimal256Vector
.TYPE_WIDTH
- length
, pad
);
244 if (length
<= TYPE_WIDTH
) {
245 // copy data from value to outAddress
246 PlatformDependent
.copyMemory(value
, 0, outAddress
+ Decimal256Vector
.TYPE_WIDTH
- length
, length
);
248 final byte pad
= (byte) (value
[0] < 0 ?
0xFF : 0x00);
249 PlatformDependent
.setMemory(outAddress
, Decimal256Vector
.TYPE_WIDTH
- length
, pad
);
253 throw new IllegalArgumentException(
254 "Invalid decimal value length. Valid length in [1 - 32], got " + length
);
258 * Set the element at the given index to the given value.
260 * @param index position of element
261 * @param start start index of data in the buffer
262 * @param buffer ArrowBuf containing decimal value.
264 public void set(int index
, long start
, ArrowBuf buffer
) {
265 BitVectorHelper
.setBit(validityBuffer
, index
);
266 valueBuffer
.setBytes((long) index
* TYPE_WIDTH
, buffer
, start
, TYPE_WIDTH
);
270 * Sets the element at given index using the buffer whose size maybe <= 32 bytes.
271 * @param index index to write the decimal to
272 * @param start start of value in the buffer
273 * @param buffer contains the decimal in native endian bytes
274 * @param length length of the value in the buffer
276 public void setSafe(int index
, long start
, ArrowBuf buffer
, int length
) {
278 BitVectorHelper
.setBit(validityBuffer
, index
);
280 // do the bound checks.
281 buffer
.checkBytes(start
, start
+ length
);
282 valueBuffer
.checkBytes((long) index
* TYPE_WIDTH
, (long) (index
+ 1) * TYPE_WIDTH
);
284 long inAddress
= buffer
.memoryAddress() + start
;
285 long outAddress
= valueBuffer
.memoryAddress() + (long) index
* TYPE_WIDTH
;
287 PlatformDependent
.copyMemory(inAddress
, outAddress
, length
);
289 if (length
< TYPE_WIDTH
) {
290 byte msb
= PlatformDependent
.getByte(inAddress
+ length
- 1);
291 final byte pad
= (byte) (msb
< 0 ?
0xFF : 0x00);
292 PlatformDependent
.setMemory(outAddress
+ length
, Decimal256Vector
.TYPE_WIDTH
- length
, pad
);
295 PlatformDependent
.copyMemory(inAddress
, outAddress
+ Decimal256Vector
.TYPE_WIDTH
- length
, length
);
297 if (length
< TYPE_WIDTH
) {
298 byte msb
= PlatformDependent
.getByte(inAddress
);
299 final byte pad
= (byte) (msb
< 0 ?
0xFF : 0x00);
300 PlatformDependent
.setMemory(outAddress
, Decimal256Vector
.TYPE_WIDTH
- length
, pad
);
307 * Sets the element at given index using the buffer whose size maybe <= 32 bytes.
308 * @param index index to write the decimal to
309 * @param start start of value in the buffer
310 * @param buffer contains the decimal in big endian bytes
311 * @param length length of the value in the buffer
313 public void setBigEndianSafe(int index
, long start
, ArrowBuf buffer
, int length
) {
315 BitVectorHelper
.setBit(validityBuffer
, index
);
317 // do the bound checks.
318 buffer
.checkBytes(start
, start
+ length
);
319 valueBuffer
.checkBytes((long) index
* TYPE_WIDTH
, (long) (index
+ 1) * TYPE_WIDTH
);
321 // not using buffer.getByte() to avoid boundary checks for every byte.
322 long inAddress
= buffer
.memoryAddress() + start
;
323 long outAddress
= valueBuffer
.memoryAddress() + (long) index
* TYPE_WIDTH
;
325 // swap bytes to convert BE to LE
326 for (int byteIdx
= 0; byteIdx
< length
; ++byteIdx
) {
327 byte val
= PlatformDependent
.getByte((inAddress
+ length
- 1) - byteIdx
);
328 PlatformDependent
.putByte(outAddress
+ byteIdx
, val
);
332 byte msb
= PlatformDependent
.getByte(inAddress
);
333 final byte pad
= (byte) (msb
< 0 ?
0xFF : 0x00);
334 PlatformDependent
.setMemory(outAddress
+ length
, Decimal256Vector
.TYPE_WIDTH
- length
, pad
);
337 PlatformDependent
.copyMemory(inAddress
, outAddress
+ Decimal256Vector
.TYPE_WIDTH
- length
, length
);
339 if (length
< TYPE_WIDTH
) {
340 byte msb
= PlatformDependent
.getByte(inAddress
);
341 final byte pad
= (byte) (msb
< 0 ?
0xFF : 0x00);
342 PlatformDependent
.setMemory(outAddress
, Decimal256Vector
.TYPE_WIDTH
- length
, pad
);
348 * Set the element at the given index to the given value.
350 * @param index position of element
351 * @param value BigDecimal containing decimal value.
353 public void set(int index
, BigDecimal value
) {
354 BitVectorHelper
.setBit(validityBuffer
, index
);
355 DecimalUtility
.checkPrecisionAndScale(value
, precision
, scale
);
356 DecimalUtility
.writeBigDecimalToArrowBuf(value
, valueBuffer
, index
, TYPE_WIDTH
);
360 * Set the element at the given index to the given value.
362 * @param index position of element
363 * @param value long value.
365 public void set(int index
, long value
) {
366 BitVectorHelper
.setBit(validityBuffer
, index
);
367 DecimalUtility
.writeLongToArrowBuf(value
, valueBuffer
, index
, TYPE_WIDTH
);
371 * Set the element at the given index to the value set in data holder.
372 * If the value in holder is not indicated as set, element in the
373 * at the given index will be null.
375 * @param index position of element
376 * @param holder nullable data holder for value of element
378 public void set(int index
, NullableDecimal256Holder holder
) throws IllegalArgumentException
{
379 if (holder
.isSet
< 0) {
380 throw new IllegalArgumentException();
381 } else if (holder
.isSet
> 0) {
382 BitVectorHelper
.setBit(validityBuffer
, index
);
383 valueBuffer
.setBytes((long) index
* TYPE_WIDTH
, holder
.buffer
, holder
.start
, TYPE_WIDTH
);
385 BitVectorHelper
.unsetBit(validityBuffer
, index
);
390 * Set the element at the given index to the value set in data holder.
392 * @param index position of element
393 * @param holder data holder for value of element
395 public void set(int index
, Decimal256Holder holder
) {
396 BitVectorHelper
.setBit(validityBuffer
, index
);
397 valueBuffer
.setBytes((long) index
* TYPE_WIDTH
, holder
.buffer
, holder
.start
, TYPE_WIDTH
);
401 * Same as {@link #set(int, ArrowBuf)} except that it handles the
402 * case when index is greater than or equal to existing
403 * value capacity {@link #getValueCapacity()}.
405 * @param index position of element
406 * @param buffer ArrowBuf containing decimal value.
408 public void setSafe(int index
, ArrowBuf buffer
) {
414 * Same as {@link #setBigEndian(int, byte[])} except that it handles the
415 * case when index is greater than or equal to existing
416 * value capacity {@link #getValueCapacity()}.
418 public void setBigEndianSafe(int index
, byte[] value
) {
420 setBigEndian(index
, value
);
424 * Same as {@link #set(int, int, ArrowBuf)} except that it handles the
425 * case when index is greater than or equal to existing
426 * value capacity {@link #getValueCapacity()}.
428 * @param index position of element
429 * @param start start index of data in the buffer
430 * @param buffer ArrowBuf containing decimal value.
432 public void setSafe(int index
, long start
, ArrowBuf buffer
) {
434 set(index
, start
, buffer
);
438 * Same as {@link #set(int, BigDecimal)} except that it handles the
439 * case when index is greater than or equal to existing
440 * value capacity {@link #getValueCapacity()}.
442 * @param index position of element
443 * @param value BigDecimal containing decimal value.
445 public void setSafe(int index
, BigDecimal value
) {
451 * Same as {@link #set(int, long)} except that it handles the
452 * case when index is greater than or equal to existing
453 * value capacity {@link #getValueCapacity()}.
455 * @param index position of element
456 * @param value long value.
458 public void setSafe(int index
, long value
) {
464 * Same as {@link #set(int, NullableDecimalHolder)} except that it handles the
465 * case when index is greater than or equal to existing
466 * value capacity {@link #getValueCapacity()}.
468 * @param index position of element
469 * @param holder nullable data holder for value of element
471 public void setSafe(int index
, NullableDecimal256Holder holder
) throws IllegalArgumentException
{
477 * Same as {@link #set(int, Decimal256Holder)} except that it handles the
478 * case when index is greater than or equal to existing
479 * value capacity {@link #getValueCapacity()}.
481 * @param index position of element
482 * @param holder data holder for value of element
484 public void setSafe(int index
, Decimal256Holder holder
) {
490 * Store the given value at a particular position in the vector. isSet indicates
491 * whether the value is NULL or not.
493 * @param index position of the new value
494 * @param isSet 0 for NULL value, 1 otherwise
495 * @param start start position of the value in the buffer
496 * @param buffer buffer containing the value to be stored in the vector
498 public void set(int index
, int isSet
, long start
, ArrowBuf buffer
) {
500 set(index
, start
, buffer
);
502 BitVectorHelper
.unsetBit(validityBuffer
, index
);
507 * Same as {@link #setSafe(int, int, int, ArrowBuf)} except that it handles
508 * the case when the position of new value is beyond the current value
509 * capacity of the vector.
511 * @param index position of the new value
512 * @param isSet 0 for NULL value, 1 otherwise
513 * @param start start position of the value in the buffer
514 * @param buffer buffer containing the value to be stored in the vector
516 public void setSafe(int index
, int isSet
, long start
, ArrowBuf buffer
) {
518 set(index
, isSet
, start
, buffer
);
521 /*----------------------------------------------------------------*
525 *----------------------------------------------------------------*/
529 * Construct a TransferPair comprising of this and a target vector of
532 * @param ref name of the target vector
533 * @param allocator allocator for the target vector
534 * @return {@link TransferPair}
537 public TransferPair
getTransferPair(String ref
, BufferAllocator allocator
) {
538 return new TransferImpl(ref
, allocator
);
542 * Construct a TransferPair with a desired target vector of the same type.
544 * @param to target vector
545 * @return {@link TransferPair}
548 public TransferPair
makeTransferPair(ValueVector to
) {
549 return new TransferImpl((Decimal256Vector
) to
);
552 private class TransferImpl
implements TransferPair
{
555 public TransferImpl(String ref
, BufferAllocator allocator
) {
556 to
= new Decimal256Vector(ref
, allocator
, Decimal256Vector
.this.precision
,
557 Decimal256Vector
.this.scale
);
560 public TransferImpl(Decimal256Vector to
) {
565 public Decimal256Vector
getTo() {
570 public void transfer() {
575 public void splitAndTransfer(int startIndex
, int length
) {
576 splitAndTransferTo(startIndex
, length
, to
);
580 public void copyValueSafe(int fromIndex
, int toIndex
) {
581 to
.copyFromSafe(fromIndex
, toIndex
, Decimal256Vector
.this);