From fe26b88ceeb30b11fd8b0e222a602de504a8f7cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=ED=98=95=EC=A4=80?= Date: Fri, 1 Aug 2014 12:23:19 +0900 Subject: [PATCH] TAJO-979: Dividing float value by zero should throw "Divide by zero Exception" --- .../java/org/apache/tajo/conf/TajoConf.java | 4 +- .../java/org/apache/tajo/datum/Datum.java | 72 ++++ .../org/apache/tajo/datum/Float4Datum.java | 60 ++- .../org/apache/tajo/datum/Float8Datum.java | 78 +++- .../java/org/apache/tajo/datum/Int2Datum.java | 76 +++- .../java/org/apache/tajo/datum/Int4Datum.java | 78 +++- .../java/org/apache/tajo/datum/Int8Datum.java | 78 +++- .../org/apache/tajo/datum/IntervalDatum.java | 16 +- .../tajo/datum/TestArithmeticOperator.java | 377 ++++++++++++++++++ 9 files changed, 748 insertions(+), 91 deletions(-) create mode 100644 tajo-common/src/test/java/org/apache/tajo/datum/TestArithmeticOperator.java diff --git a/tajo-common/src/main/java/org/apache/tajo/conf/TajoConf.java b/tajo-common/src/main/java/org/apache/tajo/conf/TajoConf.java index a8e6d8d126..462e81985c 100644 --- a/tajo-common/src/main/java/org/apache/tajo/conf/TajoConf.java +++ b/tajo-common/src/main/java/org/apache/tajo/conf/TajoConf.java @@ -344,7 +344,9 @@ public static enum ConfVars { TAJO_DEBUG("tajo.debug", false), // ONLY FOR TESTCASE - TESTCASE_MIN_TASK_NUM("tajo.testcase.min.task.num", -1) + TESTCASE_MIN_TASK_NUM("tajo.testcase.min.task.num", -1), + + ABORT_DIVIDE_BY_ZERO("tajo.abort.dividebyzero", false); ; public final String varname; diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/Datum.java b/tajo-common/src/main/java/org/apache/tajo/datum/Datum.java index af88ebed5d..87cc21a796 100644 --- a/tajo-common/src/main/java/org/apache/tajo/datum/Datum.java +++ b/tajo-common/src/main/java/org/apache/tajo/datum/Datum.java @@ -19,6 +19,8 @@ package org.apache.tajo.datum; import com.google.gson.annotations.Expose; +import org.apache.tajo.conf.TajoConf; +import org.apache.tajo.conf.TajoConf.ConfVars; import org.apache.tajo.exception.InvalidCastException; import org.apache.tajo.exception.InvalidOperationException; import org.apache.tajo.json.CommonGsonHelper; @@ -27,6 +29,12 @@ import static org.apache.tajo.common.TajoDataTypes.Type; public abstract class Datum implements Comparable, GsonObject { + static boolean abortWhenDivideByZero; + + static { + initAbortWhenDivideByZero(new TajoConf()); + } + @Expose private final Type type; public Datum(Type type) { @@ -105,6 +113,10 @@ public boolean isReal() { this.type == Type.FLOAT8; } + protected static void initAbortWhenDivideByZero(TajoConf tajoConf) { + abortWhenDivideByZero = tajoConf.getBoolVar(ConfVars.ABORT_DIVIDE_BY_ZERO); + } + public abstract int size(); public Datum and(Datum datum) { @@ -190,4 +202,64 @@ public String toJson() { public String toString() { return asChars(); } + + protected boolean validateDivideZero(short value) { + if (value == (short)0) { + if (abortWhenDivideByZero) { + throw new ArithmeticException("/ by zero"); + } else { + return false; + } + } else { + return true; + } + } + + protected boolean validateDivideZero(int value) { + if (value == 0) { + if (abortWhenDivideByZero) { + throw new ArithmeticException("/ by zero"); + } else { + return false; + } + } else { + return true; + } + } + + protected boolean validateDivideZero(long value) { + if (value == 0L) { + if (abortWhenDivideByZero) { + throw new ArithmeticException("/ by zero"); + } else { + return false; + } + } else { + return true; + } + } + + protected boolean validateDivideZero(float value) { + if (value == 0.0f) { + if (abortWhenDivideByZero) { + throw new ArithmeticException("/ by zero"); + } else { + return false; + } + } else { + return true; + } + } + + protected boolean validateDivideZero(double value) { + if (value == 0.0) { + if (abortWhenDivideByZero) { + throw new ArithmeticException("/ by zero"); + } else { + return false; + } + } else { + return true; + } + } } \ No newline at end of file diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/Float4Datum.java b/tajo-common/src/main/java/org/apache/tajo/datum/Float4Datum.java index 610ea9571b..8b16528a65 100644 --- a/tajo-common/src/main/java/org/apache/tajo/datum/Float4Datum.java +++ b/tajo-common/src/main/java/org/apache/tajo/datum/Float4Datum.java @@ -277,15 +277,35 @@ public Datum multiply(Datum datum) { public Datum divide(Datum datum) { switch (datum.type()) { case INT2: - return DatumFactory.createFloat4(val / datum.asInt2()); + short paramValueI2 = datum.asInt2(); + if (!validateDivideZero(paramValueI2)) { + return NullDatum.get(); + } + return DatumFactory.createFloat4(val / paramValueI2); case INT4: - return DatumFactory.createFloat4(val / datum.asInt4()); + int paramValueI4 = datum.asInt4(); + if (!validateDivideZero(paramValueI4)) { + return NullDatum.get(); + } + return DatumFactory.createFloat4(val / paramValueI4); case INT8: - return DatumFactory.createFloat4(val / datum.asInt8()); + long paramValueI8 = datum.asInt8(); + if (!validateDivideZero(paramValueI8)) { + return NullDatum.get(); + } + return DatumFactory.createFloat4(val / paramValueI8); case FLOAT4: - return DatumFactory.createFloat4(val / datum.asFloat4()); + float paramValueF4 = datum.asFloat4(); + if (!validateDivideZero(paramValueF4)) { + return NullDatum.get(); + } + return DatumFactory.createFloat4(val / paramValueF4); case FLOAT8: - return DatumFactory.createFloat8(val / datum.asFloat8()); + double paramValueF8 = datum.asFloat8(); + if (!validateDivideZero(paramValueF8)) { + return NullDatum.get(); + } + return DatumFactory.createFloat8(val / paramValueF8); case NULL_TYPE: return datum; default: @@ -297,15 +317,35 @@ public Datum divide(Datum datum) { public Datum modular(Datum datum) { switch (datum.type()) { case INT2: - return DatumFactory.createFloat4(val % datum.asInt2()); + short paramValueI2 = datum.asInt2(); + if (!validateDivideZero(paramValueI2)) { + return NullDatum.get(); + } + return DatumFactory.createFloat4(val % paramValueI2); case INT4: - return DatumFactory.createFloat4(val % datum.asInt4()); + int paramValueI4 = datum.asInt4(); + if (!validateDivideZero(paramValueI4)) { + return NullDatum.get(); + } + return DatumFactory.createFloat4(val % paramValueI4); case INT8: - return DatumFactory.createFloat4(val % datum.asInt8()); + long paramValueI8 = datum.asInt8(); + if (!validateDivideZero(paramValueI8)) { + return NullDatum.get(); + } + return DatumFactory.createFloat4(val % paramValueI8); case FLOAT4: - return DatumFactory.createFloat4(val % datum.asFloat4()); + float paramValueF4 = datum.asFloat4(); + if (!validateDivideZero(paramValueF4)) { + return NullDatum.get(); + } + return DatumFactory.createFloat4(val % paramValueF4); case FLOAT8: - return DatumFactory.createFloat8(val % datum.asFloat8()); + double paramValueF8 = datum.asFloat8(); + if (!validateDivideZero(paramValueF8)) { + return NullDatum.get(); + } + return DatumFactory.createFloat8(val % paramValueF8); case NULL_TYPE: return datum; default: diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/Float8Datum.java b/tajo-common/src/main/java/org/apache/tajo/datum/Float8Datum.java index 90adcc724a..d41af2d73e 100644 --- a/tajo-common/src/main/java/org/apache/tajo/datum/Float8Datum.java +++ b/tajo-common/src/main/java/org/apache/tajo/datum/Float8Datum.java @@ -265,20 +265,40 @@ public Datum multiply(Datum datum) { @Override public Datum divide(Datum datum) { switch (datum.type()) { - case INT2: - return DatumFactory.createFloat8(val / datum.asInt2()); - case INT4: - return DatumFactory.createFloat8(val / datum.asInt4()); - case INT8: - return DatumFactory.createFloat8(val / datum.asInt8()); - case FLOAT4: - return DatumFactory.createFloat8(val / datum.asFloat4()); - case FLOAT8: - return DatumFactory.createFloat8(val / datum.asFloat8()); - case NULL_TYPE: - return datum; - default: - throw new InvalidOperationException(datum.type()); + case INT2: + short paramValueI2 = datum.asInt2(); + if (!validateDivideZero(paramValueI2)) { + return NullDatum.get(); + } + return DatumFactory.createFloat8(val / paramValueI2); + case INT4: + int paramValueI4 = datum.asInt4(); + if (!validateDivideZero(paramValueI4)) { + return NullDatum.get(); + } + return DatumFactory.createFloat8(val / paramValueI4); + case INT8: + long paramValueI8 = datum.asInt8(); + if (!validateDivideZero(paramValueI8)) { + return NullDatum.get(); + } + return DatumFactory.createFloat8(val / paramValueI8); + case FLOAT4: + float paramValueF4 = datum.asFloat4(); + if (!validateDivideZero(paramValueF4)) { + return NullDatum.get(); + } + return DatumFactory.createFloat8(val / paramValueF4); + case FLOAT8: + double paramValueF8 = datum.asFloat8(); + if (!validateDivideZero(paramValueF8)) { + return NullDatum.get(); + } + return DatumFactory.createFloat8(val / paramValueF8); + case NULL_TYPE: + return datum; + default: + throw new InvalidOperationException(datum.type()); } } @@ -286,15 +306,35 @@ public Datum divide(Datum datum) { public Datum modular(Datum datum) { switch (datum.type()) { case INT2: - return DatumFactory.createFloat8(val % datum.asInt2()); + short paramValueI2 = datum.asInt2(); + if (!validateDivideZero(paramValueI2)) { + return NullDatum.get(); + } + return DatumFactory.createFloat8(val % paramValueI2); case INT4: - return DatumFactory.createFloat8(val % datum.asInt4()); + int paramValueI4 = datum.asInt4(); + if (!validateDivideZero(paramValueI4)) { + return NullDatum.get(); + } + return DatumFactory.createFloat8(val % paramValueI4); case INT8: - return DatumFactory.createFloat8(val % datum.asInt8()); + long paramValueI8 = datum.asInt8(); + if (!validateDivideZero(paramValueI8)) { + return NullDatum.get(); + } + return DatumFactory.createFloat8(val % paramValueI8); case FLOAT4: - return DatumFactory.createFloat8(val % datum.asFloat4()); + float paramValueF4 = datum.asFloat4(); + if (!validateDivideZero(paramValueF4)) { + return NullDatum.get(); + } + return DatumFactory.createFloat8(val % paramValueF4); case FLOAT8: - return DatumFactory.createFloat8(val % datum.asFloat8()); + double paramValueF8 = datum.asFloat8(); + if (!validateDivideZero(paramValueF8)) { + return NullDatum.get(); + } + return DatumFactory.createFloat8(val % paramValueF8); case NULL_TYPE: return datum; default: diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/Int2Datum.java b/tajo-common/src/main/java/org/apache/tajo/datum/Int2Datum.java index ab17bdc421..2a6c691cbf 100644 --- a/tajo-common/src/main/java/org/apache/tajo/datum/Int2Datum.java +++ b/tajo-common/src/main/java/org/apache/tajo/datum/Int2Datum.java @@ -267,20 +267,40 @@ public Datum multiply(Datum datum) { @Override public Datum divide(Datum datum) { switch (datum.type()) { - case INT2: - return DatumFactory.createInt2((short) (val / datum.asInt2())); - case INT4: - return DatumFactory.createInt4(val / datum.asInt4()); - case INT8: - return DatumFactory.createInt8(val / datum.asInt8()); - case FLOAT4: - return DatumFactory.createFloat4(val / datum.asFloat4()); - case FLOAT8: - return DatumFactory.createFloat8(val / datum.asFloat8()); - case NULL_TYPE: - return datum; - default: - throw new InvalidOperationException(datum.type()); + case INT2: + short paramValueI2 = datum.asInt2(); + if (!validateDivideZero(paramValueI2)) { + return NullDatum.get(); + } + return DatumFactory.createInt2((short) (val / paramValueI2)); + case INT4: + int paramValueI4 = datum.asInt4(); + if (!validateDivideZero(paramValueI4)) { + return NullDatum.get(); + } + return DatumFactory.createInt4(val / paramValueI4); + case INT8: + long paramValueI8 = datum.asInt8(); + if (!validateDivideZero(paramValueI8)) { + return NullDatum.get(); + } + return DatumFactory.createInt8(val / paramValueI8); + case FLOAT4: + float paramValueF4 = datum.asFloat4(); + if (!validateDivideZero(paramValueF4)) { + return NullDatum.get(); + } + return DatumFactory.createFloat4(val / paramValueF4); + case FLOAT8: + double paramValueF8 = datum.asFloat8(); + if (!validateDivideZero(paramValueF8)) { + return NullDatum.get(); + } + return DatumFactory.createFloat8(val / paramValueF8); + case NULL_TYPE: + return datum; + default: + throw new InvalidOperationException(datum.type()); } } @@ -288,14 +308,34 @@ public Datum divide(Datum datum) { public Datum modular(Datum datum) { switch (datum.type()) { case INT2: - return DatumFactory.createInt2((short) (val % datum.asInt2())); + short paramValueI2 = datum.asInt2(); + if (!validateDivideZero(paramValueI2)) { + return NullDatum.get(); + } + return DatumFactory.createInt2((short) (val % paramValueI2)); case INT4: - return DatumFactory.createInt4(val % datum.asInt4()); + int paramValueI4 = datum.asInt4(); + if (!validateDivideZero(paramValueI4)) { + return NullDatum.get(); + } + return DatumFactory.createInt4(val % paramValueI4); case INT8: - return DatumFactory.createInt8(val % datum.asInt8()); + long paramValueI8 = datum.asInt8(); + if (!validateDivideZero(paramValueI8)) { + return NullDatum.get(); + } + return DatumFactory.createInt8(val % paramValueI8); case FLOAT4: - return DatumFactory.createFloat4(val % datum.asFloat4()); + float paramValueF4 = datum.asFloat4(); + if (!validateDivideZero(paramValueF4)) { + return NullDatum.get(); + } + return DatumFactory.createFloat4(val % paramValueF4); case FLOAT8: + double paramValueF8 = datum.asFloat8(); + if (!validateDivideZero(paramValueF8)) { + return NullDatum.get(); + } return DatumFactory.createFloat8(val % datum.asFloat8()); case NULL_TYPE: return datum; diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/Int4Datum.java b/tajo-common/src/main/java/org/apache/tajo/datum/Int4Datum.java index 9a60863598..26201fbe7f 100644 --- a/tajo-common/src/main/java/org/apache/tajo/datum/Int4Datum.java +++ b/tajo-common/src/main/java/org/apache/tajo/datum/Int4Datum.java @@ -271,20 +271,40 @@ public Datum multiply(Datum datum) { @Override public Datum divide(Datum datum) { switch (datum.type()) { - case INT2: - return DatumFactory.createInt4(val / datum.asInt2()); - case INT4: - return DatumFactory.createInt4(val / datum.asInt4()); - case INT8: - return DatumFactory.createInt8(val / datum.asInt8()); - case FLOAT4: - return DatumFactory.createFloat4(val / datum.asFloat4()); - case FLOAT8: - return DatumFactory.createFloat8(val / datum.asFloat8()); - case NULL_TYPE: - return datum; - default: - throw new InvalidOperationException(datum.type()); + case INT2: + short paramValueI2 = datum.asInt2(); + if (!validateDivideZero(paramValueI2)) { + return NullDatum.get(); + } + return DatumFactory.createInt4(val / paramValueI2); + case INT4: + int paramValueI4 = datum.asInt4(); + if (!validateDivideZero(paramValueI4)) { + return NullDatum.get(); + } + return DatumFactory.createInt4(val / paramValueI4); + case INT8: + long paramValueI8 = datum.asInt8(); + if (!validateDivideZero(paramValueI8)) { + return NullDatum.get(); + } + return DatumFactory.createInt8(val / paramValueI8); + case FLOAT4: + float paramValueF4 = datum.asFloat4(); + if (!validateDivideZero(paramValueF4)) { + return NullDatum.get(); + } + return DatumFactory.createFloat4(val / paramValueF4); + case FLOAT8: + double paramValueF8 = datum.asFloat8(); + if (!validateDivideZero(paramValueF8)) { + return NullDatum.get(); + } + return DatumFactory.createFloat8(val / paramValueF8); + case NULL_TYPE: + return datum; + default: + throw new InvalidOperationException(datum.type()); } } @@ -292,15 +312,35 @@ public Datum divide(Datum datum) { public Datum modular(Datum datum) { switch (datum.type()) { case INT2: - return DatumFactory.createInt4(val % datum.asInt2()); + short paramValueI2 = datum.asInt2(); + if (!validateDivideZero(paramValueI2)) { + return NullDatum.get(); + } + return DatumFactory.createInt4(val % paramValueI2); case INT4: - return DatumFactory.createInt4(val % datum.asInt4()); + int paramValueI4 = datum.asInt4(); + if (!validateDivideZero(paramValueI4)) { + return NullDatum.get(); + } + return DatumFactory.createInt4(val % paramValueI4); case INT8: - return DatumFactory.createInt8(val % datum.asInt8()); + long paramValueI8 = datum.asInt8(); + if (!validateDivideZero(paramValueI8)) { + return NullDatum.get(); + } + return DatumFactory.createInt8(val % paramValueI8); case FLOAT4: - return DatumFactory.createFloat4(val % datum.asFloat4()); + float paramValueF4 = datum.asFloat4(); + if (!validateDivideZero(paramValueF4)) { + return NullDatum.get(); + } + return DatumFactory.createFloat4(val % paramValueF4); case FLOAT8: - return DatumFactory.createFloat8(val % datum.asFloat8()); + double paramValueF8 = datum.asFloat8(); + if (!validateDivideZero(paramValueF8)) { + return NullDatum.get(); + } + return DatumFactory.createFloat8(val % paramValueF8); case NULL_TYPE: return datum; default: diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/Int8Datum.java b/tajo-common/src/main/java/org/apache/tajo/datum/Int8Datum.java index db8a12bc06..9fa41d15ef 100644 --- a/tajo-common/src/main/java/org/apache/tajo/datum/Int8Datum.java +++ b/tajo-common/src/main/java/org/apache/tajo/datum/Int8Datum.java @@ -280,20 +280,40 @@ public Datum multiply(Datum datum) { @Override public Datum divide(Datum datum) { switch (datum.type()) { - case INT2: - return DatumFactory.createInt8(val / datum.asInt2()); - case INT4: - return DatumFactory.createInt8(val / datum.asInt4()); - case INT8: - return DatumFactory.createInt8(val / datum.asInt8()); - case FLOAT4: - return DatumFactory.createFloat8(val / datum.asFloat4()); - case FLOAT8: - return DatumFactory.createFloat8(val / datum.asFloat8()); - case NULL_TYPE: - return datum; - default: - throw new InvalidOperationException(datum.type()); + case INT2: + short paramValueI2 = datum.asInt2(); + if (!validateDivideZero(paramValueI2)) { + return NullDatum.get(); + } + return DatumFactory.createInt8(val / paramValueI2); + case INT4: + int paramValueI4 = datum.asInt4(); + if (!validateDivideZero(paramValueI4)) { + return NullDatum.get(); + } + return DatumFactory.createInt8(val / paramValueI4); + case INT8: + long paramValueI8 = datum.asInt8(); + if (!validateDivideZero(paramValueI8)) { + return NullDatum.get(); + } + return DatumFactory.createInt8(val / paramValueI8); + case FLOAT4: + float paramValueF4 = datum.asFloat4(); + if (!validateDivideZero(paramValueF4)) { + return NullDatum.get(); + } + return DatumFactory.createFloat8(val / paramValueF4); + case FLOAT8: + double paramValueF8 = datum.asFloat8(); + if (!validateDivideZero(paramValueF8)) { + return NullDatum.get(); + } + return DatumFactory.createFloat8(val / paramValueF8); + case NULL_TYPE: + return datum; + default: + throw new InvalidOperationException(datum.type()); } } @@ -301,15 +321,35 @@ public Datum divide(Datum datum) { public Datum modular(Datum datum) { switch (datum.type()) { case INT2: - return DatumFactory.createInt8(val % datum.asInt2()); + short paramValueI2 = datum.asInt2(); + if (!validateDivideZero(paramValueI2)) { + return NullDatum.get(); + } + return DatumFactory.createInt8(val % paramValueI2); case INT4: - return DatumFactory.createInt8(val % datum.asInt4()); + int paramValueI4 = datum.asInt4(); + if (!validateDivideZero(paramValueI4)) { + return NullDatum.get(); + } + return DatumFactory.createInt8(val % paramValueI4); case INT8: - return DatumFactory.createInt8(val % datum.asInt8()); + long paramValueI8 = datum.asInt8(); + if (!validateDivideZero(paramValueI8)) { + return NullDatum.get(); + } + return DatumFactory.createInt8(val % paramValueI8); case FLOAT4: - return DatumFactory.createFloat8(val % datum.asFloat4()); + float paramValueF4 = datum.asFloat4(); + if (!validateDivideZero(paramValueF4)) { + return NullDatum.get(); + } + return DatumFactory.createFloat8(val % paramValueF4); case FLOAT8: - return DatumFactory.createFloat8(val % datum.asFloat8()); + double paramValueF8 = datum.asFloat8(); + if (!validateDivideZero(paramValueF8)) { + return NullDatum.get(); + } + return DatumFactory.createFloat8(val % paramValueF8); case NULL_TYPE: return datum; default: diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/IntervalDatum.java b/tajo-common/src/main/java/org/apache/tajo/datum/IntervalDatum.java index 28a0a475ee..c6f3922185 100644 --- a/tajo-common/src/main/java/org/apache/tajo/datum/IntervalDatum.java +++ b/tajo-common/src/main/java/org/apache/tajo/datum/IntervalDatum.java @@ -289,16 +289,22 @@ public Datum multiply(Datum datum) { @Override public Datum divide(Datum datum) { - switch(datum.type()) { + switch (datum.type()) { case INT2: case INT4: case INT8: - long int8Val = datum.asInt8(); - return createIntervalDatum((double)months / int8Val, (double) millieconds / int8Val); + long paramValueI8 = datum.asInt8(); + if (!validateDivideZero(paramValueI8)) { + return NullDatum.get(); + } + return createIntervalDatum((double) months / paramValueI8, (double) millieconds / paramValueI8); case FLOAT4: case FLOAT8: - double float8Val = datum.asFloat8(); - return createIntervalDatum((double)months / float8Val, (double) millieconds / float8Val); + double paramValueF8 = datum.asFloat8(); + if (!validateDivideZero(paramValueF8)) { + return NullDatum.get(); + } + return createIntervalDatum((double) months / paramValueF8, (double) millieconds / paramValueF8); default: throw new InvalidOperationException(datum.type()); } diff --git a/tajo-common/src/test/java/org/apache/tajo/datum/TestArithmeticOperator.java b/tajo-common/src/test/java/org/apache/tajo/datum/TestArithmeticOperator.java new file mode 100644 index 0000000000..95fc1cca48 --- /dev/null +++ b/tajo-common/src/test/java/org/apache/tajo/datum/TestArithmeticOperator.java @@ -0,0 +1,377 @@ +/** + * 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.tajo.datum; + +import org.apache.tajo.conf.TajoConf; +import org.apache.tajo.conf.TajoConf.ConfVars; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import java.util.Arrays; +import java.util.Collection; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +@RunWith(Parameterized.class) +public class TestArithmeticOperator { + String option; + + public TestArithmeticOperator(String option) { + this.option = option; + } + + @Parameters + public static Collection generateParameters() { + return Arrays.asList(new Object[][]{ + {"Zero_Null"}, + {"Zero_Exception"}, + }); + } + + @Before + public void setUp() { + TajoConf tajoConf = new TajoConf(); + if ("Zero_Exception".equals(option)) { + tajoConf.setBoolVar(ConfVars.ABORT_DIVIDE_BY_ZERO, true); + } else { + tajoConf.setBoolVar(ConfVars.ABORT_DIVIDE_BY_ZERO, false); + } + Datum.initAbortWhenDivideByZero(tajoConf); + } + + @Test + public void testInt2Datum() throws Exception { + //plus + runAndAssert("plus", new Int2Datum((short)10), new Int2Datum((short)5), new Int2Datum((short)15)); + runAndAssert("plus", new Int2Datum((short)10), new Int4Datum(5), new Int4Datum(15)); + runAndAssert("plus", new Int2Datum((short)10), new Int8Datum(5), new Int8Datum(15)); + runAndAssert("plus", new Int2Datum((short)10), new Float4Datum(5.0f), new Float4Datum(15.0f)); + runAndAssert("plus", new Int2Datum((short)10), new Float8Datum(5.0), new Float8Datum(15.0)); + + //minus + runAndAssert("minus", new Int2Datum((short)10), new Int2Datum((short)5), new Int2Datum((short)5)); + runAndAssert("minus", new Int2Datum((short)10), new Int4Datum(5), new Int4Datum(5)); + runAndAssert("minus", new Int2Datum((short)10), new Int8Datum(5), new Int8Datum(5)); + runAndAssert("minus", new Int2Datum((short)10), new Float4Datum(5.0f), new Float4Datum(5.0f)); + runAndAssert("minus", new Int2Datum((short)10), new Float8Datum(5.0), new Float8Datum(5.0)); + + runAndAssert("minus", new Int2Datum((short)5), new Int2Datum((short)10), new Int2Datum((short)-5)); + runAndAssert("minus", new Int2Datum((short)5), new Int4Datum(10), new Int4Datum(-5)); + runAndAssert("minus", new Int2Datum((short)5), new Int8Datum(10), new Int8Datum(-5)); + runAndAssert("minus", new Int2Datum((short)5), new Float4Datum(10.0f), new Float4Datum(-5.0f)); + runAndAssert("minus", new Int2Datum((short)5), new Float8Datum(10.0), new Float8Datum(-5.0)); + + //multiply + runAndAssert("multiply", new Int2Datum((short)10), new Int2Datum((short)5), new Int4Datum(50)); + runAndAssert("multiply", new Int2Datum((short)10), new Int4Datum(5), new Int4Datum(50)); + runAndAssert("multiply", new Int2Datum((short)10), new Int8Datum(5), new Int8Datum(50)); + runAndAssert("multiply", new Int2Datum((short)10), new Float4Datum(5.0f), new Float4Datum(50.0f)); + runAndAssert("multiply", new Int2Datum((short)10), new Float8Datum(5.0), new Float8Datum(50.0)); + + //divide + runAndAssert("divide", new Int2Datum((short)10), new Int2Datum((short)5), new Int2Datum((short)2)); + runAndAssert("divide", new Int2Datum((short)10), new Int4Datum(5), new Int4Datum(2)); + runAndAssert("divide", new Int2Datum((short)10), new Int8Datum(5), new Int8Datum(2)); + runAndAssert("divide", new Int2Datum((short)10), new Float4Datum(5.0f), new Float4Datum(2.0f)); + runAndAssert("divide", new Int2Datum((short)10), new Float8Datum(5.0), new Float8Datum(2.0)); + + runAndAssert("divide", new Int2Datum((short)10), new Int2Datum((short) 0), NullDatum.get()); + runAndAssert("divide", new Int2Datum((short)10), new Int4Datum(0), NullDatum.get()); + runAndAssert("divide", new Int2Datum((short)10), new Int8Datum(0), NullDatum.get()); + runAndAssert("divide", new Int2Datum((short)10), new Float4Datum(0.0f), NullDatum.get()); + runAndAssert("divide", new Int2Datum((short)10), new Float8Datum(0.0), NullDatum.get()); + + //modular + runAndAssert("modular", new Int2Datum((short)10), new Int2Datum((short)3), new Int2Datum((short)1)); + runAndAssert("modular", new Int2Datum((short)10), new Int4Datum(3), new Int4Datum(1)); + runAndAssert("modular", new Int2Datum((short)10), new Int8Datum(3), new Int8Datum(1)); + runAndAssert("modular", new Int2Datum((short)10), new Float4Datum(3.0f), new Float4Datum(1.0f)); + runAndAssert("modular", new Int2Datum((short)10), new Float8Datum(3.0), new Float8Datum(1.0)); + + runAndAssert("modular", new Int2Datum((short)10), new Int2Datum((short) 0), NullDatum.get()); + runAndAssert("modular", new Int2Datum((short)10), new Int4Datum(0), NullDatum.get()); + runAndAssert("modular", new Int2Datum((short)10), new Int8Datum(0), NullDatum.get()); + runAndAssert("modular", new Int2Datum((short)10), new Float4Datum(0.0f), NullDatum.get()); + runAndAssert("modular", new Int2Datum((short)10), new Float8Datum(0.0), NullDatum.get()); + } + + @Test + public void testInt4Datum() throws Exception { + //plus + runAndAssert("plus", new Int4Datum(10), new Int2Datum((short)5), new Int4Datum(15)); + runAndAssert("plus", new Int4Datum(10), new Int4Datum(5), new Int4Datum(15)); + runAndAssert("plus", new Int4Datum(10), new Int8Datum(5), new Int8Datum(15)); + runAndAssert("plus", new Int4Datum(10), new Float4Datum(5.0f), new Float4Datum(15.0f)); + runAndAssert("plus", new Int4Datum(10), new Float8Datum(5.0), new Float8Datum(15.0)); + + //minus + runAndAssert("minus", new Int4Datum(10), new Int2Datum((short)5), new Int4Datum(5)); + runAndAssert("minus", new Int4Datum(10), new Int4Datum(5), new Int4Datum(5)); + runAndAssert("minus", new Int4Datum(10), new Int8Datum(5), new Int8Datum(5)); + runAndAssert("minus", new Int4Datum(10), new Float4Datum(5.0f), new Float4Datum(5.0f)); + runAndAssert("minus", new Int4Datum(10), new Float8Datum(5.0), new Float8Datum(5.0)); + + runAndAssert("minus", new Int4Datum(5), new Int2Datum((short)10), new Int4Datum(-5)); + runAndAssert("minus", new Int4Datum(5), new Int4Datum(10), new Int4Datum(-5)); + runAndAssert("minus", new Int4Datum(5), new Int8Datum(10), new Int8Datum(-5)); + runAndAssert("minus", new Int4Datum(5), new Float4Datum(10.0f), new Float4Datum(-5.0f)); + runAndAssert("minus", new Int4Datum(5), new Float8Datum(10.0), new Float8Datum(-5.0)); + + //multiply + runAndAssert("multiply", new Int4Datum(10), new Int2Datum((short)5), new Int4Datum(50)); + runAndAssert("multiply", new Int4Datum(10), new Int4Datum(5), new Int4Datum(50)); + runAndAssert("multiply", new Int4Datum(10), new Int8Datum(5), new Int8Datum(50)); + runAndAssert("multiply", new Int4Datum(10), new Float4Datum(5.0f), new Float4Datum(50.0f)); + runAndAssert("multiply", new Int4Datum(10), new Float8Datum(5.0), new Float8Datum(50.0)); + + //divide + runAndAssert("divide", new Int4Datum(10), new Int2Datum((short)5), new Int4Datum(2)); + runAndAssert("divide", new Int4Datum(10), new Int4Datum(5), new Int4Datum(2)); + runAndAssert("divide", new Int4Datum(10), new Int8Datum(5), new Int8Datum(2)); + runAndAssert("divide", new Int4Datum(10), new Float4Datum(5.0f), new Float4Datum(2.0f)); + runAndAssert("divide", new Int4Datum(10), new Float8Datum(5.0), new Float8Datum(2.0)); + + runAndAssert("divide", new Int4Datum(10), new Int2Datum((short) 0), NullDatum.get()); + runAndAssert("divide", new Int4Datum(10), new Int4Datum(0), NullDatum.get()); + runAndAssert("divide", new Int4Datum(10), new Int8Datum(0), NullDatum.get()); + runAndAssert("divide", new Int4Datum(10), new Float4Datum(0.0f), NullDatum.get()); + runAndAssert("divide", new Int4Datum(10), new Float8Datum(0.0), NullDatum.get()); + + //modular + runAndAssert("modular", new Int4Datum(10), new Int2Datum((short)3), new Int4Datum(1)); + runAndAssert("modular", new Int4Datum(10), new Int4Datum(3), new Int4Datum(1)); + runAndAssert("modular", new Int4Datum(10), new Int8Datum(3), new Int8Datum(1)); + runAndAssert("modular", new Int4Datum(10), new Float4Datum(3.0f), new Float4Datum(1.0f)); + runAndAssert("modular", new Int4Datum(10), new Float8Datum(3.0), new Float8Datum(1.0)); + + runAndAssert("modular", new Int4Datum(10), new Int2Datum((short) 0), NullDatum.get()); + runAndAssert("modular", new Int4Datum(10), new Int4Datum(0), NullDatum.get()); + runAndAssert("modular", new Int4Datum(10), new Int8Datum(0), NullDatum.get()); + runAndAssert("modular", new Int4Datum(10), new Float4Datum(0.0f), NullDatum.get()); + runAndAssert("modular", new Int4Datum(10), new Float8Datum(0.0), NullDatum.get()); + } + + @Test + public void testInt8Datum() throws Exception { + //plus + runAndAssert("plus", new Int8Datum(10), new Int2Datum((short)5), new Int8Datum(15)); + runAndAssert("plus", new Int8Datum(10), new Int4Datum(5), new Int8Datum(15)); + runAndAssert("plus", new Int8Datum(10), new Int8Datum(5), new Int8Datum(15)); + runAndAssert("plus", new Int8Datum(10), new Float4Datum(5.0f), new Float8Datum(15.0f)); + runAndAssert("plus", new Int8Datum(10), new Float8Datum(5.0), new Float8Datum(15.0)); + + //minus + runAndAssert("minus", new Int8Datum(10), new Int2Datum((short)5), new Int8Datum(5)); + runAndAssert("minus", new Int8Datum(10), new Int4Datum(5), new Int8Datum(5)); + runAndAssert("minus", new Int8Datum(10), new Int8Datum(5), new Int8Datum(5)); + runAndAssert("minus", new Int8Datum(10), new Float4Datum(5.0f), new Float8Datum(5.0f)); + runAndAssert("minus", new Int8Datum(10), new Float8Datum(5.0), new Float8Datum(5.0)); + + runAndAssert("minus", new Int8Datum(5), new Int2Datum((short)10), new Int8Datum(-5)); + runAndAssert("minus", new Int8Datum(5), new Int4Datum(10), new Int8Datum(-5)); + runAndAssert("minus", new Int8Datum(5), new Int8Datum(10), new Int8Datum(-5)); + runAndAssert("minus", new Int8Datum(5), new Float4Datum(10.0f), new Float8Datum(-5.0f)); + runAndAssert("minus", new Int8Datum(5), new Float8Datum(10.0), new Float8Datum(-5.0)); + + //multiply + runAndAssert("multiply", new Int8Datum(10), new Int2Datum((short)5), new Int8Datum(50)); + runAndAssert("multiply", new Int8Datum(10), new Int4Datum(5), new Int8Datum(50)); + runAndAssert("multiply", new Int8Datum(10), new Int8Datum(5), new Int8Datum(50)); + runAndAssert("multiply", new Int8Datum(10), new Float4Datum(5.0f), new Float8Datum(50.0f)); + runAndAssert("multiply", new Int8Datum(10), new Float8Datum(5.0), new Float8Datum(50.0)); + + //divide + runAndAssert("divide", new Int8Datum(10), new Int2Datum((short)5), new Int8Datum(2)); + runAndAssert("divide", new Int8Datum(10), new Int4Datum(5), new Int8Datum(2)); + runAndAssert("divide", new Int8Datum(10), new Int8Datum(5), new Int8Datum(2)); + runAndAssert("divide", new Int8Datum(10), new Float4Datum(5.0f), new Float8Datum(2.0f)); + runAndAssert("divide", new Int8Datum(10), new Float8Datum(5.0), new Float8Datum(2.0)); + + runAndAssert("divide", new Int8Datum(10), new Int2Datum((short) 0), NullDatum.get()); + runAndAssert("divide", new Int8Datum(10), new Int4Datum(0), NullDatum.get()); + runAndAssert("divide", new Int8Datum(10), new Int8Datum(0), NullDatum.get()); + runAndAssert("divide", new Int8Datum(10), new Float4Datum(0.0f), NullDatum.get()); + runAndAssert("divide", new Int8Datum(10), new Float8Datum(0.0), NullDatum.get()); + + //modular + runAndAssert("modular", new Int8Datum(10), new Int2Datum((short)3), new Int8Datum(1)); + runAndAssert("modular", new Int8Datum(10), new Int4Datum(3), new Int8Datum(1)); + runAndAssert("modular", new Int8Datum(10), new Int8Datum(3), new Int8Datum(1)); + runAndAssert("modular", new Int8Datum(10), new Float4Datum(3.0f), new Float8Datum(1.0f)); + runAndAssert("modular", new Int8Datum(10), new Float8Datum(3.0), new Float8Datum(1.0)); + + runAndAssert("modular", new Int8Datum(10), new Int2Datum((short) 0), NullDatum.get()); + runAndAssert("modular", new Int8Datum(10), new Int4Datum(0), NullDatum.get()); + runAndAssert("modular", new Int8Datum(10), new Int8Datum(0), NullDatum.get()); + runAndAssert("modular", new Int8Datum(10), new Float4Datum(0.0f), NullDatum.get()); + runAndAssert("modular", new Int8Datum(10), new Float8Datum(0.0), NullDatum.get()); + } + + @Test + public void testFloat4Datum() throws Exception { + //plus + runAndAssert("plus", new Float4Datum(10.0f), new Int2Datum((short)5), new Float4Datum(15.0f)); + runAndAssert("plus", new Float4Datum(10.0f), new Int4Datum(5), new Float4Datum(15.0f)); + runAndAssert("plus", new Float4Datum(10.0f), new Int8Datum(5), new Float4Datum(15.0f)); + runAndAssert("plus", new Float4Datum(10.0f), new Float4Datum(5.0f), new Float4Datum(15.0f)); + runAndAssert("plus", new Float4Datum(10.0f), new Float8Datum(5.0), new Float8Datum(15.0)); + + //minus + runAndAssert("minus", new Float4Datum(10.0f), new Int2Datum((short)5), new Float4Datum(5.0f)); + runAndAssert("minus", new Float4Datum(10.0f), new Int4Datum(5), new Float4Datum(5.0f)); + runAndAssert("minus", new Float4Datum(10.0f), new Int8Datum(5), new Float4Datum(5.0f)); + runAndAssert("minus", new Float4Datum(10.0f), new Float4Datum(5.0f), new Float4Datum(5.0f)); + runAndAssert("minus", new Float4Datum(10.0f), new Float8Datum(5.0), new Float8Datum(5.0)); + + runAndAssert("minus", new Float4Datum(5.0f), new Int2Datum((short)10), new Float4Datum(-5.0f)); + runAndAssert("minus", new Float4Datum(5.0f), new Int4Datum(10), new Float4Datum(-5.0f)); + runAndAssert("minus", new Float4Datum(5.0f), new Float4Datum(10.0f), new Float4Datum(-5.0f)); + runAndAssert("minus", new Float4Datum(5.0f), new Float4Datum(10.0f), new Float4Datum(-5.0f)); + runAndAssert("minus", new Float4Datum(5.0f), new Float8Datum(10.0), new Float8Datum(-5.0)); + + //multiply + runAndAssert("multiply", new Float4Datum(10.0f), new Int2Datum((short)5), new Float4Datum(50.0f)); + runAndAssert("multiply", new Float4Datum(10.0f), new Int4Datum(5), new Float4Datum(50.0f)); + runAndAssert("multiply", new Float4Datum(10.0f), new Int8Datum(5), new Float4Datum(50.0f)); + runAndAssert("multiply", new Float4Datum(10.0f), new Float4Datum(5.0f), new Float4Datum(50.0f)); + runAndAssert("multiply", new Float4Datum(10.0f), new Float8Datum(5.0), new Float8Datum(50.0)); + + //divide + runAndAssert("divide", new Float4Datum(10.0f), new Int2Datum((short)5), new Float4Datum(2.0f)); + runAndAssert("divide", new Float4Datum(10.0f), new Int4Datum(5), new Float4Datum(2.0f)); + runAndAssert("divide", new Float4Datum(10.0f), new Int8Datum(5), new Float4Datum(2.0f)); + runAndAssert("divide", new Float4Datum(10.0f), new Float4Datum(5.0f), new Float4Datum(2.0f)); + runAndAssert("divide", new Float4Datum(10.0f), new Float8Datum(5.0), new Float8Datum(2.0)); + + runAndAssert("divide", new Float4Datum(10.0f), new Int2Datum((short) 0), NullDatum.get()); + runAndAssert("divide", new Float4Datum(10.0f), new Int4Datum(0), NullDatum.get()); + runAndAssert("divide", new Float4Datum(10.0f), new Int8Datum(0), NullDatum.get()); + runAndAssert("divide", new Float4Datum(10.0f), new Float4Datum(0.0f), NullDatum.get()); + runAndAssert("divide", new Float4Datum(10.0f), new Float8Datum(0.0), NullDatum.get()); + + //modular + runAndAssert("modular", new Float4Datum(10.0f), new Int2Datum((short)3), new Float4Datum(1.0f)); + runAndAssert("modular", new Float4Datum(10.0f), new Int4Datum(3), new Float4Datum(1.0f)); + runAndAssert("modular", new Float4Datum(10.0f), new Int8Datum(3), new Float4Datum(1.0f)); + runAndAssert("modular", new Float4Datum(10.0f), new Float4Datum(3.0f), new Float4Datum(1.0f)); + runAndAssert("modular", new Float4Datum(10.0f), new Float8Datum(3.0), new Float8Datum(1.0)); + + runAndAssert("modular", new Float4Datum(10.0f), new Int2Datum((short) 0), NullDatum.get()); + runAndAssert("modular", new Float4Datum(10.0f), new Int4Datum(0), NullDatum.get()); + runAndAssert("modular", new Float4Datum(10.0f), new Int8Datum(0), NullDatum.get()); + runAndAssert("modular", new Float4Datum(10.0f), new Float4Datum(0.0f), NullDatum.get()); + runAndAssert("modular", new Float4Datum(10.0f), new Float8Datum(0.0), NullDatum.get()); + } + + @Test + public void testFloat8Datum() throws Exception { + //plus + runAndAssert("plus", new Float8Datum(10.0), new Int2Datum((short)5), new Float8Datum(15.0)); + runAndAssert("plus", new Float8Datum(10.0), new Int4Datum(5), new Float8Datum(15.0)); + runAndAssert("plus", new Float8Datum(10.0), new Int8Datum(5), new Float8Datum(15.0)); + runAndAssert("plus", new Float8Datum(10.0), new Float4Datum(5.0f), new Float8Datum(15.0)); + runAndAssert("plus", new Float8Datum(10.0), new Float8Datum(5.0), new Float8Datum(15.0)); + + //minus + runAndAssert("minus", new Float8Datum(10.0), new Int2Datum((short)5), new Float8Datum(5.0)); + runAndAssert("minus", new Float8Datum(10.0), new Int4Datum(5), new Float8Datum(5.0)); + runAndAssert("minus", new Float8Datum(10.0), new Int8Datum(5), new Float8Datum(5.0)); + runAndAssert("minus", new Float8Datum(10.0), new Float4Datum(5.0f), new Float8Datum(5.0)); + runAndAssert("minus", new Float8Datum(10.0), new Float8Datum(5.0), new Float8Datum(5.0)); + + runAndAssert("minus", new Float8Datum(5.0), new Int2Datum((short)10), new Float8Datum(-5.0)); + runAndAssert("minus", new Float8Datum(5.0), new Int4Datum(10), new Float8Datum(-5.0)); + runAndAssert("minus", new Float8Datum(5.0), new Float8Datum(10.0), new Float8Datum(-5.0)); + runAndAssert("minus", new Float8Datum(5.0), new Float8Datum(10.0), new Float8Datum(-5.0)); + runAndAssert("minus", new Float8Datum(5.0), new Float8Datum(10.0), new Float8Datum(-5.0)); + + //multiply + runAndAssert("multiply", new Float8Datum(10.0), new Int2Datum((short)5), new Float8Datum(50.0)); + runAndAssert("multiply", new Float8Datum(10.0), new Int4Datum(5), new Float8Datum(50.0)); + runAndAssert("multiply", new Float8Datum(10.0), new Int8Datum(5), new Float8Datum(50.0)); + runAndAssert("multiply", new Float8Datum(10.0), new Float4Datum(5.0f), new Float8Datum(50.0)); + runAndAssert("multiply", new Float8Datum(10.0), new Float8Datum(5.0), new Float8Datum(50.0)); + + //divide + runAndAssert("divide", new Float8Datum(10.0), new Int2Datum((short)5), new Float8Datum(2.0)); + runAndAssert("divide", new Float8Datum(10.0), new Int4Datum(5), new Float8Datum(2.0)); + runAndAssert("divide", new Float8Datum(10.0), new Int8Datum(5), new Float8Datum(2.0)); + runAndAssert("divide", new Float8Datum(10.0), new Float4Datum(5.0f), new Float8Datum(2.0)); + runAndAssert("divide", new Float8Datum(10.0), new Float8Datum(5.0), new Float8Datum(2.0)); + + runAndAssert("divide", new Float8Datum(10.0), new Int2Datum((short) 0), NullDatum.get()); + runAndAssert("divide", new Float8Datum(10.0), new Int4Datum(0), NullDatum.get()); + runAndAssert("divide", new Float8Datum(10.0), new Int8Datum(0), NullDatum.get()); + runAndAssert("divide", new Float8Datum(10.0), new Float4Datum(0.0f), NullDatum.get()); + runAndAssert("divide", new Float8Datum(10.0), new Float8Datum(0.0), NullDatum.get()); + + //modular + runAndAssert("modular", new Float8Datum(10.0), new Int2Datum((short)3), new Float8Datum(1.0)); + runAndAssert("modular", new Float8Datum(10.0), new Int4Datum(3), new Float8Datum(1.0)); + runAndAssert("modular", new Float8Datum(10.0), new Int8Datum(3), new Float8Datum(1.0)); + runAndAssert("modular", new Float8Datum(10.0), new Float4Datum(3.0f), new Float8Datum(1.0)); + runAndAssert("modular", new Float8Datum(10.0), new Float8Datum(3.0), new Float8Datum(1.0)); + + //modular by zero + runAndAssert("modular", new Float8Datum(10.0), new Int2Datum((short) 0), NullDatum.get()); + runAndAssert("modular", new Float8Datum(10.0), new Int4Datum(0), NullDatum.get()); + runAndAssert("modular", new Float8Datum(10.0), new Int8Datum(0), NullDatum.get()); + runAndAssert("modular", new Float8Datum(10.0), new Float4Datum(0.0f), NullDatum.get()); + runAndAssert("modular", new Float8Datum(10.0), new Float8Datum(0.0), NullDatum.get()); + } + + private void runAndAssert(String op, Datum left, Datum right, Datum expected) throws Exception { + Datum result = null; + try { + if ("plus".equals(op)) { + result = left.plus(right); + } else if ("minus".equals(op)) { + result = left.minus(right); + } else if ("multiply".equals(op)) { + result = left.multiply(right); + } else if ("divide".equals(op)) { + result = left.divide(right); + if (right.asFloat8() == 0) { + if (Datum.abortWhenDivideByZero) { + fail("should throw DivideByZeroException in the case of nullIfZero false"); + } + } + } else if ("modular".equals(op)) { + result = left.modular(right); + if (right.asFloat8() == 0) { + if (Datum.abortWhenDivideByZero) { + fail("should throw DivideByZeroException in the case of nullIfZero false"); + } + } + } + assertEquals(expected.type(), result.type()); + assertEquals(expected, result); + } catch (ArithmeticException e) { + if (!Datum.abortWhenDivideByZero) { + fail(op + " throws DivideByZeroException"); + } else { + //success + } + } + } +}