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)