/* * 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. */ import org.apache.drill.exec.expr.annotations.Workspace; <@pp.dropOutputFile /> <#-- TODO: Refactor comparison code from here into ComparisonFunctions (to eliminate duplicate template code and so that ComparisonFunctions actually as all comparison functions. --> <#macro compareNullsSubblock leftType rightType output breakTarget nullCompare nullComparesHigh> <#if nullCompare> <#if nullComparesHigh> <#assign leftNullResult = 1> <#-- if only L is null and nulls are high, then "L > R" (1) --> <#assign rightNullResult = -1> <#else> <#assign leftNullResult = -1> <#-- if only L is null and nulls are low, then "L < R" (-1) --> <#assign rightNullResult = 1> </#if> <#if leftType?starts_with("Nullable")> <#if rightType?starts_with("Nullable")> <#-- Both are nullable. --> if ( left.isSet == 0 ) { if ( right.isSet == 0 ) { <#-- Both are null--result is "L = R". --> ${output} = 0; break ${breakTarget}; } else { <#-- Only left is null--result is "L < R" or "L > R" per null ordering. --> ${output} = ${leftNullResult}; break ${breakTarget}; } } else if ( right.isSet == 0 ) { <#-- Only right is null--result is "L > R" or "L < R" per null ordering. --> ${output} = ${rightNullResult}; break ${breakTarget}; } <#else> <#-- Left is nullable but right is not. --> if ( left.isSet == 0 ) { <#-- Only left is null--result is "L < R" or "L > R" per null ordering. --> ${output} = ${leftNullResult}; break ${breakTarget}; } </#if> <#elseif rightType?starts_with("Nullable")> <#-- Left is not nullable but right is. --> if ( right.isSet == 0 ) { <#-- Only right is null--result is "L > R" or "L < R" per null ordering. --> ${output} = ${rightNullResult}; break ${breakTarget}; } </#if> </#if> </#macro> <#macro compareBlock leftType rightType absCompare output nullCompare nullComparesHigh> outside: { <@compareNullsSubblock leftType=leftType rightType=rightType output=output breakTarget="outside" nullCompare=nullCompare nullComparesHigh=nullComparesHigh /> ${output} = org.apache.drill.exec.util.DecimalUtility.compareSparseBytes(left.buffer, left.start, left.getSign(left.start, left.buffer), left.scale, left.precision, right.buffer, right.start, right.getSign(right.start, right.buffer), right.precision, right.scale, left.WIDTH, left.nDecimalDigits, ${absCompare}); } // outside </#macro> <#macro adjustScale javaType leftType rightType> // Adjust the scale of the two inputs to be the same if (left.scale < right.scale) { left.value = (${javaType}) (org.apache.drill.exec.util.DecimalUtility.adjustScaleMultiply(left.value, (int) (right.scale - left.scale))); left.scale = right.scale; } else if (right.scale < left.scale) { right.value = (${javaType}) (org.apache.drill.exec.util.DecimalUtility.adjustScaleMultiply(right.value, (int) (left.scale - right.scale))); right.scale = left.scale; } </#macro> <#-- For each DECIMAL... type (in DecimalTypes.tdd) ... --> <#list comparisonTypesDecimal.decimalTypes as type> <#if type.name.endsWith("Sparse")> <@pp.changeOutputFile name="/org/apache/drill/exec/expr/fn/impl/${type.name}Functions.java" /> <#include "/@includes/license.ftl" /> package org.apache.drill.exec.expr.fn.impl; <#include "/@includes/vv_imports.ftl" /> import org.apache.drill.exec.expr.DrillSimpleFunc; import org.apache.drill.exec.expr.annotations.FunctionTemplate; import org.apache.drill.exec.expr.annotations.FunctionTemplate.NullHandling; import org.apache.drill.exec.expr.annotations.Output; import org.apache.drill.exec.expr.annotations.Param; import org.apache.drill.exec.expr.annotations.Workspace; import org.apache.drill.exec.expr.fn.FunctionGenerationHelper; import org.apache.drill.exec.expr.holders.*; import org.apache.drill.exec.record.RecordBatch; import io.netty.buffer.ByteBuf; import io.netty.buffer.DrillBuf; import java.nio.ByteBuffer; /* * This class is generated using freemarker and the ${.template_name} template. */ @SuppressWarnings("unused") public class ${type.name}Functions { @FunctionTemplate(name = "subtract", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_ADD_SCALE, nulls = NullHandling.NULL_IF_NULL, checkPrecisionRange = true) public static class ${type.name}SubtractFunction implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param ${type.name}Holder right; @Inject DrillBuf buffer; @Workspace int outputScale; @Workspace int outputPrecision; @Output ${type.name}Holder result; public void setup() { int size = (${type.storage} * (org.apache.drill.exec.util.DecimalUtility.INTEGER_SIZE)); buffer = buffer.reallocIfNeeded(size); 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; java.math.BigDecimal leftInput = org.apache.drill.exec.util.DecimalUtility.getBigDecimalFromSparse(left.buffer, left.start, left.nDecimalDigits, left.scale); java.math.BigDecimal rightInput = org.apache.drill.exec.util.DecimalUtility.getBigDecimalFromSparse(right.buffer, right.start, right.nDecimalDigits, right.scale); java.math.BigDecimal addResult = leftInput.subtract(rightInput); // Set the scale addResult.setScale(result.scale, java.math.BigDecimal.ROUND_HALF_UP); org.apache.drill.exec.util.DecimalUtility.getSparseFromBigDecimal(addResult, result.buffer, result.start, result.scale, result.precision, result.nDecimalDigits); } } @FunctionTemplate(name = "add", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_ADD_SCALE, nulls = NullHandling.NULL_IF_NULL, checkPrecisionRange = true) public static class ${type.name}AddFunction implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param ${type.name}Holder right; @Workspace int outputScale; @Workspace int outputPrecision; @Inject DrillBuf buffer; @Output ${type.name}Holder result; public void setup() { int size = (${type.storage} * (org.apache.drill.exec.util.DecimalUtility.INTEGER_SIZE)); buffer = buffer.reallocIfNeeded(size); 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; java.math.BigDecimal leftInput = org.apache.drill.exec.util.DecimalUtility.getBigDecimalFromSparse(left.buffer, left.start, left.nDecimalDigits, left.scale); java.math.BigDecimal rightInput = org.apache.drill.exec.util.DecimalUtility.getBigDecimalFromSparse(right.buffer, right.start, right.nDecimalDigits, right.scale); java.math.BigDecimal addResult = leftInput.add(rightInput); // Set the scale addResult.setScale(result.scale, java.math.BigDecimal.ROUND_HALF_UP); org.apache.drill.exec.util.DecimalUtility.getSparseFromBigDecimal(addResult, result.buffer, result.start, result.scale, result.precision, result.nDecimalDigits); } } @FunctionTemplate(name = "multiply", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_SUM_SCALE, nulls = NullHandling.NULL_IF_NULL, checkPrecisionRange = true) public static class ${type.name}MultiplyFunction implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param ${type.name}Holder right; @Inject DrillBuf buffer; @Workspace int[] tempResult; @Workspace int outputScale; @Workspace int outputPrecision; @Output ${type.name}Holder result; public void setup() { int size = (${type.storage} * (org.apache.drill.exec.util.DecimalUtility.INTEGER_SIZE)); buffer = buffer.reallocIfNeeded(size); 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; // Re initialize the temporary array for (int i = 0; i < ${type.storage} * ${type.storage}; i++) { tempResult[i] = 0; } // Remove the leading zeroes from the integer part of the input int leftIndex = 0; int leftStopIndex = left.nDecimalDigits - org.apache.drill.exec.util.DecimalUtility.roundUp(left.scale); while (leftIndex < leftStopIndex) { if (left.getInteger(leftIndex, left.start, left.buffer) > 0) break; leftIndex++; } int leftIntegerSize = leftStopIndex - leftIndex; /* Remove the leading zeroes from the integer part of the input */ int rightIndex = 0; int rightStopIndex = right.nDecimalDigits - org.apache.drill.exec.util.DecimalUtility.roundUp(right.scale); while(rightIndex < rightStopIndex) { if (right.getInteger(rightIndex, right.start, right.buffer) > 0) break; rightIndex++; } int rightIntegerSize = rightStopIndex - rightIndex; int resultIntegerSize = leftIntegerSize + rightIntegerSize; int resultScaleSize = org.apache.drill.exec.util.DecimalUtility.roundUp(left.scale + right.scale); int leftSize = left.nDecimalDigits - 1; int rightSize = right.nDecimalDigits - 1; int resultIndex = tempResult.length - 1; int currentIndex = 0; for (int i = leftSize; i >= leftIndex; i--) { currentIndex = resultIndex; int carry = 0; for (int j = rightSize; j >= rightIndex; j--) { long mulResult = (long) right.getInteger(j, right.start, right.buffer) * (long) left.getInteger(i, left.start, left.buffer); long tempSum = tempResult[currentIndex] + mulResult + carry; if (tempSum >= org.apache.drill.exec.util.DecimalUtility.DIGITS_BASE) { tempResult[currentIndex] = (int) (tempSum % org.apache.drill.exec.util.DecimalUtility.DIGITS_BASE); carry = (int) (tempSum / org.apache.drill.exec.util.DecimalUtility.DIGITS_BASE); } else { tempResult[currentIndex] = (int) tempSum; carry = 0; } currentIndex--; } /* Propagate the carry */ if (carry > 0) tempResult[currentIndex] += carry; resultIndex--; } /* We have computed the result of the multiplication; check if we need to * round a portion of the fractional part */ resultScaleSize = org.apache.drill.exec.util.DecimalUtility.roundUp(result.scale); if (result.scale < (left.scale + right.scale)) { /* The scale of the output data type is less than the scale * we obtained as a result of multiplication, we need to round * a chunk of the fractional part */ int lastScaleIndex = currentIndex + resultIntegerSize + resultScaleSize - 1; // Compute the power of 10 necessary to find if we need to round up int roundFactor = (int) (org.apache.drill.exec.util.DecimalUtility.getPowerOfTen( org.apache.drill.exec.util.DecimalUtility.MAX_DIGITS - ((result.scale + 1) % org.apache.drill.exec.util.DecimalUtility.MAX_DIGITS))); // Index of rounding digit int roundIndex = currentIndex + resultIntegerSize + org.apache.drill.exec.util.DecimalUtility.roundUp(result.scale + 1) - 1; // Check the first chopped digit to see if we need to round up int carry = ((tempResult[roundIndex] / roundFactor) % 10) > 4 ? 1 : 0; if (result.scale > 0) { // Compute the power of 10 necessary to chop of the fractional part int scaleFactor = (int) (org.apache.drill.exec.util.DecimalUtility.getPowerOfTen( org.apache.drill.exec.util.DecimalUtility.MAX_DIGITS - (result.scale % org.apache.drill.exec.util.DecimalUtility.MAX_DIGITS))); // Chop the unwanted fractional part tempResult[lastScaleIndex] /= scaleFactor; tempResult[lastScaleIndex] *= scaleFactor; // Adjust the carry so that it gets added to the correct digit carry *= scaleFactor; } // Propagate the carry while (carry > 0 && lastScaleIndex >= 0) { int tempSum = tempResult[lastScaleIndex] + carry; if (tempSum >= org.apache.drill.exec.util.DecimalUtility.DIGITS_BASE) { tempResult[lastScaleIndex] = (tempSum % org.apache.drill.exec.util.DecimalUtility.DIGITS_BASE); carry = (int) (tempSum / org.apache.drill.exec.util.DecimalUtility.DIGITS_BASE); } else { tempResult[lastScaleIndex] = tempSum; carry = 0; } lastScaleIndex--; } // Check if carry has increased integer digit if ((lastScaleIndex + 1) < currentIndex) { resultIntegerSize++; currentIndex = lastScaleIndex + 1; } } if (resultIntegerSize > result.nDecimalDigits) { throw new org.apache.drill.common.exceptions.DrillRuntimeException("Cannot fit multiplication result in the given decimal type"); } int outputIndex = result.nDecimalDigits - 1; for (int i = (currentIndex + resultIntegerSize + resultScaleSize - 1); i >= currentIndex; i--) { result.setInteger(outputIndex--, tempResult[i], result.start, result.buffer); } // Set the remaining digits to be zero while(outputIndex >= 0) { result.setInteger(outputIndex--, 0, result.start, result.buffer); } result.setSign(left.getSign(left.start, left.buffer) != right.getSign(right.start, right.buffer), result.start, result.buffer); } } @FunctionTemplate(name = "exact_divide", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_DIV_SCALE, nulls = NullHandling.NULL_IF_NULL, checkPrecisionRange = true) public static class ${type.name}DivideFunction implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param ${type.name}Holder right; @Output ${type.name}Holder result; @Inject DrillBuf buffer; @Workspace int outputScale; @Workspace int outputPrecision; public void setup() { int size = (${type.storage} * (org.apache.drill.exec.util.DecimalUtility.INTEGER_SIZE)); buffer = buffer.reallocIfNeeded(size); 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.scale = outputScale; result.precision = outputPrecision; result.buffer = buffer; result.start = 0; java.math.BigDecimal numerator = org.apache.drill.exec.util.DecimalUtility.getBigDecimalFromDrillBuf(left.buffer, left.start, left.nDecimalDigits, left.scale, true); java.math.BigDecimal denominator = org.apache.drill.exec.util.DecimalUtility.getBigDecimalFromDrillBuf(right.buffer, right.start, right.nDecimalDigits, right.scale, true); java.math.BigDecimal output = numerator.divide(denominator, (int) result.scale, java.math.BigDecimal.ROUND_HALF_UP); org.apache.drill.exec.util.DecimalUtility.getSparseFromBigDecimal(output, result.buffer, result.start, result.scale, result.precision, result.nDecimalDigits); } } @FunctionTemplate(name = "mod", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_MOD_SCALE, nulls = NullHandling.NULL_IF_NULL, checkPrecisionRange = true) public static class ${type.name}ModFunction implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param ${type.name}Holder right; @Output ${type.name}Holder result; @Inject DrillBuf buffer; @Workspace int outputScale; @Workspace int outputPrecision; public void setup() { int size = (${type.storage} * (org.apache.drill.exec.util.DecimalUtility.INTEGER_SIZE)); buffer = buffer.reallocIfNeeded(size); outputPrecision = Integer.MIN_VALUE; } public void eval() { if (outputPrecision == Integer.MIN_VALUE) { org.apache.drill.common.util.DecimalScalePrecisionModFunction resultScalePrec = new org.apache.drill.common.util.DecimalScalePrecisionModFunction((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; java.math.BigDecimal numerator = org.apache.drill.exec.util.DecimalUtility.getBigDecimalFromDrillBuf(left.buffer, left.start, left.nDecimalDigits, left.scale, true); java.math.BigDecimal denominator = org.apache.drill.exec.util.DecimalUtility.getBigDecimalFromDrillBuf(right.buffer, right.start, right.nDecimalDigits, right.scale, true); java.math.BigDecimal output = numerator.remainder(denominator); output.setScale(result.scale, java.math.BigDecimal.ROUND_HALF_UP); org.apache.drill.exec.util.DecimalUtility.getSparseFromBigDecimal(output, result.buffer, result.start, result.scale, result.precision, result.nDecimalDigits); } } @FunctionTemplate(name = "abs", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_MAX_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}AbsFunction implements DrillSimpleFunc { @Param ${type.name}Holder in; @Output ${type.name}Holder out; public void setup() { } public void eval() { out.scale = in.scale; out.precision = in.precision; out.buffer = in.buffer; out.start = in.start; // Set the output buffer with the positive sign out.buffer.setInt(out.start, (out.buffer.getInt(out.start) & 0x7fffffff)); } } @FunctionTemplate(name = "sign", scope = FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}SignFunction implements DrillSimpleFunc { @Param ${type.name}Holder in; @Output IntHolder out; public void setup() {} public void eval() { boolean zeroValue = true; if (in.getSign(in.start, in.buffer) == true) { out.value = -1; } else { for (int i = 0; i < ${type.storage}; i++) { if (in.getInteger(i, in.start, in.buffer) != 0) { zeroValue = false; break; } } out.value = (zeroValue == true) ? 0 : 1; } } } @FunctionTemplate(names = {"ceil", "ceiling"}, scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_ZERO_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}CeilFunction implements DrillSimpleFunc { @Param ${type.name}Holder in; @Output ${type.name}Holder out; public void setup() { } public void eval() { out.scale = 0; out.precision = in.precision; out.buffer = in.buffer; out.start = in.start; boolean sign = in.getSign(in.start, in.buffer); // Indicates whether we need to add 1 to the integer part, while performing ceil int carry = 0; int scaleStartIndex = ${type.storage} - org.apache.drill.exec.util.DecimalUtility.roundUp(in.scale); int srcIntIndex = scaleStartIndex - 1; if (sign == false) { // For negative values ceil we don't need to increment the integer part while (scaleStartIndex < ${type.storage}) { if (out.getInteger(scaleStartIndex, out.start, out.buffer) != 0) { carry = 1; break; } scaleStartIndex++; } } // Truncate the fractional part, move the integer part int destIndex = ${type.storage} - 1; while (srcIntIndex >= 0) { out.setInteger(destIndex--, out.getInteger(srcIntIndex--, out.start, out.buffer), out.start, out.buffer); } // Set the remaining portion of the decimal to be zeroes while (destIndex >= 0) { out.setInteger(destIndex--, 0, out.start, out.buffer); } // Add the carry if (carry != 0) { destIndex = ${type.storage} - 1; while (destIndex >= 0) { int intValue = out.getInteger(destIndex, out.start, out.buffer); intValue += carry; if (intValue >= org.apache.drill.exec.util.DecimalUtility.DIGITS_BASE) { out.setInteger(destIndex--, intValue % org.apache.drill.exec.util.DecimalUtility.DIGITS_BASE, out.start, out.buffer); carry = intValue / org.apache.drill.exec.util.DecimalUtility.DIGITS_BASE; } else { out.setInteger(destIndex--, intValue, out.start, out.buffer); break; } } } // Set the sign out.setSign(sign, out.start, out.buffer); } } @FunctionTemplate(name = "floor", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_ZERO_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}FloorFunction implements DrillSimpleFunc { @Param ${type.name}Holder in; @Output ${type.name}Holder out; public void setup() { } public void eval() { out.scale = 0; out.precision = in.precision; out.buffer = in.buffer; out.start = in.start; boolean sign = in.getSign(in.start, in.buffer); // Indicates whether we need to decrement 1 from the integer part, while performing floor, done for -ve values int carry = 0; int scaleStartIndex = ${type.storage} - org.apache.drill.exec.util.DecimalUtility.roundUp(in.scale); int srcIntIndex = scaleStartIndex - 1; if (sign == true) { // For negative values ceil we don't need to increment the integer part while (scaleStartIndex < ${type.storage}) { if (out.getInteger(scaleStartIndex, out.start, out.buffer) != 0) { carry = 1; break; } scaleStartIndex++; } } // Truncate the fractional part, move the integer part int destIndex = ${type.storage} - 1; while (srcIntIndex >= 0) { out.setInteger(destIndex--, out.getInteger(srcIntIndex--, out.start, out.buffer), out.start, out.buffer); } // Set the remaining portion of the decimal to be zeroes while (destIndex >= 0) { out.setInteger(destIndex--, 0, out.start, out.buffer); } // Add the carry if (carry != 0) { destIndex = ${type.storage} - 1; while (destIndex >= 0) { int intValue = out.getInteger(destIndex, out.start, out.buffer); intValue += carry; if (intValue >= org.apache.drill.exec.util.DecimalUtility.DIGITS_BASE) { out.setInteger(destIndex--, intValue % org.apache.drill.exec.util.DecimalUtility.DIGITS_BASE, out.start, out.buffer); carry = intValue / org.apache.drill.exec.util.DecimalUtility.DIGITS_BASE; } else { out.setInteger(destIndex--, intValue, out.start, out.buffer); break; } } } // Set the sign out.setSign(sign, out.start, out.buffer); } } @FunctionTemplate(names = {"trunc", "truncate"}, scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_ZERO_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}TruncateFunction implements DrillSimpleFunc { @Param ${type.name}Holder in; @Output ${type.name}Holder out; public void setup() { } public void eval() { out.scale = 0; out.precision = in.precision; out.buffer = in.buffer; out.start = in.start; boolean sign = in.getSign(in.start, in.buffer); // Integer part's src index int srcIntIndex = ${type.storage} - org.apache.drill.exec.util.DecimalUtility.roundUp(in.scale) - 1; // Truncate the fractional part, move the integer part int destIndex = ${type.storage} - 1; while (srcIntIndex >= 0) { out.setInteger(destIndex--, out.getInteger(srcIntIndex--, out.start, out.buffer), out.start, out.buffer); } // Set the remaining portion of the decimal to be zeroes while (destIndex >= 0) { out.setInteger(destIndex--, 0, out.start, out.buffer); } // Set the sign out.setSign(sign, out.start, out.buffer); } } @FunctionTemplate(names = {"trunc", "truncate"}, scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_SET_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}TruncateScaleFunction implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param IntHolder right; @Output ${type.name}Holder result; public void setup() { } public void eval() { result.scale = right.value; result.precision = left.precision; result.buffer = left.buffer; result.start = left.start; boolean sign = left.getSign(left.start, left.buffer); int newScaleRoundedUp = org.apache.drill.exec.util.DecimalUtility.roundUp(right.value); int origScaleRoundedUp = org.apache.drill.exec.util.DecimalUtility.roundUp(left.scale); if (right.value < left.scale) { // Get the source index beyond which we will truncate int srcIntIndex = ${type.storage} - origScaleRoundedUp - 1; int srcIndex = srcIntIndex + newScaleRoundedUp; // Truncate the remaining fractional part, move the integer part int destIndex = ${type.storage} - 1; if (srcIndex != destIndex) { while (srcIndex >= 0) { result.setInteger(destIndex--, result.getInteger(srcIndex--, result.start, result.buffer), result.start, result.buffer); } // Set the remaining portion of the decimal to be zeroes while (destIndex >= 0) { result.setInteger(destIndex--, 0, result.start, result.buffer); } } // We truncated the decimal digit. Now we need to truncate within the base 1 billion fractional digit int truncateFactor = org.apache.drill.exec.util.DecimalUtility.MAX_DIGITS - (right.value % org.apache.drill.exec.util.DecimalUtility.MAX_DIGITS); if (truncateFactor != org.apache.drill.exec.util.DecimalUtility.MAX_DIGITS) { truncateFactor = (int) org.apache.drill.exec.util.DecimalUtility.getPowerOfTen(truncateFactor); int fractionalDigits = result.getInteger(${type.storage} - 1, result.start, result.buffer); fractionalDigits /= truncateFactor; result.setInteger(${type.storage} - 1, fractionalDigits * truncateFactor, result.start, result.buffer); } } else if (right.value > left.scale) { // Add fractional digits to the decimal // Check if we need to shift the decimal digits to the left if (newScaleRoundedUp > origScaleRoundedUp) { int srcIndex = 0; int destIndex = newScaleRoundedUp - origScaleRoundedUp; // Check while extending scale, we are not overwriting integer part while (srcIndex < destIndex) { if (result.getInteger(srcIndex++, result.start, result.buffer) != 0) { throw new org.apache.drill.common.exceptions.DrillRuntimeException("Truncate resulting in loss of integer part, reduce scale specified"); } } srcIndex = 0; while (destIndex < ${type.storage}) { result.setInteger(srcIndex++, result.getInteger(destIndex++, result.start, result.buffer), result.start, result.buffer); } // Clear the remaining part while (srcIndex < ${type.storage}) { result.setInteger(srcIndex++, 0, result.start, result.buffer); } } } // Set the sign result.setSign(sign, result.start, result.buffer); } } @FunctionTemplate(name = "round", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_ZERO_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}RoundFunction implements DrillSimpleFunc { @Param ${type.name}Holder in; @Output ${type.name}Holder out; public void setup() { } public void eval() { out.scale = 0; out.precision = in.precision; out.buffer = in.buffer; out.start = in.start; boolean sign = in.getSign(in.start, in.buffer); boolean roundUp = false; // Get the first fractional digit to see if want to round up or not int scaleIndex = ${type.storage} - org.apache.drill.exec.util.DecimalUtility.roundUp(in.scale); if (scaleIndex < ${type.storage}) { int fractionalPart = out.getInteger(scaleIndex, out.start, out.buffer); int digit = fractionalPart / (org.apache.drill.exec.util.DecimalUtility.DIGITS_BASE / 10); if (digit > 4) { roundUp = true; } } // Integer part's src index int srcIntIndex = scaleIndex - 1; // Truncate the fractional part, move the integer part int destIndex = ${type.storage} - 1; while (srcIntIndex >= 0) { out.setInteger(destIndex--, out.getInteger(srcIntIndex--, out.start, out.buffer), out.start, out.buffer); } // Set the remaining portion of the decimal to be zeroes while (destIndex >= 0) { out.setInteger(destIndex--, 0, out.start, out.buffer); } // Perform the roundup srcIntIndex = ${type.storage} - 1; if (roundUp == true) { while (srcIntIndex >= 0) { int value = out.getInteger(srcIntIndex, out.start, out.buffer) + 1; if (value >= org.apache.drill.exec.util.DecimalUtility.DIGITS_BASE) { out.setInteger(srcIntIndex--, value % org.apache.drill.exec.util.DecimalUtility.DIGITS_BASE, out.start, out.buffer); value = value / org.apache.drill.exec.util.DecimalUtility.DIGITS_BASE; } else { out.setInteger(srcIntIndex--, value, out.start, out.buffer); break; } } } // Set the sign out.setSign(sign, out.start, out.buffer); } } @FunctionTemplate(name = "round", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_SET_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}RoundScaleFunction implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param IntHolder right; @Output ${type.name}Holder result; public void setup() { } public void eval() { result.scale = right.value; result.precision = left.precision; result.buffer = left.buffer; result.start = left.start; boolean sign = left.getSign(left.start, left.buffer); org.apache.drill.exec.util.DecimalUtility.roundDecimal(result.buffer, result.start, result.nDecimalDigits, result.scale, left.scale); // Set the sign result.setSign(sign, result.start, result.buffer); } } <#-- Handle 2 x 2 combinations of nullable and non-nullable arguments. --> <#list ["Nullable${type.name}", "${type.name}"] as leftType > <#list ["Nullable${type.name}", "${type.name}"] as rightType > <#-- Comparison function for sorting and grouping relational operators (not for comparison expression operators (=, <, etc.)). --> @FunctionTemplate(name = FunctionGenerationHelper.COMPARE_TO_NULLS_HIGH, scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_MAX_SCALE, nulls = NullHandling.INTERNAL) public static class GCompare${leftType}Vs${rightType}NullHigh implements DrillSimpleFunc { @Param ${leftType}Holder left; @Param ${rightType}Holder right; @Output IntHolder out; public void setup() {} public void eval() { <@compareBlock leftType=leftType rightType=rightType absCompare="false" output="out.value" nullCompare=true nullComparesHigh=true /> } } <#-- Comparison function for sorting and grouping relational operators (not for comparison expression operators (=, <, etc.)). --> @FunctionTemplate(name = FunctionGenerationHelper.COMPARE_TO_NULLS_LOW, scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_MAX_SCALE, nulls = NullHandling.INTERNAL) public static class GCompare${leftType}Vs${rightType}NullLow implements DrillSimpleFunc { @Param ${leftType}Holder left; @Param ${rightType}Holder right; @Output IntHolder out; public void setup() {} public void eval() { <@compareBlock leftType=leftType rightType=rightType absCompare="false" output="out.value" nullCompare=true nullComparesHigh=false /> } } </#list> </#list> <#-- Comparison function for comparison expression operator (=, <, etc.), not for sorting and grouping relational operators.) --> @FunctionTemplate(name = "less than", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_MAX_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}LessThan implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param ${type.name}Holder right; @Output BitHolder out; public void setup() {} public void eval() { int cmp; <@compareBlock leftType="leftType" rightType="rightType" absCompare="false" output="cmp" nullCompare=false nullComparesHigh=false /> out.value = cmp == -1 ? 1 : 0; } } // TODO: RESOLVE: Here there are spaces in function template names, but // elsewhere there are underlines. Are things being looked up correctly? <#-- Comparison function for comparison expression operator (=, <, etc.), not for sorting and grouping relational operators.) --> @FunctionTemplate(name = "less than or equal to", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_MAX_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}LessThanEq implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param ${type.name}Holder right; @Output BitHolder out; public void setup() {} public void eval() { int cmp; <@compareBlock leftType="leftType" rightType="rightType" absCompare="false" output="cmp" nullCompare=false nullComparesHigh=false /> out.value = cmp < 1 ? 1 : 0; } } <#-- Comparison function for comparison expression operator (=, <, etc.), not for sorting and grouping relational operators.) --> @FunctionTemplate(name = "greater than", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_MAX_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}GreaterThan implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param ${type.name}Holder right; @Output BitHolder out; public void setup() {} public void eval() { int cmp; <@compareBlock leftType="leftType" rightType="rightType" absCompare="false" output="cmp" nullCompare=false nullComparesHigh=false /> out.value = cmp == 1 ? 1 : 0; } } <#-- Comparison function for comparison expression operator (=, <, etc.), not for sorting and grouping relational operators.) --> @FunctionTemplate(name = "greater than or equal to", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_MAX_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}GreaterThanEq implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param ${type.name}Holder right; @Output BitHolder out; public void setup() {} public void eval() { int cmp; <@compareBlock leftType="leftType" rightType="rightType" absCompare="false" output="cmp" nullCompare=false nullComparesHigh=false /> out.value = cmp > -1 ? 1 : 0; } } <#-- Comparison function for comparison expression operator (=, <, etc.), not for sorting and grouping relational operators.) --> @FunctionTemplate(name = "Equal", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_MAX_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}Equal implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param ${type.name}Holder right; @Output BitHolder out; public void setup() {} public void eval() { int cmp; <@compareBlock leftType="leftType" rightType="rightType" absCompare="false" output="cmp" nullCompare=false nullComparesHigh=false /> out.value = cmp == 0 ? 1 : 0; } } <#-- Comparison function for comparison expression operator (=, <, etc.), not for sorting and grouping relational operators.) --> @FunctionTemplate(name = "not equal", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_MAX_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}NotEqual implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param ${type.name}Holder right; @Output BitHolder out; public void setup() {} public void eval() { int cmp; <@compareBlock leftType="leftType" rightType="rightType" absCompare="false" output="cmp" nullCompare=false nullComparesHigh=false /> out.value = cmp != 0 ? 1 : 0; } } } <#elseif type.name.endsWith("Dense")> <@pp.changeOutputFile name="/org/apache/drill/exec/expr/fn/impl/${type.name}Functions.java" /> <#include "/@includes/license.ftl" /> package org.apache.drill.exec.expr.fn.impl; <#include "/@includes/vv_imports.ftl" /> import org.apache.drill.exec.expr.DrillSimpleFunc; import org.apache.drill.exec.expr.annotations.FunctionTemplate; import org.apache.drill.exec.expr.annotations.FunctionTemplate.NullHandling; import org.apache.drill.exec.expr.annotations.Output; import org.apache.drill.exec.expr.annotations.Param; import org.apache.drill.exec.expr.fn.FunctionGenerationHelper; import org.apache.drill.exec.expr.holders.*; import org.apache.drill.exec.record.RecordBatch; import io.netty.buffer.ByteBuf; import java.nio.ByteBuffer; /* * This class is generated using freemarker and the ${.template_name} template. */ @SuppressWarnings("unused") public class ${type.name}Functions { <#-- Handle 2 x 2 combinations of nullable and non-nullable arguments. --> <#list ["Nullable${type.name}", "${type.name}"] as leftType > <#list ["Nullable${type.name}", "${type.name}"] as rightType > <#-- Comparison function for sorting and grouping relational operators (not for comparison expression operators (=, <, etc.)). --> @FunctionTemplate(name = FunctionGenerationHelper.COMPARE_TO_NULLS_HIGH, scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_MAX_SCALE, nulls = NullHandling.INTERNAL) public static class GCompare${leftType}Vs${rightType}NullHigh implements DrillSimpleFunc { @Param ${leftType}Holder left; @Param ${rightType}Holder right; @Output IntHolder out; public void setup() {} public void eval() { outside: { <@compareNullsSubblock leftType=leftType rightType=rightType output="out.value" breakTarget="outside" nullCompare=true nullComparesHigh=true /> out.value = org.apache.drill.exec.util.DecimalUtility.compareDenseBytes(left.buffer, left.start, left.getSign(left.start, left.buffer), right.buffer, right.start, right.getSign(right.start, right.buffer), left.WIDTH); } // outside } } <#-- Comparison function for sorting and grouping relational operators (not for comparison expression operators (=, <, etc.)). --> @FunctionTemplate(name = FunctionGenerationHelper.COMPARE_TO_NULLS_LOW, scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_MAX_SCALE, nulls = NullHandling.INTERNAL) public static class GCompare${leftType}Vs${rightType}NullLow implements DrillSimpleFunc { @Param ${leftType}Holder left; @Param ${rightType}Holder right; @Output IntHolder out; public void setup() {} public void eval() { outside: { <@compareNullsSubblock leftType=leftType rightType=rightType output="out.value" breakTarget="outside" nullCompare=true nullComparesHigh=false /> out.value = org.apache.drill.exec.util.DecimalUtility.compareDenseBytes(left.buffer, left.start, left.getSign(left.start, left.buffer), right.buffer, right.start, right.getSign(right.start, right.buffer), left.WIDTH); } // outside } } </#list> </#list> <#-- Comparison function for comparison expression operator (=, <, etc.), not for sorting and grouping relational operators.) --> @FunctionTemplate(name = "less than", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_MAX_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}LessThan implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param ${type.name}Holder right; @Output BitHolder out; public void setup() {} public void eval() { int cmp = org.apache.drill.exec.util.DecimalUtility.compareDenseBytes(left.buffer, left.start, left.getSign(left.start, left.buffer), right.buffer, right.start, right.getSign(right.start, right.buffer), left.WIDTH); out.value = cmp == -1 ? 1 : 0; } } <#-- Comparison function for comparison expression operator (=, <, etc.), not for sorting and grouping relational operators.) --> @FunctionTemplate(name = "less than or equal to", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_MAX_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}LessThanEq implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param ${type.name}Holder right; @Output BitHolder out; public void setup() {} public void eval() { int cmp = org.apache.drill.exec.util.DecimalUtility.compareDenseBytes(left.buffer, left.start, left.getSign(left.start, left.buffer), right.buffer, right.start, right.getSign(right.start, right.buffer), left.WIDTH); out.value = cmp < 1 ? 1 : 0; } } <#-- Comparison function for comparison expression operator (=, <, etc.), not for sorting and grouping relational operators.) --> @FunctionTemplate(name = "greater than", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_MAX_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}GreaterThan implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param ${type.name}Holder right; @Output BitHolder out; public void setup() {} public void eval() { int cmp = org.apache.drill.exec.util.DecimalUtility.compareDenseBytes(left.buffer, left.start, left.getSign(left.start, left.buffer), right.buffer, right.start, right.getSign(right.start, right.buffer), left.WIDTH); out.value = cmp == 1 ? 1 : 0; } } <#-- Comparison function for comparison expression operator (=, <, etc.), not for sorting and grouping relational operators.) --> @FunctionTemplate(name = "greater than or equal to", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_MAX_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}GreaterThanEq implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param ${type.name}Holder right; @Output BitHolder out; public void setup() {} public void eval() { int cmp = org.apache.drill.exec.util.DecimalUtility.compareDenseBytes(left.buffer, left.start, left.getSign(left.start, left.buffer), right.buffer, right.start, right.getSign(right.start, right.buffer), left.WIDTH); out.value = cmp > -1 ? 1 : 0; } } <#-- Comparison function for comparison expression operator (=, <, etc.), not for sorting and grouping relational operators.) --> @FunctionTemplate(name = "Equal", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_MAX_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}Equal implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param ${type.name}Holder right; @Output BitHolder out; public void setup() {} public void eval() { int cmp = org.apache.drill.exec.util.DecimalUtility.compareDenseBytes(left.buffer, left.start, left.getSign(left.start, left.buffer), right.buffer, right.start, right.getSign(right.start, right.buffer), left.WIDTH); out.value = cmp == 0 ? 1 : 0; } } <#-- Comparison function for comparison expression operator (=, <, etc.), not for sorting and grouping relational operators.) --> @FunctionTemplate(name = "not equal", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_MAX_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}NotEqual implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param ${type.name}Holder right; @Output BitHolder out; public void setup() {} public void eval() { int cmp = org.apache.drill.exec.util.DecimalUtility.compareDenseBytes(left.buffer, left.start, left.getSign(left.start, left.buffer), right.buffer, right.start, right.getSign(right.start, right.buffer), left.WIDTH); out.value = cmp != 0 ? 1 : 0; } } } <#elseif type.name.endsWith("Decimal9") || type.name.endsWith("Decimal18")> <@pp.changeOutputFile name="/org/apache/drill/exec/expr/fn/impl/${type.name}Functions.java" /> <#include "/@includes/license.ftl" /> package org.apache.drill.exec.expr.fn.impl; <#include "/@includes/vv_imports.ftl" /> import org.apache.drill.exec.expr.DrillSimpleFunc; import org.apache.drill.exec.expr.annotations.FunctionTemplate; import org.apache.drill.exec.expr.annotations.FunctionTemplate.NullHandling; import org.apache.drill.exec.expr.annotations.Output; import org.apache.drill.exec.expr.annotations.Param; import org.apache.drill.exec.expr.annotations.Workspace; import org.apache.drill.exec.expr.fn.FunctionGenerationHelper; import org.apache.drill.exec.expr.holders.*; import org.apache.drill.exec.record.RecordBatch; import io.netty.buffer.ByteBuf; import java.nio.ByteBuffer; @SuppressWarnings("unused") public class ${type.name}Functions { @FunctionTemplate(name = "add", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_ADD_SCALE, nulls = NullHandling.NULL_IF_NULL, checkPrecisionRange = true) 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() { 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 javaType=type.storage leftType="leftType" rightType="rightType"/> result.value = left.value + right.value; result.precision = outputPrecision; result.scale = outputScale; } } @FunctionTemplate(name = "subtract", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_ADD_SCALE, nulls = NullHandling.NULL_IF_NULL, checkPrecisionRange = true) 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() { 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 javaType=type.storage leftType="leftType" rightType="rightType"/> result.value = left.value - right.value; result.precision = outputPrecision; result.scale = outputScale; } } @FunctionTemplate(name = "multiply", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_SUM_SCALE, nulls = NullHandling.NULL_IF_NULL, checkPrecisionRange = true) public static class ${type.name}MultiplyFunction 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() { 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 = outputPrecision; result.scale = outputScale; } } @FunctionTemplate(name = "abs", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_MAX_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}AbsFunction implements DrillSimpleFunc { @Param ${type.name}Holder in; @Output ${type.name}Holder out; public void setup() {} public void eval() { out.precision = out.maxPrecision; out.scale = in.scale; out.value = in.value; if (out.value < 0){ out.value *= -1; } } } @FunctionTemplate(name = "exact_divide", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_DIV_SCALE, nulls = NullHandling.NULL_IF_NULL, checkPrecisionRange = true) public static class ${type.name}DivideFunction implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param ${type.name}Holder right; @Output ${type.name}Holder result; @Workspace int outputScale; @Workspace int outputPrecision; public void setup() { 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.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); java.math.BigDecimal output = numerator.divide(denominator, (int) result.scale, java.math.BigDecimal.ROUND_HALF_UP); result.value = output.unscaledValue().${type.storage}Value(); } } @FunctionTemplate(name = "mod", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_MOD_SCALE, nulls = NullHandling.NULL_IF_NULL, checkPrecisionRange = true) public static class ${type.name}ModFunction 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() { outputPrecision = Integer.MIN_VALUE; } public void eval() { if (outputPrecision == Integer.MIN_VALUE) { org.apache.drill.common.util.DecimalScalePrecisionModFunction resultScalePrec = new org.apache.drill.common.util.DecimalScalePrecisionModFunction((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(result.scale, java.math.BigDecimal.ROUND_HALF_UP); result.value = output.unscaledValue().${type.storage}Value(); } } @FunctionTemplate(name = "sign", scope = FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}SignFunction implements DrillSimpleFunc { @Param ${type.name}Holder in; @Output IntHolder out; public void setup() {} public void eval() { out.value = (in.value < 0) ? -1 : ((in.value > 0) ? 1 : 0); } } @FunctionTemplate(names = {"trunc", "truncate"}, scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_ZERO_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}TruncFunction implements DrillSimpleFunc { @Param ${type.name}Holder in; @Output ${type.name}Holder out; public void setup() {} public void eval() { out.value =(${type.storage}) (org.apache.drill.exec.util.DecimalUtility.adjustScaleDivide(in.value, (int) in.scale)); out.precision = out.maxPrecision; out.scale = 0; } } @FunctionTemplate(names = {"trunc", "truncate"}, scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_SET_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}TruncateScaleFunction implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param IntHolder right; @Output ${type.name}Holder out; public void setup() {} public void eval() { out.value = (${type.storage}) (org.apache.drill.exec.util.DecimalUtility.adjustScaleDivide(left.value, (int) (left.scale - right.value))); out.precision = out.maxPrecision; out.scale = right.value; } } @FunctionTemplate(names = {"ceil", "ceiling"}, scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_ZERO_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}CeilFunction implements DrillSimpleFunc { @Param ${type.name}Holder in; @Output ${type.name}Holder out; public void setup() { } public void eval() { ${type.storage} scaleFactor = (${type.storage}) (org.apache.drill.exec.util.DecimalUtility.getPowerOfTen((int) in.scale)); // Get the integer part ${type.storage} integerPart = in.value / scaleFactor; // Get the fractional part, if its non-zero increment the integer part ${type.storage} fractionalPart = (${type.storage}) (in.value % scaleFactor); if (fractionalPart != 0 && in.value >= 0) { integerPart++; } out.scale = 0; out.value = integerPart; } } @FunctionTemplate(name = "floor", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_ZERO_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}FloorFunction implements DrillSimpleFunc { @Param ${type.name}Holder in; @Output ${type.name}Holder out; public void setup() { } public void eval() { ${type.storage} scaleFactor = (${type.storage}) (org.apache.drill.exec.util.DecimalUtility.getPowerOfTen((int) in.scale)); out.scale = 0; out.value = (in.value / scaleFactor); // For negative values we have to decrement by 1 if (in.value < 0) { ${type.storage} fractionalPart = (${type.storage}) (in.value % scaleFactor); if (fractionalPart != 0) { out.value--; } } } } @FunctionTemplate(name = "round", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_ZERO_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}RoundFunction implements DrillSimpleFunc { @Param ${type.name}Holder in; @Output ${type.name}Holder out; public void setup() { } public void eval() { ${type.storage} scaleFactor = (${type.storage}) (org.apache.drill.exec.util.DecimalUtility.getPowerOfTen((int) in.scale)); ${type.storage} extractDigit = scaleFactor / 10; out.scale = 0; // Assign the integer part to the output out.value = in.value / scaleFactor; // Get the fractional part ${type.storage} fractionalPart = in.value % scaleFactor; // Get the first digit to check for rounding int digit = Math.abs((int) (fractionalPart / extractDigit)); if (digit > 4) { if (in.value > 0) { out.value++; } else if (in.value < 0) { out.value--; } } } } @FunctionTemplate(name = "round", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_SET_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}RoundScaleFunction implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param IntHolder right; @Output ${type.name}Holder out; public void setup() { } public void eval() { ${type.storage} scaleFactor = (${type.storage}) (org.apache.drill.exec.util.DecimalUtility.getPowerOfTen((int) left.scale)); ${type.storage} newScaleFactor = (${type.storage}) (org.apache.drill.exec.util.DecimalUtility.getPowerOfTen((int) right.value)); ${type.storage} truncScaleFactor = (${type.storage}) (org.apache.drill.exec.util.DecimalUtility.getPowerOfTen( Math.abs(left.scale - right.value))); int truncFactor = (int) (left.scale - right.value); // If rounding scale is >= current scale if (right.value >= left.scale) { out.value = (${type.storage}) (org.apache.drill.exec.util.DecimalUtility.adjustScaleMultiply(left.value, (int) (right.value - left.scale))); } else { out.scale = right.value; // Assign the integer part to the output out.value = left.value / scaleFactor; // Get the fractional part ${type.storage} fractionalPart = left.value % scaleFactor; // From the entire fractional part extract the digits upto which rounding is needed ${type.storage} newFractionalPart = (${type.storage}) (org.apache.drill.exec.util.DecimalUtility.adjustScaleDivide(fractionalPart, truncFactor)); ${type.storage} truncatedFraction = fractionalPart % truncScaleFactor; // Get the truncated fractional part and extract the first digit to see if we need to add 1 int digit = Math.abs((int) org.apache.drill.exec.util.DecimalUtility.adjustScaleDivide(truncatedFraction, truncFactor - 1)); if (digit > 4) { if (left.value > 0) { newFractionalPart++; } else if (left.value < 0) { newFractionalPart--; } } out.value = (out.value * newScaleFactor) + newFractionalPart; } } } <#-- Handle 2 x 2 combinations of nullable and non-nullable arguments. --> <#list ["Nullable${type.name}", "${type.name}"] as leftType > <#list ["Nullable${type.name}", "${type.name}"] as rightType > <#-- Comparison function for sorting and grouping relational operators (not for comparison expression operators (=, <, etc.)). --> @FunctionTemplate(name = FunctionGenerationHelper.COMPARE_TO_NULLS_HIGH, scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_MAX_SCALE, nulls = NullHandling.INTERNAL) public static class GCompare${leftType}Vs${rightType}NullHigh implements DrillSimpleFunc { @Param ${leftType}Holder left; @Param ${rightType}Holder right; @Output IntHolder out; public void setup() {} public void eval() { outside: { <@compareNullsSubblock leftType=leftType rightType=rightType output="out.value" breakTarget="outside" nullCompare=true nullComparesHigh=true /> <@adjustScale javaType=type.storage leftType="leftType" rightType="rightType"/> out.value = (left.value < right.value) ? -1 : (left.value > right.value) ? 1 : 0; } // outside } } <#-- Comparison function for sorting and grouping relational operators (not for comparison expression operators (=, <, etc.)). --> @FunctionTemplate(name = FunctionGenerationHelper.COMPARE_TO_NULLS_LOW, scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_MAX_SCALE, nulls = NullHandling.INTERNAL) public static class GCompare${leftType}Vs${rightType}NullLow implements DrillSimpleFunc { @Param ${leftType}Holder left; @Param ${rightType}Holder right; @Output IntHolder out; public void setup() {} public void eval() { outside: { <@compareNullsSubblock leftType=leftType rightType=rightType output="out.value" breakTarget="outside" nullCompare=true nullComparesHigh=false /> <@adjustScale javaType=type.storage leftType="leftType" rightType="rightType"/> out.value = (left.value < right.value) ? -1 : (left.value > right.value) ? 1 : 0; } // outside } } </#list> </#list> <#-- Comparison function for comparison expression operator (=, <, etc.), not for sorting and grouping relational operators.) --> @FunctionTemplate(name = "less than", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_MAX_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}LessThan implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param ${type.name}Holder right; @Output BitHolder out; public void setup() {} public void eval() { <@adjustScale javaType=type.storage leftType="leftType" rightType="rightType"/> out.value = (left.value < right.value) ? 1 : 0; } } <#-- Comparison function for comparison expression operator (=, <, etc.), not for sorting and grouping relational operators.) --> @FunctionTemplate(name = "less than or equal to", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_MAX_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}LessThanEq implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param ${type.name}Holder right; @Output BitHolder out; public void setup() {} public void eval() { <@adjustScale javaType=type.storage leftType="leftType" rightType="rightType"/> out.value = (left.value <= right.value) ? 1 : 0; } } <#-- Comparison function for comparison expression operator (=, <, etc.), not for sorting and grouping relational operators.) --> @FunctionTemplate(name = "greater than", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_MAX_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}GreaterThan implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param ${type.name}Holder right; @Output BitHolder out; public void setup() {} public void eval() { <@adjustScale javaType=type.storage leftType="leftType" rightType="rightType"/> out.value = (left.value > right.value) ? 1 : 0; } } <#-- Comparison function for comparison expression operator (=, <, etc.), not for sorting and grouping relational operators.) --> @FunctionTemplate(name = "greater than or equal to", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_MAX_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}GreaterThanEq implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param ${type.name}Holder right; @Output BitHolder out; public void setup() {} public void eval() { <@adjustScale javaType=type.storage leftType="leftType" rightType="rightType"/> out.value = (left.value >= right.value) ? 1 : 0; } } <#-- Comparison function for comparison expression operator (=, <, etc.), not for sorting and grouping relational operators.) --> @FunctionTemplate(name = "Equal", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_MAX_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}Equal implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param ${type.name}Holder right; @Output BitHolder out; public void setup() {} public void eval() { <@adjustScale javaType=type.storage leftType="leftType" rightType="rightType"/> out.value = (left.value == right.value) ? 1 : 0; } } <#-- Comparison function for comparison expression operator (=, <, etc.), not for sorting and grouping relational operators.) --> @FunctionTemplate(name = "not equal", scope = FunctionTemplate.FunctionScope.SIMPLE, returnType = FunctionTemplate.ReturnType.DECIMAL_MAX_SCALE, nulls = NullHandling.NULL_IF_NULL) public static class ${type.name}NotEqual implements DrillSimpleFunc { @Param ${type.name}Holder left; @Param ${type.name}Holder right; @Output BitHolder out; public void setup() {} public void eval() { <@adjustScale javaType=type.storage leftType="leftType" rightType="rightType"/> out.value = (left.value != right.value) ? 1 : 0; } } } </#if> </#list>