DRILL-794: Fix IOB while performing decimal subtraction
Project: http://git-wip-us.apache.org/repos/asf/incubator-drill/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-drill/commit/67c303cb Tree: http://git-wip-us.apache.org/repos/asf/incubator-drill/tree/67c303cb Diff: http://git-wip-us.apache.org/repos/asf/incubator-drill/diff/67c303cb Branch: refs/heads/master Commit: 67c303cb96103afa790d73d740a544917d67757e Parents: 85b8cef Author: Mehant Baid <meha...@gmail.com> Authored: Wed Jul 2 00:13:38 2014 -0700 Committer: Aditya Kishore <adi...@maprtech.com> Committed: Wed Jul 2 23:00:27 2014 -0700 ---------------------------------------------------------------------- .../util/DecimalScalePrecisionAddFunction.java | 40 ++++++ .../DecimalScalePrecisionDivideFunction.java | 20 ++- .../util/DecimalScalePrecisionMulFunction.java | 17 +-- .../util/DrillBaseComputeScalePrecision.java | 37 +++++ .../templates/Decimal/DecimalFunctions.java | 143 +++++++++---------- .../exec/expr/annotations/FunctionTemplate.java | 3 +- .../exec/expr/fn/DrillDecimalAddFuncHolder.java | 79 ++++++++++ .../drill/exec/expr/fn/FunctionConverter.java | 5 +- .../resources/decimal/test_decimal_complex.json | 2 +- .../drill/jdbc/test/TestFunctionsQuery.java | 4 +- 10 files changed, 246 insertions(+), 104 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/67c303cb/common/src/main/java/org/apache/drill/common/util/DecimalScalePrecisionAddFunction.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/org/apache/drill/common/util/DecimalScalePrecisionAddFunction.java b/common/src/main/java/org/apache/drill/common/util/DecimalScalePrecisionAddFunction.java new file mode 100644 index 0000000..f37bc29 --- /dev/null +++ b/common/src/main/java/org/apache/drill/common/util/DecimalScalePrecisionAddFunction.java @@ -0,0 +1,40 @@ +/** + * 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.drill.common.util; + +public class DecimalScalePrecisionAddFunction extends DrillBaseComputeScalePrecision { + + public DecimalScalePrecisionAddFunction(int leftPrecision, int leftScale, int rightPrecision, int rightScale) { + super(leftPrecision, leftScale, rightPrecision, rightScale); + } + + @Override + public void computeScalePrecision(int leftPrecision, int leftScale, int rightPrecision, int rightScale) { + // compute the output scale and precision here + outputScale = Math.max(leftScale, rightScale); + int maxResultIntegerDigits = Math.max((leftPrecision - leftScale), (rightPrecision - rightScale)) + 1; + + outputPrecision = (outputScale + maxResultIntegerDigits); + + // If we are beyond the maximum precision range, cut down the fractional part + if (outputPrecision > 38) { + outputPrecision = 38; + outputScale = (outputPrecision - maxResultIntegerDigits >= 0) ? (outputPrecision - maxResultIntegerDigits) : 0; + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/67c303cb/common/src/main/java/org/apache/drill/common/util/DecimalScalePrecisionDivideFunction.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/org/apache/drill/common/util/DecimalScalePrecisionDivideFunction.java b/common/src/main/java/org/apache/drill/common/util/DecimalScalePrecisionDivideFunction.java index 5a53603..e662371 100644 --- a/common/src/main/java/org/apache/drill/common/util/DecimalScalePrecisionDivideFunction.java +++ b/common/src/main/java/org/apache/drill/common/util/DecimalScalePrecisionDivideFunction.java @@ -40,12 +40,16 @@ package org.apache.drill.common.util; * output scale ==> 7 + (18 - 12) = 13 * output precision ==> 18 */ -public class DecimalScalePrecisionDivideFunction { - private int outputScale = 0; - private int outputPrecision = 0; +public class DecimalScalePrecisionDivideFunction extends DrillBaseComputeScalePrecision { public DecimalScalePrecisionDivideFunction(int leftPrecision, int leftScale, int rightPrecision, int rightScale) { - // compute the output scale and precision here + super(leftPrecision, leftScale, rightPrecision, rightScale); + } + + @Override + public void computeScalePrecision(int leftPrecision, int leftScale, int rightPrecision, int rightScale) { + + // compute the output scale and precision here outputScale = leftScale + rightScale; int integerDigits = (leftPrecision - leftScale) + (rightPrecision - rightScale); @@ -54,12 +58,4 @@ public class DecimalScalePrecisionDivideFunction { // Try and increase the scale if we have any room outputScale = (outputPrecision - integerDigits >= 0) ? (outputPrecision - integerDigits) : 0; } - - public int getOutputScale() { - return outputScale; - } - - public int getOutputPrecision() { - return outputPrecision; - } } http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/67c303cb/common/src/main/java/org/apache/drill/common/util/DecimalScalePrecisionMulFunction.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/org/apache/drill/common/util/DecimalScalePrecisionMulFunction.java b/common/src/main/java/org/apache/drill/common/util/DecimalScalePrecisionMulFunction.java index 1fd3427..7693f20 100644 --- a/common/src/main/java/org/apache/drill/common/util/DecimalScalePrecisionMulFunction.java +++ b/common/src/main/java/org/apache/drill/common/util/DecimalScalePrecisionMulFunction.java @@ -23,11 +23,14 @@ package org.apache.drill.common.util; * We simply add the input scale and precision to determine the output's scale * and precision */ -public class DecimalScalePrecisionMulFunction { - private int outputScale = 0; - private int outputPrecision = 0; +public class DecimalScalePrecisionMulFunction extends DrillBaseComputeScalePrecision { public DecimalScalePrecisionMulFunction(int leftPrecision, int leftScale, int rightPrecision, int rightScale) { + super(leftPrecision, leftScale, rightPrecision, rightScale); + } + + @Override + public void computeScalePrecision(int leftPrecision, int leftScale, int rightPrecision, int rightScale) { // compute the output scale and precision here outputScale = leftScale + rightScale; int integerDigits = (leftPrecision - leftScale) + (rightPrecision - rightScale); @@ -40,13 +43,5 @@ public class DecimalScalePrecisionMulFunction { outputScale = (outputPrecision - integerDigits >= 0) ? (outputPrecision - integerDigits) : 0; } } - - public int getOutputScale() { - return outputScale; - } - - public int getOutputPrecision() { - return outputPrecision; - } } http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/67c303cb/common/src/main/java/org/apache/drill/common/util/DrillBaseComputeScalePrecision.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/org/apache/drill/common/util/DrillBaseComputeScalePrecision.java b/common/src/main/java/org/apache/drill/common/util/DrillBaseComputeScalePrecision.java new file mode 100644 index 0000000..be07a35 --- /dev/null +++ b/common/src/main/java/org/apache/drill/common/util/DrillBaseComputeScalePrecision.java @@ -0,0 +1,37 @@ +/** + * 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.drill.common.util; + +public abstract class DrillBaseComputeScalePrecision { + protected int outputScale = 0; + protected int outputPrecision = 0; + + public DrillBaseComputeScalePrecision(int leftPrecision, int leftScale, int rightPrecision, int rightScale) { + computeScalePrecision(leftPrecision, leftScale, rightPrecision, rightScale); + } + + public abstract void computeScalePrecision(int leftPrecision, int leftScale, int rightPrecision, int rightScale); + + public int getOutputScale() { + return outputScale; + } + + public int getOutputPrecision() { + return outputPrecision; + } +} http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/67c303cb/exec/java-exec/src/main/codegen/templates/Decimal/DecimalFunctions.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/codegen/templates/Decimal/DecimalFunctions.java b/exec/java-exec/src/main/codegen/templates/Decimal/DecimalFunctions.java index 864c461..27279f0 100644 --- a/exec/java-exec/src/main/codegen/templates/Decimal/DecimalFunctions.java +++ b/exec/java-exec/src/main/codegen/templates/Decimal/DecimalFunctions.java @@ -33,11 +33,6 @@ import org.apache.drill.exec.expr.annotations.Workspace; <#macro subtractBlock holderType in1 in2 result> - /* compute the result's size, integer part and fractional part */ - result.scale = Math.max(${in1}.scale, ${in2}.scale); - result.precision = result.maxPrecision; - - int resultScaleRoundedUp = org.apache.drill.common.util.DecimalUtility.roundUp(result.scale); int resultIndex = result.nDecimalDigits- 1; @@ -125,10 +120,6 @@ import org.apache.drill.exec.expr.annotations.Workspace; <#macro addBlock holderType in1 in2 result> - /* compute the result scale */ - result.scale = Math.max(${in1}.scale, ${in2}.scale); - result.precision = result.maxPrecision; - int resultScaleRoundedUp = org.apache.drill.common.util.DecimalUtility.roundUp(result.scale); int leftScaleRoundedUp = org.apache.drill.common.util.DecimalUtility.roundUp(${in1}.scale); @@ -267,22 +258,32 @@ import java.nio.ByteBuffer; @SuppressWarnings("unused") public class ${type.name}Functions { - @FunctionTemplate(name = "subtract", scope = FunctionTemplate.FunctionScope.DECIMAL_MAX_SCALE, nulls = NullHandling.NULL_IF_NULL) + @FunctionTemplate(name = "subtract", scope = FunctionTemplate.FunctionScope.DECIMAL_ADD_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}SubtractFunction implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param ${type.name}Holder right; @Workspace ByteBuf buffer; + @Workspace int outputScale; + @Workspace int outputPrecision; @Output ${type.name}Holder result; public void setup(RecordBatch incoming) { int size = (${type.storage} * (org.apache.drill.common.util.DecimalUtility.integerSize)); buffer = io.netty.buffer.Unpooled.wrappedBuffer(new byte[size]); buffer = new io.netty.buffer.SwappedByteBuf(buffer); + outputPrecision = Integer.MIN_VALUE; } public void eval() { - + if (outputPrecision == Integer.MIN_VALUE) { + org.apache.drill.common.util.DecimalScalePrecisionAddFunction resultScalePrec = + new org.apache.drill.common.util.DecimalScalePrecisionAddFunction((int) left.precision, (int) left.scale, (int) right.precision, (int) right.scale); + outputScale = resultScalePrec.getOutputScale(); + outputPrecision = resultScalePrec.getOutputPrecision(); + } + result.precision = outputPrecision; + result.scale = outputScale; result.buffer = buffer; result.start = 0; @@ -290,44 +291,23 @@ public class ${type.name}Functions { for (int i = 0; i < ${type.storage}; i++) { result.setInteger(i, 0); } + java.math.BigDecimal leftInput = org.apache.drill.common.util.DecimalUtility.getBigDecimalFromSparse(left.buffer, left.start, left.nDecimalDigits, left.scale); + java.math.BigDecimal rightInput = org.apache.drill.common.util.DecimalUtility.getBigDecimalFromSparse(right.buffer, right.start, right.nDecimalDigits, right.scale); + java.math.BigDecimal addResult = leftInput.subtract(rightInput); - /* If the sign of the two inputs is different, then the subtract - * causes the sign of one of the inputs to change and hence it effectively - * becomes addition - */ - if (left.getSign() != right.getSign()) { - <@addBlock holderType=type.name in1="left" in2="right" result="result"/> - result.setSign(left.getSign()); - } else { - /* Sign of the inputs are the same, meaning we have to perform subtraction - * For subtraction we need left input to be greater than right input - * Compare the two inputs, swap if necessary - */ - int cmp; - <@compareBlock holderType=type.name left="left" right="right" absCompare="true" output="cmp"/> - - if (cmp == -1) { - <@subtractBlock holderType=type.name in1="right" in2="left" result="result"/> - } else { - <@subtractBlock holderType=type.name in1="left" in2="right" result="result"/> - } - - //Determine the sign of the result - if ((left.getSign() == false && cmp == -1) || (left.getSign() == true && cmp == 1)) { - result.setSign(true); - } else { - result.setSign(false); - } - } - + // set the scale + addResult.setScale(result.scale, java.math.BigDecimal.ROUND_HALF_UP); + org.apache.drill.common.util.DecimalUtility.getSparseFromBigDecimal(addResult, result.buffer, result.start, result.scale, result.precision, result.nDecimalDigits); } } - @FunctionTemplate(name = "add", scope = FunctionTemplate.FunctionScope.DECIMAL_MAX_SCALE, nulls = NullHandling.NULL_IF_NULL) + @FunctionTemplate(name = "add", scope = FunctionTemplate.FunctionScope.DECIMAL_ADD_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}AddFunction implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param ${type.name}Holder right; + @Workspace int outputScale; + @Workspace int outputPrecision; @Workspace ByteBuf buffer; @Output ${type.name}Holder result; @@ -335,9 +315,18 @@ public class ${type.name}Functions { int size = (${type.storage} * (org.apache.drill.common.util.DecimalUtility.integerSize)); buffer = io.netty.buffer.Unpooled.wrappedBuffer(new byte[size]); buffer = new io.netty.buffer.SwappedByteBuf(buffer); + outputPrecision = Integer.MIN_VALUE; } public void eval() { + if (outputPrecision == Integer.MIN_VALUE) { + org.apache.drill.common.util.DecimalScalePrecisionAddFunction resultScalePrec = + new org.apache.drill.common.util.DecimalScalePrecisionAddFunction((int) left.precision, (int) left.scale, (int) right.precision, (int) right.scale); + outputScale = resultScalePrec.getOutputScale(); + outputPrecision = resultScalePrec.getOutputPrecision(); + } + result.precision = outputPrecision; + result.scale = outputScale; result.buffer = buffer; result.start = 0; @@ -345,34 +334,17 @@ public class ${type.name}Functions { for (int i = 0; i < ${type.storage}; i++) { result.setInteger(i, 0); } + java.math.BigDecimal leftInput = org.apache.drill.common.util.DecimalUtility.getBigDecimalFromSparse(left.buffer, left.start, left.nDecimalDigits, left.scale); + java.math.BigDecimal rightInput = org.apache.drill.common.util.DecimalUtility.getBigDecimalFromSparse(right.buffer, right.start, right.nDecimalDigits, right.scale); + java.math.BigDecimal addResult = leftInput.add(rightInput); - /* If sign is different use the subtraction logic */ - if (left.getSign() != right.getSign()) { - - /* Subtract logic assumes, left input is greater than right input - * swap if necessary - */ - int cmp; - <@compareBlock holderType=type.name left="left" right="right" absCompare="true" output="cmp"/> - - if (cmp == -1) { - <@subtractBlock holderType=type.name in1="right" in2="left" result="result"/> - result.setSign(right.getSign()); - } else { - <@subtractBlock holderType=type.name in1="left" in2="right" result="result"/> - result.setSign(left.getSign()); - } - - - } else { - /* Sign of the two input decimals is the same, use the add logic */ - <@addBlock holderType=type.name in1="left" in2="right" result="result"/> - result.setSign(left.getSign()); - } + // set the scale + addResult.setScale(result.scale, java.math.BigDecimal.ROUND_HALF_UP); + org.apache.drill.common.util.DecimalUtility.getSparseFromBigDecimal(addResult, result.buffer, result.start, result.scale, result.precision, result.nDecimalDigits); } } - @FunctionTemplate(name = "multiply", scope = FunctionTemplate.FunctionScope.DECIMAL_SUM_SCALE, nulls = NullHandling.NULL_IF_NULL) + @FunctionTemplate(name = "multiply", scope = FunctionTemplate.FunctionScope.DECIMAL_MUL_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}MultiplyFunction implements DrillSimpleFunc { @Param ${type.name}Holder left; @@ -1248,44 +1220,63 @@ import java.nio.ByteBuffer; @SuppressWarnings("unused") public class ${type.name}Functions { - @FunctionTemplate(name = "add", scope = FunctionTemplate.FunctionScope.DECIMAL_MAX_SCALE, nulls = NullHandling.NULL_IF_NULL) + @FunctionTemplate(name = "add", scope = FunctionTemplate.FunctionScope.DECIMAL_ADD_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}AddFunction implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param ${type.name}Holder right; + @Workspace int outputScale; + @Workspace int outputPrecision; @Output ${type.name}Holder result; - public void setup(RecordBatch incoming) {} + public void setup(RecordBatch incoming) { + outputPrecision = Integer.MIN_VALUE; + } - public void eval() { + public void eval() { + if (outputPrecision == Integer.MIN_VALUE) { + org.apache.drill.common.util.DecimalScalePrecisionAddFunction resultScalePrec = + new org.apache.drill.common.util.DecimalScalePrecisionAddFunction((int) left.precision, (int) left.scale, (int) right.precision, (int) right.scale); + outputScale = resultScalePrec.getOutputScale(); + outputPrecision = resultScalePrec.getOutputPrecision(); + } <@adjustScale holderType=type.name javaType=type.storage left="left" right="right"/> result.value = left.value + right.value; - result.precision = result.maxPrecision; - result.scale = Math.max(left.scale, right.scale); + result.precision = outputPrecision; + result.scale = outputScale; } } - @FunctionTemplate(name = "subtract", scope = FunctionTemplate.FunctionScope.DECIMAL_MAX_SCALE, nulls = NullHandling.NULL_IF_NULL) + @FunctionTemplate(name = "subtract", scope = FunctionTemplate.FunctionScope.DECIMAL_ADD_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}SubtractFunction implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param ${type.name}Holder right; + @Workspace int outputScale; + @Workspace int outputPrecision; @Output ${type.name}Holder result; - public void setup(RecordBatch incoming) {} + public void setup(RecordBatch incoming) { + outputPrecision = Integer.MIN_VALUE; + } public void eval() { - + if (outputPrecision == Integer.MIN_VALUE) { + org.apache.drill.common.util.DecimalScalePrecisionAddFunction resultScalePrec = + new org.apache.drill.common.util.DecimalScalePrecisionAddFunction((int) left.precision, (int) left.scale, (int) right.precision, (int) right.scale); + outputScale = resultScalePrec.getOutputScale(); + outputPrecision = resultScalePrec.getOutputPrecision(); + } <@adjustScale holderType=type.name javaType=type.storage left="left" right="right"/> result.value = left.value - right.value; - result.precision = result.maxPrecision; - result.scale = Math.max(left.scale, right.scale); + result.precision = outputPrecision; + result.scale = outputScale; } } - @FunctionTemplate(name = "multiply", scope = FunctionTemplate.FunctionScope.DECIMAL_SUM_SCALE, nulls = NullHandling.NULL_IF_NULL) + @FunctionTemplate(name = "multiply", scope = FunctionTemplate.FunctionScope.DECIMAL_MUL_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}MultiplyFunction implements DrillSimpleFunc { @Param ${type.name}Holder left; http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/67c303cb/exec/java-exec/src/main/java/org/apache/drill/exec/expr/annotations/FunctionTemplate.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/annotations/FunctionTemplate.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/annotations/FunctionTemplate.java index be43d38..c2ad3d5 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/annotations/FunctionTemplate.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/annotations/FunctionTemplate.java @@ -59,9 +59,10 @@ public @interface FunctionTemplate { HOLISTIC_AGGREGATE, RANGE_AGGREGATE, DECIMAL_MAX_SCALE, - DECIMAL_SUM_SCALE, + DECIMAL_MUL_SCALE, DECIMAL_CAST, DECIMAL_DIV_SCALE, + DECIMAL_ADD_SCALE, DECIMAL_SET_SCALE, DECIMAL_ZERO_SCALE, SC_BOOLEAN_OPERATOR http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/67c303cb/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillDecimalAddFuncHolder.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillDecimalAddFuncHolder.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillDecimalAddFuncHolder.java new file mode 100644 index 0000000..98c1c85 --- /dev/null +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillDecimalAddFuncHolder.java @@ -0,0 +1,79 @@ +/** + * 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.drill.exec.expr.fn; + +import java.util.List; +import java.util.Map; + +import org.apache.drill.common.expression.LogicalExpression; +import org.apache.drill.common.types.TypeProtos; +import org.apache.drill.common.types.TypeProtos.MajorType; + +import org.apache.drill.common.util.DecimalScalePrecisionAddFunction; +import org.apache.drill.common.util.DecimalScalePrecisionDivideFunction; +import org.apache.drill.common.util.DecimalUtility; +import org.apache.drill.exec.expr.annotations.FunctionTemplate.FunctionScope; +import org.apache.drill.exec.expr.annotations.FunctionTemplate.NullHandling; + +public class DrillDecimalAddFuncHolder extends DrillSimpleFuncHolder{ + + + public DrillDecimalAddFuncHolder(FunctionScope scope, NullHandling nullHandling, boolean isBinaryCommutative, boolean isRandom, + String[] registeredNames, ValueReference[] parameters, ValueReference returnValue, WorkspaceReference[] workspaceVars, + Map<String, String> methods, List<String> imports) { + super(scope, nullHandling, isBinaryCommutative, isRandom, registeredNames, parameters, returnValue, workspaceVars, methods, imports); + } + + /* + * This function scope is used by add and subtract functions for decimal data type. + * DecimalScalePrecisionAddFunction is used to compute the output types' + * scale and precision + */ + @Override + public MajorType getReturnType(List<LogicalExpression> args) { + + TypeProtos.DataMode mode = returnValue.type.getMode(); + + if (nullHandling == NullHandling.NULL_IF_NULL) { + // if any one of the input types is nullable, then return nullable return type + for (LogicalExpression e : args) { + if (e.getMajorType().getMode() == TypeProtos.DataMode.OPTIONAL) { + mode = TypeProtos.DataMode.OPTIONAL; + break; + } + } + } + + + /* Get the result's scale and precision. This is a function scope for add function, assert we have + * only two inputs + */ + assert args.size() == 2; + + DecimalScalePrecisionAddFunction outputScalePrec = + new DecimalScalePrecisionAddFunction(args.get(0).getMajorType().getPrecision(), args.get(0).getMajorType().getScale(), + args.get(1).getMajorType().getPrecision(), args.get(1).getMajorType().getScale()); + return (TypeProtos.MajorType.newBuilder().setMinorType(DecimalUtility.getDecimalDataType(outputScalePrec.getOutputPrecision())) + .setScale(outputScalePrec.getOutputScale()).setPrecision(outputScalePrec.getOutputPrecision()).setMode(mode).build()); + } + + @Override + public boolean checkPrecisionRange() { + return true; + } +} http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/67c303cb/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/FunctionConverter.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/FunctionConverter.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/FunctionConverter.java index 8328549..3c8536c 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/FunctionConverter.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/FunctionConverter.java @@ -244,9 +244,12 @@ public class FunctionConverter { case DECIMAL_MAX_SCALE: return new DrillDecimalMaxScaleFuncHolder(template.scope(), template.nulls(), template.isBinaryCommutative(), template.isRandom(), registeredNames, ps, outputField, works, methods, imports); - case DECIMAL_SUM_SCALE: + case DECIMAL_MUL_SCALE: return new DrillDecimalSumScaleFuncHolder(template.scope(), template.nulls(), template.isBinaryCommutative(), template.isRandom(), registeredNames, ps, outputField, works, methods, imports); + case DECIMAL_ADD_SCALE: + return new DrillDecimalAddFuncHolder(template.scope(), template.nulls(), template.isBinaryCommutative(), + template.isRandom(), registeredNames, ps, outputField, works, methods, imports); case DECIMAL_CAST: return new DrillDecimalCastFuncHolder(template.scope(), template.nulls(), template.isBinaryCommutative(), template.isRandom(), registeredNames, ps, outputField, works, methods, imports); http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/67c303cb/exec/java-exec/src/test/resources/decimal/test_decimal_complex.json ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/resources/decimal/test_decimal_complex.json b/exec/java-exec/src/test/resources/decimal/test_decimal_complex.json index 3f98174..b909411 100644 --- a/exec/java-exec/src/test/resources/decimal/test_decimal_complex.json +++ b/exec/java-exec/src/test/resources/decimal/test_decimal_complex.json @@ -20,7 +20,7 @@ "@id" : 2, "exprs" : [ { "ref" : "DE", - "expr" : " (cast(B as decimal38sparse(38, 9))) " + "expr" : " (cast(B as decimal38sparse(28, 9))) " }, {"ref" : "DE1", "expr": " cast(A as decimal18(15, 6))" } ], http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/67c303cb/exec/jdbc/src/test/java/org/apache/drill/jdbc/test/TestFunctionsQuery.java ---------------------------------------------------------------------- diff --git a/exec/jdbc/src/test/java/org/apache/drill/jdbc/test/TestFunctionsQuery.java b/exec/jdbc/src/test/java/org/apache/drill/jdbc/test/TestFunctionsQuery.java index 1e5052a..1189ac5 100644 --- a/exec/jdbc/src/test/java/org/apache/drill/jdbc/test/TestFunctionsQuery.java +++ b/exec/jdbc/src/test/java/org/apache/drill/jdbc/test/TestFunctionsQuery.java @@ -490,7 +490,7 @@ public class TestFunctionsQuery { @Test public void testDecimalAddConstant() throws Exception { - String query = "select (cast('-1' as decimal(38, 3)) + cast (employee_id as decimal(38, 3))) as CNT " + + String query = "select (cast('-1' as decimal(37, 3)) + cast (employee_id as decimal(37, 3))) as CNT " + "from cp.`employee.json` where employee_id <= 4"; JdbcAssert.withNoDefaultSchema() @@ -503,7 +503,7 @@ public class TestFunctionsQuery { @Test public void testDecimalAddIntConstant() throws Exception { - String query = "select 1 + cast(employee_id as decimal(9, 3)) as DEC_9 , 1 + cast(employee_id as decimal(38, 5)) as DEC_38 " + + String query = "select 1 + cast(employee_id as decimal(9, 3)) as DEC_9 , 1 + cast(employee_id as decimal(37, 5)) as DEC_38 " + "from cp.`employee.json` where employee_id <= 2"; JdbcAssert.withNoDefaultSchema()