ASTERIXDB-1166: Fix numeric overflow guarding
This should stop the issues with numerics acting funny.
Instead of reinventing the wheel here and trying to detect when an overflow may happen,
I opted to use the new methods in Java 8 that are intended to guard against overflow
where it's not desired.
Also, fix the docker image to use Java 8.
Change-Id: I520b22861a76346caca646122bc736e66c8d8b1f
Reviewed-on: https://asterix-gerrit.ics.uci.edu/478
Reviewed-by: Cameron Samak <csamak@apache.org>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Till Westmann <tillw@apache.org>
diff --git a/asterix-app/src/test/resources/runtimets/queries/numeric/issue_1166/issue_1166.1.query.aql b/asterix-app/src/test/resources/runtimets/queries/numeric/issue_1166/issue_1166.1.query.aql
new file mode 100644
index 0000000..bd73cce
--- /dev/null
+++ b/asterix-app/src/test/resources/runtimets/queries/numeric/issue_1166/issue_1166.1.query.aql
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+(-0.999 * 5)
+(-1.001 * 5)
+(-1 * 5)
diff --git a/asterix-app/src/test/resources/runtimets/results/numeric/issue_1166/issue_1166.1.adm b/asterix-app/src/test/resources/runtimets/results/numeric/issue_1166/issue_1166.1.adm
new file mode 100644
index 0000000..06a5b6d
--- /dev/null
+++ b/asterix-app/src/test/resources/runtimets/results/numeric/issue_1166/issue_1166.1.adm
@@ -0,0 +1,3 @@
+-4.995d
+-5.004999999999999d
+-5
diff --git a/asterix-app/src/test/resources/runtimets/testsuite.xml b/asterix-app/src/test/resources/runtimets/testsuite.xml
index 563163b..4d35ac0 100644
--- a/asterix-app/src/test/resources/runtimets/testsuite.xml
+++ b/asterix-app/src/test/resources/runtimets/testsuite.xml
@@ -3887,6 +3887,11 @@
</compilation-unit>
</test-case>
<test-case FilePath="numeric">
+ <compilation-unit name="issue_1166">
+ <output-dir compare="Text">issue_1166</output-dir>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="numeric">
<compilation-unit name="multiply_int8">
<output-dir compare="Text">multiply_int8</output-dir>
</compilation-unit>
diff --git a/asterix-docker/docker/Dockerfile b/asterix-docker/docker/Dockerfile
index 9303bce..4e11474 100644
--- a/asterix-docker/docker/Dockerfile
+++ b/asterix-docker/docker/Dockerfile
@@ -21,7 +21,7 @@
RUN echo 'LANG="en_US.UTF-8"' > /etc/sysconfig/i18n ;echo 'ZONE="America/Los_Angeles"' > /etc/sysconfig/clock ;cp -a /usr/share/zoneinfo/America/Los_Angeles /etc/localtime
RUN echo "include_only=.us" >> /etc/yum/pluginconf.d/fastestmirror.conf
-RUN yum install -y unzip java-1.7.0-openjdk openssh-server openssh-clients python-setuptools wget curl
+RUN yum install -y unzip java-1.8.0-openjdk openssh-server openssh-clients python-setuptools wget curl
RUN easy_install supervisor
RUN mkdir /asterixdb
COPY asterix-server*.zip .
@@ -34,7 +34,7 @@
COPY fbm.adm /asterixdb/fbm.adm
WORKDIR /asterixdb/bin
-ENV JAVA_HOME /usr/lib/jvm/jre-1.7.0
+ENV JAVA_HOME /usr/lib/jvm/jre-1.8.0
ENV JAVA_OPTS -Xmx1536m
EXPOSE 19001 19002 8888 19003 50031
diff --git a/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/NumericAddDescriptor.java b/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/NumericAddDescriptor.java
index 226dd8d..265f68e 100644
--- a/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/NumericAddDescriptor.java
+++ b/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/NumericAddDescriptor.java
@@ -24,6 +24,7 @@
import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
import org.apache.hyracks.api.exceptions.HyracksDataException;
+import java.lang.Math;
public class NumericAddDescriptor extends AbstractNumericArithmeticEval {
@@ -41,13 +42,7 @@
@Override
protected long evaluateInteger(long x, long y) throws HyracksDataException {
- long z = x + y;
- if (x > 0) {
- if (y > 0 && z < 0)
- throw new ArithmeticException("Overflow adding " + x + " + " + y);
- } else if (y < 0 && z > 0)
- throw new ArithmeticException("Underflow adding " + x + " + " + y);
- return z;
+ return Math.addExact(x, y);
}
@Override
diff --git a/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/NumericCaretDescriptor.java b/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/NumericCaretDescriptor.java
index 2412ddc..60f1233 100644
--- a/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/NumericCaretDescriptor.java
+++ b/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/NumericCaretDescriptor.java
@@ -18,6 +18,7 @@
*/
package org.apache.asterix.runtime.evaluators.functions;
+import com.google.common.math.LongMath;
import org.apache.asterix.om.functions.AsterixBuiltinFunctions;
import org.apache.asterix.om.functions.IFunctionDescriptor;
import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
@@ -40,14 +41,10 @@
*/
@Override
protected long evaluateInteger(long lhs, long rhs) throws HyracksDataException {
- double result = Math.pow(lhs, rhs);
- if (result > Long.MAX_VALUE) {
- throw new ArithmeticException("Overflow of caret operation: " + lhs + " ^ " + rhs);
+ if(rhs > Integer.MAX_VALUE){
+ throw new ArithmeticException("Exponent cannot be larger than 2^31-1");
}
- if (result < Long.MIN_VALUE) {
- throw new ArithmeticException("Underflow of caret operation: " + lhs + " ^ " + rhs);
- }
- return (long) result;
+ return LongMath.checkedPow(lhs, (int) rhs);
}
/* (non-Javadoc)
diff --git a/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/NumericDivideDescriptor.java b/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/NumericDivideDescriptor.java
index b4265c7..1c5cb9c 100644
--- a/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/NumericDivideDescriptor.java
+++ b/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/NumericDivideDescriptor.java
@@ -41,8 +41,12 @@
@Override
protected long evaluateInteger(long lhs, long rhs) throws HyracksDataException {
- if (rhs == 0)
- throw new HyracksDataException("Divide by Zero.");
+ if (rhs == 0) {
+ throw new ArithmeticException("Division by Zero.");
+ }
+ if ( (lhs == Long.MIN_VALUE) && (rhs == -1L) ) {
+ throw new ArithmeticException(("Overflow in integer division"));
+ }
return lhs / rhs;
}
diff --git a/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/NumericMultiplyDescriptor.java b/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/NumericMultiplyDescriptor.java
index 4bb29e7..c3f6580 100644
--- a/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/NumericMultiplyDescriptor.java
+++ b/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/NumericMultiplyDescriptor.java
@@ -24,6 +24,7 @@
import org.apache.hyracks.algebricks.common.exceptions.NotImplementedException;
import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
import org.apache.hyracks.api.exceptions.HyracksDataException;
+import java.lang.Math;
public class NumericMultiplyDescriptor extends AbstractNumericArithmeticEval {
@@ -41,25 +42,11 @@
@Override
protected long evaluateInteger(long lhs, long rhs) throws HyracksDataException {
- int signLhs = lhs > 0 ? 1 : (lhs < 0 ? -1 : 0);
- int signRhs = rhs > 0 ? 1 : (rhs < 0 ? -1 : 0);
- long maximum = signLhs == signRhs ? Long.MAX_VALUE : Long.MIN_VALUE;
-
- if (lhs != 0 && (rhs > 0 && rhs > maximum / lhs || rhs < 0 && rhs < maximum / lhs))
- throw new HyracksDataException("Overflow Happened.");
-
- return lhs * rhs;
+ return Math.multiplyExact(lhs, rhs);
}
@Override
protected double evaluateDouble(double lhs, double rhs) throws HyracksDataException {
- int signLhs = lhs > 0 ? 1 : (lhs < 0 ? -1 : 0);
- int signRhs = rhs > 0 ? 1 : (rhs < 0 ? -1 : 0);
- double maximum = signLhs == signRhs ? Double.MAX_VALUE : -Double.MAX_VALUE;
-
- if (lhs != 0 && (rhs > 0 && rhs > maximum / lhs || rhs < 0 && rhs < maximum / lhs))
- throw new HyracksDataException("Overflow Happened.");
-
return lhs * rhs;
}
diff --git a/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/NumericSubDescriptor.java b/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/NumericSubDescriptor.java
index 6c67b53..2cb4411 100644
--- a/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/NumericSubDescriptor.java
+++ b/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/NumericSubDescriptor.java
@@ -44,13 +44,7 @@
*/
@Override
protected long evaluateInteger(long lhs, long rhs) throws HyracksDataException {
- long res = lhs - rhs;
- if (lhs > 0) {
- if (rhs < 0 && res < 0)
- throw new HyracksDataException("Overflow adding " + lhs + " + " + rhs);
- } else if (rhs > 0 && res > 0)
- throw new HyracksDataException("Underflow adding " + lhs + " + " + rhs);
- return res;
+ return Math.subtractExact(lhs, rhs);
}
/* (non-Javadoc)