This is an automated email from the ASF dual-hosted git repository.

ravindra pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/master by this push:
     new 0e2a641  ARROW-5860: [Java][Vector] Fix decimal utils to handle 
negative values.
0e2a641 is described below

commit 0e2a641e500f8af394757976ffe5537d458d0ea4
Author: Praveen <prav...@dremio.com>
AuthorDate: Mon Jul 8 11:48:05 2019 +0530

    ARROW-5860: [Java][Vector] Fix decimal utils to handle negative values.
    
    - Padvalue was defaulted to zero
    - This incorrectly writes negative numbers to buffers.
    
    Author: Praveen <prav...@dremio.com>
    
    Closes #4811 from praveenbingo/ARROW-5860 and squashes the following 
commits:
    
    9c529d5d5 <Praveen> ARROW-5860:  Fix decimal utils method to handle 
negative numbers correctly.
---
 .../apache/arrow/vector/util/DecimalUtility.java   |  27 ++----
 .../arrow/vector/util/DecimalUtilityTest.java      | 104 +++++++++++++++++++++
 2 files changed, 113 insertions(+), 18 deletions(-)

diff --git 
a/java/vector/src/main/java/org/apache/arrow/vector/util/DecimalUtility.java 
b/java/vector/src/main/java/org/apache/arrow/vector/util/DecimalUtility.java
index d091152..a9f7a17 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/util/DecimalUtility.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/util/DecimalUtility.java
@@ -31,6 +31,8 @@ public class DecimalUtility {
   private DecimalUtility() {}
 
   public static final int DECIMAL_BYTE_LENGTH = 16;
+  public static final byte [] zeroes = new byte[] 
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+  public static final byte [] minus_one = new byte[] 
{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
 
   /**
    * Read an ArrowType.Decimal at the given value index in the ArrowBuf and 
convert to a BigDecimal
@@ -100,8 +102,7 @@ public class DecimalUtility {
    */
   public static void writeBigDecimalToArrowBuf(BigDecimal value, ArrowBuf 
bytebuf, int index) {
     final byte[] bytes = value.unscaledValue().toByteArray();
-    final int padValue = value.signum() == -1 ? 0xFF : 0;
-    writeByteArrayToArrowBuf(bytes, bytebuf, index, padValue);
+    writeByteArrayToArrowBufHelper(bytes, bytebuf, index);
   }
 
   /**
@@ -120,10 +121,10 @@ public class DecimalUtility {
    * width.
    */
   public static void writeByteArrayToArrowBuf(byte[] bytes, ArrowBuf bytebuf, 
int index) {
-    writeByteArrayToArrowBuf(bytes, bytebuf, index, 0);
+    writeByteArrayToArrowBufHelper(bytes, bytebuf, index);
   }
 
-  private static void writeByteArrayToArrowBuf(byte[] bytes, ArrowBuf bytebuf, 
int index, int padValue) {
+  private static void writeByteArrayToArrowBufHelper(byte[] bytes, ArrowBuf 
bytebuf, int index) {
     final int startIndex = index * DECIMAL_BYTE_LENGTH;
     if (bytes.length > DECIMAL_BYTE_LENGTH) {
       throw new UnsupportedOperationException("Decimal size greater than 16 
bytes");
@@ -131,23 +132,13 @@ public class DecimalUtility {
 
     // Decimal stored as little endian, need to swap data bytes before writing 
to ArrowBuf
     byte[] bytesLE = new byte[bytes.length];
-    int stop = bytes.length / 2;
-    for (int i = 0, j; i < stop; i++) {
-      j = (bytes.length - 1) - i;
-      bytesLE[i] = bytes[j];
-      bytesLE[j] = bytes[i];
-    }
-    if (bytes.length % 2 != 0) {
-      int i = (bytes.length / 2);
-      bytesLE[i] = bytes[i];
+    for (int i = 0; i < bytes.length; i++) {
+      bytesLE[i] = bytes[bytes.length - 1 - i];
     }
 
     // Write LE data
+    byte [] padByes = bytes[0] < 0 ? minus_one : zeroes;
     bytebuf.setBytes(startIndex, bytesLE, 0, bytes.length);
-
-    // Write padding after data
-    for (int i = bytes.length; i < DECIMAL_BYTE_LENGTH; i++) {
-      bytebuf.setByte(startIndex + i, padValue);
-    }
+    bytebuf.setBytes(startIndex + bytes.length, padByes, 0, 
DECIMAL_BYTE_LENGTH - bytes.length);
   }
 }
diff --git 
a/java/vector/src/test/java/org/apache/arrow/vector/util/DecimalUtilityTest.java
 
b/java/vector/src/test/java/org/apache/arrow/vector/util/DecimalUtilityTest.java
new file mode 100644
index 0000000..1840b4e
--- /dev/null
+++ 
b/java/vector/src/test/java/org/apache/arrow/vector/util/DecimalUtilityTest.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.arrow.vector.util;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import org.apache.arrow.memory.BufferAllocator;
+import org.apache.arrow.memory.RootAllocator;
+import org.junit.Assert;
+import org.junit.Test;
+
+import io.netty.buffer.ArrowBuf;
+
+public class DecimalUtilityTest {
+  private static final BigInteger MAX_BIG_INT = 
java.math.BigInteger.valueOf(10).pow(38)
+          .subtract(java.math.BigInteger.ONE);
+  private static final BigDecimal MAX_DECIMAL = new 
java.math.BigDecimal(MAX_BIG_INT, 0);
+  private static final BigInteger MIN_BIG_INT = 
MAX_BIG_INT.multiply(BigInteger.valueOf(-1));
+  private static final BigDecimal MIN_DECIMAL = new 
java.math.BigDecimal(MIN_BIG_INT, 0);
+
+  @Test
+  public void testSetByteArrayInDecimalArrowBuf() {
+    try (BufferAllocator allocator = new RootAllocator(128);
+         ArrowBuf buf = allocator.buffer(16);
+    ) {
+      int [] intValues = new int [] {Integer.MAX_VALUE, Integer.MIN_VALUE, 0};
+      for (int val : intValues) {
+        buf.clear();
+        
DecimalUtility.writeByteArrayToArrowBuf(BigInteger.valueOf(val).toByteArray(), 
buf, 0);
+        BigDecimal actual = DecimalUtility.getBigDecimalFromArrowBuf(buf, 0, 
0);
+        BigDecimal expected = BigDecimal.valueOf(val);
+        Assert.assertEquals(expected, actual);
+      }
+
+      long [] longValues = new long[] {Long.MIN_VALUE, 0 , Long.MAX_VALUE};
+      for (long val : longValues) {
+        buf.clear();
+        
DecimalUtility.writeByteArrayToArrowBuf(BigInteger.valueOf(val).toByteArray(), 
buf, 0);
+        BigDecimal actual = DecimalUtility.getBigDecimalFromArrowBuf(buf, 0, 
0);
+        BigDecimal expected = BigDecimal.valueOf(val);
+        Assert.assertEquals(expected, actual);
+      }
+
+      BigInteger [] decimals = new BigInteger[] {MAX_BIG_INT, new 
BigInteger("0"), MIN_BIG_INT};
+      for (BigInteger val : decimals) {
+        buf.clear();
+        DecimalUtility.writeByteArrayToArrowBuf(val.toByteArray(), buf, 0);
+        BigDecimal actual = DecimalUtility.getBigDecimalFromArrowBuf(buf, 0, 
0);
+        BigDecimal expected = new BigDecimal(val);
+        Assert.assertEquals(expected, actual);
+      }
+    }
+  }
+
+  @Test
+  public void testSetBigDecimalInDecimalArrowBuf() {
+    try (BufferAllocator allocator = new RootAllocator(128);
+         ArrowBuf buf = allocator.buffer(16);
+    ) {
+      int [] intValues = new int [] {Integer.MAX_VALUE, Integer.MIN_VALUE, 0};
+      for (int val : intValues) {
+        buf.clear();
+        DecimalUtility.writeBigDecimalToArrowBuf(BigDecimal.valueOf(val), buf, 
0);
+        BigDecimal actual = DecimalUtility.getBigDecimalFromArrowBuf(buf, 0, 
0);
+        BigDecimal expected = BigDecimal.valueOf(val);
+        Assert.assertEquals(expected, actual);
+      }
+
+      long [] longValues = new long[] {Long.MIN_VALUE, 0 , Long.MAX_VALUE};
+      for (long val : longValues) {
+        buf.clear();
+        DecimalUtility.writeBigDecimalToArrowBuf(BigDecimal.valueOf(val), buf, 
0);
+        BigDecimal actual = DecimalUtility.getBigDecimalFromArrowBuf(buf, 0, 
0);
+        BigDecimal expected = BigDecimal.valueOf(val);
+        Assert.assertEquals(expected, actual);
+      }
+
+      BigInteger [] decimals = new BigInteger[] {MAX_BIG_INT, new 
BigInteger("0"), MIN_BIG_INT};
+      for (BigInteger val : decimals) {
+        buf.clear();
+        DecimalUtility.writeBigDecimalToArrowBuf(new BigDecimal(val), buf, 0);
+        BigDecimal actual = DecimalUtility.getBigDecimalFromArrowBuf(buf, 0, 
0);
+        BigDecimal expected = new BigDecimal(val);
+        Assert.assertEquals(expected, actual);
+      }
+    }
+  }
+}

Reply via email to