/** * 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. */ /** NOTE: ComparisonFunctions.java does not contain/generate all comparison functions. DecimalFunctions.java and DateIntervalFunctions.java contain some. */ <#-- TODO: Refactor comparison code from DecimalFunctions.java and DateIntervalFunctions.java into here (to eliminate duplicate template code and so that ComparisonFunctions actually has all comparison functions. --> <@pp.dropOutputFile /> <#macro intervalCompareBlock leftType rightType leftMonths leftDays leftMillis rightMonths rightDays rightMillis output> org.joda.time.MutableDateTime leftDate = new org.joda.time.MutableDateTime(1970, 1, 1, 0, 0, 0, 0, org.joda.time.DateTimeZone.UTC); org.joda.time.MutableDateTime rightDate = new org.joda.time.MutableDateTime(1970, 1, 1, 0, 0, 0, 0, org.joda.time.DateTimeZone.UTC); // Left and right date have the same starting point (epoch), add the interval period and compare the two leftDate.addMonths(${leftMonths}); leftDate.addDays(${leftDays}); leftDate.add(${leftMillis}); rightDate.addMonths(${rightMonths}); rightDate.addDays(${rightDays}); rightDate.add(${rightMillis}); long leftMS = leftDate.getMillis(); long rightMS = rightDate.getMillis(); ${output} = leftMS < rightMS ? -1 : (leftMS > rightMS ? 1 : 0); </#macro> <#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: Generates block handling comparison, including NULL. --> <#-- Parameters: > <#-- - mode: selects case of comparison code --> <#-- - leftType: name of left argument's type (e.g., NullableFloat4) --> <#-- - rightType: name of right argument's type --> <#-- - output: output variable name --> <#-- - nullCompare: whether to generate null-comparison code --> <#-- - nullComparesHigh: whether NULL compares as the highest value or the lowest value --> <#macro compareBlock mode leftType rightType output nullCompare nullComparesHigh> outside: { <@compareNullsSubblock leftType=leftType rightType=rightType output="out.value" breakTarget="outside" nullCompare=true nullComparesHigh=nullComparesHigh /> <#if mode == "primitive"> ${output} = left.value < right.value ? -1 : (left.value == right.value ? 0 : 1); <#elseif mode == "varString"> ${output} = org.apache.drill.exec.expr.fn.impl.ByteFunctionHelpers.compare( left.buffer, left.start, left.end, right.buffer, right.start, right.end ); <#elseif mode == "intervalNameThis"> <@intervalCompareBlock leftType=leftType rightType=rightType leftMonths ="left.months" leftDays ="left.days" leftMillis ="left.milliseconds" rightMonths="right.months" rightDays="right.days" rightMillis="right.milliseconds" output="${output}"/> <#elseif mode == "intervalDay"> <@intervalCompareBlock leftType=leftType rightType=rightType leftMonths ="0" leftDays ="left.days" leftMillis ="left.milliseconds" rightMonths="0" rightDays="right.days" rightMillis="right.milliseconds" output="${output}"/> <#-- TODO: Refactor other comparison code to here. --> <#else> ${mode_HAS_BAD_VALUE} </#if> } // outside </#macro> <#-- 1. For each group of cross-comparable types: --> <#list comparisonTypesMain.typeGroups as typeGroup> <#-- 2. For each pair of (cross-comparable) types in group: --> <#list typeGroup.comparables as leftTypeBase> <#list typeGroup.comparables as rightTypeBase> <#-- Generate one file for each pair of base types (includes Nullable cases). --> <@pp.changeOutputFile name="/org/apache/drill/exec/expr/fn/impl/GCompare${leftTypeBase}Vs${rightTypeBase}.java" /> <#include "/@includes/license.ftl" /> package org.apache.drill.exec.expr.fn.impl; 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.fn.impl.ByteFunctionHelpers; import org.apache.drill.exec.expr.holders.*; import org.apache.drill.exec.record.RecordBatch; import javax.inject.Inject; import io.netty.buffer.DrillBuf; /* * This class is generated using freemarker and the ${.template_name} template. */ @SuppressWarnings("unused") public class GCompare${leftTypeBase}Vs${rightTypeBase} { <#-- 3. For each combination of Nullable vs. not (of given non-nullable types): --> <#list ["${leftTypeBase}", "Nullable${leftTypeBase}"] as leftType > <#list ["${rightTypeBase}", "Nullable${rightTypeBase}"] 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, 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 mode=typeGroup.mode leftType=leftType rightType=rightType 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, 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 mode=typeGroup.mode leftType=leftType rightType=rightType output="out.value" nullCompare=true nullComparesHigh=false /> } } </#list> </#list> <#-- 3. Nullable combinations --> <#-- Comparison function for comparison expression operator (=, <, etc.), not for sorting and grouping relational operators. --> @FunctionTemplate(names = {"less_than", "<"}, scope = FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL) public static class LessThan${leftTypeBase}Vs${rightTypeBase} implements DrillSimpleFunc { @Param ${leftTypeBase}Holder left; @Param ${rightTypeBase}Holder right; @Output BitHolder out; public void setup() {} public void eval() { <#if typeGroup.mode == "primitive"> out.value = left.value < right.value ? 1 : 0; <#elseif typeGroup.mode == "varString" || typeGroup.mode == "intervalNameThis" || typeGroup.mode == "intervalDay" > int cmp; <@compareBlock mode=typeGroup.mode leftType=leftTypeBase rightType=rightTypeBase output="cmp" nullCompare=false nullComparesHigh=false /> out.value = cmp == -1 ? 1 : 0; <#-- TODO: Refactor other comparison code to here. --> <#else> ${mode_HAS_BAD_VALUE} </#if> } } <#-- Comparison function for comparison expression operator (=, <, etc.), not for sorting and grouping relational operators. --> @FunctionTemplate(names = {"less_than_or_equal_to", "<="}, scope = FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL) public static class LessThanEq${leftTypeBase}Vs${rightTypeBase} implements DrillSimpleFunc { @Param ${leftTypeBase}Holder left; @Param ${rightTypeBase}Holder right; @Output BitHolder out; public void setup() {} public void eval() { <#if typeGroup.mode == "primitive"> out.value = left.value <= right.value ? 1 : 0; <#elseif typeGroup.mode == "varString" || typeGroup.mode == "intervalNameThis" || typeGroup.mode == "intervalDay" > int cmp; <@compareBlock mode=typeGroup.mode leftType=leftTypeBase rightType=rightTypeBase output="cmp" nullCompare=false nullComparesHigh=false /> out.value = cmp < 1 ? 1 : 0; <#-- TODO: Refactor other comparison code to here. --> <#else> ${mode_HAS_BAD_VALUE} </#if> } } <#-- Comparison function for comparison expression operator (=, <, etc.), not for sorting and grouping relational operators. --> @FunctionTemplate(names = {"greater_than", ">"}, scope = FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL) public static class GreaterThan${leftTypeBase}Vs${rightTypeBase} implements DrillSimpleFunc { @Param ${leftTypeBase}Holder left; @Param ${rightTypeBase}Holder right; @Output BitHolder out; public void setup() {} public void eval() { <#if typeGroup.mode == "primitive"> out.value = left.value > right.value ? 1 : 0; <#elseif typeGroup.mode == "varString" || typeGroup.mode == "intervalNameThis" || typeGroup.mode == "intervalDay" > int cmp; <@compareBlock mode=typeGroup.mode leftType=leftTypeBase rightType=rightTypeBase output="cmp" nullCompare=false nullComparesHigh=false /> out.value = cmp == 1 ? 1 : 0; <#-- TODO: Refactor other comparison code to here. --> <#else> ${mode_HAS_BAD_VALUE} </#if> } } <#-- Comparison function for comparison expression operator (=, <, etc.), not for sorting and grouping relational operators. --> @FunctionTemplate(names = {"greater_than_or_equal_to", ">="}, scope = FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL) public static class GreaterThanEq${leftTypeBase}Vs${rightTypeBase} implements DrillSimpleFunc { @Param ${leftTypeBase}Holder left; @Param ${rightTypeBase}Holder right; @Output BitHolder out; public void setup() {} public void eval() { <#if typeGroup.mode == "primitive"> out.value = left.value >= right.value ? 1 : 0; <#elseif typeGroup.mode == "varString" || typeGroup.mode == "intervalNameThis" || typeGroup.mode == "intervalDay" > int cmp; <@compareBlock mode=typeGroup.mode leftType=leftTypeBase rightType=rightTypeBase output="cmp" nullCompare=false nullComparesHigh=false /> out.value = cmp > -1 ? 1 : 0; <#-- TODO: Refactor other comparison code to here. --> <#else> ${mode_HAS_BAD_VALUE} </#if> } } <#-- Comparison function for comparison expression operator (=, <, etc.), not for sorting and grouping relational operators. --> @FunctionTemplate(names = {"equal", "==", "="}, scope = FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL) public static class Equals${leftTypeBase}Vs${rightTypeBase} implements DrillSimpleFunc { @Param ${leftTypeBase}Holder left; @Param ${rightTypeBase}Holder right; @Output BitHolder out; public void setup() {} public void eval() { <#if typeGroup.mode == "primitive"> out.value = left.value == right.value ? 1 : 0; <#elseif typeGroup.mode == "varString" > out.value = org.apache.drill.exec.expr.fn.impl.ByteFunctionHelpers.equal( left.buffer, left.start, left.end, right.buffer, right.start, right.end); <#elseif typeGroup.mode == "intervalNameThis" || typeGroup.mode == "intervalDay" > int cmp; <@compareBlock mode=typeGroup.mode leftType=leftTypeBase rightType=rightTypeBase output="cmp" nullCompare=false nullComparesHigh=false /> out.value = cmp == 0 ? 1 : 0; <#-- TODO: Refactor other comparison code to here. --> <#else> ${mode_HAS_BAD_VALUE} </#if> } } <#-- Comparison function for comparison expression operator (=, <, etc.), not for sorting and grouping relational operators. --> @FunctionTemplate(names = {"not_equal", "<>", "!="}, scope = FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL) public static class NotEquals${leftTypeBase}Vs${rightTypeBase} implements DrillSimpleFunc { @Param ${leftTypeBase}Holder left; @Param ${rightTypeBase}Holder right; @Output BitHolder out; public void setup() {} public void eval() { <#if typeGroup.mode == "primitive"> out.value = left.value != right.value ? 1 : 0; <#elseif typeGroup.mode == "varString" || typeGroup.mode == "intervalNameThis" || typeGroup.mode == "intervalDay" > int cmp; <@compareBlock mode=typeGroup.mode leftType=leftTypeBase rightType=rightTypeBase output="cmp" nullCompare=false nullComparesHigh=false /> out.value = cmp == 0 ? 0 : 1; <#-- TODO: Refactor other comparison code to here. --> <#else> ${mode_HAS_BAD_VALUE} </#if> } } } </#list> <#-- 2. Pair of types--> </#list> </#list> <#-- 1. Group -->