diff --git common/src/java/org/apache/hadoop/hive/common/type/Decimal128.java common/src/java/org/apache/hadoop/hive/common/type/Decimal128.java
index fa7a257..f5ec972 100644
--- common/src/java/org/apache/hadoop/hive/common/type/Decimal128.java
+++ common/src/java/org/apache/hadoop/hive/common/type/Decimal128.java
@@ -1575,23 +1575,58 @@ public int hashCode() {
*/
@Override
public long longValue() {
+
+ // Avoid allocating temporary variables for special cases: signum or scale is zero
if (signum == 0) {
return 0L;
}
-
- long ret;
- UnsignedInt128 tmp;
if (scale == 0) {
+ long ret;
ret = this.unscaledValue.getV1();
ret <<= 32L;
ret |= SqlMathUtil.LONG_MASK & this.unscaledValue.getV0();
+ if (signum >= 0) {
+ return ret;
+ } else {
+ return -ret;
+ }
} else {
- tmp = new UnsignedInt128(this.unscaledValue);
- tmp.scaleDownTenDestructive(scale);
- ret = tmp.getV1();
- ret <<= 32L;
- ret |= SqlMathUtil.LONG_MASK & tmp.getV0();
+ Decimal128 dec = new Decimal128(this);
+ UnsignedInt128 scratch = new UnsignedInt128(this.unscaledValue);
+ return dec.longValueDestructive(scratch);
+ }
+ }
+
+ /**
+ * Converts this {@code Decimal128} to a {@code long}. This conversion is
+ * analogous to the narrowing primitive conversion from {@code double}
+ * to {@code short} as defined in section 5.1.3 of The Java™
+ * Language Specification: any fractional part of this
+ * {@code Decimal128} will be discarded, and if the resulting "
+ * {@code UnsignedInt128}" is too big to fit in a {@code long}, only the
+ * low-order 64 bits are returned. Note that this conversion can lose
+ * information about the overall magnitude and precision of this
+ * {@code Decimal128} value.
+ *
+ * @return this {@code Decimal128} converted to a {@code long}.
+ */
+ public long longValueDestructive(UnsignedInt128 scratchUnsignedInt128) {
+ if (signum == 0) {
+ return 0L;
+ }
+
+ long ret;
+ if (scale > 0) {
+ /*
+ * Divide by a power of 10 equal to 10**scale to logically shift the digits
+ * places right by "scale" positions to discard them.
+ */
+ UnsignedInt128 powerTenDivisor = SqlMathUtil.POWER_TENS_INT128[scale];
+ this.getUnscaledValue().divideDestructive(powerTenDivisor, scratchUnsignedInt128);
}
+ ret = this.unscaledValue.getV1();
+ ret <<= 32L;
+ ret |= SqlMathUtil.LONG_MASK & this.unscaledValue.getV0();
if (signum >= 0) {
return ret;
diff --git common/src/test/org/apache/hadoop/hive/common/type/TestDecimal128.java common/src/test/org/apache/hadoop/hive/common/type/TestDecimal128.java
index 426c03d..91bb8b5 100644
--- common/src/test/org/apache/hadoop/hive/common/type/TestDecimal128.java
+++ common/src/test/org/apache/hadoop/hive/common/type/TestDecimal128.java
@@ -786,5 +786,11 @@ public void testToLong() {
assertEquals(4294967295L, d.longValue());
d.update("4294967296.01", (short) 2); // 2^32 + .01
assertEquals(4294967296L, d.longValue());
+
+ // Compare long value with HiveDecimal#longValue
+ d.update(37.678, (short)5);
+ HiveDecimal hd = HiveDecimal.create(BigDecimal.valueOf(37.678));
+ assertEquals(hd.longValue(), d.longValue());
}
+
}
diff --git ql/src/java/org/apache/hadoop/hive/ql/exec/vector/expressions/CastDecimalToLong.java ql/src/java/org/apache/hadoop/hive/ql/exec/vector/expressions/CastDecimalToLong.java
index d5f34d5..d591dcc 100644
--- ql/src/java/org/apache/hadoop/hive/ql/exec/vector/expressions/CastDecimalToLong.java
+++ ql/src/java/org/apache/hadoop/hive/ql/exec/vector/expressions/CastDecimalToLong.java
@@ -18,6 +18,8 @@
package org.apache.hadoop.hive.ql.exec.vector.expressions;
+import org.apache.hadoop.hive.common.type.Decimal128;
+import org.apache.hadoop.hive.common.type.UnsignedInt128;
import org.apache.hadoop.hive.ql.exec.vector.DecimalColumnVector;
import org.apache.hadoop.hive.ql.exec.vector.LongColumnVector;
@@ -27,6 +29,9 @@
public class CastDecimalToLong extends FuncDecimalToLong {
private static final long serialVersionUID = 1L;
+ private Decimal128 scratchDecimal = new Decimal128();
+ private UnsignedInt128 scratchUnsigned = new UnsignedInt128();
+
public CastDecimalToLong() {
super();
}
@@ -37,6 +42,7 @@ public CastDecimalToLong(int inputColumn, int outputColumn) {
@Override
protected void func(LongColumnVector outV, DecimalColumnVector inV, int i) {
- outV.vector[i] = inV.vector[i].longValue();
+ scratchDecimal.update(inV.vector[i]);
+ outV.vector[i] = scratchDecimal.longValueDestructive(scratchUnsigned);
}
}
diff --git ql/src/java/org/apache/hadoop/hive/ql/exec/vector/expressions/CastDecimalToTimestamp.java ql/src/java/org/apache/hadoop/hive/ql/exec/vector/expressions/CastDecimalToTimestamp.java
index df7e1ee..0a4e9b5 100644
--- ql/src/java/org/apache/hadoop/hive/ql/exec/vector/expressions/CastDecimalToTimestamp.java
+++ ql/src/java/org/apache/hadoop/hive/ql/exec/vector/expressions/CastDecimalToTimestamp.java
@@ -20,6 +20,7 @@
import org.apache.hadoop.hive.common.type.Decimal128;
import org.apache.hadoop.hive.common.type.SqlMathUtil;
+import org.apache.hadoop.hive.common.type.UnsignedInt128;
import org.apache.hadoop.hive.ql.exec.vector.DecimalColumnVector;
import org.apache.hadoop.hive.ql.exec.vector.LongColumnVector;
@@ -37,6 +38,7 @@
* its own copy of the variable.
*/
private transient Decimal128 tmp = null;
+ private transient UnsignedInt128 scratcUint128 = new UnsignedInt128();
private static transient Decimal128 tenE9 = new Decimal128(1000000000);
public CastDecimalToTimestamp(int inputColumn, int outputColumn) {
@@ -56,6 +58,6 @@ protected void func(LongColumnVector outV, DecimalColumnVector inV, int i) {
tmp.multiplyDestructive(tenE9, (short) 0);
// set output
- outV.vector[i] = tmp.longValue();
+ outV.vector[i] = tmp.longValueDestructive(scratcUint128);
}
}