Skip to content

Commit 073378a

Browse files
vkorukantiyongyanw
authored andcommitted
ARROW-2368: Correctly pad negative values in DecimalVector#setBigEndian
1 parent d6bad11 commit 073378a

File tree

2 files changed

+76
-4
lines changed

2 files changed

+76
-4
lines changed

java/vector/src/main/java/org/apache/arrow/vector/DecimalVector.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,6 @@ public void set(int index, ArrowBuf buffer) {
212212
* @param value array of bytes containing decimal in big endian byte order.
213213
*/
214214
public void setBigEndian(int index, byte[] value) {
215-
assert value.length <= TYPE_WIDTH;
216215
BitVectorHelper.setValidityBitToOne(validityBuffer, index);
217216
final int length = value.length;
218217
int startIndex = index * TYPE_WIDTH;
@@ -224,13 +223,32 @@ public void setBigEndian(int index, byte[] value) {
224223
valueBuffer.setByte(startIndex + 3, value[i-3]);
225224
startIndex += 4;
226225
}
227-
} else {
226+
227+
return;
228+
}
229+
230+
if (length == 0) {
231+
valueBuffer.setZero(startIndex, TYPE_WIDTH);
232+
return;
233+
}
234+
235+
if (length < 16) {
228236
for (int i = length - 1; i >= 0; i--) {
229237
valueBuffer.setByte(startIndex, value[i]);
230238
startIndex++;
231239
}
232-
valueBuffer.setZero(startIndex, TYPE_WIDTH - length);
240+
241+
final byte pad = (byte) (value[0] < 0 ? 0xFF : 0x00);
242+
final int maxStartIndex = (index + 1) * TYPE_WIDTH;
243+
while (startIndex < maxStartIndex) {
244+
valueBuffer.setByte(startIndex, pad);
245+
startIndex++;
246+
}
247+
248+
return;
233249
}
250+
251+
throw new IllegalArgumentException("Invalid decimal value length. Valid length in [1 - 16], got " + length);
234252
}
235253

236254
/**
@@ -468,4 +486,4 @@ public void copyValueSafe(int fromIndex, int toIndex) {
468486
to.copyFromSafe(fromIndex, toIndex, DecimalVector.this);
469487
}
470488
}
471-
}
489+
}

java/vector/src/test/java/org/apache/arrow/vector/TestDecimalVector.java

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import static org.junit.Assert.assertEquals;
2222
import static org.junit.Assert.assertTrue;
23+
import static org.junit.Assert.fail;
2324

2425
import java.math.BigDecimal;
2526
import java.math.BigInteger;
@@ -190,4 +191,57 @@ public void testBigDecimalReadWrite() {
190191
assertEquals(decimal8, decimalVector.getObject(7));
191192
}
192193
}
194+
195+
/**
196+
* Test {@link DecimalVector#setBigEndian(int, byte[])} which takes BE layout input and stores in LE layout.
197+
* Cases to cover: value given in byte array in different lengths in range [1-16] and negative values.
198+
*/
199+
@Test
200+
public void decimalBE2LE() {
201+
try (DecimalVector decimalVector = TestUtils.newVector(DecimalVector.class, "decimal", new ArrowType.Decimal(21, 2), allocator);) {
202+
decimalVector.allocateNew();
203+
204+
BigInteger[] testBigInts = new BigInteger[] {
205+
new BigInteger("0"),
206+
new BigInteger("-1"),
207+
new BigInteger("23"),
208+
new BigInteger("234234"),
209+
new BigInteger("-234234234"),
210+
new BigInteger("234234234234"),
211+
new BigInteger("-56345345345345"),
212+
new BigInteger("29823462983462893462934679234653456345"), // converts to 16 byte array
213+
new BigInteger("-3894572983475982374598324598234346536"), // converts to 16 byte array
214+
new BigInteger("-345345"),
215+
new BigInteger("754533")
216+
};
217+
218+
int insertionIdx = 0;
219+
insertionIdx++; // insert a null
220+
for (BigInteger val : testBigInts) {
221+
decimalVector.setBigEndian(insertionIdx++, val.toByteArray());
222+
}
223+
insertionIdx++; // insert a null
224+
// insert a zero length buffer
225+
decimalVector.setBigEndian(insertionIdx++, new byte[0]);
226+
227+
// Try inserting a buffer larger than 16bytes and expect a failure
228+
try {
229+
decimalVector.setBigEndian(insertionIdx, new byte[17]);
230+
fail("above statement should have failed");
231+
} catch (IllegalArgumentException ex) {
232+
assertTrue(ex.getMessage().equals("Invalid decimal value length. Valid length in [1 - 16], got 17"));
233+
}
234+
decimalVector.setValueCount(insertionIdx);
235+
236+
// retrieve values and check if they are correct
237+
int outputIdx = 0;
238+
assertTrue(decimalVector.isNull(outputIdx++));
239+
for (BigInteger expected : testBigInts) {
240+
final BigDecimal actual = decimalVector.getObject(outputIdx++);
241+
assertEquals(expected, actual.unscaledValue());
242+
}
243+
assertTrue(decimalVector.isNull(outputIdx++));
244+
assertEquals(BigInteger.valueOf(0), decimalVector.getObject(outputIdx).unscaledValue());
245+
}
246+
}
193247
}

0 commit comments

Comments
 (0)