You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@drill.apache.org by pa...@apache.org on 2017/05/13 17:39:00 UTC
[2/7] drill git commit: DRILL-5419: Calculate return string length
for literals & some string functions
http://git-wip-us.apache.org/repos/asf/drill/blob/6741e68a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/FunctionUtils.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/FunctionUtils.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/FunctionUtils.java
new file mode 100644
index 0000000..f565b67
--- /dev/null
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/FunctionUtils.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.exec.expr.fn;
+
+import org.apache.drill.common.expression.LogicalExpression;
+import org.apache.drill.common.types.TypeProtos;
+import org.apache.drill.exec.expr.annotations.FunctionTemplate;
+
+import java.util.List;
+
+public class FunctionUtils {
+
+ /**
+ * Calculates return type data mode based on give logical expressions.
+ * If null handling strategy is internal, returns return value data mode.
+ * If null handling strategy is null if null and at least one of the input types are nullable,
+ * return nullable data mode.
+ *
+ * @param logicalExpressions logical expressions
+ * @param attributes function attributes
+ * @return data mode
+ */
+ public static TypeProtos.DataMode getReturnTypeDataMode(final List<LogicalExpression> logicalExpressions, FunctionAttributes attributes) {
+ if (attributes.getNullHandling() == FunctionTemplate.NullHandling.NULL_IF_NULL) {
+ for (final LogicalExpression logicalExpression : logicalExpressions) {
+ if (logicalExpression.getMajorType().getMode() == TypeProtos.DataMode.OPTIONAL) {
+ return TypeProtos.DataMode.OPTIONAL;
+ }
+ }
+ }
+ return attributes.getReturnValue().getType().getMode();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/drill/blob/6741e68a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/ValueReference.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/ValueReference.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/ValueReference.java
new file mode 100644
index 0000000..9fc2151
--- /dev/null
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/ValueReference.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.exec.expr.fn;
+
+import com.google.common.base.Preconditions;
+import org.apache.drill.common.types.TypeProtos.MajorType;
+import org.apache.drill.common.types.TypeProtos.MinorType;
+import org.apache.drill.common.types.Types;
+
+public class ValueReference {
+ private final MajorType type;
+ private final String name;
+ private boolean isConstant = false;
+ private boolean isFieldReader = false;
+ private boolean isComplexWriter = false;
+
+ public ValueReference(MajorType type, String name) {
+ Preconditions.checkNotNull(type);
+ Preconditions.checkNotNull(name);
+ this.type = type;
+ this.name = name;
+ }
+
+ public void setConstant(boolean isConstant) {
+ this.isConstant = isConstant;
+ }
+
+ public MajorType getType() {
+ return type;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public boolean isConstant() {
+ return isConstant;
+ }
+
+ public boolean isFieldReader() {
+ return isFieldReader;
+ }
+
+ public boolean isComplexWriter() {
+ return isComplexWriter;
+ }
+
+ @Override
+ public String toString() {
+ return "ValueReference [type=" + Types.toString(type) + ", name=" + name + "]";
+ }
+
+ public static ValueReference createFieldReaderRef(String name) {
+ MajorType type = Types.required(MinorType.LATE);
+ ValueReference ref = new ValueReference(type, name);
+ ref.isFieldReader = true;
+ return ref;
+ }
+
+ public static ValueReference createComplexWriterRef(String name) {
+ MajorType type = Types.required(MinorType.LATE);
+ ValueReference ref = new ValueReference(type, name);
+ ref.isComplexWriter = true;
+ return ref;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/drill/blob/6741e68a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/WorkspaceReference.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/WorkspaceReference.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/WorkspaceReference.java
new file mode 100644
index 0000000..e2ba449
--- /dev/null
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/WorkspaceReference.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.exec.expr.fn;
+
+import com.google.common.base.Preconditions;
+import org.apache.drill.common.types.TypeProtos.MajorType;
+import org.apache.drill.common.types.Types;
+
+public class WorkspaceReference {
+
+ private final Class<?> type;
+ private final String name;
+ private final boolean inject;
+ private MajorType majorType;
+
+ public WorkspaceReference(Class<?> type, String name, boolean inject) {
+ Preconditions.checkNotNull(type);
+ Preconditions.checkNotNull(name);
+ this.type = type;
+ this.name = name;
+ this.inject = inject;
+ }
+
+ void setMajorType(MajorType majorType) {
+ this.majorType = majorType;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public boolean isInject() {
+ return inject;
+ }
+
+ public Class<?> getType() {
+ return type;
+ }
+
+ public MajorType getMajorType() {
+ return majorType;
+ }
+
+ @Override
+ public String toString() {
+ return "WorkspaceReference [type= " + type +", major type=" + Types.toString(majorType) + ", name=" + name + "]";
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/drill/blob/6741e68a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/BitFunctions.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/BitFunctions.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/BitFunctions.java
index e19f284..4930aef 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/BitFunctions.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/BitFunctions.java
@@ -35,7 +35,7 @@ import org.apache.drill.exec.expr.holders.IntHolder;
public class BitFunctions {
@FunctionTemplate(names = {"booleanOr", "or", "||", "orNoShortCircuit"},
- scope = FunctionScope.SC_BOOLEAN_OPERATOR,
+ scope = FunctionScope.SIMPLE,
nulls = NullHandling.NULL_IF_NULL)
public static class BitOr implements DrillSimpleFunc {
@@ -51,7 +51,7 @@ public class BitFunctions {
}
@FunctionTemplate(names = {"booleanAnd", "and", "&&"},
- scope = FunctionScope.SC_BOOLEAN_OPERATOR,
+ scope = FunctionScope.SIMPLE,
nulls = NullHandling.NULL_IF_NULL)
public static class BitAnd implements DrillSimpleFunc {
http://git-wip-us.apache.org/repos/asf/drill/blob/6741e68a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/SimpleCastFunctions.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/SimpleCastFunctions.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/SimpleCastFunctions.java
index 346190a..807fbb9 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/SimpleCastFunctions.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/SimpleCastFunctions.java
@@ -1,4 +1,4 @@
-/**
+/*
* 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
@@ -51,7 +51,10 @@ public class SimpleCastFunctions {
}
}
- @FunctionTemplate(name = "castVARCHAR", scope = FunctionTemplate.FunctionScope.SIMPLE, nulls=NullHandling.NULL_IF_NULL)
+ @FunctionTemplate(name = "castVARCHAR",
+ scope = FunctionTemplate.FunctionScope.SIMPLE,
+ returnType = FunctionTemplate.ReturnType.STRING_CAST,
+ nulls = NullHandling.NULL_IF_NULL)
public static class CastBooleanVarChar implements DrillSimpleFunc {
@Param BitHolder in;
http://git-wip-us.apache.org/repos/asf/drill/blob/6741e68a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/StringFunctions.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/StringFunctions.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/StringFunctions.java
index d90581e..a6fa255 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/StringFunctions.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/StringFunctions.java
@@ -29,6 +29,7 @@ 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.NullHandling;
+import org.apache.drill.exec.expr.annotations.FunctionTemplate.ReturnType;
import org.apache.drill.exec.expr.annotations.Output;
import org.apache.drill.exec.expr.annotations.Param;
import org.apache.drill.exec.expr.annotations.Workspace;
@@ -483,7 +484,10 @@ public class StringFunctions{
/*
* Convert string to lower case.
*/
- @FunctionTemplate(name = "lower", scope = FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
+ @FunctionTemplate(name = "lower",
+ scope = FunctionScope.SIMPLE,
+ returnType = ReturnType.SAME_IN_OUT_LENGTH,
+ nulls = NullHandling.NULL_IF_NULL)
public static class LowerCase implements DrillSimpleFunc {
@Param VarCharHolder input;
@Output VarCharHolder out;
@@ -515,7 +519,10 @@ public class StringFunctions{
/*
* Convert string to upper case.
*/
- @FunctionTemplate(name = "upper", scope = FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
+ @FunctionTemplate(name = "upper",
+ scope = FunctionScope.SIMPLE,
+ returnType = ReturnType.SAME_IN_OUT_LENGTH,
+ nulls = NullHandling.NULL_IF_NULL)
public static class UpperCase implements DrillSimpleFunc {
@Param VarCharHolder input;
@@ -775,7 +782,10 @@ public class StringFunctions{
}
- @FunctionTemplate(name = "initcap", scope = FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
+ @FunctionTemplate(name = "initcap",
+ scope = FunctionScope.SIMPLE,
+ returnType = ReturnType.SAME_IN_OUT_LENGTH,
+ nulls = NullHandling.NULL_IF_NULL)
public static class InitCap implements DrillSimpleFunc {
@Param VarCharHolder input;
@Output VarCharHolder out;
@@ -860,7 +870,10 @@ public class StringFunctions{
* Fill up the string to length 'length' by prepending the characters 'fill' in the beginning of 'text'.
* If the string is already longer than length, then it is truncated (on the right).
*/
- @FunctionTemplate(name = "lpad", scope = FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
+ @FunctionTemplate(name = "lpad",
+ scope = FunctionScope.SIMPLE,
+ returnType = ReturnType.PAD,
+ nulls = NullHandling.NULL_IF_NULL)
public static class Lpad implements DrillSimpleFunc {
@Param VarCharHolder text;
@Param BigIntHolder length;
@@ -935,7 +948,10 @@ public class StringFunctions{
* Fill up the string to length 'length' by prepending the character ' ' in the beginning of 'text'.
* If the string is already longer than length, then it is truncated (on the right).
*/
- @FunctionTemplate(name = "lpad", scope = FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
+ @FunctionTemplate(name = "lpad",
+ scope = FunctionScope.SIMPLE,
+ returnType = ReturnType.PAD,
+ nulls = NullHandling.NULL_IF_NULL)
public static class LpadTwoArg implements DrillSimpleFunc {
@Param VarCharHolder text;
@Param BigIntHolder length;
@@ -994,7 +1010,10 @@ public class StringFunctions{
* Fill up the string to length "length" by appending the characters 'fill' at the end of 'text'
* If the string is already longer than length then it is truncated.
*/
- @FunctionTemplate(name = "rpad", scope = FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
+ @FunctionTemplate(name = "rpad",
+ scope = FunctionScope.SIMPLE,
+ returnType = ReturnType.PAD,
+ nulls = NullHandling.NULL_IF_NULL)
public static class Rpad implements DrillSimpleFunc {
@Param VarCharHolder text;
@Param BigIntHolder length;
@@ -1072,7 +1091,10 @@ public class StringFunctions{
* Fill up the string to length "length" by appending the characters ' ' at the end of 'text'
* If the string is already longer than length then it is truncated.
*/
- @FunctionTemplate(name = "rpad", scope = FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
+ @FunctionTemplate(name = "rpad",
+ scope = FunctionScope.SIMPLE,
+ returnType = ReturnType.PAD,
+ nulls = NullHandling.NULL_IF_NULL)
public static class RpadTwoArg implements DrillSimpleFunc {
@Param VarCharHolder text;
@Param BigIntHolder length;
@@ -1389,7 +1411,10 @@ public class StringFunctions{
}
- @FunctionTemplate(name = "concatOperator", scope = FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
+ @FunctionTemplate(name = "concatOperator",
+ scope = FunctionScope.SIMPLE,
+ returnType = ReturnType.CONCAT,
+ nulls = NullHandling.NULL_IF_NULL)
public static class ConcatOperator implements DrillSimpleFunc {
@Param VarCharHolder left;
@Param VarCharHolder right;
@@ -1418,7 +1443,10 @@ public class StringFunctions{
//Concatenate the text representations of the arguments. NULL arguments are ignored.
//TODO: NullHanding.INTERNAL for DrillSimpleFunc requires change in code generation.
- @FunctionTemplate(name = "concat", scope = FunctionScope.SIMPLE, nulls = NullHandling.INTERNAL)
+ @FunctionTemplate(name = "concat",
+ scope = FunctionScope.SIMPLE,
+ returnType = ReturnType.CONCAT,
+ nulls = NullHandling.INTERNAL)
public static class Concat implements DrillSimpleFunc {
@Param VarCharHolder left;
@Param VarCharHolder right;
@@ -1445,7 +1473,10 @@ public class StringFunctions{
}
}
- @FunctionTemplate(name = "concat", scope = FunctionScope.SIMPLE, nulls = NullHandling.INTERNAL)
+ @FunctionTemplate(name = "concat",
+ scope = FunctionScope.SIMPLE,
+ returnType = ReturnType.CONCAT,
+ nulls = NullHandling.INTERNAL)
public static class ConcatRightNullInput implements DrillSimpleFunc {
@Param VarCharHolder left;
@Param NullableVarCharHolder right;
@@ -1474,7 +1505,10 @@ public class StringFunctions{
}
}
- @FunctionTemplate(name = "concat", scope = FunctionScope.SIMPLE, nulls = NullHandling.INTERNAL)
+ @FunctionTemplate(name = "concat",
+ scope = FunctionScope.SIMPLE,
+ returnType = ReturnType.CONCAT,
+ nulls = NullHandling.INTERNAL)
public static class ConcatLeftNullInput implements DrillSimpleFunc {
@Param NullableVarCharHolder left;
@Param VarCharHolder right;
@@ -1503,7 +1537,10 @@ public class StringFunctions{
}
}
- @FunctionTemplate(name = "concat", scope = FunctionScope.SIMPLE, nulls = NullHandling.INTERNAL)
+ @FunctionTemplate(name = "concat",
+ scope = FunctionScope.SIMPLE,
+ returnType = ReturnType.CONCAT,
+ nulls = NullHandling.INTERNAL)
public static class ConcatBothNullInput implements DrillSimpleFunc {
@Param NullableVarCharHolder left;
@Param NullableVarCharHolder right;
@@ -1682,7 +1719,10 @@ public class StringFunctions{
/**
* Returns the reverse string for given input.
*/
- @FunctionTemplate(name = "reverse", scope = FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
+ @FunctionTemplate(name = "reverse",
+ scope = FunctionScope.SIMPLE,
+ returnType = ReturnType.SAME_IN_OUT_LENGTH,
+ nulls = NullHandling.NULL_IF_NULL)
public static class ReverseString implements DrillSimpleFunc {
@Param VarCharHolder in;
@Output VarCharHolder out;
http://git-wip-us.apache.org/repos/asf/drill/blob/6741e68a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/output/ConcatReturnTypeInference.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/output/ConcatReturnTypeInference.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/output/ConcatReturnTypeInference.java
new file mode 100644
index 0000000..eea02e7
--- /dev/null
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/output/ConcatReturnTypeInference.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.exec.expr.fn.output;
+
+import org.apache.drill.common.expression.LogicalExpression;
+import org.apache.drill.common.types.TypeProtos;
+import org.apache.drill.common.types.Types;
+import org.apache.drill.exec.expr.fn.FunctionAttributes;
+import org.apache.drill.exec.expr.fn.FunctionUtils;
+
+import java.util.List;
+
+/**
+ * Return type calculation implementation for functions with return type set as
+ * {@link org.apache.drill.exec.expr.annotations.FunctionTemplate.ReturnType#CONCAT}.
+ */
+public class ConcatReturnTypeInference implements ReturnTypeInference {
+
+ public static final ConcatReturnTypeInference INSTANCE = new ConcatReturnTypeInference();
+
+ /**
+ * Defines function return type and sets precision if it can be calculated.
+ * Return type precision is sum of input types precisions.
+ * If at least one input type does not have precision, return type will be without precision.
+ * If calculated precision is greater than {@link Types#MAX_VARCHAR_LENGTH},
+ * it is replaced with {@link Types#MAX_VARCHAR_LENGTH}.
+ *
+ * @param logicalExpressions logical expressions
+ * @param attributes function attributes
+ * @return return type
+ */
+ @Override
+ public TypeProtos.MajorType getType(List<LogicalExpression> logicalExpressions, FunctionAttributes attributes) {
+ TypeProtos.MajorType.Builder builder = TypeProtos.MajorType.newBuilder()
+ .setMinorType(attributes.getReturnValue().getType().getMinorType())
+ .setMode(FunctionUtils.getReturnTypeDataMode(logicalExpressions, attributes));
+
+ int totalPrecision = 0;
+ for (LogicalExpression expression : logicalExpressions) {
+ if (expression.getMajorType().hasPrecision()) {
+ totalPrecision += expression.getMajorType().getPrecision();
+ } else {
+ // if at least one expression has unknown precision, return type without precision
+ return builder.build();
+ }
+ }
+ return builder.setPrecision(totalPrecision > Types.MAX_VARCHAR_LENGTH ? Types.MAX_VARCHAR_LENGTH : totalPrecision).build();
+ }
+}
http://git-wip-us.apache.org/repos/asf/drill/blob/6741e68a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/output/DecimalReturnTypeInference.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/output/DecimalReturnTypeInference.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/output/DecimalReturnTypeInference.java
new file mode 100644
index 0000000..ba43b39
--- /dev/null
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/output/DecimalReturnTypeInference.java
@@ -0,0 +1,369 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.exec.expr.fn.output;
+
+import org.apache.drill.common.exceptions.DrillRuntimeException;
+import org.apache.drill.common.expression.LogicalExpression;
+import org.apache.drill.common.expression.ValueExpressions;
+import org.apache.drill.common.types.TypeProtos;
+import org.apache.drill.common.util.DecimalScalePrecisionAddFunction;
+import org.apache.drill.common.util.DecimalScalePrecisionDivideFunction;
+import org.apache.drill.common.util.DecimalScalePrecisionModFunction;
+import org.apache.drill.common.util.DecimalScalePrecisionMulFunction;
+import org.apache.drill.exec.expr.annotations.FunctionTemplate;
+import org.apache.drill.exec.expr.fn.FunctionAttributes;
+import org.apache.drill.exec.expr.fn.FunctionUtils;
+import org.apache.drill.exec.util.DecimalUtility;
+
+import java.util.List;
+
+public class DecimalReturnTypeInference {
+
+ /**
+ * Return type calculation implementation for functions with return type set as
+ * {@link org.apache.drill.exec.expr.annotations.FunctionTemplate.ReturnType#DECIMAL_ADD_SCALE}.
+ */
+ public static class DecimalAddReturnTypeInference implements ReturnTypeInference {
+
+ public static final DecimalAddReturnTypeInference INSTANCE = new DecimalAddReturnTypeInference();
+
+ /**
+ * This return type is used by add and subtract functions for decimal data type.
+ * DecimalScalePrecisionAddFunction is used to compute the output types' scale and precision.
+ *
+ * @param logicalExpressions logical expressions
+ * @param attributes function attributes
+ * @return return type
+ */
+ @Override
+ public TypeProtos.MajorType getType(List<LogicalExpression> logicalExpressions, FunctionAttributes attributes) {
+ TypeProtos.DataMode mode = FunctionUtils.getReturnTypeDataMode(logicalExpressions, attributes);
+
+ assert logicalExpressions.size() == 2;
+
+ DecimalScalePrecisionAddFunction outputScalePrec =
+ new DecimalScalePrecisionAddFunction(logicalExpressions.get(0).getMajorType().getPrecision(),
+ logicalExpressions.get(0).getMajorType().getScale(),
+ logicalExpressions.get(1).getMajorType().getPrecision(),
+ logicalExpressions.get(1).getMajorType().getScale());
+ return TypeProtos.MajorType.newBuilder()
+ .setMinorType(DecimalUtility.getDecimalDataType(outputScalePrec.getOutputPrecision()))
+ .setScale(outputScalePrec.getOutputScale())
+ .setPrecision(outputScalePrec.getOutputPrecision())
+ .setMode(mode)
+ .build();
+ }
+ }
+
+ /**
+ * Return type calculation implementation for functions with return type set as
+ * {@link org.apache.drill.exec.expr.annotations.FunctionTemplate.ReturnType#DECIMAL_AGGREGATE}.
+ */
+ public static class DecimalAggReturnTypeInference implements ReturnTypeInference {
+
+ public static final DecimalAggReturnTypeInference INSTANCE = new DecimalAggReturnTypeInference();
+
+ @Override
+ public TypeProtos.MajorType getType(List<LogicalExpression> logicalExpressions, FunctionAttributes attributes) {
+ int scale = 0;
+ int precision = 0;
+
+ // Get the max scale and precision from the inputs
+ for (LogicalExpression e : logicalExpressions) {
+ scale = Math.max(scale, e.getMajorType().getScale());
+ precision = Math.max(precision, e.getMajorType().getPrecision());
+ }
+
+ return TypeProtos.MajorType.newBuilder()
+ .setMinorType(attributes.getReturnValue().getType().getMinorType())
+ .setScale(scale)
+ .setPrecision(precision)
+ .setMode(TypeProtos.DataMode.REQUIRED)
+ .build();
+ }
+ }
+
+ /**
+ * Return type calculation implementation for functions with return type set as
+ * {@link org.apache.drill.exec.expr.annotations.FunctionTemplate.ReturnType#DECIMAL_CAST}.
+ */
+ public static class DecimalCastReturnTypeInference implements ReturnTypeInference {
+
+ public static final DecimalCastReturnTypeInference INSTANCE = new DecimalCastReturnTypeInference();
+
+ @Override
+ public TypeProtos.MajorType getType(List<LogicalExpression> logicalExpressions, FunctionAttributes attributes) {
+ TypeProtos.DataMode mode = FunctionUtils.getReturnTypeDataMode(logicalExpressions, attributes);
+
+ if (logicalExpressions.size() != 3) {
+ StringBuilder err = new StringBuilder();
+ for (int i = 0; i < logicalExpressions.size(); i++) {
+ err.append("arg").append(i).append(": ").append(logicalExpressions.get(i).getMajorType().getMinorType());
+ }
+ throw new DrillRuntimeException("Decimal cast function invoked with incorrect arguments" + err);
+ }
+
+ int scale = (int) ((ValueExpressions.LongExpression)(logicalExpressions.get(logicalExpressions.size() - 1))).getLong();
+ int precision = (int) ((ValueExpressions.LongExpression)(logicalExpressions.get(logicalExpressions.size() - 2))).getLong();
+ return TypeProtos.MajorType.newBuilder()
+ .setMinorType(attributes.getReturnValue().getType().getMinorType())
+ .setScale(scale)
+ .setPrecision(precision)
+ .setMode(mode)
+ .build();
+ }
+ }
+
+ /**
+ * Return type calculation implementation for functions with return type set as
+ * {@link org.apache.drill.exec.expr.annotations.FunctionTemplate.ReturnType#DECIMAL_DIV_SCALE}.
+ */
+ public static class DecimalDivScaleReturnTypeInference implements ReturnTypeInference {
+
+ public static final DecimalDivScaleReturnTypeInference INSTANCE = new DecimalDivScaleReturnTypeInference();
+
+ /**
+ * Return type is used by divide functions for decimal data type.
+ * DecimalScalePrecisionDivideFunction is used to compute the output types' scale and precision.
+ *
+ * @param logicalExpressions logical expressions
+ * @param attributes function attributes
+ * @return return type
+ */
+ @Override
+ public TypeProtos.MajorType getType(List<LogicalExpression> logicalExpressions, FunctionAttributes attributes) {
+ TypeProtos.DataMode mode = FunctionUtils.getReturnTypeDataMode(logicalExpressions, attributes);
+
+ assert logicalExpressions.size() == 2;
+
+ DecimalScalePrecisionDivideFunction outputScalePrec =
+ new DecimalScalePrecisionDivideFunction(logicalExpressions.get(0).getMajorType().getPrecision(),
+ logicalExpressions.get(0).getMajorType().getScale(),
+ logicalExpressions.get(1).getMajorType().getPrecision(),
+ logicalExpressions.get(1).getMajorType().getScale());
+ return TypeProtos.MajorType.newBuilder()
+ .setMinorType(DecimalUtility.getDecimalDataType(outputScalePrec.getOutputPrecision()))
+ .setScale(outputScalePrec.getOutputScale())
+ .setPrecision(outputScalePrec.getOutputPrecision())
+ .setMode(mode)
+ .build();
+ }
+ }
+
+ /**
+ * Return type calculation implementation for functions with return type set as
+ * {@link org.apache.drill.exec.expr.annotations.FunctionTemplate.ReturnType#DECIMAL_MAX_SCALE}.
+ */
+ public static class DecimalMaxScaleReturnTypeInference implements ReturnTypeInference {
+
+ public static final DecimalMaxScaleReturnTypeInference INSTANCE = new DecimalMaxScaleReturnTypeInference();
+
+ @Override
+ public TypeProtos.MajorType getType(List<LogicalExpression> logicalExpressions, FunctionAttributes attributes) {
+
+ TypeProtos.DataMode mode = FunctionUtils.getReturnTypeDataMode(logicalExpressions, attributes);
+ int scale = 0;
+ int precision = 0;
+
+ for (LogicalExpression e : logicalExpressions) {
+ scale = Math.max(scale, e.getMajorType().getScale());
+ precision = Math.max(precision, e.getMajorType().getPrecision());
+ }
+
+ return TypeProtos.MajorType.newBuilder()
+ .setMinorType(attributes.getReturnValue().getType().getMinorType())
+ .setScale(scale)
+ .setPrecision(precision)
+ .setMode(mode)
+ .build();
+ }
+ }
+
+ /**
+ * Return type calculation implementation for functions with return type set as
+ * {@link org.apache.drill.exec.expr.annotations.FunctionTemplate.ReturnType#DECIMAL_MOD_SCALE}.
+ */
+ public static class DecimalModScaleReturnTypeInference implements ReturnTypeInference {
+
+ public static final DecimalModScaleReturnTypeInference INSTANCE = new DecimalModScaleReturnTypeInference();
+
+ /**
+ * Return type is used by divide functions for decimal data type.
+ * DecimalScalePrecisionDivideFunction is used to compute the output types' scale and precision.
+ *
+ * @param logicalExpressions logical expressions
+ * @param attributes function attributes
+ * @return return type
+ */
+ @Override
+ public TypeProtos.MajorType getType(List<LogicalExpression> logicalExpressions, FunctionAttributes attributes) {
+ TypeProtos.DataMode mode = FunctionUtils.getReturnTypeDataMode(logicalExpressions, attributes);
+
+ assert logicalExpressions.size() == 2;
+
+ DecimalScalePrecisionModFunction outputScalePrec =
+ new DecimalScalePrecisionModFunction(logicalExpressions.get(0).getMajorType().getPrecision(),
+ logicalExpressions.get(0).getMajorType().getScale(),
+ logicalExpressions.get(1).getMajorType().getPrecision(),
+ logicalExpressions.get(1).getMajorType().getScale());
+ return TypeProtos.MajorType.newBuilder()
+ .setMinorType(DecimalUtility.getDecimalDataType(outputScalePrec.getOutputPrecision()))
+ .setScale(outputScalePrec.getOutputScale())
+ .setPrecision(outputScalePrec.getOutputPrecision())
+ .setMode(mode)
+ .build();
+ }
+ }
+
+ /**
+ * Return type calculation implementation for functions with return type set as
+ * {@link org.apache.drill.exec.expr.annotations.FunctionTemplate.ReturnType#DECIMAL_SET_SCALE}.
+ */
+ public static class DecimalSetScaleReturnTypeInference implements ReturnTypeInference {
+
+ public static final DecimalSetScaleReturnTypeInference INSTANCE = new DecimalSetScaleReturnTypeInference();
+
+ @Override
+ public TypeProtos.MajorType getType(List<LogicalExpression> logicalExpressions, FunctionAttributes attributes) {
+ TypeProtos.DataMode mode = attributes.getReturnValue().getType().getMode();
+ int scale = 0;
+ int precision = 0;
+
+ if (attributes.getNullHandling() == FunctionTemplate.NullHandling.NULL_IF_NULL) {
+ // if any one of the input types is nullable, then return nullable return type
+ for (LogicalExpression e : logicalExpressions) {
+
+ precision = Math.max(precision, e.getMajorType().getPrecision());
+ if (e.getMajorType().getMode() == TypeProtos.DataMode.OPTIONAL) {
+ mode = TypeProtos.DataMode.OPTIONAL;
+ }
+ }
+
+ // Used by functions like round, truncate which specify the scale for the output as the second argument
+ assert (logicalExpressions.size() == 2) && (logicalExpressions.get(1) instanceof ValueExpressions.IntExpression);
+
+ // Get the scale from the second argument which should be a constant
+ scale = ((ValueExpressions.IntExpression) logicalExpressions.get(1)).getInt();
+ }
+
+ return TypeProtos.MajorType.newBuilder()
+ .setMinorType(attributes.getReturnValue().getType().getMinorType())
+ .setScale(scale)
+ .setPrecision(precision)
+ .setMode(mode)
+ .build();
+ }
+ }
+
+ /**
+ * Return type calculation implementation for functions with return type set as
+ * {@link org.apache.drill.exec.expr.annotations.FunctionTemplate.ReturnType#DECIMAL_SUM_AGGREGATE}.
+ */
+ public static class DecimalSumAggReturnTypeInference implements ReturnTypeInference {
+
+ public static final DecimalSumAggReturnTypeInference INSTANCE = new DecimalSumAggReturnTypeInference();
+
+ @Override
+ public TypeProtos.MajorType getType(List<LogicalExpression> logicalExpressions, FunctionAttributes attributes) {
+ int scale = 0;
+ int precision = 0;
+
+ // Get the max scale and precision from the inputs
+ for (LogicalExpression e : logicalExpressions) {
+ scale = Math.max(scale, e.getMajorType().getScale());
+ precision = Math.max(precision, e.getMajorType().getPrecision());
+ }
+
+ return (TypeProtos.MajorType.newBuilder()
+ .setMinorType(attributes.getReturnValue().getType().getMinorType())
+ .setScale(scale)
+ .setPrecision(38)
+ .setMode(TypeProtos.DataMode.REQUIRED)
+ .build());
+ }
+ }
+
+ /**
+ * Return type calculation implementation for functions with return type set as
+ * {@link org.apache.drill.exec.expr.annotations.FunctionTemplate.ReturnType#DECIMAL_SUM_SCALE}.
+ */
+ public static class DecimalSumScaleReturnTypeInference implements ReturnTypeInference {
+
+ public static final DecimalSumScaleReturnTypeInference INSTANCE = new DecimalSumScaleReturnTypeInference();
+
+ @Override
+ public TypeProtos.MajorType getType(List<LogicalExpression> logicalExpressions, FunctionAttributes attributes) {
+
+ TypeProtos.DataMode mode = FunctionUtils.getReturnTypeDataMode(logicalExpressions, attributes);
+
+ assert logicalExpressions.size() == 2;
+
+ DecimalScalePrecisionMulFunction outputScalePrec =
+ new DecimalScalePrecisionMulFunction(logicalExpressions.get(0).getMajorType().getPrecision(),
+ logicalExpressions.get(0).getMajorType().getScale(),
+ logicalExpressions.get(1).getMajorType().getPrecision(),
+ logicalExpressions.get(1).getMajorType().getScale());
+ return TypeProtos.MajorType.newBuilder()
+ .setMinorType(DecimalUtility.getDecimalDataType(outputScalePrec.getOutputPrecision()))
+ .setScale(outputScalePrec.getOutputScale())
+ .setPrecision(outputScalePrec.getOutputPrecision())
+ .setMode(mode)
+ .build();
+ }
+ }
+
+ /**
+ * Return type calculation implementation for functions with return type set as
+ * {@link org.apache.drill.exec.expr.annotations.FunctionTemplate.ReturnType#DECIMAL_ZERO_SCALE}.
+ */
+ public static class DecimalZeroScaleReturnTypeInference implements ReturnTypeInference {
+
+ public static final DecimalZeroScaleReturnTypeInference INSTANCE = new DecimalZeroScaleReturnTypeInference();
+
+ /**
+ * Return type is used for functions where we need to remove the scale part.
+ * For example, truncate and round functions.
+ *
+ * @param logicalExpressions logical expressions
+ * @param attributes function attributes
+ * @return return type
+ */
+ @Override
+ public TypeProtos.MajorType getType(List<LogicalExpression> logicalExpressions, FunctionAttributes attributes) {
+
+ int precision = 0;
+ TypeProtos.DataMode mode = attributes.getReturnValue().getType().getMode();
+
+ if (attributes.getNullHandling() == FunctionTemplate.NullHandling.NULL_IF_NULL) {
+ // if any one of the input types is nullable, then return nullable return type
+ for (LogicalExpression e : logicalExpressions) {
+ if (e.getMajorType().getMode() == TypeProtos.DataMode.OPTIONAL) {
+ mode = TypeProtos.DataMode.OPTIONAL;
+ }
+ precision = Math.max(precision, e.getMajorType().getPrecision());
+ }
+ }
+
+ return TypeProtos.MajorType.newBuilder()
+ .setMinorType(attributes.getReturnValue().getType().getMinorType())
+ .setScale(0)
+ .setPrecision(precision)
+ .setMode(mode)
+ .build();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/drill/blob/6741e68a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/output/DefaultReturnTypeInference.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/output/DefaultReturnTypeInference.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/output/DefaultReturnTypeInference.java
new file mode 100644
index 0000000..02e6b1e
--- /dev/null
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/output/DefaultReturnTypeInference.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.exec.expr.fn.output;
+
+import com.google.common.collect.Sets;
+import org.apache.drill.common.expression.LogicalExpression;
+import org.apache.drill.common.types.TypeProtos;
+import org.apache.drill.exec.expr.fn.FunctionAttributes;
+import org.apache.drill.exec.expr.fn.FunctionUtils;
+import org.apache.drill.exec.expr.fn.ValueReference;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Return type calculation implementation for functions with return type set as
+ * {@link org.apache.drill.exec.expr.annotations.FunctionTemplate.ReturnType#DEFAULT}.
+ */
+public class DefaultReturnTypeInference implements ReturnTypeInference {
+
+ public static final DefaultReturnTypeInference INSTANCE = new DefaultReturnTypeInference();
+
+ /**
+ * Calculates return type and its nullability. Precision and scale is not included.
+ *
+ * @param logicalExpressions logical expressions
+ * @param attributes function attributes
+ * @return return type
+ */
+ @Override
+ public TypeProtos.MajorType getType(List<LogicalExpression> logicalExpressions, FunctionAttributes attributes) {
+ if (attributes.getReturnValue().getType().getMinorType() == TypeProtos.MinorType.UNION) {
+ final Set<TypeProtos.MinorType> subTypes = Sets.newHashSet();
+ for (final ValueReference ref : attributes.getParameters()) {
+ subTypes.add(ref.getType().getMinorType());
+ }
+
+ final TypeProtos.MajorType.Builder builder = TypeProtos.MajorType.newBuilder()
+ .setMinorType(TypeProtos.MinorType.UNION)
+ .setMode(TypeProtos.DataMode.OPTIONAL);
+
+ for (final TypeProtos.MinorType subType : subTypes) {
+ builder.addSubType(subType);
+ }
+ return builder.build();
+ }
+ return attributes.getReturnValue().getType().toBuilder()
+ .setMode(FunctionUtils.getReturnTypeDataMode(logicalExpressions, attributes))
+ .build();
+ }
+}
http://git-wip-us.apache.org/repos/asf/drill/blob/6741e68a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/output/PadReturnTypeInference.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/output/PadReturnTypeInference.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/output/PadReturnTypeInference.java
new file mode 100644
index 0000000..aac4703
--- /dev/null
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/output/PadReturnTypeInference.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.exec.expr.fn.output;
+
+import org.apache.drill.common.expression.LogicalExpression;
+import org.apache.drill.common.expression.ValueExpressions;
+import org.apache.drill.common.types.TypeProtos;
+import org.apache.drill.exec.expr.fn.FunctionAttributes;
+import org.apache.drill.exec.expr.fn.FunctionUtils;
+
+import java.util.List;
+
+/**
+ * Return type calculation implementation for functions with return type set as
+ * {@link org.apache.drill.exec.expr.annotations.FunctionTemplate.ReturnType#PAD}.
+ */
+public class PadReturnTypeInference implements ReturnTypeInference {
+
+ public static final PadReturnTypeInference INSTANCE = new PadReturnTypeInference();
+
+ /**
+ * Defines function return type and sets precision if it pad length parameter is int expression.
+ * If pad length is less than zero, return type precision is 0.
+ *
+ * @param logicalExpressions logical expressions
+ * @param attributes function attributes
+ * @return return type
+ */
+ @Override
+ public TypeProtos.MajorType getType(List<LogicalExpression> logicalExpressions, FunctionAttributes attributes) {
+ TypeProtos.MajorType.Builder builder = TypeProtos.MajorType.newBuilder()
+ .setMinorType(attributes.getReturnValue().getType().getMinorType())
+ .setMode(FunctionUtils.getReturnTypeDataMode(logicalExpressions, attributes));
+
+ if (logicalExpressions.get(1).iterator().hasNext() &&
+ logicalExpressions.get(1).iterator().next() instanceof ValueExpressions.IntExpression) {
+ int precision = ((ValueExpressions.IntExpression) logicalExpressions.get(1).iterator().next()).getInt();
+ // if pad length is less than zero, output length is 0
+ builder.setPrecision(Math.max(precision, 0));
+ }
+ return builder.build();
+ }
+}
http://git-wip-us.apache.org/repos/asf/drill/blob/6741e68a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/output/ReturnTypeInference.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/output/ReturnTypeInference.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/output/ReturnTypeInference.java
new file mode 100644
index 0000000..05375a0
--- /dev/null
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/output/ReturnTypeInference.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.exec.expr.fn.output;
+
+import org.apache.drill.common.expression.LogicalExpression;
+import org.apache.drill.common.types.TypeProtos;
+import org.apache.drill.exec.expr.fn.FunctionAttributes;
+
+import java.util.List;
+
+/**
+ * Return type calculation interface for functions that have return type set as with enum
+ * {@link org.apache.drill.exec.expr.annotations.FunctionTemplate.ReturnType}.
+ */
+public interface ReturnTypeInference {
+
+ TypeProtos.MajorType getType(List<LogicalExpression> logicalExpressions, FunctionAttributes attributes);
+
+}
http://git-wip-us.apache.org/repos/asf/drill/blob/6741e68a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/output/SameInOutLengthReturnTypeInference.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/output/SameInOutLengthReturnTypeInference.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/output/SameInOutLengthReturnTypeInference.java
new file mode 100644
index 0000000..92bfae1
--- /dev/null
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/output/SameInOutLengthReturnTypeInference.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.exec.expr.fn.output;
+
+import org.apache.drill.common.expression.LogicalExpression;
+import org.apache.drill.common.types.TypeProtos;
+import org.apache.drill.common.types.Types;
+import org.apache.drill.exec.expr.fn.FunctionAttributes;
+import org.apache.drill.exec.expr.fn.FunctionUtils;
+
+import java.util.List;
+
+/**
+ * Return type calculation implementation for functions with return type set as
+ * {@link org.apache.drill.exec.expr.annotations.FunctionTemplate.ReturnType#SAME_IN_OUT_LENGTH}.
+ */
+public class SameInOutLengthReturnTypeInference implements ReturnTypeInference {
+
+ public static final SameInOutLengthReturnTypeInference INSTANCE = new SameInOutLengthReturnTypeInference();
+
+ /**
+ * Defines function return type and sets precision and scale if input type has them.
+ *
+ * @param logicalExpressions logical expressions
+ * @param attributes function attributes
+ * @return return type
+ */
+ @Override
+ public TypeProtos.MajorType getType(List<LogicalExpression> logicalExpressions, FunctionAttributes attributes) {
+ TypeProtos.MajorType majorType = logicalExpressions.get(0).getMajorType();
+
+ TypeProtos.MajorType.Builder builder = TypeProtos.MajorType.newBuilder()
+ .setMinorType(attributes.getReturnValue().getType().getMinorType())
+ .setMode(FunctionUtils.getReturnTypeDataMode(logicalExpressions, attributes));
+
+ builder = Types.calculateTypePrecisionAndScale(majorType, majorType, builder);
+ return builder.build();
+ }
+}
http://git-wip-us.apache.org/repos/asf/drill/blob/6741e68a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/output/StringCastReturnTypeInference.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/output/StringCastReturnTypeInference.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/output/StringCastReturnTypeInference.java
new file mode 100644
index 0000000..95c30cd
--- /dev/null
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/output/StringCastReturnTypeInference.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.exec.expr.fn.output;
+
+import com.google.common.primitives.Ints;
+import org.apache.drill.common.expression.LogicalExpression;
+import org.apache.drill.common.expression.ValueExpressions;
+import org.apache.drill.common.types.TypeProtos;
+import org.apache.drill.exec.expr.fn.FunctionAttributes;
+import org.apache.drill.exec.expr.fn.FunctionUtils;
+
+import java.util.List;
+
+/**
+ * Return type calculation implementation for functions with return type set as
+ * {@link org.apache.drill.exec.expr.annotations.FunctionTemplate.ReturnType#STRING_CAST}.
+ */
+public class StringCastReturnTypeInference implements ReturnTypeInference {
+
+ public static final StringCastReturnTypeInference INSTANCE = new StringCastReturnTypeInference();
+
+ /**
+ * Defines function return type and sets cast length as type precision
+ * if cast length is simple long expression.
+ *
+ * @param logicalExpressions logical expressions
+ * @param attributes function attributes
+ * @return return type
+ */
+ @Override
+ public TypeProtos.MajorType getType(List<LogicalExpression> logicalExpressions, FunctionAttributes attributes) {
+ TypeProtos.MajorType.Builder builder = TypeProtos.MajorType.newBuilder()
+ .setMinorType(attributes.getReturnValue().getType().getMinorType())
+ .setMode(FunctionUtils.getReturnTypeDataMode(logicalExpressions, attributes));
+
+ LogicalExpression logicalExpression = logicalExpressions.get(1);
+ if (logicalExpressions.get(1) instanceof ValueExpressions.LongExpression) {
+ long precision = ((ValueExpressions.LongExpression) logicalExpression).getLong();
+ builder.setPrecision(Ints.checkedCast(precision));
+ }
+ return builder.build();
+ }
+}
http://git-wip-us.apache.org/repos/asf/drill/blob/6741e68a/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/project/ProjectRecordBatch.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/project/ProjectRecordBatch.java b/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/project/ProjectRecordBatch.java
index 1ecdaf5..a35e3f1 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/project/ProjectRecordBatch.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/project/ProjectRecordBatch.java
@@ -45,7 +45,6 @@ import org.apache.drill.exec.expr.ClassGenerator.HoldingContainer;
import org.apache.drill.exec.expr.CodeGenerator;
import org.apache.drill.exec.expr.DrillFuncHolderExpr;
import org.apache.drill.exec.expr.ExpressionTreeMaterializer;
-import org.apache.drill.exec.expr.TypeHelper;
import org.apache.drill.exec.expr.ValueVectorReadExpression;
import org.apache.drill.exec.expr.ValueVectorWriteExpression;
import org.apache.drill.exec.expr.fn.DrillComplexWriterFuncHolder;
@@ -517,12 +516,8 @@ public class ProjectRecordBatch extends AbstractSingleRecordBatch<Project> {
final String castFuncName = CastFunctions.getCastFunc(MinorType.VARCHAR);
final List<LogicalExpression> castArgs = Lists.newArrayList();
castArgs.add(convertToJson); //input_expr
- /*
- * We are implicitly casting to VARCHAR so we don't have a max length,
- * using an arbitrary value. We trim down the size of the stored bytes
- * to the actual size so this size doesn't really matter.
- */
- castArgs.add(new ValueExpressions.LongExpression(TypeHelper.VARCHAR_DEFAULT_CAST_LEN, null)); //
+ // implicitly casting to varchar, since we don't know actual source length, cast to undefined length, which will preserve source length
+ castArgs.add(new ValueExpressions.LongExpression(Types.MAX_VARCHAR_LENGTH, null));
final FunctionCall castCall = new FunctionCall(castFuncName, castArgs, ExpressionPosition.UNKNOWN);
exprs.add(new NamedExpression(castCall, new FieldReference(field.getPath())));
} else {
http://git-wip-us.apache.org/repos/asf/drill/blob/6741e68a/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/union/UnionAllRecordBatch.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/union/UnionAllRecordBatch.java b/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/union/UnionAllRecordBatch.java
index 06b7bdb..985c4ae 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/union/UnionAllRecordBatch.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/union/UnionAllRecordBatch.java
@@ -29,13 +29,13 @@ import org.apache.drill.common.expression.SchemaPath;
import org.apache.drill.common.types.TypeProtos.DataMode;
import org.apache.drill.common.types.TypeProtos.MajorType;
import org.apache.drill.common.types.TypeProtos.MinorType;
+import org.apache.drill.common.types.Types;
import org.apache.drill.exec.exception.ClassTransformationException;
import org.apache.drill.exec.exception.OutOfMemoryException;
import org.apache.drill.exec.exception.SchemaChangeException;
import org.apache.drill.exec.expr.ClassGenerator;
import org.apache.drill.exec.expr.CodeGenerator;
import org.apache.drill.exec.expr.ExpressionTreeMaterializer;
-import org.apache.drill.exec.expr.ValueVectorReadExpression;
import org.apache.drill.exec.expr.ValueVectorWriteExpression;
import org.apache.drill.exec.ops.FragmentContext;
import org.apache.drill.exec.physical.config.UnionAll;
@@ -198,16 +198,14 @@ public class UnionAllRecordBatch extends AbstractRecordBatch<UnionAll> {
// transfer directly,
// rename columns or
// cast data types (Minortype or DataMode)
- if(hasSameTypeAndMode(outputFields.get(index), vw.getValueVector().getField())) {
+ if (hasSameTypeAndMode(outputFields.get(index), vw.getValueVector().getField())) {
// Transfer column
- if(outputFields.get(index).getPath().equals(inputPath)) {
- final LogicalExpression expr = ExpressionTreeMaterializer.materialize(inputPath, current, collector, context.getFunctionRegistry());
- if (collector.hasErrors()) {
- throw new SchemaChangeException(String.format("Failure while trying to materialize incoming schema. Errors:\n %s.", collector.toErrorString()));
- }
- ValueVectorReadExpression vectorRead = (ValueVectorReadExpression) expr;
- ValueVector vvOut = container.addOrGet(MaterializedField.create(outputPath.getAsUnescapedPath(), vectorRead.getMajorType()));
+ MajorType outputFieldType = outputFields.get(index).getType();
+ MaterializedField outputField = MaterializedField.create(outputPath.getAsUnescapedPath(), outputFieldType);
+
+ if (outputFields.get(index).getPath().equals(inputPath.getAsUnescapedPath())) {
+ ValueVector vvOut = container.addOrGet(outputField);
TransferPair tp = vvIn.makeTransferPair(vvOut);
transfers.add(tp);
// Copy data in order to rename the column
@@ -217,7 +215,6 @@ public class UnionAllRecordBatch extends AbstractRecordBatch<UnionAll> {
throw new SchemaChangeException(String.format("Failure while trying to materialize incoming schema. Errors:\n %s.", collector.toErrorString()));
}
- MaterializedField outputField = MaterializedField.create(outputPath.getAsUnescapedPath(), expr.getMajorType());
ValueVector vv = container.addOrGet(outputField, callBack);
allocationVectors.add(vv);
TypedFieldId fid = container.getValueVectorId(SchemaPath.getSimplePath(outputField.getPath()));
@@ -571,39 +568,40 @@ public class UnionAllRecordBatch extends AbstractRecordBatch<UnionAll> {
Iterator<MaterializedField> rightIter = rightSchema.iterator();
int index = 1;
- while(leftIter.hasNext() && rightIter.hasNext()) {
+ while (leftIter.hasNext() && rightIter.hasNext()) {
MaterializedField leftField = leftIter.next();
MaterializedField rightField = rightIter.next();
- if(hasSameTypeAndMode(leftField, rightField)) {
- outputFields.add(MaterializedField.create(leftField.getPath(), leftField.getType()));
+ if (hasSameTypeAndMode(leftField, rightField)) {
+ MajorType.Builder builder = MajorType.newBuilder().setMinorType(leftField.getType().getMinorType()).setMode(leftField.getDataMode());
+ builder = Types.calculateTypePrecisionAndScale(leftField.getType(), rightField.getType(), builder);
+ outputFields.add(MaterializedField.create(leftField.getPath(), builder.build()));
} else {
// If the output type is not the same,
// cast the column of one of the table to a data type which is the Least Restrictive
- MinorType outputMinorType;
- if(leftField.getType().getMinorType() == rightField.getType().getMinorType()) {
- outputMinorType = leftField.getType().getMinorType();
+ MajorType.Builder builder = MajorType.newBuilder();
+ if (leftField.getType().getMinorType() == rightField.getType().getMinorType()) {
+ builder.setMinorType(leftField.getType().getMinorType());
+ builder = Types.calculateTypePrecisionAndScale(leftField.getType(), rightField.getType(), builder);
} else {
List<MinorType> types = Lists.newLinkedList();
types.add(leftField.getType().getMinorType());
types.add(rightField.getType().getMinorType());
- outputMinorType = TypeCastRules.getLeastRestrictiveType(types);
- if(outputMinorType == null) {
+ MinorType outputMinorType = TypeCastRules.getLeastRestrictiveType(types);
+ if (outputMinorType == null) {
throw new DrillRuntimeException("Type mismatch between " + leftField.getType().getMinorType().toString() +
" on the left side and " + rightField.getType().getMinorType().toString() +
" on the right side in column " + index + " of UNION ALL");
}
+ builder.setMinorType(outputMinorType);
}
// The output data mode should be as flexible as the more flexible one from the two input tables
List<DataMode> dataModes = Lists.newLinkedList();
dataModes.add(leftField.getType().getMode());
dataModes.add(rightField.getType().getMode());
- DataMode dataMode = TypeCastRules.getLeastRestrictiveDataMode(dataModes);
+ builder.setMode(TypeCastRules.getLeastRestrictiveDataMode(dataModes));
- MajorType.Builder builder = MajorType.newBuilder();
- builder.setMinorType(outputMinorType);
- builder.setMode(dataMode);
outputFields.add(MaterializedField.create(leftField.getPath(), builder.build()));
}
++index;
http://git-wip-us.apache.org/repos/asf/drill/blob/6741e68a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillOptiq.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillOptiq.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillOptiq.java
index 5a90787..db0cfbd 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillOptiq.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillOptiq.java
@@ -294,20 +294,19 @@ public class DrillOptiq {
private LogicalExpression getDrillCastFunctionFromOptiq(RexCall call){
LogicalExpression arg = call.getOperands().get(0).accept(this);
- MajorType castType = null;
+ MajorType castType;
switch(call.getType().getSqlTypeName().getName()){
case "VARCHAR":
case "CHAR":
- castType = Types.required(MinorType.VARCHAR).toBuilder().setWidth(call.getType().getPrecision()).build();
+ castType = Types.required(MinorType.VARCHAR).toBuilder().setPrecision(call.getType().getPrecision()).build();
break;
case "INTEGER": castType = Types.required(MinorType.INT); break;
case "FLOAT": castType = Types.required(MinorType.FLOAT4); break;
case "DOUBLE": castType = Types.required(MinorType.FLOAT8); break;
case "DECIMAL":
- if (context.getPlannerSettings().getOptions().
- getOption(PlannerSettings.ENABLE_DECIMAL_DATA_TYPE_KEY).bool_val == false ) {
+ if (!context.getPlannerSettings().getOptions().getOption(PlannerSettings.ENABLE_DECIMAL_DATA_TYPE_KEY).bool_val) {
throw UserException
.unsupportedError()
.message(ExecErrorConstants.DECIMAL_DISABLE_ERR_MSG)
@@ -334,7 +333,7 @@ public class DrillOptiq {
case "INTERVAL_YEAR_MONTH": castType = Types.required(MinorType.INTERVALYEAR); break;
case "INTERVAL_DAY_TIME": castType = Types.required(MinorType.INTERVALDAY); break;
case "BOOLEAN": castType = Types.required(MinorType.BIT); break;
- case "BINARY": castType = Types.required(MinorType.VARBINARY).toBuilder().setWidth(call.getType().getPrecision()).build(); break;
+ case "BINARY": castType = Types.required(MinorType.VARBINARY); break;
case "ANY": return arg; // Type will be same as argument.
default: castType = Types.required(MinorType.valueOf(call.getType().getSqlTypeName().getName()));
}
@@ -422,7 +421,7 @@ public class DrillOptiq {
* (empty string literal) to the list of arguments.
*/
List<LogicalExpression> concatArgs = new LinkedList<>(args);
- concatArgs.add(new QuotedString("", ExpressionPosition.UNKNOWN));
+ concatArgs.add(QuotedString.EMPTY_STRING);
return FunctionCallFactory.createExpression(functionName, concatArgs);
@@ -512,9 +511,9 @@ public class DrillOptiq {
return ValueExpressions.getBit(((Boolean) literal.getValue()));
case CHAR:
if (isLiteralNull(literal)) {
- return createNullExpr(MinorType.VARCHAR);
+ return createStringNullExpr(literal.getType().getPrecision());
}
- return ValueExpressions.getChar(((NlsString)literal.getValue()).getValue());
+ return ValueExpressions.getChar(((NlsString)literal.getValue()).getValue(), literal.getType().getPrecision());
case DOUBLE:
if (isLiteralNull(literal)){
return createNullExpr(MinorType.FLOAT8);
@@ -556,14 +555,14 @@ public class DrillOptiq {
return ValueExpressions.getFloat8(dbl);
case VARCHAR:
if (isLiteralNull(literal)) {
- return createNullExpr(MinorType.VARCHAR);
+ return createStringNullExpr(literal.getType().getPrecision());
}
- return ValueExpressions.getChar(((NlsString)literal.getValue()).getValue());
+ return ValueExpressions.getChar(((NlsString)literal.getValue()).getValue(), literal.getType().getPrecision());
case SYMBOL:
if (isLiteralNull(literal)) {
- return createNullExpr(MinorType.VARCHAR);
+ return createStringNullExpr(literal.getType().getPrecision());
}
- return ValueExpressions.getChar(literal.getValue().toString());
+ return ValueExpressions.getChar(literal.getValue().toString(), literal.getType().getPrecision());
case DATE:
if (isLiteralNull(literal)) {
return createNullExpr(MinorType.DATE);
@@ -599,10 +598,28 @@ public class DrillOptiq {
throw new UnsupportedOperationException(String.format("Unable to convert the value of %s and type %s to a Drill constant expression.", literal, literal.getType().getSqlTypeName()));
}
}
- }
- private static final TypedNullConstant createNullExpr(MinorType type) {
- return new TypedNullConstant(Types.optional(type));
+ /**
+ * Create nullable major type using given minor type
+ * and wraps it in typed null constant.
+ *
+ * @param type minor type
+ * @return typed null constant instance
+ */
+ private TypedNullConstant createNullExpr(MinorType type) {
+ return new TypedNullConstant(Types.optional(type));
+ }
+
+ /**
+ * Create nullable varchar major type with given precision
+ * and wraps it in typed null constant.
+ *
+ * @param precision precision value
+ * @return typed null constant instance
+ */
+ private TypedNullConstant createStringNullExpr(int precision) {
+ return new TypedNullConstant(Types.withPrecision(MinorType.VARCHAR, TypeProtos.DataMode.OPTIONAL, precision));
+ }
}
public static boolean isLiteralNull(RexLiteral literal) {
http://git-wip-us.apache.org/repos/asf/drill/blob/6741e68a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/SqlConverter.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/SqlConverter.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/SqlConverter.java
index 845848c..5778041 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/SqlConverter.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/SqlConverter.java
@@ -55,6 +55,7 @@ import org.apache.calcite.sql2rel.RelDecorrelator;
import org.apache.calcite.sql2rel.SqlToRelConverter;
import org.apache.drill.common.config.DrillConfig;
import org.apache.drill.common.exceptions.UserException;
+import org.apache.drill.common.types.Types;
import org.apache.drill.exec.ExecConstants;
import org.apache.drill.exec.expr.fn.FunctionImplementationRegistry;
import org.apache.drill.exec.ops.QueryContext;
@@ -226,7 +227,7 @@ public class SqlConverter {
case BINARY:
case VARCHAR:
case VARBINARY:
- return 65536;
+ return Types.MAX_VARCHAR_LENGTH;
default:
return super.getDefaultPrecision(typeName);
}
http://git-wip-us.apache.org/repos/asf/drill/blob/6741e68a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/TypeInferenceUtils.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/TypeInferenceUtils.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/TypeInferenceUtils.java
index b7942ed..523b721 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/TypeInferenceUtils.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/TypeInferenceUtils.java
@@ -1,4 +1,4 @@
-/**
+/*
* 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
@@ -30,9 +30,8 @@ import org.apache.calcite.sql.SqlIntervalQualifier;
import org.apache.calcite.sql.SqlKind;
import org.apache.calcite.sql.SqlLiteral;
import org.apache.calcite.sql.SqlNode;
-import org.apache.calcite.sql.SqlOperator;
+import org.apache.calcite.sql.SqlNumericLiteral;
import org.apache.calcite.sql.SqlOperatorBinding;
-import org.apache.calcite.sql.SqlRankFunction;
import org.apache.calcite.sql.fun.SqlAvgAggFunction;
import org.apache.calcite.sql.parser.SqlParserPos;
import org.apache.calcite.sql.type.SqlReturnTypeInference;
@@ -46,7 +45,6 @@ import org.apache.drill.common.expression.MajorTypeInLogicalExpression;
import org.apache.drill.common.exceptions.UserException;
import org.apache.drill.common.types.TypeProtos;
import org.apache.drill.common.types.Types;
-import org.apache.drill.exec.expr.TypeHelper;
import org.apache.drill.exec.expr.fn.DrillFuncHolder;
import org.apache.drill.exec.resolver.FunctionResolver;
import org.apache.drill.exec.resolver.FunctionResolverFactory;
@@ -126,14 +124,15 @@ public class TypeInferenceUtils {
.put("DATE_PART", DrillDatePartSqlReturnTypeInference.INSTANCE)
.put("SUM", DrillSumSqlReturnTypeInference.INSTANCE)
.put("COUNT", DrillCountSqlReturnTypeInference.INSTANCE)
- .put("CONCAT", DrillConcatSqlReturnTypeInference.INSTANCE)
+ .put("CONCAT", DrillConcatSqlReturnTypeInference.INSTANCE_CONCAT)
+ .put("CONCATOPERATOR", DrillConcatSqlReturnTypeInference.INSTANCE_CONCAT_OP)
.put("LENGTH", DrillLengthSqlReturnTypeInference.INSTANCE)
- .put("LPAD", DrillPadTrimSqlReturnTypeInference.INSTANCE)
- .put("RPAD", DrillPadTrimSqlReturnTypeInference.INSTANCE)
- .put("LTRIM", DrillPadTrimSqlReturnTypeInference.INSTANCE)
- .put("RTRIM", DrillPadTrimSqlReturnTypeInference.INSTANCE)
- .put("BTRIM", DrillPadTrimSqlReturnTypeInference.INSTANCE)
- .put("TRIM", DrillPadTrimSqlReturnTypeInference.INSTANCE)
+ .put("LPAD", DrillPadSqlReturnTypeInference.INSTANCE)
+ .put("RPAD", DrillPadSqlReturnTypeInference.INSTANCE)
+ .put("LTRIM", DrillTrimSqlReturnTypeInference.INSTANCE)
+ .put("RTRIM", DrillTrimSqlReturnTypeInference.INSTANCE)
+ .put("BTRIM", DrillTrimSqlReturnTypeInference.INSTANCE)
+ .put("TRIM", DrillTrimSqlReturnTypeInference.INSTANCE)
.put("CONVERT_TO", DrillConvertToSqlReturnTypeInference.INSTANCE)
.put("EXTRACT", DrillExtractSqlReturnTypeInference.INSTANCE)
.put("SQRT", DrillSqrtSqlReturnTypeInference.INSTANCE)
@@ -142,6 +141,12 @@ public class TypeInferenceUtils {
.put("KVGEN", DrillDeferToExecSqlReturnTypeInference.INSTANCE)
.put("CONVERT_FROM", DrillDeferToExecSqlReturnTypeInference.INSTANCE)
+ // Functions that return the same type
+ .put("LOWER", DrillSameSqlReturnTypeInference.INSTANCE)
+ .put("UPPER", DrillSameSqlReturnTypeInference.INSTANCE)
+ .put("INITCAP", DrillSameSqlReturnTypeInference.INSTANCE)
+ .put("REVERSE", DrillSameSqlReturnTypeInference.INSTANCE)
+
// Window Functions
// RANKING
.put(SqlKind.CUME_DIST.name(), DrillRankingSqlReturnTypeInference.INSTANCE_DOUBLE)
@@ -158,8 +163,8 @@ public class TypeInferenceUtils {
.put("LAG", DrillLeadLagSqlReturnTypeInference.INSTANCE)
// FIRST_VALUE, LAST_VALUE
- .put("FIRST_VALUE", DrillFirstLastValueSqlReturnTypeInference.INSTANCE)
- .put("LAST_VALUE", DrillFirstLastValueSqlReturnTypeInference.INSTANCE)
+ .put("FIRST_VALUE", DrillSameSqlReturnTypeInference.INSTANCE)
+ .put("LAST_VALUE", DrillSameSqlReturnTypeInference.INSTANCE)
// Functions rely on DrillReduceAggregatesRule for expression simplification as opposed to getting evaluated directly
.put(SqlAvgAggFunction.Subtype.AVG.name(), DrillAvgAggSqlReturnTypeInference.INSTANCE)
@@ -214,6 +219,16 @@ public class TypeInferenceUtils {
}
}
+ /**
+ * Checks if given type is string scalar type.
+ *
+ * @param sqlTypeName Calcite's sql type name
+ * @return true if given type is string scalar type
+ */
+ public static boolean isScalarStringType(final SqlTypeName sqlTypeName) {
+ return sqlTypeName == SqlTypeName.VARCHAR || sqlTypeName == SqlTypeName.CHAR;
+ }
+
private static class DrillDefaultSqlReturnTypeInference implements SqlReturnTypeInference {
private final List<DrillFuncHolder> functions;
@@ -394,31 +409,37 @@ public class TypeInferenceUtils {
}
private static class DrillConcatSqlReturnTypeInference implements SqlReturnTypeInference {
- private static final DrillConcatSqlReturnTypeInference INSTANCE = new DrillConcatSqlReturnTypeInference();
+ // Difference between concat function and concat operator ('||') is that concat function resolves nulls internally,
+ // i.e. does not return nulls at all.
+ private static final DrillConcatSqlReturnTypeInference INSTANCE_CONCAT = new DrillConcatSqlReturnTypeInference(false);
+ private static final DrillConcatSqlReturnTypeInference INSTANCE_CONCAT_OP = new DrillConcatSqlReturnTypeInference(true);
+
+ private final boolean isNullIfNull;
+
+ public DrillConcatSqlReturnTypeInference(boolean isNullIfNull) {
+ this.isNullIfNull = isNullIfNull;
+ }
@Override
public RelDataType inferReturnType(SqlOperatorBinding opBinding) {
- final RelDataTypeFactory factory = opBinding.getTypeFactory();
- boolean isNullable = true;
- int precision = 0;
- for(RelDataType relDataType : opBinding.collectOperandTypes()) {
- if(!relDataType.isNullable()) {
- isNullable = false;
- }
-
- // If the underlying columns cannot offer information regarding the precision (i.e., the length) of the VarChar,
- // Drill uses the largest to represent it
- if(relDataType.getPrecision() == TypeHelper.VARCHAR_DEFAULT_CAST_LEN
- || relDataType.getPrecision() == RelDataType.PRECISION_NOT_SPECIFIED) {
- precision = TypeHelper.VARCHAR_DEFAULT_CAST_LEN;
+ // If the underlying columns cannot offer information regarding the precision of the VarChar,
+ // Drill uses the largest to represent it.
+ int totalPrecision = 0;
+ for (RelDataType relDataType : opBinding.collectOperandTypes()) {
+ if (isScalarStringType(relDataType.getSqlTypeName()) && relDataType.getPrecision() != RelDataType.PRECISION_NOT_SPECIFIED) {
+ totalPrecision += relDataType.getPrecision();
} else {
- precision += relDataType.getPrecision();
+ totalPrecision = Types.MAX_VARCHAR_LENGTH;
+ break;
}
}
- return factory.createTypeWithNullability(
- factory.createSqlType(SqlTypeName.VARCHAR, precision),
+ totalPrecision = totalPrecision > Types.MAX_VARCHAR_LENGTH ? Types.MAX_VARCHAR_LENGTH : totalPrecision;
+ boolean isNullable = isNullIfNull && isNullable(opBinding.collectOperandTypes());
+
+ return opBinding.getTypeFactory().createTypeWithNullability(
+ opBinding.getTypeFactory().createSqlType(SqlTypeName.VARCHAR, totalPrecision),
isNullable);
}
}
@@ -441,23 +462,56 @@ public class TypeInferenceUtils {
}
}
- private static class DrillPadTrimSqlReturnTypeInference implements SqlReturnTypeInference {
- private static final DrillPadTrimSqlReturnTypeInference INSTANCE = new DrillPadTrimSqlReturnTypeInference();
+ private static class DrillPadSqlReturnTypeInference implements SqlReturnTypeInference {
+ private static final DrillPadSqlReturnTypeInference INSTANCE = new DrillPadSqlReturnTypeInference();
@Override
public RelDataType inferReturnType(SqlOperatorBinding opBinding) {
- final RelDataTypeFactory factory = opBinding.getTypeFactory();
- final SqlTypeName sqlTypeName = SqlTypeName.VARCHAR;
+ if (opBinding instanceof SqlCallBinding && (((SqlCallBinding) opBinding).operand(1) instanceof SqlNumericLiteral)) {
+ int precision = ((SqlNumericLiteral) ((SqlCallBinding) opBinding).operand(1)).intValue(true);
+ RelDataType sqlType = opBinding.getTypeFactory().createSqlType(SqlTypeName.VARCHAR, Math.max(precision, 0));
+ return opBinding.getTypeFactory().createTypeWithNullability(sqlType, isNullable(opBinding.collectOperandTypes()));
+ }
- for(int i = 0; i < opBinding.getOperandCount(); ++i) {
- if(opBinding.getOperandType(i).isNullable()) {
- return createCalciteTypeWithNullability(
- factory, sqlTypeName, true);
- }
+ return createCalciteTypeWithNullability(
+ opBinding.getTypeFactory(),
+ SqlTypeName.VARCHAR,
+ isNullable(opBinding.collectOperandTypes()));
+
+ }
+ }
+
+ private static class DrillTrimSqlReturnTypeInference implements SqlReturnTypeInference {
+ private static final DrillTrimSqlReturnTypeInference INSTANCE = new DrillTrimSqlReturnTypeInference();
+
+ @Override
+ public RelDataType inferReturnType(SqlOperatorBinding opBinding) {
+ return createCalciteTypeWithNullability(
+ opBinding.getTypeFactory(),
+ SqlTypeName.VARCHAR,
+ isNullable(opBinding.collectOperandTypes()));
+ }
+ }
+
+ private static class DrillSubstringSqlReturnTypeInference implements SqlReturnTypeInference {
+ private static final DrillSubstringSqlReturnTypeInference INSTANCE = new DrillSubstringSqlReturnTypeInference();
+
+ @Override
+ public RelDataType inferReturnType(SqlOperatorBinding opBinding) {
+ boolean isNullable = isNullable(opBinding.collectOperandTypes());
+
+ boolean isScalarString = isScalarStringType(opBinding.getOperandType(0).getSqlTypeName());
+ int precision = opBinding.getOperandType(0).getPrecision();
+
+ if (isScalarString && precision != RelDataType.PRECISION_NOT_SPECIFIED) {
+ RelDataType sqlType = opBinding.getTypeFactory().createSqlType(SqlTypeName.VARCHAR, precision);
+ return opBinding.getTypeFactory().createTypeWithNullability(sqlType, isNullable);
}
return createCalciteTypeWithNullability(
- factory, sqlTypeName, false);
+ opBinding.getTypeFactory(),
+ SqlTypeName.VARCHAR,
+ isNullable);
}
}
@@ -511,21 +565,20 @@ public class TypeInferenceUtils {
@Override
public RelDataType inferReturnType(SqlOperatorBinding opBinding) {
final RelDataTypeFactory factory = opBinding.getTypeFactory();
+ final boolean isNullable = opBinding.getOperandType(1).isNullable();
- final SqlNode firstOperand = ((SqlCallBinding) opBinding).operand(0);
- if(!(firstOperand instanceof SqlCharStringLiteral)) {
+ if (!(opBinding instanceof SqlCallBinding) || !(((SqlCallBinding) opBinding).operand(0) instanceof SqlCharStringLiteral)) {
return createCalciteTypeWithNullability(factory,
SqlTypeName.ANY,
- opBinding.getOperandType(1).isNullable());
+ isNullable);
}
- final String part = ((SqlCharStringLiteral) firstOperand)
+ final String part = ((SqlCharStringLiteral) ((SqlCallBinding) opBinding).operand(0))
.getNlsString()
.getValue()
.toUpperCase();
final SqlTypeName sqlTypeName = getSqlTypeNameForTimeUnit(part);
- final boolean isNullable = opBinding.getOperandType(1).isNullable();
return createCalciteTypeWithNullability(
factory,
sqlTypeName,
@@ -598,15 +651,12 @@ public class TypeInferenceUtils {
private static final DrillLeadLagSqlReturnTypeInference INSTANCE = new DrillLeadLagSqlReturnTypeInference();
@Override
public RelDataType inferReturnType(SqlOperatorBinding opBinding) {
- return createCalciteTypeWithNullability(
- opBinding.getTypeFactory(),
- opBinding.getOperandType(0).getSqlTypeName(),
- true);
+ return opBinding.getTypeFactory().createTypeWithNullability(opBinding.getOperandType(0), true);
}
}
- private static class DrillFirstLastValueSqlReturnTypeInference implements SqlReturnTypeInference {
- private static final DrillFirstLastValueSqlReturnTypeInference INSTANCE = new DrillFirstLastValueSqlReturnTypeInference();
+ private static class DrillSameSqlReturnTypeInference implements SqlReturnTypeInference {
+ private static final DrillSameSqlReturnTypeInference INSTANCE = new DrillSameSqlReturnTypeInference();
@Override
public RelDataType inferReturnType(SqlOperatorBinding opBinding) {
return opBinding.getOperandType(0);
@@ -697,7 +747,7 @@ public class TypeInferenceUtils {
TimeUnit.MONTH,
SqlParserPos.ZERO));
} else if (sqlTypeName == SqlTypeName.VARCHAR) {
- type = typeFactory.createSqlType(sqlTypeName, TypeHelper.VARCHAR_DEFAULT_CAST_LEN);
+ type = typeFactory.createSqlType(sqlTypeName, Types.MAX_VARCHAR_LENGTH);
} else {
type = typeFactory.createSqlType(sqlTypeName);
}
@@ -734,6 +784,21 @@ public class TypeInferenceUtils {
}
/**
+ * Checks if at least one of the operand types is nullable.
+ *
+ * @param operandTypes operand types
+ * @return true if one of the operands is nullable, false otherwise
+ */
+ private static boolean isNullable(List<RelDataType> operandTypes) {
+ for (RelDataType relDataType : operandTypes) {
+ if (relDataType.isNullable()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* This class is not intended to be instantiated
*/
private TypeInferenceUtils() {
http://git-wip-us.apache.org/repos/asf/drill/blob/6741e68a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/FindLimit0Visitor.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/FindLimit0Visitor.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/FindLimit0Visitor.java
index 6df6e0d..d5216e7 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/FindLimit0Visitor.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/FindLimit0Visitor.java
@@ -1,4 +1,4 @@
-/**
+/*
* 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
@@ -84,23 +84,27 @@ public class FindLimit0Visitor extends RelShuttleImpl {
*/
public static DrillRel getDirectScanRelIfFullySchemaed(RelNode rel) {
final List<RelDataTypeField> fieldList = rel.getRowType().getFieldList();
- final List<SqlTypeName> columnTypes = Lists.newArrayList();
- final List<TypeProtos.DataMode> dataModes = Lists.newArrayList();
+ final List<TypeProtos.MajorType> columnTypes = Lists.newArrayList();
+
for (final RelDataTypeField field : fieldList) {
final SqlTypeName sqlTypeName = field.getType().getSqlTypeName();
if (!TYPES.contains(sqlTypeName)) {
return null;
} else {
- columnTypes.add(sqlTypeName);
- dataModes.add(field.getType().isNullable() ?
- TypeProtos.DataMode.OPTIONAL : TypeProtos.DataMode.REQUIRED);
+ final TypeProtos.MajorType.Builder builder = TypeProtos.MajorType.newBuilder()
+ .setMode(field.getType().isNullable() ? TypeProtos.DataMode.OPTIONAL : TypeProtos.DataMode.REQUIRED)
+ .setMinorType(TypeInferenceUtils.getDrillTypeFromCalciteType(sqlTypeName));
+
+ if (TypeInferenceUtils.isScalarStringType(sqlTypeName)) {
+ builder.setPrecision(field.getType().getPrecision());
+ }
+
+ columnTypes.add(builder.build());
}
}
-
final RelTraitSet traits = rel.getTraitSet().plus(DrillRel.DRILL_LOGICAL);
- final RelDataTypeReader reader = new RelDataTypeReader(rel.getRowType().getFieldNames(), columnTypes,
- dataModes);
+ final RelDataTypeReader reader = new RelDataTypeReader(rel.getRowType().getFieldNames(), columnTypes);
return new DrillDirectScanRel(rel.getCluster(), traits,
new DirectGroupScan(reader, ScanStats.ZERO_RECORD_TABLE), rel.getRowType());
}
@@ -197,25 +201,18 @@ public class FindLimit0Visitor extends RelShuttleImpl {
public static class RelDataTypeReader extends AbstractRecordReader {
public final List<String> columnNames;
- public final List<SqlTypeName> columnTypes;
- public final List<TypeProtos.DataMode> dataModes;
+ public final List<TypeProtos.MajorType> columnTypes;
- public RelDataTypeReader(List<String> columnNames, List<SqlTypeName> columnTypes,
- List<TypeProtos.DataMode> dataModes) {
- Preconditions.checkArgument(columnNames.size() == columnTypes.size() &&
- columnTypes.size() == dataModes.size());
+ public RelDataTypeReader(List<String> columnNames, List<TypeProtos.MajorType> columnTypes) {
+ Preconditions.checkArgument(columnNames.size() == columnTypes.size(), "Number of columns and their types should match");
this.columnNames = columnNames;
this.columnTypes = columnTypes;
- this.dataModes = dataModes;
}
@Override
public void setup(OperatorContext context, OutputMutator output) throws ExecutionSetupException {
for (int i = 0; i < columnNames.size(); i++) {
- final TypeProtos.MajorType type = TypeProtos.MajorType.newBuilder()
- .setMode(dataModes.get(i))
- .setMinorType(TypeInferenceUtils.getDrillTypeFromCalciteType(columnTypes.get(i)))
- .build();
+ final TypeProtos.MajorType type = columnTypes.get(i);
final MaterializedField field = MaterializedField.create(columnNames.get(i), type);
final Class vvClass = TypeHelper.getValueVectorClass(type.getMinorType(), type.getMode());
try {