Steven Jacobs has submitted this change and it was merged. Change subject: Convert comparisons with current-datetime, current-date, and current-time to applicable index searches as though they were constants ......................................................................
Convert comparisons with current-datetime, current-date, and current-time to applicable index searches as though they were constants Change-Id: Ied64276873afcfbdd31dac313009e47429d8f9b0 Reviewed-on: https://asterix-gerrit.ics.uci.edu/367 Tested-by: Jenkins <[email protected]> Reviewed-by: Yingyi Bu <[email protected]> --- M asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AbstractIntroduceAccessMethodRule.java M asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java M asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/BTreeAccessMethod.java M asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IAccessMethod.java M asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IOptimizableFuncExpr.java M asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceJoinAccessMethodRule.java M asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceLSMComponentFilterRule.java M asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceSelectAccessMethodRule.java M asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/InvertedIndexAccessMethod.java M asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/OptimizableFuncExpr.java M asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/RTreeAccessMethod.java A asterix-app/src/test/resources/optimizerts/queries/btree-index/btree-datetime-01.aql A asterix-app/src/test/resources/optimizerts/queries/btree-index/btree-datetime-02.aql A asterix-app/src/test/resources/optimizerts/queries/btree-index/btree-datetime-03.aql A asterix-app/src/test/resources/optimizerts/queries/btree-index/btree-datetime-04.aql A asterix-app/src/test/resources/optimizerts/results/btree-index/btree-datetime-01.plan A asterix-app/src/test/resources/optimizerts/results/btree-index/btree-datetime-02.plan A asterix-app/src/test/resources/optimizerts/results/btree-index/btree-datetime-03.plan A asterix-app/src/test/resources/optimizerts/results/btree-index/btree-datetime-04.plan 19 files changed, 430 insertions(+), 123 deletions(-) Approvals: Yingyi Bu: Looks good to me, approved Jenkins: Verified diff --git a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AbstractIntroduceAccessMethodRule.java b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AbstractIntroduceAccessMethodRule.java index b736361..d274259 100644 --- a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AbstractIntroduceAccessMethodRule.java +++ b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AbstractIntroduceAccessMethodRule.java @@ -25,8 +25,6 @@ import java.util.List; import java.util.Map; -import org.apache.commons.lang3.mutable.Mutable; - import org.apache.asterix.common.config.DatasetConfig.IndexType; import org.apache.asterix.dataflow.data.common.AqlExpressionTypeComputer; import org.apache.asterix.metadata.api.IMetadataEntity; @@ -44,6 +42,7 @@ import org.apache.asterix.om.types.IAType; import org.apache.asterix.om.types.hierachy.ATypeHierarchy; import org.apache.asterix.optimizer.rules.am.OptimizableOperatorSubTree.DataSourceType; +import org.apache.commons.lang3.mutable.Mutable; import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException; import org.apache.hyracks.algebricks.common.utils.Pair; import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression; @@ -110,14 +109,14 @@ } } - protected void pruneIndexCandidates(Map<IAccessMethod, AccessMethodAnalysisContext> analyzedAMs) - throws AlgebricksException { + protected void pruneIndexCandidates(Map<IAccessMethod, AccessMethodAnalysisContext> analyzedAMs, + IOptimizationContext context, IVariableTypeEnvironment typeEnvironment) throws AlgebricksException { Iterator<Map.Entry<IAccessMethod, AccessMethodAnalysisContext>> amIt = analyzedAMs.entrySet().iterator(); // Check applicability of indexes by access method type. while (amIt.hasNext()) { Map.Entry<IAccessMethod, AccessMethodAnalysisContext> entry = amIt.next(); AccessMethodAnalysisContext amCtx = entry.getValue(); - pruneIndexCandidates(entry.getKey(), amCtx); + pruneIndexCandidates(entry.getKey(), amCtx, context, typeEnvironment); // Remove access methods for which there are definitely no // applicable indexes. if (amCtx.indexExprsAndVars.isEmpty()) { @@ -174,11 +173,11 @@ * only require a match on a prefix of fields to be applicable. This methods * removes all index candidates indexExprs that are definitely not * applicable according to the expressions involved. - * + * * @throws AlgebricksException */ - public void pruneIndexCandidates(IAccessMethod accessMethod, AccessMethodAnalysisContext analysisCtx) - throws AlgebricksException { + public void pruneIndexCandidates(IAccessMethod accessMethod, AccessMethodAnalysisContext analysisCtx, + IOptimizationContext context, IVariableTypeEnvironment typeEnvironment) throws AlgebricksException { Iterator<Map.Entry<Index, List<Pair<Integer, Integer>>>> indexExprAndVarIt = analysisCtx.indexExprsAndVars .entrySet().iterator(); // Used to keep track of matched expressions (added for prefix search) @@ -222,11 +221,14 @@ for (int j = 0; j < optFuncExpr.getNumLogicalVars(); j++) if (j != exprAndVarIdx.second) indexedTypes.add(optFuncExpr.getFieldType(j)); + //add constants in case of select - if (indexedTypes.size() < 2 && optFuncExpr.getNumLogicalVars() == 1) { - indexedTypes.add((IAType) AqlExpressionTypeComputer.INSTANCE.getType(new ConstantExpression( - optFuncExpr.getConstantVal(0)), null, null)); + if (indexedTypes.size() < 2 && optFuncExpr.getNumLogicalVars() == 1 + && optFuncExpr.getNumConstantAtRuntimeExpr() > 0) { + indexedTypes.add((IAType) AqlExpressionTypeComputer.INSTANCE.getType( + optFuncExpr.getConstantAtRuntimeExpr(0), context.getMetadataProvider(), typeEnvironment)); } + //infer type of logicalExpr based on index keyType indexedTypes.add((IAType) AqlExpressionTypeComputer.INSTANCE.getType( optFuncExpr.getLogicalExpr(exprAndVarIdx.second), null, new IVariableTypeEnvironment() { @@ -329,9 +331,12 @@ * Analyzes the given selection condition, filling analyzedAMs with * applicable access method types. At this point we are not yet consulting * the metadata whether an actual index exists or not. + * + * @throws AlgebricksException */ protected boolean analyzeCondition(ILogicalExpression cond, List<AbstractLogicalOperator> assignsAndUnnests, - Map<IAccessMethod, AccessMethodAnalysisContext> analyzedAMs) { + Map<IAccessMethod, AccessMethodAnalysisContext> analyzedAMs, IOptimizationContext context, + IVariableTypeEnvironment typeEnvironment) throws AlgebricksException { AbstractFunctionCallExpression funcExpr = (AbstractFunctionCallExpression) cond; FunctionIdentifier funcIdent = funcExpr.getFunctionIdentifier(); // Don't consider optimizing a disjunctive condition with an index (too @@ -339,14 +344,15 @@ if (funcIdent == AlgebricksBuiltinFunctions.OR) { return false; } - boolean found = analyzeFunctionExpr(funcExpr, assignsAndUnnests, analyzedAMs); + boolean found = analyzeFunctionExpr(funcExpr, assignsAndUnnests, analyzedAMs, context, typeEnvironment); for (Mutable<ILogicalExpression> arg : funcExpr.getArguments()) { ILogicalExpression argExpr = arg.getValue(); if (argExpr.getExpressionTag() != LogicalExpressionTag.FUNCTION_CALL) { continue; } AbstractFunctionCallExpression argFuncExpr = (AbstractFunctionCallExpression) argExpr; - boolean matchFound = analyzeFunctionExpr(argFuncExpr, assignsAndUnnests, analyzedAMs); + boolean matchFound = analyzeFunctionExpr(argFuncExpr, assignsAndUnnests, analyzedAMs, context, + typeEnvironment); found = found || matchFound; } return found; @@ -356,9 +362,13 @@ * Finds applicable access methods for the given function expression based * on the function identifier, and an analysis of the function's arguments. * Updates the analyzedAMs accordingly. + * + * @throws AlgebricksException */ protected boolean analyzeFunctionExpr(AbstractFunctionCallExpression funcExpr, - List<AbstractLogicalOperator> assignsAndUnnests, Map<IAccessMethod, AccessMethodAnalysisContext> analyzedAMs) { + List<AbstractLogicalOperator> assignsAndUnnests, + Map<IAccessMethod, AccessMethodAnalysisContext> analyzedAMs, IOptimizationContext context, + IVariableTypeEnvironment typeEnvironment) throws AlgebricksException { FunctionIdentifier funcIdent = funcExpr.getFunctionIdentifier(); if (funcIdent == AlgebricksBuiltinFunctions.AND) { return false; @@ -380,7 +390,8 @@ } // Analyzes the funcExpr's arguments to see if the accessMethod is // truly applicable. - boolean matchFound = accessMethod.analyzeFuncExprArgs(funcExpr, assignsAndUnnests, analysisCtx); + boolean matchFound = accessMethod.analyzeFuncExprArgs(funcExpr, assignsAndUnnests, analysisCtx, context, + typeEnvironment); if (matchFound) { // If we've used the current new context placeholder, replace it // with a new one. @@ -398,7 +409,7 @@ * Finds secondary indexes whose keys include fieldName, and adds a mapping * in analysisCtx.indexEsprs from that index to the a corresponding * optimizable function expression. - * + * * @return true if a candidate index was added to foundIndexExprs, false * otherwise * @throws AlgebricksException diff --git a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java index 7f713f8..831b3f7 100644 --- a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java +++ b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java @@ -21,10 +21,9 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; - -import org.apache.commons.lang3.mutable.Mutable; -import org.apache.commons.lang3.mutable.MutableObject; +import java.util.Set; import org.apache.asterix.algebra.operators.physical.ExternalDataLookupPOperator; import org.apache.asterix.aql.util.FunctionUtils; @@ -47,6 +46,8 @@ import org.apache.asterix.om.types.IAType; import org.apache.asterix.om.types.hierachy.ATypeHierarchy; import org.apache.asterix.om.util.NonTaggedFormatUtil; +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.common.utils.Pair; import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression; @@ -57,7 +58,7 @@ import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable; import org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression; import org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression; -import org.apache.hyracks.algebricks.core.algebra.expressions.IAlgebricksConstantValue; +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.expressions.UnnestingFunctionCallExpression; import org.apache.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression; @@ -122,32 +123,47 @@ } public static boolean analyzeFuncExprArgsForOneConstAndVar(AbstractFunctionCallExpression funcExpr, - AccessMethodAnalysisContext analysisCtx) { - IAlgebricksConstantValue constFilterVal = null; + AccessMethodAnalysisContext analysisCtx, IOptimizationContext context, + IVariableTypeEnvironment typeEnvironment) throws AlgebricksException { + ILogicalExpression constExpression = null; + IAType constantExpressionType = null; LogicalVariable fieldVar = null; ILogicalExpression arg1 = funcExpr.getArguments().get(0).getValue(); ILogicalExpression arg2 = funcExpr.getArguments().get(1).getValue(); - // One of the args must be a constant, and the other arg must be a variable. - if (arg1.getExpressionTag() == LogicalExpressionTag.CONSTANT + // One of the args must be a runtime constant, and the other arg must be a variable. + if (arg1.getExpressionTag() == LogicalExpressionTag.VARIABLE && arg2.getExpressionTag() == LogicalExpressionTag.VARIABLE) { + return false; + } + if (arg2.getExpressionTag() == LogicalExpressionTag.VARIABLE) { // The arguments of contains() function are asymmetrical, we can only use index if it is on the first argument if (funcExpr.getFunctionIdentifier() == AsterixBuiltinFunctions.CONTAINS) { return false; } - ConstantExpression constExpr = (ConstantExpression) arg1; - constFilterVal = constExpr.getValue(); + IAType expressionType = constantRuntimeResultType(arg1, context, typeEnvironment); + if (expressionType == null) { + //Not constant at runtime + return false; + } + constantExpressionType = expressionType; + constExpression = arg1; VariableReferenceExpression varExpr = (VariableReferenceExpression) arg2; fieldVar = varExpr.getVariableReference(); - } else if (arg1.getExpressionTag() == LogicalExpressionTag.VARIABLE - && arg2.getExpressionTag() == LogicalExpressionTag.CONSTANT) { - ConstantExpression constExpr = (ConstantExpression) arg2; - constFilterVal = constExpr.getValue(); + } else if (arg1.getExpressionTag() == LogicalExpressionTag.VARIABLE) { + IAType expressionType = constantRuntimeResultType(arg2, context, typeEnvironment); + if (expressionType == null) { + //Not constant at runtime + return false; + } + constantExpressionType = expressionType; + constExpression = arg2; VariableReferenceExpression varExpr = (VariableReferenceExpression) arg1; fieldVar = varExpr.getVariableReference(); } else { return false; } - OptimizableFuncExpr newOptFuncExpr = new OptimizableFuncExpr(funcExpr, fieldVar, constFilterVal); + OptimizableFuncExpr newOptFuncExpr = new OptimizableFuncExpr(funcExpr, fieldVar, constExpression, + constantExpressionType); for (IOptimizableFuncExpr optFuncExpr : analysisCtx.matchedFuncExprs) { //avoid additional optFuncExpressions in case of a join if (optFuncExpr.getFuncExpr().equals(funcExpr)) @@ -171,7 +187,7 @@ return false; } OptimizableFuncExpr newOptFuncExpr = new OptimizableFuncExpr(funcExpr, new LogicalVariable[] { fieldVar1, - fieldVar2 }, null); + fieldVar2 }, new ILogicalExpression[0], new IAType[0]); for (IOptimizableFuncExpr optFuncExpr : analysisCtx.matchedFuncExprs) { //avoid additional optFuncExpressions in case of a join if (optFuncExpr.getFuncExpr().equals(funcExpr)) @@ -308,7 +324,7 @@ * Returns the search key expression which feeds a secondary-index search. If we are optimizing a selection query then this method returns * the a ConstantExpression from the first constant value in the optimizable function expression. * If we are optimizing a join, then this method returns the VariableReferenceExpression that should feed the secondary index probe. - * + * * @throws AlgebricksException */ public static Pair<ILogicalExpression, Boolean> createSearchKeyExpr(IOptimizableFuncExpr optFuncExpr, @@ -318,8 +334,19 @@ // We are optimizing a selection query. Search key is a constant. // Type Checking and type promotion is done here IAType fieldType = optFuncExpr.getFieldType(0); - IAObject constantObj = ((AsterixConstantValue) optFuncExpr.getConstantVal(0)).getObject(); - ATypeTag constantValueTag = constantObj.getType().getTypeTag(); + + ILogicalExpression constantAtRuntimeExpression = null; + AsterixConstantValue constantValue = null; + ATypeTag constantValueTag = null; + + constantAtRuntimeExpression = optFuncExpr.getConstantAtRuntimeExpr(0); + + if (constantAtRuntimeExpression.getExpressionTag() == LogicalExpressionTag.CONSTANT) { + constantValue = (AsterixConstantValue) ((ConstantExpression) constantAtRuntimeExpression).getValue(); + } + + constantValueTag = optFuncExpr.getConstantType(0).getTypeTag(); + // type casting applied? boolean typeCastingApplied = false; // type casting happened from real (FLOAT, DOUBLE) value -> INT value? @@ -327,9 +354,9 @@ AsterixConstantValue replacedConstantValue = null; // if the constant type and target type does not match, we do a type conversion - if (constantValueTag != fieldType.getTypeTag()) { - replacedConstantValue = ATypeHierarchy.getAsterixConstantValueFromNumericTypeObject(constantObj, - fieldType.getTypeTag()); + if (constantValueTag != fieldType.getTypeTag() && constantValue != null) { + replacedConstantValue = ATypeHierarchy.getAsterixConstantValueFromNumericTypeObject( + constantValue.getObject(), fieldType.getTypeTag()); if (replacedConstantValue != null) { typeCastingApplied = true; } @@ -358,8 +385,7 @@ return new Pair<ILogicalExpression, Boolean>(new ConstantExpression(replacedConstantValue), realTypeConvertedToIntegerType); } else { - return new Pair<ILogicalExpression, Boolean>(new ConstantExpression(optFuncExpr.getConstantVal(0)), - false); + return new Pair<ILogicalExpression, Boolean>(optFuncExpr.getConstantAtRuntimeExpr(0), false); } } else { // We are optimizing a join query. Determine which variable feeds the secondary index. @@ -610,4 +636,16 @@ secondaryIndex, primaryKeyVars, false, retainInput, retainNull)); return externalLookupOp; } + + //If the expression is constant at runtime, runturn the type + public static IAType constantRuntimeResultType(ILogicalExpression expr, IOptimizationContext context, + IVariableTypeEnvironment typeEnvironment) throws AlgebricksException { + Set<LogicalVariable> usedVariables = new HashSet<LogicalVariable>(); + expr.getUsedVariables(usedVariables); + if (usedVariables.size() > 0) { + return null; + } + return (IAType) context.getExpressionTypeComputer().getType(expr, context.getMetadataProvider(), + typeEnvironment); + } } diff --git a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/BTreeAccessMethod.java b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/BTreeAccessMethod.java index 7b76fa4..de28e4a 100644 --- a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/BTreeAccessMethod.java +++ b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/BTreeAccessMethod.java @@ -28,9 +28,6 @@ import java.util.List; import java.util.Set; -import org.apache.commons.lang3.mutable.Mutable; -import org.apache.commons.lang3.mutable.MutableObject; - import org.apache.asterix.aql.util.FunctionUtils; import org.apache.asterix.common.annotations.SkipSecondaryIndexSearchExpressionAnnotation; import org.apache.asterix.common.config.DatasetConfig.DatasetType; @@ -39,6 +36,8 @@ import org.apache.asterix.metadata.entities.Index; import org.apache.asterix.om.types.ARecordType; import org.apache.asterix.optimizer.rules.util.EquivalenceClassUtils; +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.common.utils.Pair; import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression; @@ -47,6 +46,7 @@ import org.apache.hyracks.algebricks.core.algebra.base.LogicalExpressionTag; import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable; 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.IndexedNLJoinExpressionAnnotation; import org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression; import org.apache.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression; @@ -96,8 +96,10 @@ @Override public boolean analyzeFuncExprArgs(AbstractFunctionCallExpression funcExpr, - List<AbstractLogicalOperator> assignsAndUnnests, AccessMethodAnalysisContext analysisCtx) { - boolean matches = AccessMethodUtils.analyzeFuncExprArgsForOneConstAndVar(funcExpr, analysisCtx); + List<AbstractLogicalOperator> assignsAndUnnests, AccessMethodAnalysisContext analysisCtx, + IOptimizationContext context, IVariableTypeEnvironment typeEnvironment) throws AlgebricksException { + boolean matches = AccessMethodUtils.analyzeFuncExprArgsForOneConstAndVar(funcExpr, analysisCtx, context, + typeEnvironment); if (!matches) { matches = AccessMethodUtils.analyzeFuncExprArgsForTwoVars(funcExpr, analysisCtx); } @@ -234,6 +236,8 @@ LimitType[] highKeyLimits = new LimitType[numSecondaryKeys]; boolean[] lowKeyInclusive = new boolean[numSecondaryKeys]; boolean[] highKeyInclusive = new boolean[numSecondaryKeys]; + ILogicalExpression[] constantAtRuntimeExpressions = new ILogicalExpression[numSecondaryKeys]; + LogicalVariable[] constAtRuntimeExprVars = new LogicalVariable[numSecondaryKeys]; // TODO: For now we don't do any sophisticated analysis of the func exprs to come up with "the best" range predicate. // If we can't figure out how to integrate a certain funcExpr into the current predicate, we just bail by setting this flag. @@ -267,6 +271,12 @@ Pair<ILogicalExpression, Boolean> returnedSearchKeyExpr = AccessMethodUtils.createSearchKeyExpr( optFuncExpr, indexSubTree, probeSubTree); ILogicalExpression searchKeyExpr = returnedSearchKeyExpr.first; + if (searchKeyExpr.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) { + constantAtRuntimeExpressions[keyPos] = searchKeyExpr; + constAtRuntimeExprVars[keyPos] = context.newVar(); + searchKeyExpr = new VariableReferenceExpression(constAtRuntimeExprVars[keyPos]); + + } realTypeConvertedToIntegerType = returnedSearchKeyExpr.second; LimitType limit = getLimitType(optFuncExpr, probeSubTree); @@ -446,9 +456,9 @@ ArrayList<LogicalVariable> assignKeyVarList = new ArrayList<LogicalVariable>(); ArrayList<Mutable<ILogicalExpression>> assignKeyExprList = new ArrayList<Mutable<ILogicalExpression>>(); int numLowKeys = createKeyVarsAndExprs(numSecondaryKeys, lowKeyLimits, lowKeyExprs, assignKeyVarList, - assignKeyExprList, keyVarList, context); + assignKeyExprList, keyVarList, context, constantAtRuntimeExpressions, constAtRuntimeExprVars); int numHighKeys = createKeyVarsAndExprs(numSecondaryKeys, highKeyLimits, highKeyExprs, assignKeyVarList, - assignKeyExprList, keyVarList, context); + assignKeyExprList, keyVarList, context, constantAtRuntimeExpressions, constAtRuntimeExprVars); BTreeJobGenParams jobGenParams = new BTreeJobGenParams(chosenIndex.getIndexName(), IndexType.BTREE, dataset.getDataverseName(), dataset.getDatasetName(), retainInput, retainNull, requiresBroadcast); @@ -526,12 +536,14 @@ private int createKeyVarsAndExprs(int numKeys, LimitType[] keyLimits, ILogicalExpression[] searchKeyExprs, ArrayList<LogicalVariable> assignKeyVarList, ArrayList<Mutable<ILogicalExpression>> assignKeyExprList, - ArrayList<LogicalVariable> keyVarList, IOptimizationContext context) { + ArrayList<LogicalVariable> keyVarList, IOptimizationContext context, ILogicalExpression[] constExpressions, + LogicalVariable[] constExprVars) { if (keyLimits[0] == null) { return 0; } for (int i = 0; i < numKeys; i++) { ILogicalExpression searchKeyExpr = searchKeyExprs[i]; + ILogicalExpression constExpression = constExpressions[i]; LogicalVariable keyVar = null; if (searchKeyExpr.getExpressionTag() == LogicalExpressionTag.CONSTANT) { keyVar = context.newVar(); @@ -539,6 +551,10 @@ assignKeyVarList.add(keyVar); } else { keyVar = ((VariableReferenceExpression) searchKeyExpr).getVariableReference(); + if (constExpression != null) { + assignKeyExprList.add(new MutableObject<ILogicalExpression>(constExpression)); + assignKeyVarList.add(constExprVars[i]); + } } keyVarList.add(keyVar); } @@ -630,7 +646,7 @@ private boolean probeIsOnLhs(IOptimizableFuncExpr optFuncExpr, OptimizableOperatorSubTree probeSubTree) { if (probeSubTree == null) { // We are optimizing a selection query. Search key is a constant. Return true if constant is on lhs. - return optFuncExpr.getFuncExpr().getArguments().get(0) == optFuncExpr.getConstantVal(0); + return optFuncExpr.getFuncExpr().getArguments().get(0) == optFuncExpr.getConstantAtRuntimeExpr(0); } else { // We are optimizing a join query. Determine whether the feeding variable is on the lhs. return (optFuncExpr.getOperatorSubTree(0) == null || optFuncExpr.getOperatorSubTree(0) == probeSubTree); diff --git a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IAccessMethod.java b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IAccessMethod.java index 50d39aa..432d933 100644 --- a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IAccessMethod.java +++ b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IAccessMethod.java @@ -20,13 +20,13 @@ import java.util.List; -import org.apache.commons.lang3.mutable.Mutable; - import org.apache.asterix.metadata.entities.Index; +import org.apache.commons.lang3.mutable.Mutable; import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException; 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.expressions.AbstractFunctionCallExpression; +import org.apache.hyracks.algebricks.core.algebra.expressions.IVariableTypeEnvironment; import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier; import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator; @@ -51,17 +51,19 @@ * optimizable by this access method based on its function identifier. If * funcExpr has been found to be optimizable, this method adds an * OptimizableFunction to analysisCtx.matchedFuncExprs for further analysis. - * + * * @return true if funcExpr is optimizable by this access method, false * otherwise + * @throws AlgebricksException */ - public boolean analyzeFuncExprArgs(AbstractFunctionCallExpression funcExpr, - List<AbstractLogicalOperator> assignsAndUnnests, AccessMethodAnalysisContext analysisCtx); + boolean analyzeFuncExprArgs(AbstractFunctionCallExpression funcExpr, + List<AbstractLogicalOperator> assignsAndUnnests, AccessMethodAnalysisContext analysisCtx, + IOptimizationContext context, IVariableTypeEnvironment typeEnvironment) throws AlgebricksException; /** * Indicates whether all index expressions must be matched in order for this * index to be applicable. - * + * * @return boolean */ public boolean matchAllIndexExprs(); @@ -69,7 +71,7 @@ /** * Indicates whether this index is applicable if only a prefix of the index * expressions are matched. - * + * * @return boolean */ public boolean matchPrefixIndexExprs(); @@ -97,4 +99,5 @@ * @throws AlgebricksException */ public boolean exprIsOptimizable(Index index, IOptimizableFuncExpr optFuncExpr) throws AlgebricksException; + } diff --git a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IOptimizableFuncExpr.java b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IOptimizableFuncExpr.java index 85f8545..b4f8c9f 100644 --- a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IOptimizableFuncExpr.java +++ b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IOptimizableFuncExpr.java @@ -24,7 +24,6 @@ import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression; import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable; import org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression; -import org.apache.hyracks.algebricks.core.algebra.expressions.IAlgebricksConstantValue; /** * Describes a function expression that is optimizable by an access method. @@ -36,7 +35,7 @@ public int getNumLogicalVars(); - public int getNumConstantVals(); + public int getNumConstantAtRuntimeExpr(); public LogicalVariable getLogicalVar(int index); @@ -56,7 +55,7 @@ public OptimizableOperatorSubTree getOperatorSubTree(int index); - public IAlgebricksConstantValue getConstantVal(int index); + public ILogicalExpression getConstantAtRuntimeExpr(int index); public int findLogicalVar(LogicalVariable var); @@ -71,4 +70,10 @@ public void setSourceVar(int index, LogicalVariable var); public LogicalVariable getSourceVar(int index); + + void setConstType(int index, IAType fieldType); + + IAType getConstantType(int index); + + void setConstantAtRuntimeExpr(int index, ILogicalExpression expr); } diff --git a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceJoinAccessMethodRule.java b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceJoinAccessMethodRule.java index 67b60df..4c150c0 100644 --- a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceJoinAccessMethodRule.java +++ b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceJoinAccessMethodRule.java @@ -34,6 +34,7 @@ import org.apache.hyracks.algebricks.core.algebra.base.LogicalExpressionTag; import org.apache.hyracks.algebricks.core.algebra.base.LogicalOperatorTag; 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.algebra.operators.logical.AbstractBinaryJoinOperator; @@ -79,6 +80,7 @@ protected AbstractFunctionCallExpression joinCond = null; protected final OptimizableOperatorSubTree leftSubTree = new OptimizableOperatorSubTree(); protected final OptimizableOperatorSubTree rightSubTree = new OptimizableOperatorSubTree(); + protected IVariableTypeEnvironment typeEnvironment = null; protected boolean isLeftOuterJoin = false; protected boolean hasGroupBy = true; @@ -105,10 +107,12 @@ boolean matchInLeftSubTree = false; boolean matchInRightSubTree = false; if (leftSubTree.hasDataSource()) { - matchInLeftSubTree = analyzeCondition(joinCond, leftSubTree.assignsAndUnnests, analyzedAMs); + matchInLeftSubTree = analyzeCondition(joinCond, leftSubTree.assignsAndUnnests, analyzedAMs, context, + typeEnvironment); } if (rightSubTree.hasDataSource()) { - matchInRightSubTree = analyzeCondition(joinCond, rightSubTree.assignsAndUnnests, analyzedAMs); + matchInRightSubTree = analyzeCondition(joinCond, rightSubTree.assignsAndUnnests, analyzedAMs, context, + typeEnvironment); } if (!matchInLeftSubTree && !matchInRightSubTree) { return false; @@ -133,7 +137,7 @@ if (checkRightSubTreeMetadata) { fillSubTreeIndexExprs(rightSubTree, analyzedAMs, context); } - pruneIndexCandidates(analyzedAMs); + pruneIndexCandidates(analyzedAMs, context, typeEnvironment); // Prioritize the order of index that will be applied. If the right subtree (inner branch) has indexes, // those indexes will be used. @@ -229,6 +233,7 @@ join = (LeftOuterJoinOperator) joinRef.getValue(); } + typeEnvironment = context.getOutputTypeEnvironment(join); // Check that the select's condition is a function call. ILogicalExpression condExpr = join.getCondition().getValue(); if (condExpr.getExpressionTag() != LogicalExpressionTag.FUNCTION_CALL) { diff --git a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceLSMComponentFilterRule.java b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceLSMComponentFilterRule.java index f337bbd..f374b9a 100644 --- a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceLSMComponentFilterRule.java +++ b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceLSMComponentFilterRule.java @@ -22,9 +22,6 @@ import java.util.Arrays; import java.util.List; -import org.apache.commons.lang3.mutable.Mutable; -import org.apache.commons.lang3.mutable.MutableObject; - import org.apache.asterix.common.config.DatasetConfig.DatasetType; import org.apache.asterix.metadata.declared.AqlDataSource; import org.apache.asterix.metadata.declared.AqlMetadataProvider; @@ -39,6 +36,8 @@ import org.apache.asterix.om.types.ARecordType; import org.apache.asterix.om.types.ATypeTag; 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.common.utils.Pair; import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression; @@ -50,6 +49,7 @@ import org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression; import org.apache.hyracks.algebricks.core.algebra.expressions.AbstractLogicalExpression; import org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression; +import org.apache.hyracks.algebricks.core.algebra.expressions.IVariableTypeEnvironment; import org.apache.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression; import org.apache.hyracks.algebricks.core.algebra.functions.AlgebricksBuiltinFunctions; import org.apache.hyracks.algebricks.core.algebra.functions.AlgebricksBuiltinFunctions.ComparisonKind; @@ -63,6 +63,8 @@ import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule; public class IntroduceLSMComponentFilterRule implements IAlgebraicRewriteRule { + + protected IVariableTypeEnvironment typeEnvironment = null; @Override public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException { @@ -78,8 +80,9 @@ } AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue(); + typeEnvironment = context.getOutputTypeEnvironment(op); ILogicalExpression condExpr = ((SelectOperator) op).getCondition().getValue(); - AccessMethodAnalysisContext analysisCtx = analyzeCondition(condExpr); + AccessMethodAnalysisContext analysisCtx = analyzeCondition(condExpr, context, typeEnvironment); if (analysisCtx.matchedFuncExprs.isEmpty()) { return false; } @@ -128,7 +131,7 @@ for (IOptimizableFuncExpr optFuncExpr : optFuncExprs) { ComparisonKind ck = AlgebricksBuiltinFunctions.getComparisonType(optFuncExpr.getFuncExpr() .getFunctionIdentifier()); - ILogicalExpression searchKeyExpr = new ConstantExpression(optFuncExpr.getConstantVal(0)); + ILogicalExpression searchKeyExpr = optFuncExpr.getConstantAtRuntimeExpr(0); LogicalVariable var = context.newVar(); assignKeyExprList.add(new MutableObject<ILogicalExpression>(searchKeyExpr)); assignKeyVarList.add(var); @@ -260,29 +263,31 @@ return true; } - private AccessMethodAnalysisContext analyzeCondition(ILogicalExpression cond) { + private AccessMethodAnalysisContext analyzeCondition(ILogicalExpression cond, IOptimizationContext context, + IVariableTypeEnvironment typeEnvironment) throws AlgebricksException { AccessMethodAnalysisContext analysisCtx = new AccessMethodAnalysisContext(); AbstractFunctionCallExpression funcExpr = (AbstractFunctionCallExpression) cond; FunctionIdentifier funcIdent = funcExpr.getFunctionIdentifier(); if (funcIdent != AlgebricksBuiltinFunctions.OR) { - analyzeFunctionExpr(funcExpr, analysisCtx); + analyzeFunctionExpr(funcExpr, analysisCtx, context, typeEnvironment); for (Mutable<ILogicalExpression> arg : funcExpr.getArguments()) { ILogicalExpression argExpr = arg.getValue(); if (argExpr.getExpressionTag() != LogicalExpressionTag.FUNCTION_CALL) { continue; } - analyzeFunctionExpr((AbstractFunctionCallExpression) argExpr, analysisCtx); + analyzeFunctionExpr((AbstractFunctionCallExpression) argExpr, analysisCtx, context, typeEnvironment); } } return analysisCtx; } - private void analyzeFunctionExpr(AbstractFunctionCallExpression funcExpr, AccessMethodAnalysisContext analysisCtx) { + private void analyzeFunctionExpr(AbstractFunctionCallExpression funcExpr, AccessMethodAnalysisContext analysisCtx, + IOptimizationContext context, IVariableTypeEnvironment typeEnvironment) throws AlgebricksException { FunctionIdentifier funcIdent = funcExpr.getFunctionIdentifier(); if (funcIdent == AlgebricksBuiltinFunctions.LE || funcIdent == AlgebricksBuiltinFunctions.GE || funcIdent == AlgebricksBuiltinFunctions.LT || funcIdent == AlgebricksBuiltinFunctions.GT || funcIdent == AlgebricksBuiltinFunctions.EQ) { - AccessMethodUtils.analyzeFuncExprArgsForOneConstAndVar(funcExpr, analysisCtx); + AccessMethodUtils.analyzeFuncExprArgsForOneConstAndVar(funcExpr, analysisCtx, context, typeEnvironment); } } diff --git a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceSelectAccessMethodRule.java b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceSelectAccessMethodRule.java index 9084caf..7414c93 100644 --- a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceSelectAccessMethodRule.java +++ b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceSelectAccessMethodRule.java @@ -22,10 +22,9 @@ import java.util.List; import java.util.Map; -import org.apache.commons.lang3.mutable.Mutable; - import org.apache.asterix.metadata.declared.AqlMetadataProvider; import org.apache.asterix.metadata.entities.Index; +import org.apache.commons.lang3.mutable.Mutable; import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException; import org.apache.hyracks.algebricks.common.utils.Pair; import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression; @@ -34,6 +33,7 @@ import org.apache.hyracks.algebricks.core.algebra.base.LogicalExpressionTag; import org.apache.hyracks.algebricks.core.algebra.base.LogicalOperatorTag; 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.functions.FunctionIdentifier; import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator; import org.apache.hyracks.algebricks.core.algebra.operators.logical.SelectOperator; @@ -70,6 +70,7 @@ protected Mutable<ILogicalOperator> selectRef = null; protected SelectOperator select = null; protected AbstractFunctionCallExpression selectCond = null; + protected IVariableTypeEnvironment typeEnvironment = null; protected final OptimizableOperatorSubTree subTree = new OptimizableOperatorSubTree(); // Register access methods. @@ -93,7 +94,7 @@ // Analyze select condition. Map<IAccessMethod, AccessMethodAnalysisContext> analyzedAMs = new HashMap<IAccessMethod, AccessMethodAnalysisContext>(); - if (!analyzeCondition(selectCond, subTree.assignsAndUnnests, analyzedAMs)) { + if (!analyzeCondition(selectCond, subTree.assignsAndUnnests, analyzedAMs, context, typeEnvironment)) { return false; } @@ -103,7 +104,7 @@ } fillSubTreeIndexExprs(subTree, analyzedAMs, context); - pruneIndexCandidates(analyzedAMs); + pruneIndexCandidates(analyzedAMs, context, typeEnvironment); // Choose index to be applied. Pair<IAccessMethod, Index> chosenIndex = chooseIndex(analyzedAMs); @@ -135,6 +136,8 @@ // Set and analyze select. selectRef = opRef; select = (SelectOperator) op1; + + typeEnvironment = context.getOutputTypeEnvironment(op1); // Check that the select's condition is a function call. ILogicalExpression condExpr = select.getCondition().getValue(); if (condExpr.getExpressionTag() != LogicalExpressionTag.FUNCTION_CALL) { diff --git a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/InvertedIndexAccessMethod.java b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/InvertedIndexAccessMethod.java index efe506f..ca70189 100644 --- a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/InvertedIndexAccessMethod.java +++ b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/InvertedIndexAccessMethod.java @@ -24,14 +24,12 @@ import java.util.List; import java.util.Map; -import org.apache.commons.lang3.mutable.Mutable; -import org.apache.commons.lang3.mutable.MutableObject; - import org.apache.asterix.algebra.base.LogicalOperatorDeepCopyVisitor; import org.apache.asterix.aql.util.FunctionUtils; import org.apache.asterix.common.annotations.SkipSecondaryIndexSearchExpressionAnnotation; import org.apache.asterix.common.config.DatasetConfig.IndexType; import org.apache.asterix.common.exceptions.AsterixException; +import org.apache.asterix.dataflow.data.common.AqlExpressionTypeComputer; import org.apache.asterix.formats.nontagged.AqlBinaryTokenizerFactoryProvider; import org.apache.asterix.metadata.entities.Dataset; import org.apache.asterix.metadata.entities.Index; @@ -47,6 +45,8 @@ import org.apache.asterix.om.types.ATypeTag; import org.apache.asterix.om.types.IAType; import org.apache.asterix.om.types.hierachy.ATypeHierarchy; +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.common.utils.Triple; import org.apache.hyracks.algebricks.core.algebra.base.Counter; @@ -58,7 +58,6 @@ import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable; import org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression; import org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression; -import org.apache.hyracks.algebricks.core.algebra.expressions.IAlgebricksConstantValue; 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.expressions.VariableReferenceExpression; @@ -125,10 +124,12 @@ @Override public boolean analyzeFuncExprArgs(AbstractFunctionCallExpression funcExpr, - List<AbstractLogicalOperator> assignsAndUnnests, AccessMethodAnalysisContext analysisCtx) { + List<AbstractLogicalOperator> assignsAndUnnests, AccessMethodAnalysisContext analysisCtx, + IOptimizationContext context, IVariableTypeEnvironment typeEnvironment) throws AlgebricksException { if (funcExpr.getFunctionIdentifier() == AsterixBuiltinFunctions.CONTAINS) { - boolean matches = AccessMethodUtils.analyzeFuncExprArgsForOneConstAndVar(funcExpr, analysisCtx); + boolean matches = AccessMethodUtils.analyzeFuncExprArgsForOneConstAndVar(funcExpr, analysisCtx, context, + typeEnvironment); if (!matches) { matches = AccessMethodUtils.analyzeFuncExprArgsForTwoVars(funcExpr, analysisCtx); } @@ -138,7 +139,8 @@ } public boolean analyzeGetItemFuncExpr(AbstractFunctionCallExpression funcExpr, - List<AbstractLogicalOperator> assignsAndUnnests, AccessMethodAnalysisContext analysisCtx) { + List<AbstractLogicalOperator> assignsAndUnnests, AccessMethodAnalysisContext analysisCtx) + throws AlgebricksException { if (funcExpr.getFunctionIdentifier() != AsterixBuiltinFunctions.GET_ITEM) { return false; } @@ -222,15 +224,13 @@ private boolean analyzeJoinSimilarityCheckFuncExprArgs(AbstractFunctionCallExpression funcExpr, List<AbstractLogicalOperator> assignsAndUnnests, int matchedAssignOrUnnestIndex, - AccessMethodAnalysisContext analysisCtx) { + AccessMethodAnalysisContext analysisCtx) throws AlgebricksException { // There should be exactly three arguments. // The last function argument is assumed to be the similarity threshold. - IAlgebricksConstantValue constThreshVal = null; ILogicalExpression arg3 = funcExpr.getArguments().get(2).getValue(); if (arg3.getExpressionTag() != LogicalExpressionTag.CONSTANT) { return false; } - constThreshVal = ((ConstantExpression) arg3).getValue(); ILogicalExpression arg1 = funcExpr.getArguments().get(0).getValue(); ILogicalExpression arg2 = funcExpr.getArguments().get(1).getValue(); // We expect arg1 and arg2 to be non-constants for a join. @@ -249,7 +249,8 @@ return false; } OptimizableFuncExpr newOptFuncExpr = new OptimizableFuncExpr(funcExpr, new LogicalVariable[] { fieldVarExpr1, - fieldVarExpr2 }, new IAlgebricksConstantValue[] { constThreshVal }); + fieldVarExpr2 }, new ILogicalExpression[] { arg3 }, + new IAType[] { (IAType) AqlExpressionTypeComputer.INSTANCE.getType(arg3, null, null) }); for (IOptimizableFuncExpr optFuncExpr : analysisCtx.matchedFuncExprs) { //avoid additional optFuncExpressions in case of a join if (optFuncExpr.getFuncExpr().equals(funcExpr)) { @@ -262,15 +263,13 @@ private boolean analyzeSelectSimilarityCheckFuncExprArgs(AbstractFunctionCallExpression funcExpr, List<AbstractLogicalOperator> assignsAndUnnests, int matchedAssignOrUnnestIndex, - AccessMethodAnalysisContext analysisCtx) { + AccessMethodAnalysisContext analysisCtx) throws AlgebricksException { // There should be exactly three arguments. // The last function argument is assumed to be the similarity threshold. - IAlgebricksConstantValue constThreshVal = null; ILogicalExpression arg3 = funcExpr.getArguments().get(2).getValue(); if (arg3.getExpressionTag() != LogicalExpressionTag.CONSTANT) { return false; } - constThreshVal = ((ConstantExpression) arg3).getValue(); ILogicalExpression arg1 = funcExpr.getArguments().get(0).getValue(); ILogicalExpression arg2 = funcExpr.getArguments().get(1).getValue(); // Determine whether one arg is constant, and the other is non-constant. @@ -291,15 +290,16 @@ } else { return false; } - ConstantExpression constExpr = (ConstantExpression) constArg; - IAlgebricksConstantValue constFilterVal = constExpr.getValue(); LogicalVariable fieldVarExpr = getNonConstArgFieldExprPair(nonConstArg, funcExpr, assignsAndUnnests, matchedAssignOrUnnestIndex); if (fieldVarExpr == null) { return false; } + OptimizableFuncExpr newOptFuncExpr = new OptimizableFuncExpr(funcExpr, new LogicalVariable[] { fieldVarExpr }, - new IAlgebricksConstantValue[] { constFilterVal, constThreshVal }); + new ILogicalExpression[] { constArg, arg3 }, new IAType[] { + (IAType) AqlExpressionTypeComputer.INSTANCE.getType(constArg, null, null), + (IAType) AqlExpressionTypeComputer.INSTANCE.getType(arg3, null, null) }); for (IOptimizableFuncExpr optFuncExpr : analysisCtx.matchedFuncExprs) { //avoid additional optFuncExpressions in case of a join if (optFuncExpr.getFuncExpr().equals(funcExpr)) @@ -731,8 +731,7 @@ isFilterableArgs.add(new MutableObject<ILogicalExpression>(new VariableReferenceExpression( inputSearchVar))); // Since we are optimizing a join, the similarity threshold should be the only constant in the optimizable function expression. - isFilterableArgs.add(new MutableObject<ILogicalExpression>(new ConstantExpression(optFuncExpr - .getConstantVal(0)))); + isFilterableArgs.add(new MutableObject<ILogicalExpression>(optFuncExpr.getConstantAtRuntimeExpr(0))); isFilterableArgs.add(new MutableObject<ILogicalExpression>(AccessMethodUtils .createInt32Constant(chosenIndex.getGramLength()))); boolean usePrePost = optFuncExpr.containsPartialField() ? false : true; @@ -749,8 +748,7 @@ isFilterableArgs.add(new MutableObject<ILogicalExpression>(new VariableReferenceExpression( inputSearchVar))); // Since we are optimizing a join, the similarity threshold should be the only constant in the optimizable function expression. - isFilterableArgs.add(new MutableObject<ILogicalExpression>(new ConstantExpression(optFuncExpr - .getConstantVal(0)))); + isFilterableArgs.add(new MutableObject<ILogicalExpression>(optFuncExpr.getConstantAtRuntimeExpr(0))); isFilterableExpr = new ScalarFunctionCallExpression( FunctionUtils.getFunctionInfo(AsterixBuiltinFunctions.EDIT_DISTANCE_LIST_IS_FILTERABLE), isFilterableArgs); @@ -799,9 +797,7 @@ typeTag = type.getTypeTag(); } else { // We are optimizing a selection query. Add the type of the search key constant. - AsterixConstantValue constVal = (AsterixConstantValue) optFuncExpr.getConstantVal(0); - IAObject obj = constVal.getObject(); - type = obj.getType(); + type = optFuncExpr.getConstantType(0); typeTag = type.getTypeTag(); if (typeTag != ATypeTag.ORDEREDLIST && typeTag != ATypeTag.STRING && typeTag != ATypeTag.UNORDEREDLIST) { throw new AlgebricksException("Only ordered lists, string, and unordered lists types supported."); @@ -818,7 +814,8 @@ if (optFuncExpr.getFuncExpr().getFunctionIdentifier() == AsterixBuiltinFunctions.SIMILARITY_JACCARD_CHECK) { jobGenParams.setSearchModifierType(SearchModifierType.JACCARD); // Add the similarity threshold which, by convention, is the last constant value. - jobGenParams.setSimilarityThreshold(optFuncExpr.getConstantVal(optFuncExpr.getNumConstantVals() - 1)); + jobGenParams.setSimilarityThreshold(((ConstantExpression) optFuncExpr.getConstantAtRuntimeExpr(optFuncExpr + .getNumConstantAtRuntimeExpr() - 1)).getValue()); } if (optFuncExpr.getFuncExpr().getFunctionIdentifier() == AsterixBuiltinFunctions.EDIT_DISTANCE_CHECK || optFuncExpr.getFuncExpr().getFunctionIdentifier() == AsterixBuiltinFunctions.EDIT_DISTANCE_CONTAINS) { @@ -828,7 +825,8 @@ jobGenParams.setSearchModifierType(SearchModifierType.EDIT_DISTANCE); } // Add the similarity threshold which, by convention, is the last constant value. - jobGenParams.setSimilarityThreshold(optFuncExpr.getConstantVal(optFuncExpr.getNumConstantVals() - 1)); + jobGenParams.setSimilarityThreshold(((ConstantExpression) optFuncExpr.getConstantAtRuntimeExpr(optFuncExpr + .getNumConstantAtRuntimeExpr() - 1)).getValue()); } } @@ -839,7 +837,7 @@ // Add a variable and its expr to the lists which will be passed into an assign op. LogicalVariable keyVar = context.newVar(); keyVarList.add(keyVar); - keyExprList.add(new MutableObject<ILogicalExpression>(new ConstantExpression(optFuncExpr.getConstantVal(0)))); + keyExprList.add(new MutableObject<ILogicalExpression>(optFuncExpr.getConstantAtRuntimeExpr(0))); return; } @@ -868,7 +866,7 @@ private boolean isEditDistanceFuncOptimizable(Index index, IOptimizableFuncExpr optFuncExpr) throws AlgebricksException { - if (optFuncExpr.getNumConstantVals() == 1) { + if (optFuncExpr.getNumConstantAtRuntimeExpr() == 1) { return isEditDistanceFuncJoinOptimizable(index, optFuncExpr); } else { return isEditDistanceFuncSelectOptimizable(index, optFuncExpr); @@ -901,7 +899,8 @@ // Check for panic in selection query. // TODO: Panic also depends on prePost which is currently hardcoded to be true. - AsterixConstantValue listOrStrConstVal = (AsterixConstantValue) optFuncExpr.getConstantVal(0); + AsterixConstantValue listOrStrConstVal = (AsterixConstantValue) ((ConstantExpression) optFuncExpr + .getConstantAtRuntimeExpr(0)).getValue(); IAObject listOrStrObj = listOrStrConstVal.getObject(); ATypeTag typeTag = listOrStrObj.getType().getTypeTag(); @@ -909,7 +908,8 @@ return false; } - AsterixConstantValue intConstVal = (AsterixConstantValue) optFuncExpr.getConstantVal(1); + AsterixConstantValue intConstVal = (AsterixConstantValue) ((ConstantExpression) optFuncExpr.getConstantAtRuntimeExpr(1)) + .getValue(); IAObject intObj = intConstVal.getObject(); AInt32 edThresh = null; @@ -1055,7 +1055,8 @@ } private boolean isContainsFuncSelectOptimizable(Index index, IOptimizableFuncExpr optFuncExpr) { - AsterixConstantValue strConstVal = (AsterixConstantValue) optFuncExpr.getConstantVal(0); + AsterixConstantValue strConstVal = (AsterixConstantValue) ((ConstantExpression) optFuncExpr.getConstantAtRuntimeExpr(0)) + .getValue(); IAObject strObj = strConstVal.getObject(); ATypeTag typeTag = strObj.getType().getTypeTag(); diff --git a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/OptimizableFuncExpr.java b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/OptimizableFuncExpr.java index f58cf2d..2ecd504 100644 --- a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/OptimizableFuncExpr.java +++ b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/OptimizableFuncExpr.java @@ -26,7 +26,6 @@ import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression; import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable; import org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression; -import org.apache.hyracks.algebricks.core.algebra.expressions.IAlgebricksConstantValue; /** * General-purpose implementation of IOptimizableFuncExpr that supports any @@ -40,16 +39,18 @@ protected final List<List<String>> fieldNames; protected final IAType[] fieldTypes; protected final OptimizableOperatorSubTree[] subTrees; - protected final IAlgebricksConstantValue[] constantVals; + protected final ILogicalExpression[] constantAtRuntimeExpressions; + protected final IAType[] constantAtRuntimeExpressionTypes; protected boolean partialField; public OptimizableFuncExpr(AbstractFunctionCallExpression funcExpr, LogicalVariable[] logicalVars, - IAlgebricksConstantValue[] constantVals) { + ILogicalExpression[] constantExpressions, IAType[] constantExpressionTypes) { this.funcExpr = funcExpr; this.logicalVars = logicalVars; this.sourceVars = new LogicalVariable[logicalVars.length]; this.logicalExprs = new ILogicalExpression[logicalVars.length]; - this.constantVals = constantVals; + this.constantAtRuntimeExpressionTypes = constantExpressionTypes; + this.constantAtRuntimeExpressions = constantExpressions; this.fieldNames = new ArrayList<List<String>>(); for (int i = 0; i < logicalVars.length; i++) { fieldNames.add(new ArrayList<String>()); @@ -66,12 +67,13 @@ // Special, more convenient c'tor for simple binary functions. public OptimizableFuncExpr(AbstractFunctionCallExpression funcExpr, LogicalVariable logicalVar, - IAlgebricksConstantValue constantVal) { + ILogicalExpression constantExpression, IAType constantExpressionType) { this.funcExpr = funcExpr; this.logicalVars = new LogicalVariable[] { logicalVar }; this.sourceVars = new LogicalVariable[1]; this.logicalExprs = new ILogicalExpression[1]; - this.constantVals = new IAlgebricksConstantValue[] { constantVal }; + this.constantAtRuntimeExpressions = new ILogicalExpression[] { constantExpression }; + this.constantAtRuntimeExpressionTypes = new IAType[] { constantExpressionType }; this.fieldNames = new ArrayList<List<String>>(); for (int i = 0; i < logicalVars.length; i++) { fieldNames.add(new ArrayList<String>()); @@ -96,8 +98,8 @@ } @Override - public int getNumConstantVals() { - return constantVals.length; + public int getNumConstantAtRuntimeExpr() { + return constantAtRuntimeExpressions.length; } @Override @@ -136,8 +138,23 @@ } @Override - public IAlgebricksConstantValue getConstantVal(int index) { - return constantVals[index]; + public ILogicalExpression getConstantAtRuntimeExpr(int index) { + return constantAtRuntimeExpressions[index]; + } + + @Override + public void setConstType(int index, IAType fieldType) { + constantAtRuntimeExpressionTypes[index] = fieldType; + } + + @Override + public IAType getConstantType(int index) { + return constantAtRuntimeExpressionTypes[index]; + } + + @Override + public void setConstantAtRuntimeExpr(int index, ILogicalExpression expr) { + constantAtRuntimeExpressions[index] = expr; } @Override diff --git a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/RTreeAccessMethod.java b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/RTreeAccessMethod.java index 24ba967..e9e55db 100644 --- a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/RTreeAccessMethod.java +++ b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/RTreeAccessMethod.java @@ -21,9 +21,6 @@ import java.util.ArrayList; import java.util.List; -import org.apache.commons.lang3.mutable.Mutable; -import org.apache.commons.lang3.mutable.MutableObject; - import org.apache.asterix.aql.util.FunctionUtils; import org.apache.asterix.common.annotations.SkipSecondaryIndexSearchExpressionAnnotation; import org.apache.asterix.common.config.DatasetConfig.DatasetType; @@ -36,6 +33,8 @@ import org.apache.asterix.om.types.ARecordType; import org.apache.asterix.om.types.IAType; import org.apache.asterix.om.util.NonTaggedFormatUtil; +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.common.utils.Pair; import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression; @@ -44,6 +43,7 @@ import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable; import org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression; import org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression; +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.algebra.operators.logical.AbstractBinaryJoinOperator; @@ -74,8 +74,10 @@ @Override public boolean analyzeFuncExprArgs(AbstractFunctionCallExpression funcExpr, - List<AbstractLogicalOperator> assignsAndUnnests, AccessMethodAnalysisContext analysisCtx) { - boolean matches = AccessMethodUtils.analyzeFuncExprArgsForOneConstAndVar(funcExpr, analysisCtx); + List<AbstractLogicalOperator> assignsAndUnnests, AccessMethodAnalysisContext analysisCtx, + IOptimizationContext context, IVariableTypeEnvironment typeEnvironment) throws AlgebricksException { + boolean matches = AccessMethodUtils.analyzeFuncExprArgsForOneConstAndVar(funcExpr, analysisCtx, context, + typeEnvironment); if (!matches) { matches = AccessMethodUtils.analyzeFuncExprArgsForTwoVars(funcExpr, analysisCtx); } diff --git a/asterix-app/src/test/resources/optimizerts/queries/btree-index/btree-datetime-01.aql b/asterix-app/src/test/resources/optimizerts/queries/btree-index/btree-datetime-01.aql new file mode 100644 index 0000000..7179d54 --- /dev/null +++ b/asterix-app/src/test/resources/optimizerts/queries/btree-index/btree-datetime-01.aql @@ -0,0 +1,43 @@ +/* + * 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 : This test is intended to verify that the primary BTree index is used + * : for an invocation of current-datetime() + * Expected Result : Success + * Date : 27th Aug 2015 + * Author : Steven Jacobs + */ + +drop dataverse emergencyTest if exists; +create dataverse emergencyTest; +use dataverse emergencyTest; +create type CHPReport as { + "id":int, + "timestamp":datetime, + "title":string, + "message":string +} +create dataset CHPReports(CHPReport) +primary key timestamp; + +for $emergency in dataset CHPReports +where $emergency.timestamp >= current-datetime() - day-time-duration("PT10H") +and $emergency.title = "ghost" +return $emergency.message; + diff --git a/asterix-app/src/test/resources/optimizerts/queries/btree-index/btree-datetime-02.aql b/asterix-app/src/test/resources/optimizerts/queries/btree-index/btree-datetime-02.aql new file mode 100644 index 0000000..8a5fe07 --- /dev/null +++ b/asterix-app/src/test/resources/optimizerts/queries/btree-index/btree-datetime-02.aql @@ -0,0 +1,42 @@ +/* + * 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 : This test is intended to verify that the primary BTree index is used + * : for an invocation of current-datetime() + * Expected Result : Success + * Date : 27th Aug 2015 + * Author : Steven Jacobs + */ + +drop dataverse emergencyTest if exists; +create dataverse emergencyTest; +use dataverse emergencyTest; +create type CHPReport as { + "id":int, + "timestamp":datetime, + "title":string, + "message":string +} +create dataset CHPReports(CHPReport) +primary key timestamp; + +for $emergency in dataset CHPReports +let $time := current-datetime() - day-time-duration("PT10H") +where $emergency.timestamp >= $time +return $emergency; \ No newline at end of file diff --git a/asterix-app/src/test/resources/optimizerts/queries/btree-index/btree-datetime-03.aql b/asterix-app/src/test/resources/optimizerts/queries/btree-index/btree-datetime-03.aql new file mode 100644 index 0000000..f3b49ad --- /dev/null +++ b/asterix-app/src/test/resources/optimizerts/queries/btree-index/btree-datetime-03.aql @@ -0,0 +1,41 @@ +/* + * 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 : This test is intended to verify that the primary BTree index is used + * : for an invocation of current-datetime() + * Expected Result : Success + * Date : 27th Aug 2015 + * Author : Steven Jacobs + */ + +drop dataverse emergencyTest if exists; +create dataverse emergencyTest; +use dataverse emergencyTest; +create type CHPReport as { + "id":int, + "timestamp":datetime, + "title":string, + "message":string +} +create dataset CHPReports(CHPReport) +primary key timestamp; + +for $emergency in dataset CHPReports +where $emergency.timestamp >= current-datetime() +return $emergency; \ No newline at end of file diff --git a/asterix-app/src/test/resources/optimizerts/queries/btree-index/btree-datetime-04.aql b/asterix-app/src/test/resources/optimizerts/queries/btree-index/btree-datetime-04.aql new file mode 100644 index 0000000..59014bc --- /dev/null +++ b/asterix-app/src/test/resources/optimizerts/queries/btree-index/btree-datetime-04.aql @@ -0,0 +1,40 @@ +/* + * 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 : This test makes sure that the plan is still okay when not converted to index search + * Expected Result : Success + * Date : 27th Aug 2015 + * Author : Steven Jacobs + */ + +drop dataverse emergencyTest if exists; +create dataverse emergencyTest; +use dataverse emergencyTest; +create type CHPReport as { + "id":int, + "timestamp":datetime, + "title":string, + "message":string +} +create dataset CHPReports(CHPReport) +primary key id; + +for $emergency in dataset CHPReports +where $emergency.timestamp >= current-datetime() +return $emergency; \ No newline at end of file diff --git a/asterix-app/src/test/resources/optimizerts/results/btree-index/btree-datetime-01.plan b/asterix-app/src/test/resources/optimizerts/results/btree-index/btree-datetime-01.plan new file mode 100644 index 0000000..9b5e82c --- /dev/null +++ b/asterix-app/src/test/resources/optimizerts/results/btree-index/btree-datetime-01.plan @@ -0,0 +1,11 @@ +-- DISTRIBUTE_RESULT |PARTITIONED| + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + -- STREAM_PROJECT |PARTITIONED| + -- STREAM_SELECT |PARTITIONED| + -- ASSIGN |PARTITIONED| + -- STREAM_PROJECT |PARTITIONED| + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + -- BTREE_SEARCH |PARTITIONED| + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + -- ASSIGN |PARTITIONED| + -- EMPTY_TUPLE_SOURCE |PARTITIONED| \ No newline at end of file diff --git a/asterix-app/src/test/resources/optimizerts/results/btree-index/btree-datetime-02.plan b/asterix-app/src/test/resources/optimizerts/results/btree-index/btree-datetime-02.plan new file mode 100644 index 0000000..a9e223a --- /dev/null +++ b/asterix-app/src/test/resources/optimizerts/results/btree-index/btree-datetime-02.plan @@ -0,0 +1,8 @@ +-- DISTRIBUTE_RESULT |PARTITIONED| + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + -- STREAM_PROJECT |PARTITIONED| + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + -- BTREE_SEARCH |PARTITIONED| + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + -- ASSIGN |PARTITIONED| + -- EMPTY_TUPLE_SOURCE |PARTITIONED| \ No newline at end of file diff --git a/asterix-app/src/test/resources/optimizerts/results/btree-index/btree-datetime-03.plan b/asterix-app/src/test/resources/optimizerts/results/btree-index/btree-datetime-03.plan new file mode 100644 index 0000000..a9e223a --- /dev/null +++ b/asterix-app/src/test/resources/optimizerts/results/btree-index/btree-datetime-03.plan @@ -0,0 +1,8 @@ +-- DISTRIBUTE_RESULT |PARTITIONED| + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + -- STREAM_PROJECT |PARTITIONED| + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + -- BTREE_SEARCH |PARTITIONED| + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + -- ASSIGN |PARTITIONED| + -- EMPTY_TUPLE_SOURCE |PARTITIONED| \ No newline at end of file diff --git a/asterix-app/src/test/resources/optimizerts/results/btree-index/btree-datetime-04.plan b/asterix-app/src/test/resources/optimizerts/results/btree-index/btree-datetime-04.plan new file mode 100644 index 0000000..ef7eae2 --- /dev/null +++ b/asterix-app/src/test/resources/optimizerts/results/btree-index/btree-datetime-04.plan @@ -0,0 +1,8 @@ +-- DISTRIBUTE_RESULT |PARTITIONED| + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + -- STREAM_SELECT |PARTITIONED| + -- STREAM_PROJECT |PARTITIONED| + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + -- DATASOURCE_SCAN |PARTITIONED| + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + -- EMPTY_TUPLE_SOURCE |PARTITIONED| \ No newline at end of file -- To view, visit https://asterix-gerrit.ics.uci.edu/367 To unsubscribe, visit https://asterix-gerrit.ics.uci.edu/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ied64276873afcfbdd31dac313009e47429d8f9b0 Gerrit-PatchSet: 6 Gerrit-Project: asterixdb Gerrit-Branch: master Gerrit-Owner: Steven Jacobs <[email protected]> Gerrit-Reviewer: Ian Maxon <[email protected]> Gerrit-Reviewer: Ildar Absalyamov <[email protected]> Gerrit-Reviewer: Jenkins <[email protected]> Gerrit-Reviewer: Preston Carman <[email protected]> Gerrit-Reviewer: Steven Jacobs <[email protected]> Gerrit-Reviewer: Till Westmann <[email protected]> Gerrit-Reviewer: Yingyi Bu <[email protected]>
