[ASTERIXDB-2447][COMP] Parameter rewriting for if_missing, if_null functions
- user model changes: no - storage format changes: no - interface changes: no Details: - Introduce cast operation for parameters of if_missing, if_null functions (as performed for parameters of the switch_case function) - Fix union type handling in TypeResolverUtil.generalizeTypes() Change-Id: I768d8236f5b0ccb9a850304ffedd3686d911702d Reviewed-on: https://asterix-gerrit.ics.uci.edu/2935 Tested-by: Jenkins <jenk...@fulliautomatix.ics.uci.edu> Integration-Tests: Jenkins <jenk...@fulliautomatix.ics.uci.edu> Reviewed-by: Till Westmann <ti...@apache.org> Project: http://git-wip-us.apache.org/repos/asf/asterixdb/repo Commit: http://git-wip-us.apache.org/repos/asf/asterixdb/commit/8c88975a Tree: http://git-wip-us.apache.org/repos/asf/asterixdb/tree/8c88975a Diff: http://git-wip-us.apache.org/repos/asf/asterixdb/diff/8c88975a Branch: refs/heads/master Commit: 8c88975a781cd2b384da31bcd59aad2e26480e3e Parents: 9963a91 Author: Dmitry Lychagin <dmitry.lycha...@couchbase.com> Authored: Tue Aug 28 16:32:42 2018 -0700 Committer: Dmitry Lychagin <dmitry.lycha...@couchbase.com> Committed: Thu Aug 30 17:31:14 2018 -0700 ---------------------------------------------------------------------- .../rules/InjectTypeCastForSwitchCaseRule.java | 71 +++++++++++++++----- .../ifmissing/ifmissing.1.query.sqlpp | 7 ++ .../ifmissingornull.1.query.sqlpp | 7 ++ .../null-missing/ifnull/ifnull.1.query.sqlpp | 7 ++ .../null-missing/ifmissing/ifmissing.1.adm | 2 +- .../ifmissingornull/ifmissingornull.1.adm | 2 +- .../results/null-missing/ifnull/ifnull.1.adm | 2 +- .../dataflow/data/common/TypeResolverUtil.java | 2 +- 8 files changed, 81 insertions(+), 19 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/asterixdb/blob/8c88975a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/InjectTypeCastForSwitchCaseRule.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/InjectTypeCastForSwitchCaseRule.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/InjectTypeCastForSwitchCaseRule.java index fa9385a..683d29f 100644 --- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/InjectTypeCastForSwitchCaseRule.java +++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/InjectTypeCastForSwitchCaseRule.java @@ -22,6 +22,7 @@ package org.apache.asterix.optimizer.rules; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Set; import org.apache.asterix.dataflow.data.common.TypeResolverUtil; import org.apache.asterix.lang.common.util.FunctionUtil; @@ -38,14 +39,23 @@ import org.apache.hyracks.algebricks.core.algebra.base.LogicalExpressionTag; import org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression; import org.apache.hyracks.algebricks.core.algebra.expressions.IVariableTypeEnvironment; import org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression; +import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier; import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule; +import com.google.common.collect.ImmutableSet; + /** - * This rule injects cast functions for "THEN" and "ELSE" branches of a switch-case function if - * different "THEN" and "ELSE" branches have heterogeneous return types. + * This rule injects casts for function parameters if they have heterogeneous return types: + * <ul> + * <li>for "THEN" and "ELSE" branches of a switch-case function</li> + * <li>for parameters of "if missing/null" functions (if-missing(), if-null(), if-missing-or-null())</li> + * </ul> */ public class InjectTypeCastForSwitchCaseRule implements IAlgebraicRewriteRule { + private static final Set<FunctionIdentifier> IF_FUNCTIONS = + ImmutableSet.of(BuiltinFunctions.IF_MISSING, BuiltinFunctions.IF_NULL, BuiltinFunctions.IF_MISSING_OR_NULL); + @Override public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException { @@ -80,10 +90,17 @@ public class InjectTypeCastForSwitchCaseRule implements IAlgebraicRewriteRule { rewritten = true; } } - if (!func.getFunctionIdentifier().equals(BuiltinFunctions.SWITCH_CASE)) { - return rewritten; + FunctionIdentifier funcId = func.getFunctionIdentifier(); + if (funcId.equals(BuiltinFunctions.SWITCH_CASE)) { + if (rewriteSwitchCase(op, func, context)) { + rewritten = true; + } + } else if (IF_FUNCTIONS.contains(funcId)) { + if (rewriteFunction(op, func, context)) { + rewritten = true; + } } - return rewriteSwitchCase(op, func, context); + return rewritten; } // Injects casts that cast types for different "THEN" and "ELSE" branches. @@ -96,20 +113,44 @@ public class InjectTypeCastForSwitchCaseRule implements IAlgebraicRewriteRule { boolean rewritten = false; for (int argIndex = 2; argIndex < argSize; argIndex += (argIndex + 2 == argSize) ? 1 : 2) { Mutable<ILogicalExpression> argRef = argRefs.get(argIndex); - IAType type = (IAType) env.getType(argRefs.get(argIndex).getValue()); - if (TypeResolverUtil.needsCast(producedType, type)) { - ILogicalExpression argExpr = argRef.getValue(); - // Injects a cast call to cast the data type to the produced type of the switch-case function call. - ScalarFunctionCallExpression castFunc = - new ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(BuiltinFunctions.CAST_TYPE), - new ArrayList<>(Collections.singletonList(new MutableObject<>(argExpr)))); - castFunc.setSourceLocation(argExpr.getSourceLocation()); - TypeCastUtils.setRequiredAndInputTypes(castFunc, producedType, type); - argRef.setValue(castFunc); + if (rewriteFunctionArgument(argRef, producedType, env)) { + rewritten = true; + } + } + return rewritten; + } + + // Injects casts that cast types for all function parameters + private boolean rewriteFunction(ILogicalOperator op, AbstractFunctionCallExpression func, + IOptimizationContext context) throws AlgebricksException { + IVariableTypeEnvironment env = op.computeInputTypeEnvironment(context); + IAType producedType = (IAType) env.getType(func); + List<Mutable<ILogicalExpression>> argRefs = func.getArguments(); + int argSize = argRefs.size(); + boolean rewritten = false; + for (int argIndex = 0; argIndex < argSize; argIndex++) { + Mutable<ILogicalExpression> argRef = argRefs.get(argIndex); + if (rewriteFunctionArgument(argRef, producedType, env)) { rewritten = true; } } return rewritten; } + private boolean rewriteFunctionArgument(Mutable<ILogicalExpression> argRef, IAType funcOutputType, + IVariableTypeEnvironment env) throws AlgebricksException { + ILogicalExpression argExpr = argRef.getValue(); + IAType type = (IAType) env.getType(argExpr); + if (TypeResolverUtil.needsCast(funcOutputType, type)) { + // Injects a cast call to cast the data type to the produced type of the function call. + ScalarFunctionCallExpression castFunc = + new ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(BuiltinFunctions.CAST_TYPE), + new ArrayList<>(Collections.singletonList(new MutableObject<>(argExpr)))); + castFunc.setSourceLocation(argExpr.getSourceLocation()); + TypeCastUtils.setRequiredAndInputTypes(castFunc, funcOutputType, type); + argRef.setValue(castFunc); + return true; + } + return false; + } } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/8c88975a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/null-missing/ifmissing/ifmissing.1.query.sqlpp ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/null-missing/ifmissing/ifmissing.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/null-missing/ifmissing/ifmissing.1.query.sqlpp index 2f0d837..0abb997 100644 --- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/null-missing/ifmissing/ifmissing.1.query.sqlpp +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/null-missing/ifmissing/ifmissing.1.query.sqlpp @@ -29,5 +29,12 @@ missing, case when get_year(current_datetime()) > 0 then missing else false end, case when get_year(current_datetime()) > 0 then true else null end + ), + "j": ( + let v = if_missing( + case when get_year(current_datetime()) > 0 then missing else false end, + { "c": [ 2 ] } + ) + select v as b ) }; http://git-wip-us.apache.org/repos/asf/asterixdb/blob/8c88975a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/null-missing/ifmissingornull/ifmissingornull.1.query.sqlpp ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/null-missing/ifmissingornull/ifmissingornull.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/null-missing/ifmissingornull/ifmissingornull.1.query.sqlpp index 32f040f..22a8acd 100644 --- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/null-missing/ifmissingornull/ifmissingornull.1.query.sqlpp +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/null-missing/ifmissingornull/ifmissingornull.1.query.sqlpp @@ -32,5 +32,12 @@ case when get_year(current_datetime()) > 0 then missing else false end, case when get_year(current_datetime()) > 0 then null else false end, case when get_year(current_datetime()) > 0 then true else missing end + ), + "j": ( + let v = if_missing_or_null( + case when get_year(current_datetime()) > 0 then missing else false end, + { "c": [ 2 ] } + ) + select v as b ) }; \ No newline at end of file http://git-wip-us.apache.org/repos/asf/asterixdb/blob/8c88975a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/null-missing/ifnull/ifnull.1.query.sqlpp ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/null-missing/ifnull/ifnull.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/null-missing/ifnull/ifnull.1.query.sqlpp index c0683bd..0121cd8 100644 --- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/null-missing/ifnull/ifnull.1.query.sqlpp +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/null-missing/ifnull/ifnull.1.query.sqlpp @@ -30,5 +30,12 @@ null, case when get_year(current_datetime()) > 0 then null else false end, case when get_year(current_datetime()) > 0 then true else missing end + ), + "j": ( + let v = if_null( + case when get_year(current_datetime()) > 0 then null else false end, + { "c": [ 2 ] } + ) + select v as b ) }; http://git-wip-us.apache.org/repos/asf/asterixdb/blob/8c88975a/asterixdb/asterix-app/src/test/resources/runtimets/results/null-missing/ifmissing/ifmissing.1.adm ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/null-missing/ifmissing/ifmissing.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/null-missing/ifmissing/ifmissing.1.adm index 0a2275f..14620a1 100644 --- a/asterixdb/asterix-app/src/test/resources/runtimets/results/null-missing/ifmissing/ifmissing.1.adm +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/null-missing/ifmissing/ifmissing.1.adm @@ -1 +1 @@ -{ "a": true, "b": true, "c": true, "d": true, "e": true, "f": true, "g": true, "i": true } \ No newline at end of file +{ "a": true, "b": true, "c": true, "d": true, "e": true, "f": true, "g": true, "i": true, "j": [ { "b": { "c": [ 2 ] } } ] } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/asterixdb/blob/8c88975a/asterixdb/asterix-app/src/test/resources/runtimets/results/null-missing/ifmissingornull/ifmissingornull.1.adm ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/null-missing/ifmissingornull/ifmissingornull.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/null-missing/ifmissingornull/ifmissingornull.1.adm index 633c503..eff2651 100644 --- a/asterixdb/asterix-app/src/test/resources/runtimets/results/null-missing/ifmissingornull/ifmissingornull.1.adm +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/null-missing/ifmissingornull/ifmissingornull.1.adm @@ -1 +1 @@ -{ "a": true, "b": true, "c": true, "d": true, "e": true, "f": true, "g": true, "h": true, "i": true } \ No newline at end of file +{ "a": true, "b": true, "c": true, "d": true, "e": true, "f": true, "g": true, "h": true, "i": true, "j": [ { "b": { "c": [ 2 ] } } ] } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/asterixdb/blob/8c88975a/asterixdb/asterix-app/src/test/resources/runtimets/results/null-missing/ifnull/ifnull.1.adm ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/null-missing/ifnull/ifnull.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/null-missing/ifnull/ifnull.1.adm index 633c503..eff2651 100644 --- a/asterixdb/asterix-app/src/test/resources/runtimets/results/null-missing/ifnull/ifnull.1.adm +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/null-missing/ifnull/ifnull.1.adm @@ -1 +1 @@ -{ "a": true, "b": true, "c": true, "d": true, "e": true, "f": true, "g": true, "h": true, "i": true } \ No newline at end of file +{ "a": true, "b": true, "c": true, "d": true, "e": true, "f": true, "g": true, "h": true, "i": true, "j": [ { "b": { "c": [ 2 ] } } ] } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/asterixdb/blob/8c88975a/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/common/TypeResolverUtil.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/common/TypeResolverUtil.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/common/TypeResolverUtil.java index 561df5e..b7bd8ca 100644 --- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/common/TypeResolverUtil.java +++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/common/TypeResolverUtil.java @@ -106,7 +106,7 @@ public class TypeResolverUtil { // Gets the actual types for UNIONs and mark unknownable to be true. if (leftTypeTag == ATypeTag.UNION || rightTypeTag == ATypeTag.UNION) { leftType = TypeComputeUtils.getActualType(leftType); - rightType = TypeComputeUtils.getActualType(leftType); + rightType = TypeComputeUtils.getActualType(rightType); leftTypeTag = leftType.getTypeTag(); rightTypeTag = rightType.getTypeTag(); unknownable = true;