DRILL-793: Fix output type's scale and precision for math functions.
Project: http://git-wip-us.apache.org/repos/asf/incubator-drill/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-drill/commit/1465e11c Tree: http://git-wip-us.apache.org/repos/asf/incubator-drill/tree/1465e11c Diff: http://git-wip-us.apache.org/repos/asf/incubator-drill/diff/1465e11c Branch: refs/heads/master Commit: 1465e11ca58fc139ae2f444b236c2db514276687 Parents: 5079f8b Author: Mehant Baid <[email protected]> Authored: Thu Jun 12 18:09:57 2014 -0700 Committer: Jacques Nadeau <[email protected]> Committed: Tue Jun 17 16:04:09 2014 -0700 ---------------------------------------------------------------------- .../DecimalScalePrecisionDivideFunction.java | 65 +++++++++++++ .../util/DecimalScalePrecisionMulFunction.java | 52 +++++++++++ .../drill/common/util/DecimalUtility.java | 38 ++++++++ .../templates/Decimal/DecimalFunctions.java | 97 +++++++++++++++----- .../expr/fn/DrillDecimalDivScaleFuncHolder.java | 28 ++++-- .../expr/fn/DrillDecimalSumScaleFuncHolder.java | 25 ++++- .../drill/exec/expr/fn/DrillFuncHolder.java | 2 +- .../drill/exec/resolver/TypeCastRules.java | 15 +-- .../drill/exec/physical/impl/TestDecimal.java | 5 +- .../resources/decimal/test_decimal_complex.json | 8 +- .../drill/jdbc/test/TestFunctionsQuery.java | 15 +++ 11 files changed, 299 insertions(+), 51 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/1465e11c/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 new file mode 100644 index 0000000..5a53603 --- /dev/null +++ b/common/src/main/java/org/apache/drill/common/util/DecimalScalePrecisionDivideFunction.java @@ -0,0 +1,65 @@ +/** + * 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; + +/* + * Here we compute the scale and precision of the output decimal data type + * based on the input scale and precision. Since division operation can be + * a multiplication operation we compute the scale to be the sum of the inputs. + * The precision is computed by getting the sum of integer digits of the input + * and adding it with scale. The scale is further expanded to occupy the remaining + * digits in the given precision range + * + * Eg: Input1 : precision = 5, scale = 3 ==> max integer digits = 2 + * Input2 : precision = 7, scale = 4 ==> max integer digits = 3 + * + * Output: max integer digits ==> 2 + 3 = 5 + * max scale ==> 3 + 4 = 7 + * + * Minimum precision required ==> 5 + 7 = 12 + * + * Since our minimum precision required is 12, we will use DECIMAL18 as the output type + * but since this is divide we will grant the remaining digits in DECIMAL18 to scale + * so we have the following + * output scale ==> 7 + (18 - 12) = 13 + * output precision ==> 18 + */ +public class DecimalScalePrecisionDivideFunction { + private int outputScale = 0; + private int outputPrecision = 0; + + public DecimalScalePrecisionDivideFunction(int leftPrecision, int leftScale, int rightPrecision, int rightScale) { + // compute the output scale and precision here + outputScale = leftScale + rightScale; + int integerDigits = (leftPrecision - leftScale) + (rightPrecision - rightScale); + + outputPrecision = DecimalUtility.getPrecisionRange(outputScale + integerDigits); + + // 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/1465e11c/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 new file mode 100644 index 0000000..1fd3427 --- /dev/null +++ b/common/src/main/java/org/apache/drill/common/util/DecimalScalePrecisionMulFunction.java @@ -0,0 +1,52 @@ +/** + * 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; + +/* + * Here we compute the output scale and precision of the multiply function. + * 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 DecimalScalePrecisionMulFunction(int leftPrecision, int leftScale, int rightPrecision, int rightScale) { + // compute the output scale and precision here + outputScale = leftScale + rightScale; + int integerDigits = (leftPrecision - leftScale) + (rightPrecision - rightScale); + + outputPrecision = integerDigits + outputScale; + + // If we are beyond the maximum precision range, cut down the fractional part + if (outputPrecision > 38) { + outputPrecision = 38; + 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/1465e11c/common/src/main/java/org/apache/drill/common/util/DecimalUtility.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/org/apache/drill/common/util/DecimalUtility.java b/common/src/main/java/org/apache/drill/common/util/DecimalUtility.java index 4cc80ea..7f1a4a0 100644 --- a/common/src/main/java/org/apache/drill/common/util/DecimalUtility.java +++ b/common/src/main/java/org/apache/drill/common/util/DecimalUtility.java @@ -19,6 +19,7 @@ package org.apache.drill.common.util; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; +import org.apache.drill.common.types.TypeProtos; import java.math.BigDecimal; import java.math.BigInteger; @@ -646,5 +647,42 @@ public class DecimalUtility { } } + /* + * Function returns the Minor decimal type given the precision + */ + public static TypeProtos.MinorType getDecimalDataType(int precision) { + if (precision <= 9) { + return TypeProtos.MinorType.DECIMAL9; + } else if (precision <= 18) { + return TypeProtos.MinorType.DECIMAL18; + } else if (precision <= 28) { + return TypeProtos.MinorType.DECIMAL28SPARSE; + } else { + return TypeProtos.MinorType.DECIMAL38SPARSE; + } + } + + public static int getMaxPrecision(TypeProtos.MinorType decimalType) { + if (decimalType == TypeProtos.MinorType.DECIMAL9) { + return 9; + } else if (decimalType == TypeProtos.MinorType.DECIMAL18) { + return 18; + } else if (decimalType == TypeProtos.MinorType.DECIMAL28SPARSE) { + return 28; + } else if (decimalType == TypeProtos.MinorType.DECIMAL38SPARSE) { + return 38; + } + return 0; + } + + + /* + * Given a precision it provides the max precision of that decimal data type; + * For eg: given the precision 12, we would use DECIMAL18 to store the data + * which has a max precision range of 18 digits + */ + public static int getPrecisionRange(int precision) { + return getMaxPrecision(getDecimalDataType(precision)); + } } http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/1465e11c/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 b294396..a41fb20 100644 --- a/exec/java-exec/src/main/codegen/templates/Decimal/DecimalFunctions.java +++ b/exec/java-exec/src/main/codegen/templates/Decimal/DecimalFunctions.java @@ -379,6 +379,8 @@ public class ${type.name}Functions { @Param ${type.name}Holder right; @Workspace ByteBuf buffer; @Workspace int[] tempResult; + @Workspace int outputScale; + @Workspace int outputPrecision; @Output ${type.name}Holder result; public void setup(RecordBatch incoming) { @@ -386,10 +388,20 @@ public class ${type.name}Functions { buffer = io.netty.buffer.Unpooled.wrappedBuffer(new byte[size]); buffer = new io.netty.buffer.SwappedByteBuf(buffer); tempResult = new int[${type.storage} * ${type.storage}]; + outputPrecision = Integer.MIN_VALUE; } public void eval() { + if (outputPrecision == Integer.MIN_VALUE) { + org.apache.drill.common.util.DecimalScalePrecisionMulFunction resultScalePrec = + new org.apache.drill.common.util.DecimalScalePrecisionMulFunction((int) left.precision, (int) left.scale, (int) right.precision, (int) right.scale); + outputScale = resultScalePrec.getOutputScale(); + outputPrecision = resultScalePrec.getOutputPrecision(); + } + // Set the scale and precision + result.scale = outputScale; + result.precision = outputPrecision; result.buffer = buffer; result.start = 0; @@ -474,10 +486,6 @@ public class ${type.name}Functions { result.setInteger(outputIndex--, 0); } - // Set the scale and precision - result.scale = left.scale + right.scale; - result.precision = result.maxPrecision; - result.sign = (left.sign == right.sign) ? false : true; } } @@ -489,17 +497,25 @@ public class ${type.name}Functions { @Param ${type.name}Holder right; @Output ${type.name}Holder result; @Workspace ByteBuf buffer; + @Workspace int outputScale; + @Workspace int outputPrecision; 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() { - - result.scale = left.scale; - result.precision = left.precision; + if (outputPrecision == Integer.MIN_VALUE) { + org.apache.drill.common.util.DecimalScalePrecisionDivideFunction resultScalePrec = + new org.apache.drill.common.util.DecimalScalePrecisionDivideFunction((int) left.precision, (int) left.scale, (int) right.precision, (int) right.scale); + outputScale = resultScalePrec.getOutputScale(); + outputPrecision = resultScalePrec.getOutputPrecision(); + } + result.scale = outputScale; + result.precision = outputPrecision; result.buffer = buffer; result.start = 0; @@ -524,17 +540,25 @@ public class ${type.name}Functions { @Param ${type.name}Holder right; @Output ${type.name}Holder result; @Workspace ByteBuf buffer; + @Workspace int outputScale; + @Workspace int outputPrecision; 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() { - - result.scale = left.scale; - result.precision = left.precision; + if (outputPrecision == Integer.MIN_VALUE) { + org.apache.drill.common.util.DecimalScalePrecisionDivideFunction resultScalePrec = + new org.apache.drill.common.util.DecimalScalePrecisionDivideFunction((int) left.precision, (int) left.scale, (int) right.precision, (int) right.scale); + outputScale = resultScalePrec.getOutputScale(); + outputPrecision = resultScalePrec.getOutputPrecision(); + } + result.scale = outputScale; + result.precision = outputPrecision; result.buffer = buffer; result.start = 0; @@ -542,7 +566,7 @@ public class ${type.name}Functions { java.math.BigDecimal denominator = org.apache.drill.common.util.DecimalUtility.getBigDecimalFromByteBuf(right.buffer, right.start, right.nDecimalDigits, right.scale, true); java.math.BigDecimal output = numerator.remainder(denominator); - output.setScale(left.scale, java.math.BigDecimal.ROUND_DOWN); + output.setScale(result.scale, java.math.BigDecimal.ROUND_DOWN); // Initialize the result buffer for (int i = 0; i < ${type.storage}; i++) { @@ -1204,15 +1228,24 @@ public class ${type.name}Functions { @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.DecimalScalePrecisionMulFunction resultScalePrec = + new org.apache.drill.common.util.DecimalScalePrecisionMulFunction((int) left.precision, (int) left.scale, (int) right.precision, (int) right.scale); + outputScale = resultScalePrec.getOutputScale(); + outputPrecision = resultScalePrec.getOutputPrecision(); + } result.value = left.value * right.value; - result.precision = result.maxPrecision; - result.scale = left.scale + right.scale; + result.precision = outputPrecision; + result.scale = outputScale; } } @@ -1242,12 +1275,23 @@ public class ${type.name}Functions { @Param ${type.name}Holder left; @Param ${type.name}Holder right; @Output ${type.name}Holder result; + @Workspace int outputScale; + @Workspace int outputPrecision; - public void setup(RecordBatch incoming) {} + public void setup(RecordBatch incoming) { + outputPrecision = Integer.MIN_VALUE; + } public void eval() { - result.scale = left.scale; + if (outputPrecision == Integer.MIN_VALUE) { + org.apache.drill.common.util.DecimalScalePrecisionDivideFunction resultScalePrec = + new org.apache.drill.common.util.DecimalScalePrecisionDivideFunction((int) left.precision, (int) left.scale, (int) right.precision, (int) right.scale); + outputScale = resultScalePrec.getOutputScale(); + outputPrecision = resultScalePrec.getOutputPrecision(); + } + result.scale = outputScale; + result.precision = outputPrecision; java.math.BigDecimal numerator = new java.math.BigDecimal(java.math.BigInteger.valueOf(left.value), left.scale); java.math.BigDecimal denominator = new java.math.BigDecimal(java.math.BigInteger.valueOf(right.value), right.scale); @@ -1263,21 +1307,30 @@ public class ${type.name}Functions { @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.DecimalScalePrecisionDivideFunction resultScalePrec = + new org.apache.drill.common.util.DecimalScalePrecisionDivideFunction((int) left.precision, (int) left.scale, (int) right.precision, (int) right.scale); + outputScale = resultScalePrec.getOutputScale(); + outputPrecision = resultScalePrec.getOutputPrecision(); + } + result.precision = outputPrecision; + result.scale = outputScale; java.math.BigDecimal numerator = new java.math.BigDecimal(java.math.BigInteger.valueOf(left.value), left.scale); java.math.BigDecimal denominator = new java.math.BigDecimal(java.math.BigInteger.valueOf(right.value), right.scale); java.math.BigDecimal output = numerator.remainder(denominator); - output.setScale(left.scale, java.math.BigDecimal.ROUND_DOWN); + output.setScale(result.scale, java.math.BigDecimal.ROUND_DOWN); result.value = output.unscaledValue().${type.storage}Value(); - result.precision = result.maxPrecision; - result.scale = left.scale; } } http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/1465e11c/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillDecimalDivScaleFuncHolder.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillDecimalDivScaleFuncHolder.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillDecimalDivScaleFuncHolder.java index af239e4..941dc49 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillDecimalDivScaleFuncHolder.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillDecimalDivScaleFuncHolder.java @@ -24,6 +24,8 @@ 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.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; @@ -36,12 +38,15 @@ public class DrillDecimalDivScaleFuncHolder extends DrillSimpleFuncHolder{ super(scope, nullHandling, isBinaryCommutative, isRandom, registeredNames, parameters, returnValue, workspaceVars, methods, imports); } + /* + * This function scope is used by divide functions for decimal data type. + * DecimalScalePrecisionDivideFunction is used to compute the output types' + * scale and precision + */ @Override public MajorType getReturnType(List<LogicalExpression> args) { TypeProtos.DataMode mode = returnValue.type.getMode(); - int scale = 0; - int precision = 0; if (nullHandling == NullHandling.NULL_IF_NULL) { // if any one of the input types is nullable, then return nullable return type @@ -53,12 +58,21 @@ public class DrillDecimalDivScaleFuncHolder extends DrillSimpleFuncHolder{ } } - /* Set the scale to be the same as the fist input's scale - * Used by divide and modulo functions + + /* Get the result's scale and precision. This is a function scope for Divide function, assert we have + * only two inputs */ - scale = args.get(0).getMajorType().getScale(); - precision = args.get(0).getMajorType().getPrecision(); + assert args.size() == 2; - return (TypeProtos.MajorType.newBuilder().setMinorType(returnValue.type.getMinorType()).setScale(scale).setPrecision(precision).setMode(mode).build()); + DecimalScalePrecisionDivideFunction outputScalePrec = + new DecimalScalePrecisionDivideFunction(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/1465e11c/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillDecimalSumScaleFuncHolder.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillDecimalSumScaleFuncHolder.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillDecimalSumScaleFuncHolder.java index 2e82966..6c04afc 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillDecimalSumScaleFuncHolder.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillDecimalSumScaleFuncHolder.java @@ -24,6 +24,8 @@ 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.DecimalScalePrecisionMulFunction; +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; @@ -40,19 +42,32 @@ public class DrillDecimalSumScaleFuncHolder extends DrillSimpleFuncHolder{ public MajorType getReturnType(List<LogicalExpression> args) { TypeProtos.DataMode mode = returnValue.type.getMode(); - int scale = 0; - int precision = 0; 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; } - scale += e.getMajorType().getScale(); - precision = Math.max(precision, e.getMajorType().getPrecision()); } } - return (TypeProtos.MajorType.newBuilder().setMinorType(returnValue.type.getMinorType()).setScale(scale).setPrecision(precision).setMode(mode).build()); + + /* Get the result's scale and precision. This is a function scope for Multiply function, assert we have + * only two inputs + */ + assert args.size() == 2; + + DecimalScalePrecisionMulFunction outputScalePrec = + new DecimalScalePrecisionMulFunction(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/1465e11c/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillFuncHolder.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillFuncHolder.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillFuncHolder.java index fd687af..fc8dc00 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillFuncHolder.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillFuncHolder.java @@ -294,7 +294,7 @@ public abstract class DrillFuncHolder { } - public boolean matchInputOutputType() { + public boolean checkPrecisionRange() { return false; } http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/1465e11c/exec/java-exec/src/main/java/org/apache/drill/exec/resolver/TypeCastRules.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/resolver/TypeCastRules.java b/exec/java-exec/src/main/java/org/apache/drill/exec/resolver/TypeCastRules.java index 854342c..bf202c8 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/resolver/TypeCastRules.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/resolver/TypeCastRules.java @@ -28,6 +28,7 @@ import org.apache.drill.common.types.Types; import org.apache.drill.common.types.TypeProtos.DataMode; import org.apache.drill.common.types.TypeProtos.MajorType; import org.apache.drill.common.types.TypeProtos.MinorType; +import org.apache.drill.common.util.DecimalUtility; import org.apache.drill.exec.expr.annotations.FunctionTemplate.NullHandling; import org.apache.drill.exec.expr.fn.DrillFuncHolder; @@ -794,13 +795,13 @@ public class TypeCastRules { // number of arguments that could implicitly casts using precedence map or didn't require casting at all int nCasts = 0; - // Check if the function holder requires the input type and output type to match - if (holder.matchInputOutputType() == true) { - MinorType outputType = holder.getReturnType(call.args).getMinorType(); - for (int i = 0; i < holder.getParamCount(); i++) { - if (call.args.get(i).getMajorType().getMinorType() != outputType) { - return -1; - } + /* + * If we are determining function holder for decimal data type, we need to make sure the output type of + * the function can fit the precision that we need based on the input types. + */ + if (holder.checkPrecisionRange() == true) { + if (DecimalUtility.getMaxPrecision(holder.getReturnType().getMinorType()) < holder.getReturnType(call.args).getPrecision()) { + return -1; } } http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/1465e11c/exec/java-exec/src/test/java/org/apache/drill/exec/physical/impl/TestDecimal.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/java/org/apache/drill/exec/physical/impl/TestDecimal.java b/exec/java-exec/src/test/java/org/apache/drill/exec/physical/impl/TestDecimal.java index 2df4d18..f485378 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/exec/physical/impl/TestDecimal.java +++ b/exec/java-exec/src/test/java/org/apache/drill/exec/physical/impl/TestDecimal.java @@ -34,6 +34,7 @@ import org.apache.drill.exec.rpc.user.QueryResultBatch; import org.apache.drill.exec.server.Drillbit; import org.apache.drill.exec.server.RemoteServiceSet; import org.apache.drill.exec.vector.ValueVector; +import org.junit.Ignore; import org.junit.Test; import com.google.common.base.Charsets; @@ -208,22 +209,18 @@ public class TestDecimal extends PopUnitTestBase{ String addOutput[] = {"-99999998877.700000000", "11.423456789", "123456789.100000000", "-0.119998000", "100000000112.423456789" , "-99999999879.907000000", "123456789123456801.300000000"}; String subtractOutput[] = {"-100000001124.300000000", "10.823456789", "-123456788.900000000", "-0.120002000", "99999999889.823456789", "-100000000122.093000000", "123456789123456776.700000000"}; - String multiplyOutput[] = {"-112330000001123.300000000000000000", "3.337037036700000000" , "12345678.900000000000000000", "-0.000000240000000000" , "11130000000125.040740615700000000" , "-12109300000121.093000000000000000", "1518518506218518504.700000000000000000" }; Iterator<VectorWrapper<?>> itr = batchLoader.iterator(); ValueVector.Accessor addAccessor = itr.next().getValueVector().getAccessor(); ValueVector.Accessor subAccessor = itr.next().getValueVector().getAccessor(); - ValueVector.Accessor mulAccessor = itr.next().getValueVector().getAccessor(); for (int i = 0; i < addAccessor.getValueCount(); i++) { assertEquals(addAccessor.getObject(i).toString(), addOutput[i]); assertEquals(subAccessor.getObject(i).toString(), subtractOutput[i]); - assertEquals(mulAccessor.getObject(i).toString(), multiplyOutput[i]); } assertEquals(7, addAccessor.getValueCount()); assertEquals(7, subAccessor.getValueCount()); - assertEquals(7, mulAccessor.getValueCount()); batchLoader.clear(); for (QueryResultBatch result : results) { http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/1465e11c/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 b2f1929..3f98174 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 @@ -22,7 +22,7 @@ "ref" : "DE", "expr" : " (cast(B as decimal38sparse(38, 9))) " }, - {"ref" : "DE1", "expr": " cast(A as decimal38sparse(38, 9))" } + {"ref" : "DE1", "expr": " cast(A as decimal18(15, 6))" } ], "child" : 1 @@ -34,8 +34,7 @@ "ref" : "DEC38ADD", "expr" : " (DE + DE1) " }, - {"ref" : "DEC38SUB" , "expr" : " (DE - DE1) " }, - {"ref" : "DEC38MUL" , "expr" : " (DE * DE1) " } + {"ref" : "DEC38SUB" , "expr" : " (DE - DE1) " } ], "child" : 2 @@ -47,8 +46,7 @@ "ref" : "DEC38ADD", "expr" : " cast(DEC38ADD as varchar(100)) " }, - {"ref" : "DEC38SUB" , "expr" : " cast(DEC38SUB as varchar(100)) " }, - {"ref" : "DEC38MUL" , "expr" : " cast(DEC38MUL as varchar(100)) " } + {"ref" : "DEC38SUB" , "expr" : " cast(DEC38SUB as varchar(100)) " } ], "child" : 3 http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/1465e11c/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 60b8f82..c2d90fe 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 @@ -523,4 +523,19 @@ public class TestFunctionsQuery { .returns( "DECIMAL_DOUBLE_CAST=1.0001\n"); } + + @Test + public void testCastDecimalDivide() throws Exception { + String query = "select (cast('9' as decimal(9, 1)) / cast('2' as decimal(4, 1))) as DEC9_DIV, " + + "cast('123456789.123456789' as decimal(18, 9)) * cast('123456789.123456789' as decimal(18, 9)) as DEC18_MUL " + + "from cp.`employee.json` where employee_id = 1"; + + JdbcAssert.withNoDefaultSchema() + .sql(query) + .returns( + "DEC9_DIV=4.5000000; " + + "DEC18_MUL=15241578780673678.515622620750190521\n"); + } + + }
