Repository: asterixdb Updated Branches: refs/heads/master 44a7523d0 -> 6c4325f0d
[NO ISSUE][COMP] allow optimization rule to inspect other functions + fixes - user model changes: no - storage format changes: no - interface changes: no Details: 1. allow the optimization rule "InjectTypeCastForSwitchCaseRule" (renamed to "InjectTypeCastForFunctionArgumentsRule" now) to consider other functions specified by the user in addition to the ones already considered by the rule. 2. fix an issue related to ConstantFoldingRule that affects some existing functions where the rule would have the function compute the value but fail to deserialize it (read it) back due to differences in compile-time type and runtime type. 3. fix static casting of a list constructor function which fails to cast open its items when the item is a function that returns a closed derived type. Change-Id: I65679e934a41e00b04bc3fd479ed404af293eb21 Reviewed-on: https://asterix-gerrit.ics.uci.edu/2980 Sonar-Qube: Jenkins <[email protected]> Tested-by: Jenkins <[email protected]> Contrib: Jenkins <[email protected]> Integration-Tests: Jenkins <[email protected]> Reviewed-by: Dmitry Lychagin <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/asterixdb/repo Commit: http://git-wip-us.apache.org/repos/asf/asterixdb/commit/6c4325f0 Tree: http://git-wip-us.apache.org/repos/asf/asterixdb/tree/6c4325f0 Diff: http://git-wip-us.apache.org/repos/asf/asterixdb/diff/6c4325f0 Branch: refs/heads/master Commit: 6c4325f0d9b4b12c9d453b312ce29d31737a904c Parents: 44a7523 Author: Ali Alsuliman <[email protected]> Authored: Sat Oct 6 18:30:39 2018 -0700 Committer: Ali Alsuliman <[email protected]> Committed: Mon Oct 8 10:35:17 2018 -0700 ---------------------------------------------------------------------- .../asterix/optimizer/base/RuleCollections.java | 4 +- .../optimizer/rules/ConstantFoldingRule.java | 15 +- .../InjectTypeCastForFunctionArgumentsRule.java | 161 +++++++++++++++++++ .../rules/InjectTypeCastForSwitchCaseRule.java | 156 ------------------ .../rules/typecast/StaticTypeCastUtil.java | 26 ++- .../enforcing_item_type.0.query.sqlpp | 28 ++++ .../enforcing_item_type.1.query.sqlpp | 28 ++++ .../constant_folding.0.query.sqlpp | 25 +++ .../constant_folding.1.query.sqlpp | 25 +++ .../enforcing_item_type.0.adm | 1 + .../enforcing_item_type.1.adm | 12 ++ .../constant_folding/constant_folding.0.adm | 1 + .../constant_folding/constant_folding.1.adm | 8 + .../resources/runtimets/testsuite_sqlpp.xml | 10 ++ 14 files changed, 334 insertions(+), 166 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6c4325f0/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java index f9b5c38..cf01573 100644 --- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java +++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java @@ -41,7 +41,7 @@ import org.apache.asterix.optimizer.rules.FeedScanCollectionToUnnest; import org.apache.asterix.optimizer.rules.FixReplicateOperatorOutputsRule; import org.apache.asterix.optimizer.rules.FullTextContainsParameterCheckRule; import org.apache.asterix.optimizer.rules.FuzzyEqRule; -import org.apache.asterix.optimizer.rules.InjectTypeCastForSwitchCaseRule; +import org.apache.asterix.optimizer.rules.InjectTypeCastForFunctionArgumentsRule; import org.apache.asterix.optimizer.rules.InjectTypeCastForUnionRule; import org.apache.asterix.optimizer.rules.InlineUnnestFunctionRule; import org.apache.asterix.optimizer.rules.IntroduceAutogenerateIDRule; @@ -306,7 +306,7 @@ public final class RuleCollections { planCleanupRules.add(new IntroduceDynamicTypeCastForExternalFunctionRule()); planCleanupRules.add(new RemoveUnusedAssignAndAggregateRule()); planCleanupRules.add(new RemoveCartesianProductWithEmptyBranchRule()); - planCleanupRules.add(new InjectTypeCastForSwitchCaseRule()); + planCleanupRules.add(new InjectTypeCastForFunctionArgumentsRule()); planCleanupRules.add(new InjectTypeCastForUnionRule()); // Needs to invoke ByNameToByIndexFieldAccessRule as the last logical optimization rule because http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6c4325f0/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ConstantFoldingRule.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ConstantFoldingRule.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ConstantFoldingRule.java index a2c500a..f10ae1a 100644 --- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ConstantFoldingRule.java +++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ConstantFoldingRule.java @@ -43,10 +43,14 @@ import org.apache.asterix.om.base.IAObject; import org.apache.asterix.om.constants.AsterixConstantValue; import org.apache.asterix.om.functions.BuiltinFunctions; import org.apache.asterix.om.typecomputer.base.TypeCastUtils; +import org.apache.asterix.om.typecomputer.impl.TypeComputeUtils; import org.apache.asterix.om.types.ARecordType; import org.apache.asterix.om.types.ATypeTag; import org.apache.asterix.om.types.AbstractCollectionType; +import org.apache.asterix.om.types.IAType; +import org.apache.asterix.om.types.TypeTagUtil; import org.apache.asterix.om.utils.ConstantExpressionUtil; +import org.apache.asterix.runtime.evaluators.functions.PointableHelper; import org.apache.commons.lang3.mutable.Mutable; import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException; import org.apache.hyracks.algebricks.common.utils.Pair; @@ -237,11 +241,16 @@ public class ConstantFoldingRule implements IAlgebraicRewriteRule { IScalarEvaluator eval = fact.createScalarEvaluator(null); eval.evaluate(null, p); - Object t = _emptyTypeEnv.getType(expr); - + IAType returnType = (IAType) _emptyTypeEnv.getType(expr); + ATypeTag runtimeType = PointableHelper.getTypeTag(p); + if (runtimeType.isDerivedType()) { + returnType = TypeComputeUtils.getActualType(returnType); + } else { + returnType = TypeTagUtil.getBuiltinTypeByTag(runtimeType); + } @SuppressWarnings("rawtypes") ISerializerDeserializer serde = - jobGenCtx.getSerializerDeserializerProvider().getSerializerDeserializer(t); + jobGenCtx.getSerializerDeserializerProvider().getSerializerDeserializer(returnType); bbis.setByteBuffer(ByteBuffer.wrap(p.getByteArray(), p.getStartOffset(), p.getLength()), 0); IAObject o = (IAObject) serde.deserialize(dis); return new Pair<>(true, new ConstantExpression(new AsterixConstantValue(o))); http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6c4325f0/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/InjectTypeCastForFunctionArgumentsRule.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/InjectTypeCastForFunctionArgumentsRule.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/InjectTypeCastForFunctionArgumentsRule.java new file mode 100644 index 0000000..d0107c0 --- /dev/null +++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/InjectTypeCastForFunctionArgumentsRule.java @@ -0,0 +1,161 @@ +/* + * 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.asterix.optimizer.rules; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.IntPredicate; + +import org.apache.asterix.dataflow.data.common.TypeResolverUtil; +import org.apache.asterix.lang.common.util.FunctionUtil; +import org.apache.asterix.om.functions.BuiltinFunctions; +import org.apache.asterix.om.typecomputer.base.TypeCastUtils; +import org.apache.asterix.om.types.IAType; +import org.apache.commons.lang3.mutable.Mutable; +import org.apache.commons.lang3.mutable.MutableObject; +import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException; +import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression; +import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator; +import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext; +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; + +/** + * 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 InjectTypeCastForFunctionArgumentsRule implements IAlgebraicRewriteRule { + + private static final Map<FunctionIdentifier, IntPredicate> FUN_TO_ARG_CHECKER = new HashMap<>(); + + static { + addFunctionAndArgChecker(BuiltinFunctions.IF_MISSING, null); + addFunctionAndArgChecker(BuiltinFunctions.IF_NULL, null); + addFunctionAndArgChecker(BuiltinFunctions.IF_MISSING_OR_NULL, null); + } + + // allows the rule to check other functions in addition to the ones specified here + public static void addFunctionAndArgChecker(FunctionIdentifier function, IntPredicate argChecker) { + FUN_TO_ARG_CHECKER.put(function, argChecker); + } + + @Override + public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context) + throws AlgebricksException { + ILogicalOperator op = opRef.getValue(); + if (op.getInputs().isEmpty()) { + return false; + } + // Populates the latest type information. + context.computeAndSetTypeEnvironmentForOperator(op); + if (op.acceptExpressionTransform(exprRef -> injectTypeCast(op, exprRef, context))) { + // Generates the up-to-date type information. + context.computeAndSetTypeEnvironmentForOperator(op); + return true; + } + return false; + } + + // Injects type casts to cast return expressions' return types to a generalized type that conforms to every + // return type. + private boolean injectTypeCast(ILogicalOperator op, Mutable<ILogicalExpression> exprRef, + IOptimizationContext context) throws AlgebricksException { + ILogicalExpression expr = exprRef.getValue(); + if (expr.getExpressionTag() != LogicalExpressionTag.FUNCTION_CALL) { + return false; + } + boolean rewritten = false; + AbstractFunctionCallExpression func = (AbstractFunctionCallExpression) expr; + for (Mutable<ILogicalExpression> argRef : func.getArguments()) { + // Recursively rewrites arguments. + if (injectTypeCast(op, argRef, context)) { + context.computeAndSetTypeEnvironmentForOperator(op); + rewritten = true; + } + } + FunctionIdentifier funcId = func.getFunctionIdentifier(); + if (funcId.equals(BuiltinFunctions.SWITCH_CASE)) { + rewritten |= rewriteSwitchCase(op, func, context); + } else if (FUN_TO_ARG_CHECKER.containsKey(funcId)) { + rewritten |= rewriteFunction(op, func, FUN_TO_ARG_CHECKER.get(funcId), context); + } + return rewritten; + } + + // Injects casts that cast types for different "THEN" and "ELSE" branches. + private boolean rewriteSwitchCase(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 = 2; argIndex < argSize; argIndex += (argIndex + 2 == argSize) ? 1 : 2) { + Mutable<ILogicalExpression> argRef = argRefs.get(argIndex); + 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, IntPredicate argChecker, + 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++) { + if (argChecker == null || argChecker.test(argIndex)) { + rewritten |= rewriteFunctionArgument(argRefs.get(argIndex), producedType, env); + } + } + 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/6c4325f0/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 deleted file mode 100644 index 683d29f..0000000 --- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/InjectTypeCastForSwitchCaseRule.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * 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.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; -import org.apache.asterix.om.functions.BuiltinFunctions; -import org.apache.asterix.om.typecomputer.base.TypeCastUtils; -import org.apache.asterix.om.types.IAType; -import org.apache.commons.lang3.mutable.Mutable; -import org.apache.commons.lang3.mutable.MutableObject; -import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException; -import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression; -import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator; -import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext; -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 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 { - ILogicalOperator op = opRef.getValue(); - if (op.getInputs().isEmpty()) { - return false; - } - // Populates the latest type information. - context.computeAndSetTypeEnvironmentForOperator(op); - if (op.acceptExpressionTransform(exprRef -> injectTypeCast(op, exprRef, context))) { - // Generates the up-to-date type information. - context.computeAndSetTypeEnvironmentForOperator(op); - return true; - } - return false; - } - - // Injects type casts to cast return expressions' return types to a generalized type that conforms to every - // return type. - private boolean injectTypeCast(ILogicalOperator op, Mutable<ILogicalExpression> exprRef, - IOptimizationContext context) throws AlgebricksException { - ILogicalExpression expr = exprRef.getValue(); - if (expr.getExpressionTag() != LogicalExpressionTag.FUNCTION_CALL) { - return false; - } - boolean rewritten = false; - AbstractFunctionCallExpression func = (AbstractFunctionCallExpression) expr; - for (Mutable<ILogicalExpression> argRef : func.getArguments()) { - // Recursively rewrites arguments. - if (injectTypeCast(op, argRef, context)) { - context.computeAndSetTypeEnvironmentForOperator(op); - rewritten = true; - } - } - 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 rewritten; - } - - // Injects casts that cast types for different "THEN" and "ELSE" branches. - private boolean rewriteSwitchCase(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 = 2; argIndex < argSize; argIndex += (argIndex + 2 == argSize) ? 1 : 2) { - Mutable<ILogicalExpression> argRef = argRefs.get(argIndex); - 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/6c4325f0/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/typecast/StaticTypeCastUtil.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/typecast/StaticTypeCastUtil.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/typecast/StaticTypeCastUtil.java index 4b2ff76..55b174b 100644 --- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/typecast/StaticTypeCastUtil.java +++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/typecast/StaticTypeCastUtil.java @@ -27,6 +27,7 @@ import java.util.Set; import org.apache.asterix.common.exceptions.CompilationException; import org.apache.asterix.common.exceptions.ErrorCode; +import org.apache.asterix.dataflow.data.common.TypeResolverUtil; import org.apache.asterix.lang.common.util.FunctionUtil; import org.apache.asterix.om.base.ANull; import org.apache.asterix.om.base.AString; @@ -73,9 +74,9 @@ public class StaticTypeCastUtil { * * @param funcExpr * record constructor function expression - * @param requiredListType + * @param reqType * required record type - * @param inputRecordType + * @param inputType * @param env * type environment * @throws AlgebricksException @@ -179,7 +180,7 @@ public class StaticTypeCastUtil { * * @param funcExpr * record constructor function expression - * @param requiredListType + * @param requiredRecordType * required record type * @param inputRecordType * @param env @@ -223,7 +224,7 @@ public class StaticTypeCastUtil { TypeCastUtils.setRequiredAndInputTypes(funcExpr, requiredListType, inputListType); List<Mutable<ILogicalExpression>> args = funcExpr.getArguments(); - IAType itemType = requiredListType.getItemType(); + IAType requiredItemType = requiredListType.getItemType(); IAType inputItemType = inputListType.getItemType(); boolean changed = false; for (int j = 0; j < args.size(); j++) { @@ -233,7 +234,8 @@ public class StaticTypeCastUtil { switch (arg.getExpressionTag()) { case FUNCTION_CALL: ScalarFunctionCallExpression argFunc = (ScalarFunctionCallExpression) arg; - changed = rewriteFuncExpr(argFunc, itemType, currentItemType, env) || changed; + changed = rewriteFuncExpr(argFunc, requiredItemType, currentItemType, env) || changed; + changed |= castItem(requiredItemType, currentItemType, argFunc, args.get(j)); break; case VARIABLE: changed = injectCastToRelaxType(args.get(j), currentItemType, env) || changed; @@ -243,6 +245,20 @@ public class StaticTypeCastUtil { return changed; } + private static boolean castItem(IAType requiredItemType, IAType currentItemType, + ScalarFunctionCallExpression itemExpr, Mutable<ILogicalExpression> itemExprRef) throws AlgebricksException { + if (TypeResolverUtil.needsCast(requiredItemType, currentItemType) && shouldCast(itemExpr)) { + injectCastFunction(FunctionUtil.getFunctionInfo(BuiltinFunctions.CAST_TYPE), requiredItemType, + currentItemType, itemExprRef, itemExpr); + return true; + } + return false; + } + + private static boolean shouldCast(ScalarFunctionCallExpression itemExpr) { + return TypeCastUtils.getRequiredType(itemExpr) == null; + } + /** * This method statically cast the type of records from their current type to the required type. * http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6c4325f0/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/enforcing_item_type/enforcing_item_type.0.query.sqlpp ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/enforcing_item_type/enforcing_item_type.0.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/enforcing_item_type/enforcing_item_type.0.query.sqlpp new file mode 100644 index 0000000..522a352 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/enforcing_item_type/enforcing_item_type.0.query.sqlpp @@ -0,0 +1,28 @@ +/* + * 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. + */ + +/* + * Description: testing that each item conforms to the list type including function items. + */ + +select value {"id": t[0], "v": t[1]} +from [ +[ 29, CASE(2 < 1) WHEN true THEN null ELSE {"f1": "a", "f2": 3} END] +] t; + http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6c4325f0/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/enforcing_item_type/enforcing_item_type.1.query.sqlpp ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/enforcing_item_type/enforcing_item_type.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/enforcing_item_type/enforcing_item_type.1.query.sqlpp new file mode 100644 index 0000000..0abb216 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/enforcing_item_type/enforcing_item_type.1.query.sqlpp @@ -0,0 +1,28 @@ +/* + * 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. + */ + +/* + * Description: testing that each item conforms to the list type including function items. + */ + +explain select value {"id": t[0], "v": t[1]} +from [ +[ 29, CASE(2 < 1) WHEN true THEN null ELSE {"f1": "a", "f2": 3} END] +] t; + http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6c4325f0/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/constant_folding/constant_folding.0.query.sqlpp ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/constant_folding/constant_folding.0.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/constant_folding/constant_folding.0.query.sqlpp new file mode 100644 index 0000000..671ff7d --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/constant_folding/constant_folding.0.query.sqlpp @@ -0,0 +1,25 @@ +/* + * 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. + */ + +/* + * Description: testing constant folding of functions that return missable/nullable closed-type object + */ + +select value CASE(2 < 1) WHEN true THEN null ELSE { "f1": 5, "f2": 6, "f3": 7 } END; + http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6c4325f0/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/constant_folding/constant_folding.1.query.sqlpp ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/constant_folding/constant_folding.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/constant_folding/constant_folding.1.query.sqlpp new file mode 100644 index 0000000..ad5f59b --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/constant_folding/constant_folding.1.query.sqlpp @@ -0,0 +1,25 @@ +/* + * 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. + */ + +/* + * Description: testing constant folding of functions that return missable/nullable closed-type object + */ + +explain select value CASE(2 < 1) WHEN true THEN null ELSE { "f1": 5, "f2": 6, "f3": 7 } END; + http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6c4325f0/asterixdb/asterix-app/src/test/resources/runtimets/results/list/enforcing_item_type/enforcing_item_type.0.adm ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/list/enforcing_item_type/enforcing_item_type.0.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/list/enforcing_item_type/enforcing_item_type.0.adm new file mode 100644 index 0000000..325fe87 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/list/enforcing_item_type/enforcing_item_type.0.adm @@ -0,0 +1 @@ +{ "id": 29, "v": { "f1": "a", "f2": 3 } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6c4325f0/asterixdb/asterix-app/src/test/resources/runtimets/results/list/enforcing_item_type/enforcing_item_type.1.adm ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/list/enforcing_item_type/enforcing_item_type.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/list/enforcing_item_type/enforcing_item_type.1.adm new file mode 100644 index 0000000..fbe0345 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/list/enforcing_item_type/enforcing_item_type.1.adm @@ -0,0 +1,12 @@ +distribute result [$$18] +-- DISTRIBUTE_RESULT |UNPARTITIONED| + exchange + -- ONE_TO_ONE_EXCHANGE |UNPARTITIONED| + project ([$$18]) + -- STREAM_PROJECT |UNPARTITIONED| + assign [$$18] <- [{"id": get-item($$t, 0), "v": get-item($$t, 1)}] + -- ASSIGN |UNPARTITIONED| + unnest $$t <- scan-collection(ordered-list-constructor(ordered-list-constructor(29, cast({ f1: "a", f2: 3 })))) + -- UNNEST |UNPARTITIONED| + empty-tuple-source + -- EMPTY_TUPLE_SOURCE |UNPARTITIONED| \ No newline at end of file http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6c4325f0/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/constant_folding/constant_folding.0.adm ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/constant_folding/constant_folding.0.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/constant_folding/constant_folding.0.adm new file mode 100644 index 0000000..61265f7 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/constant_folding/constant_folding.0.adm @@ -0,0 +1 @@ +{ "f1": 5, "f2": 6, "f3": 7 } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6c4325f0/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/constant_folding/constant_folding.1.adm ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/constant_folding/constant_folding.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/constant_folding/constant_folding.1.adm new file mode 100644 index 0000000..379603f --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/constant_folding/constant_folding.1.adm @@ -0,0 +1,8 @@ +distribute result [$$5] +-- DISTRIBUTE_RESULT |UNPARTITIONED| + exchange + -- ONE_TO_ONE_EXCHANGE |UNPARTITIONED| + assign [$$5] <- [{ f1: 5, f2: 6, f3: 7 }] + -- ASSIGN |UNPARTITIONED| + empty-tuple-source + -- EMPTY_TUPLE_SOURCE |UNPARTITIONED| \ No newline at end of file http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6c4325f0/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml index 398b58b..52cb6e5 100644 --- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml +++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml @@ -3673,6 +3673,11 @@ </compilation-unit> </test-case> <test-case FilePath="list"> + <compilation-unit name="enforcing_item_type"> + <output-dir compare="Text">enforcing_item_type</output-dir> + </compilation-unit> + </test-case> + <test-case FilePath="list"> <compilation-unit name="exists"> <output-dir compare="Text">exists</output-dir> </compilation-unit> @@ -3791,6 +3796,11 @@ </compilation-unit> </test-case> <test-case FilePath="misc"> + <compilation-unit name="constant_folding"> + <output-dir compare="Text">constant_folding</output-dir> + </compilation-unit> + </test-case> + <test-case FilePath="misc"> <compilation-unit name="poll-dynamic"> <output-dir compare="Text">poll-dynamic</output-dir> </compilation-unit>
