DRILL-320: Rework math functions to use code generated using free marker. Contains implementation for basic functions: +, -, *, /
Signed-off-by: Jacques Nadeau <jacq...@apache.org> Project: http://git-wip-us.apache.org/repos/asf/incubator-drill/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-drill/commit/ed9dec7c Tree: http://git-wip-us.apache.org/repos/asf/incubator-drill/tree/ed9dec7c Diff: http://git-wip-us.apache.org/repos/asf/incubator-drill/diff/ed9dec7c Branch: refs/heads/master Commit: ed9dec7c3f289e4f68466b989a500523f3d18b1e Parents: 8b90cae Author: Mehant Baid <meha...@gmail.com> Authored: Fri Feb 7 22:54:06 2014 -0800 Committer: Jacques Nadeau <jacq...@apache.org> Committed: Mon Mar 3 23:22:17 2014 -0800 ---------------------------------------------------------------------- exec/java-exec/src/main/codegen/config.fmpp | 3 +- .../src/main/codegen/data/MathFunctionTypes.tdd | 72 +++++++++++++++ .../templates/MathFunctionTemplates.java | 70 ++++++++++++++ .../drill/exec/expr/fn/impl/MathFunctions.java | 59 ------------ .../drill/exec/fn/impl/TestMathFunctions.java | 96 ++++++++++++++++++++ .../functions/simple_math_functions.json | 34 +++++++ 6 files changed, 274 insertions(+), 60 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ed9dec7c/exec/java-exec/src/main/codegen/config.fmpp ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/codegen/config.fmpp b/exec/java-exec/src/main/codegen/config.fmpp index cd2b2cc..8f1060a 100644 --- a/exec/java-exec/src/main/codegen/config.fmpp +++ b/exec/java-exec/src/main/codegen/config.fmpp @@ -17,7 +17,8 @@ data: { vv: tdd(../data/ValueVectorTypes.tdd), compare: tdd(../data/CompareTypes.tdd), - cast: tdd(../data/Casts.tdd) + cast: tdd(../data/Casts.tdd), + MathFunctionTypes: tdd(../data/MathFunctionTypes.tdd) } freemarkerLinks: { includes: includes/ http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ed9dec7c/exec/java-exec/src/main/codegen/data/MathFunctionTypes.tdd ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/codegen/data/MathFunctionTypes.tdd b/exec/java-exec/src/main/codegen/data/MathFunctionTypes.tdd new file mode 100644 index 0000000..1724373 --- /dev/null +++ b/exec/java-exec/src/main/codegen/data/MathFunctionTypes.tdd @@ -0,0 +1,72 @@ +# 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. + +{ + mathFunctionTypes: [ + {className: "Add", funcName: "add", op: "+", types: [ + {input1: "Int", input2: "Int", outputType: "Int", castType: "int"}, + {input1: "BigInt", input2: "BigInt", outputType: "BigInt", castType: "long"}, + {input1: "Float4", input2: "Float4", outputType: "Float4", castType: "float"}, + {input1: "Float8", input2: "Float8", outputType: "Float8", castType: "double"}, + {input1: "SmallInt", input2: "SmallInt", outputType: "SmallInt", castType: "short"}, + {input1: "TinyInt", input2: "TinyInt", outputType: "TinyInt", castType: "byte"}, + {input1: "UInt1", input2: "UInt1", outputType: "UInt1", castType: "byte"}, + {input1: "UInt2", input2: "UInt2", outputType: "UInt2", castType: "char"}, + {input1: "UInt4", input2: "UInt4", outputType: "UInt4", castType: "int"}, + {input1: "UInt8", input2: "UInt8", outputType: "UInt8", castType: "long"} + ] + }, + {className: "Subtract", funcName: "subtract", op: "-", types: [ + {input1: "Int", input2: "Int", outputType: "Int", castType: "int"}, + {input1: "BigInt", input2: "BigInt", outputType: "BigInt", castType: "long"}, + {input1: "Float4", input2: "Float4", outputType: "Float4", castType: "float"}, + {input1: "Float8", input2: "Float8", outputType: "Float8", castType: "double"}, + {input1: "SmallInt", input2: "SmallInt", outputType: "SmallInt", castType: "short"}, + {input1: "TinyInt", input2: "TinyInt", outputType: "TinyInt", castType: "byte"}, + {input1: "UInt1", input2: "UInt1", outputType: "UInt1", castType: "byte"}, + {input1: "UInt2", input2: "UInt2", outputType: "UInt2", castType: "char"}, + {input1: "UInt4", input2: "UInt4", outputType: "UInt4", castType: "int"}, + {input1: "UInt8", input2: "UInt8", outputType: "UInt8", castType: "long"} + ] + }, + {className: "Multiply", funcName: "multiply", op: "*", types: [ + {input1: "Int", input2: "Int", outputType: "Int", castType: "int"}, + {input1: "BigInt", input2: "BigInt", outputType: "BigInt", castType: "long"}, + {input1: "Float4", input2: "Float4", outputType: "Float4", castType: "float"}, + {input1: "Float8", input2: "Float8", outputType: "Float8", castType: "double"}, + {input1: "SmallInt", input2: "SmallInt", outputType: "SmallInt", castType: "short"}, + {input1: "TinyInt", input2: "TinyInt", outputType: "TinyInt", castType: "byte"}, + {input1: "UInt1", input2: "UInt1", outputType: "UInt1", castType: "byte"}, + {input1: "UInt2", input2: "UInt2", outputType: "UInt2", castType: "char"}, + {input1: "UInt4", input2: "UInt4", outputType: "UInt4", castType: "int"}, + {input1: "UInt8", input2: "UInt8", outputType: "UInt8", castType: "long"} + ] + }, + {className: "Divide", funcName: "divide", op: "/", types: [ + {input1: "Int", input2: "Int", outputType: "Int", castType: "int"}, + {input1: "BigInt", input2: "BigInt", outputType: "BigInt", castType: "long"}, + {input1: "Float4", input2: "Float4", outputType: "Float4", castType: "float"}, + {input1: "Float8", input2: "Float8", outputType: "Float8", castType: "double"}, + {input1: "SmallInt", input2: "SmallInt", outputType: "SmallInt", castType: "short"}, + {input1: "TinyInt", input2: "TinyInt", outputType: "TinyInt", castType: "byte"}, + {input1: "UInt1", input2: "UInt1", outputType: "UInt1", castType: "byte"}, + {input1: "UInt2", input2: "UInt2", outputType: "UInt2", castType: "char"}, + {input1: "UInt4", input2: "UInt4", outputType: "UInt4", castType: "int"}, + {input1: "UInt8", input2: "UInt8", outputType: "UInt8", castType: "long"} + ] + } + ] +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ed9dec7c/exec/java-exec/src/main/codegen/templates/MathFunctionTemplates.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/codegen/templates/MathFunctionTemplates.java b/exec/java-exec/src/main/codegen/templates/MathFunctionTemplates.java new file mode 100644 index 0000000..9ec2178 --- /dev/null +++ b/exec/java-exec/src/main/codegen/templates/MathFunctionTemplates.java @@ -0,0 +1,70 @@ +/** + * 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. + */ +<@pp.dropOutputFile /> + + + +<#list MathFunctionTypes.mathFunctionTypes as inputType> +<@pp.changeOutputFile name="/org/apache/drill/exec/expr/fn/impl/${inputType.className}Functions.java" /> + +<#include "/@includes/license.ftl" /> + +<#-- A utility class that is used to generate java code for add function --> + +/* + * This class is automatically generated from AddTypes.tdd using FreeMarker. + */ + + +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.FunctionScope; +import org.apache.drill.exec.expr.annotations.FunctionTemplate.FunctionScope; +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.holders.*; +import org.apache.drill.exec.record.RecordBatch; + +@SuppressWarnings("unused") + +public class ${inputType.className}Functions { + static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(${inputType.className}Functions.class); + +<#list inputType.types as type> + + @FunctionTemplate(name = "${inputType.funcName}", scope = FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL) + public static class ${type.input1}${type.input2}${inputType.className} implements DrillSimpleFunc { + + @Param ${type.input1}Holder in1; + @Param ${type.input2}Holder in2; + @Output ${type.outputType}Holder out; + + public void setup(RecordBatch b) { + } + + public void eval() { + out.value = (${type.castType}) (in1.value ${inputType.op} in2.value); + } + } +</#list> +} +</#list> http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ed9dec7c/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/MathFunctions.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/MathFunctions.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/MathFunctions.java index ea251c3..f4e2060 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/MathFunctions.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/MathFunctions.java @@ -34,65 +34,6 @@ public class MathFunctions{ private MathFunctions(){} - @FunctionTemplate(name = "add", scope = FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL) - public static class Add1 implements DrillSimpleFunc{ - - @Param IntHolder left; - @Param IntHolder right; - @Output IntHolder out; - - public void setup(RecordBatch b){} - - public void eval(){ - out.value = left.value + right.value; - } - - } - - @FunctionTemplate(name = "add", scope = FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL) - public static class LongAdd1 implements DrillSimpleFunc{ - - @Param BigIntHolder left; - @Param BigIntHolder right; - @Output BigIntHolder out; - - public void setup(RecordBatch b){} - - public void eval(){ - out.value = left.value + right.value; - } - - } - - @FunctionTemplate(name = "add", scope = FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL) - public static class Float4Add implements DrillSimpleFunc{ - - @Param Float4Holder left; - @Param Float4Holder right; - @Output Float4Holder out; - - public void setup(RecordBatch b){} - - public void eval(){ - out.value = left.value + right.value; - } - } - - - @FunctionTemplate(name = "add", scope = FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL) - public static class Float8Add implements DrillSimpleFunc{ - - @Param Float8Holder left; - @Param Float8Holder right; - @Output Float8Holder out; - - public void setup(RecordBatch b){} - - public void eval(){ - out.value = left.value + right.value; - } - } - @FunctionTemplate(name = "negative", scope = FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL) public static class Negative implements DrillSimpleFunc{ http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ed9dec7c/exec/java-exec/src/test/java/org/apache/drill/exec/fn/impl/TestMathFunctions.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/java/org/apache/drill/exec/fn/impl/TestMathFunctions.java b/exec/java-exec/src/test/java/org/apache/drill/exec/fn/impl/TestMathFunctions.java new file mode 100644 index 0000000..cc90f13 --- /dev/null +++ b/exec/java-exec/src/test/java/org/apache/drill/exec/fn/impl/TestMathFunctions.java @@ -0,0 +1,96 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.drill.exec.fn.impl; + +import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; + +import mockit.Injectable; +import mockit.NonStrictExpectations; + +import org.apache.drill.common.config.DrillConfig; +import org.apache.drill.common.expression.ExpressionPosition; +import org.apache.drill.common.expression.SchemaPath; +import org.apache.drill.common.util.FileUtils; +import org.apache.drill.exec.expr.fn.FunctionImplementationRegistry; +import org.apache.drill.exec.memory.BufferAllocator; +import org.apache.drill.exec.memory.TopLevelAllocator; +import org.apache.drill.exec.ops.FragmentContext; +import org.apache.drill.exec.physical.PhysicalPlan; +import org.apache.drill.exec.physical.base.FragmentRoot; +import org.apache.drill.exec.physical.impl.OperatorCreatorRegistry; +import org.apache.drill.exec.physical.impl.ImplCreator; +import org.apache.drill.exec.physical.impl.SimpleRootExec; +import org.apache.drill.exec.planner.PhysicalPlanReader; +import org.apache.drill.exec.proto.BitControl; +import org.apache.drill.exec.proto.CoordinationProtos; +import org.apache.drill.exec.proto.ExecProtos.FragmentHandle; +import org.apache.drill.exec.rpc.user.UserServer.UserClientConnection; +import org.apache.drill.exec.server.DrillbitContext; +import org.apache.drill.exec.vector.BigIntVector; +import org.apache.drill.exec.vector.Float8Vector; + +import org.junit.Test; + +import com.google.common.base.Charsets; +import com.google.common.io.Files; +import com.codahale.metrics.MetricRegistry; + + +public class TestMathFunctions { + + static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(TestMathFunctions.class); + DrillConfig c = DrillConfig.create(); + + + @Test + public void testBasicMathFunctions(@Injectable final DrillbitContext bitContext, @Injectable UserClientConnection connection) throws Throwable + { + + new NonStrictExpectations(){{ + bitContext.getMetrics(); result = new MetricRegistry(); + bitContext.getAllocator(); result = new TopLevelAllocator(); + bitContext.getConfig(); result = c; + bitContext.getOperatorCreatorRegistry(); result = new OperatorCreatorRegistry(c); + }}; + + PhysicalPlanReader reader = new PhysicalPlanReader(c, c.getMapper(), CoordinationProtos.DrillbitEndpoint.getDefaultInstance()); + PhysicalPlan plan = reader.readPhysicalPlan(Files.toString(FileUtils.getResourceAsFile("/functions/simple_math_functions.json"), Charsets.UTF_8)); + FunctionImplementationRegistry registry = new FunctionImplementationRegistry(c); + FragmentContext context = new FragmentContext(bitContext, BitControl.PlanFragment.getDefaultInstance(), connection, registry); + SimpleRootExec exec = new SimpleRootExec(ImplCreator.getExec(context, (FragmentRoot) plan.getSortedOperators(false).iterator().next())); + + while(exec.next()) { + BigIntVector intMulVector = exec.getValueVectorById(new SchemaPath("INTMUL", ExpressionPosition.UNKNOWN), BigIntVector.class); + Float8Vector floatMulVector = exec.getValueVectorById(new SchemaPath("FLOATMUL", ExpressionPosition.UNKNOWN), Float8Vector.class); + BigIntVector intAddVector = exec.getValueVectorById(new SchemaPath("INTADD", ExpressionPosition.UNKNOWN), BigIntVector.class); + Float8Vector floatAddVector = exec.getValueVectorById(new SchemaPath("FLOATADD", ExpressionPosition.UNKNOWN), Float8Vector.class); + assertEquals(exec.getRecordCount(), 1); + assertEquals(intMulVector.getAccessor().get(0), 2); + assertEquals(floatMulVector.getAccessor().get(0), (1.1 * 2.2), 0); + assertEquals(intAddVector.getAccessor().get(0), 3); + assertEquals(floatAddVector.getAccessor().get(0), (1.1 + 2.2), 0); + } + + if(context.getFailureCause() != null){ + throw context.getFailureCause(); + } + assertTrue(!context.isFailed()); + } +} http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ed9dec7c/exec/java-exec/src/test/resources/functions/simple_math_functions.json ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/resources/functions/simple_math_functions.json b/exec/java-exec/src/test/resources/functions/simple_math_functions.json new file mode 100644 index 0000000..28ac5b2 --- /dev/null +++ b/exec/java-exec/src/test/resources/functions/simple_math_functions.json @@ -0,0 +1,34 @@ +{ + head : { + version : 1, + generator : { + type : "optiq", + info : "na" + }, + type : "APACHE_DRILL_PHYSICAL" + }, + graph:[ + { + @id:1, + pop:"mock-sub-scan", + url: "http://apache.org", + entries:[ + {records: 1, types: [ + {name: "blue", type: "BIGINT", mode: "REQUIRED"} + ]} + ] + }, { + pop : "project", + @id : 2, + exprs : [ + { ref : "output.INTMUL", expr : " 1 * 2 "}, + { ref : "output.FLOATMUL", expr : " 1.1 * 2.2 "}, + { ref : "output.INTADD", expr : " 1 + 2 " }, + { ref : "output.FLOATADD", expr : " 1.1 + 2.2 " } ], + child : 1 + }, { + pop : "screen", + @id : 3, + child : 2 + } ] +} \ No newline at end of file