Skip to content

Commit a14b263

Browse files
author
vkorukanti
committed
ARROW-2368: Correctly pad negative values in DecimalVector#setBigEndian
1 parent 301fdc6 commit a14b263

2 files changed

Lines changed: 76 additions & 4 deletions

File tree

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

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,6 @@ public void set(int index, ArrowBuf buffer) {
216216
* @param value array of bytes containing decimal in big endian byte order.
217217
*/
218218
public void setBigEndian(int index, byte[] value) {
219-
assert value.length <= TYPE_WIDTH;
220219
BitVectorHelper.setValidityBitToOne(validityBuffer, index);
221220
final int length = value.length;
222221
int startIndex = index * TYPE_WIDTH;
@@ -228,13 +227,32 @@ public void setBigEndian(int index, byte[] value) {
228227
valueBuffer.setByte(startIndex + 3, value[i-3]);
229228
startIndex += 4;
230229
}
231-
} else {
230+
231+
return;
232+
}
233+
234+
if (length == 0) {
235+
valueBuffer.setZero(startIndex, TYPE_WIDTH);
236+
return;
237+
}
238+
239+
if (length < 16) {
232240
for (int i = length - 1; i >= 0; i--) {
233241
valueBuffer.setByte(startIndex, value[i]);
234242
startIndex++;
235243
}
236-
valueBuffer.setZero(startIndex, TYPE_WIDTH - length);
244+
245+
final byte pad = (byte) (value[0] < 0 ? 0xFF : 0x00);
246+
final int maxStartIndex = (index + 1) * TYPE_WIDTH;
247+
while (startIndex < maxStartIndex) {
248+
valueBuffer.setByte(startIndex, pad);
249+
startIndex++;
250+
}
251+
252+
return;
237253
}
254+
255+
throw new IllegalArgumentException("Invalid decimal value length. Valid length in [1 - 16], got " + length);
238256
}
239257

240258
/**
@@ -472,4 +490,4 @@ public void copyValueSafe(int fromIndex, int toIndex) {
472490
to.copyFromSafe(fromIndex, toIndex, NullableDecimalVector.this);
473491
}
474492
}
475-
}
493+
}

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;
@@ -111,4 +112,57 @@ public void testBigDecimalDifferentScaleAndPrecision() {
111112
}
112113
}
113114
}
115+
116+
/**
117+
* Test {@link NullableDecimalVector#setBigEndian(int, byte[])} which takes BE layout input and stores in LE layout.
118+
* Cases to cover: value given in byte array in different lengths in range [1-16] and negative values.
119+
*/
120+
@Test
121+
public void decimalBE2LE() {
122+
try (NullableDecimalVector decimalVector = TestUtils.newVector(NullableDecimalVector.class, "decimal", new ArrowType.Decimal(21, 2), allocator);) {
123+
decimalVector.allocateNew();
124+
125+
BigInteger[] testBigInts = new BigInteger[] {
126+
new BigInteger("0"),
127+
new BigInteger("-1"),
128+
new BigInteger("23"),
129+
new BigInteger("234234"),
130+
new BigInteger("-234234234"),
131+
new BigInteger("234234234234"),
132+
new BigInteger("-56345345345345"),
133+
new BigInteger("29823462983462893462934679234653456345"), // converts to 16 byte array
134+
new BigInteger("-3894572983475982374598324598234346536"), // converts to 16 byte array
135+
new BigInteger("-345345"),
136+
new BigInteger("754533")
137+
};
138+
139+
int insertionIdx = 0;
140+
insertionIdx++; // insert a null
141+
for (BigInteger val : testBigInts) {
142+
decimalVector.setBigEndian(insertionIdx++, val.toByteArray());
143+
}
144+
insertionIdx++; // insert a null
145+
// insert a zero length buffer
146+
decimalVector.setBigEndian(insertionIdx++, new byte[0]);
147+
148+
// Try inserting a buffer larger than 16bytes and expect a failure
149+
try {
150+
decimalVector.setBigEndian(insertionIdx, new byte[17]);
151+
fail("above statement should have failed");
152+
} catch (IllegalArgumentException ex) {
153+
assertTrue(ex.getMessage().equals("Invalid decimal value length. Valid length in [1 - 16], got 17"));
154+
}
155+
decimalVector.setValueCount(insertionIdx);
156+
157+
// retrieve values and check if they are correct
158+
int outputIdx = 0;
159+
assertTrue(decimalVector.isNull(outputIdx++));
160+
for (BigInteger expected : testBigInts) {
161+
final BigDecimal actual = decimalVector.getObject(outputIdx++);
162+
assertEquals(expected, actual.unscaledValue());
163+
}
164+
assertTrue(decimalVector.isNull(outputIdx++));
165+
assertEquals(BigInteger.valueOf(0), decimalVector.getObject(outputIdx).unscaledValue());
166+
}
167+
}
114168
}

0 commit comments

Comments
 (0)