ASTERIXDB-1608, ASTERIXDB-1617 Match user query for nonpure function calls

This fix makes it so that nonpure functions are called in
the same place and with the same number of executions
as specified by the user in the query. This also means
that indexes cannot be used for queries that compare
with a nonpure call that is made on a per-record basis.
Added optimizer tests
Change-Id: I2dec322b30835625430c06acd7626d902bada137
Reviewed-on: https://asterix-gerrit.ics.uci.edu/1057
Tested-by: Jenkins <[email protected]>
Reviewed-by: Till Westmann <[email protected]>


Project: http://git-wip-us.apache.org/repos/asf/asterixdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/asterixdb/commit/6b8a42f3
Tree: http://git-wip-us.apache.org/repos/asf/asterixdb/tree/6b8a42f3
Diff: http://git-wip-us.apache.org/repos/asf/asterixdb/diff/6b8a42f3

Branch: refs/heads/master
Commit: 6b8a42f3df9cebb9bd5d56e5986215bc0d98e45c
Parents: 2da225b
Author: Steven Glenn Jacobs <[email protected]>
Authored: Mon Nov 28 15:40:31 2016 -0800
Committer: Till Westmann <[email protected]>
Committed: Tue Nov 29 10:05:44 2016 -0800

----------------------------------------------------------------------
 .../operators/physical/CommitPOperator.java     |   2 +-
 .../optimizer/rules/PushFieldAccessRule.java    |   6 +-
 .../am/AbstractIntroduceAccessMethodRule.java   |  10 +-
 .../optimizer/rules/am/AccessMethodUtils.java   |  43 ++++--
 .../optimizer/rules/am/BTreeAccessMethod.java   |  47 ++++++-
 .../optimizer/rules/am/IAccessMethod.java       |  21 ++-
 .../rules/am/IOptimizableFuncExpr.java          |   8 +-
 .../am/IntroduceLSMComponentFilterRule.java     |   2 +-
 .../am/IntroduceSelectAccessMethodRule.java     | 130 +++++++++++++++----
 .../rules/am/InvertedIndexAccessMethod.java     |  44 ++++---
 .../optimizer/rules/am/OptimizableFuncExpr.java |  33 +++--
 .../rules/am/OptimizableOperatorSubTree.java    |  45 ++++---
 .../optimizer/rules/am/RTreeAccessMethod.java   |  10 +-
 .../nonpure/global-datetime-no-index.aql        |  41 ++++++
 .../global-datetime-use-index-return-time.aql   |  45 +++++++
 .../nonpure/global-datetime-use-index.aql       |  42 ++++++
 .../queries/nonpure/keep-datetime-local.aql     |  74 +++++++++++
 .../nonpure/local-datetime-ignore-index.aql     |  42 ++++++
 .../queries/nonpure/local-datetime-no-index.aql |  42 ++++++
 ...in-nonpure-location-in-join-cannot-index.aql |  48 +++++++
 .../queries/nonpure/query-ASTERIXDB-1608.aql    |  33 +++++
 .../results/btree-index/btree-datetime-02.plan  |   9 +-
 .../nonpure/global-datetime-no-index.plan       |  10 ++
 .../global-datetime-use-index-return-time.plan  |  12 ++
 .../nonpure/global-datetime-use-index.plan      |  10 ++
 .../results/nonpure/keep-datetime-local.plan    |  36 +++++
 .../nonpure/local-datetime-ignore-index.plan    |   9 ++
 .../nonpure/local-datetime-no-index.plan        |  10 ++
 ...n-nonpure-location-in-join-cannot-index.plan |  25 ++++
 .../results/nonpure/query-ASTERIXDB-1608.plan   |  13 ++
 .../global-datetime-use-index.1.ddl.aql         |  30 +++++
 .../global-datetime-use-index.2.update.aql      |  26 ++++
 .../global-datetime-use-index.3.query.aql       |  26 ++++
 .../local-datetime-ignore-index.1.ddl.aql       |  30 +++++
 .../local-datetime-ignore-index.2.update.aql    |  26 ++++
 .../local-datetime-ignore-index.3.query.aql     |  26 ++++
 .../global-datetime-use-index.1.adm             |   2 +
 .../local-datetime-ignore-index.1.adm           |   2 +
 .../src/test/resources/runtimets/testsuite.xml  |  16 ++-
 .../core/algebra/base/PhysicalOperatorTag.java  |   2 +-
 .../algebra/util/OperatorPropertiesUtil.java    |  27 +++-
 .../rewriter/rules/ConsolidateAssignsRule.java  |   7 +-
 .../rules/EnforceStructuralPropertiesRule.java  |   4 +-
 .../rules/ExtractCommonExpressionsRule.java     |  29 +++--
 .../rewriter/rules/InlineVariablesRule.java     |  22 +---
 .../PushMapOperatorDownThroughProductRule.java  |   5 +
 .../rewriter/rules/SetExecutionModeRule.java    |   6 +-
 47 files changed, 1020 insertions(+), 168 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6b8a42f3/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/CommitPOperator.java
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/CommitPOperator.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/CommitPOperator.java
index 28c883a..1c01c40 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/CommitPOperator.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/CommitPOperator.java
@@ -62,7 +62,7 @@ public class CommitPOperator extends AbstractPhysicalOperator 
{
 
     @Override
     public PhysicalOperatorTag getOperatorTag() {
-        return PhysicalOperatorTag.EXTENSION_OPERATOR;
+        return PhysicalOperatorTag.DELEGATE_OPERATOR;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6b8a42f3/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushFieldAccessRule.java
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushFieldAccessRule.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushFieldAccessRule.java
index e68ad02..3fe5e30 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushFieldAccessRule.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushFieldAccessRule.java
@@ -62,11 +62,12 @@ import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.DataSourceSc
 import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.GroupByOperator;
 import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.NestedTupleSourceOperator;
 import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities;
-import org.apache.hyracks.algebricks.core.algebra.util.OperatorPropertiesUtil;
 import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
 
 public class PushFieldAccessRule implements IAlgebraicRewriteRule {
 
+    private static final String IS_MOVABLE = "isMovable";
+
     @Override
     public boolean rewritePre(Mutable<ILogicalOperator> opRef, 
IOptimizationContext context) {
         return false;
@@ -184,7 +185,8 @@ public class PushFieldAccessRule implements 
IAlgebraicRewriteRule {
                 && !(op2.getOperatorTag() == LogicalOperatorTag.SELECT && 
isAccessToIndexedField(access, context))) {
             return false;
         }
-        if (!OperatorPropertiesUtil.isMovable(op2)) {
+        Object annotation = op2.getAnnotations().get(IS_MOVABLE);
+        if (annotation != null && !((Boolean) annotation)) {
             return false;
         }
         if (tryingToPushThroughSelectionWithSameDataSource(access, op2)) {

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6b8a42f3/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AbstractIntroduceAccessMethodRule.java
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AbstractIntroduceAccessMethodRule.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AbstractIntroduceAccessMethodRule.java
index 3c79009..c44cebc 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AbstractIntroduceAccessMethodRule.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AbstractIntroduceAccessMethodRule.java
@@ -243,11 +243,13 @@ public abstract class AbstractIntroduceAccessMethodRule 
implements IAlgebraicRew
                         if (j != exprAndVarIdx.second) {
                             matchedTypes.add(optFuncExpr.getFieldType(j));
                         }
+
                     }
 
                     if (matchedTypes.size() < 2 && 
optFuncExpr.getNumLogicalVars() == 1) {
-                        matchedTypes.add((IAType) 
ExpressionTypeComputer.INSTANCE.getType(
-                                optFuncExpr.getConstantAtRuntimeExpr(0), 
context.getMetadataProvider(),
+                        matchedTypes
+                                .add((IAType) 
ExpressionTypeComputer.INSTANCE.getType(optFuncExpr.getConstantExpr(0),
+                                        context.getMetadataProvider(),
                                 typeEnvironment));
                     }
 
@@ -583,9 +585,7 @@ public abstract class AbstractIntroduceAccessMethodRule 
implements IAlgebraicRew
                     subTree.getRecordType(), optVarIndex,
                     
optFuncExpr.getFuncExpr().getArguments().get(optVarIndex).getValue(), 
datasetRecordVar,
                     subTree.getMetaRecordType(), datasetMetaVar);
-            if (fieldName == null) {
-                continue;
-            }
+
             IAType fieldType = (IAType) 
context.getOutputTypeEnvironment(assignOp).getVarType(var);
             // Set the fieldName in the corresponding matched
             // function expression.

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6b8a42f3/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java
index 2d46a0b..cee77ed 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java
@@ -74,6 +74,7 @@ import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.OrderOperato
 import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.OrderOperator.IOrder;
 import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.SelectOperator;
 import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.UnnestMapOperator;
+import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities;
 import org.apache.hyracks.algebricks.core.algebra.plan.ALogicalPlanImpl;
 import org.apache.hyracks.algebricks.core.algebra.util.OperatorPropertiesUtil;
 
@@ -308,11 +309,18 @@ public class AccessMethodUtils {
             // Type Checking and type promotion is done here
             IAType fieldType = optFuncExpr.getFieldType(0);
 
+            if (optFuncExpr.getNumConstantExpr() == 0) {
+                //We are looking at a selection case, but using two variables
+                //This means that the second variable comes from a nonPure 
function call
+                //TODO: Right now we miss on type promotion for nonpure 
functions
+                return new Pair<>(new 
VariableReferenceExpression(optFuncExpr.getLogicalVar(1)), false);
+            }
+
             ILogicalExpression constantAtRuntimeExpression = null;
             AsterixConstantValue constantValue = null;
             ATypeTag constantValueTag = null;
 
-            constantAtRuntimeExpression = 
optFuncExpr.getConstantAtRuntimeExpr(0);
+            constantAtRuntimeExpression = optFuncExpr.getConstantExpr(0);
 
             if (constantAtRuntimeExpression.getExpressionTag() == 
LogicalExpressionTag.CONSTANT) {
                 constantValue = (AsterixConstantValue) ((ConstantExpression) 
constantAtRuntimeExpression).getValue();
@@ -355,19 +363,16 @@ public class AccessMethodUtils {
             }
 
             if (typeCastingApplied) {
-                return new Pair<ILogicalExpression, Boolean>(new 
ConstantExpression(replacedConstantValue),
-                        realTypeConvertedToIntegerType);
+                return new Pair<>(new 
ConstantExpression(replacedConstantValue), realTypeConvertedToIntegerType);
             } else {
-                return new Pair<ILogicalExpression, 
Boolean>(optFuncExpr.getConstantAtRuntimeExpr(0), false);
+                return new Pair<>(optFuncExpr.getConstantExpr(0), false);
             }
         } else {
             // We are optimizing a join query. Determine which variable feeds 
the secondary index.
             if (optFuncExpr.getOperatorSubTree(0) == null || 
optFuncExpr.getOperatorSubTree(0) == probeSubTree) {
-                return new Pair<ILogicalExpression, Boolean>(
-                        new 
VariableReferenceExpression(optFuncExpr.getLogicalVar(0)), false);
+                return new Pair<>(new 
VariableReferenceExpression(optFuncExpr.getLogicalVar(0)), false);
             } else {
-                return new Pair<ILogicalExpression, Boolean>(
-                        new 
VariableReferenceExpression(optFuncExpr.getLogicalVar(1)), false);
+                return new Pair<>(new 
VariableReferenceExpression(optFuncExpr.getLogicalVar(1)), false);
             }
         }
     }
@@ -645,7 +650,7 @@ public class AccessMethodUtils {
         return unnestOp;
     }
 
-    //If the expression is constant at runtime, runturn the type
+    //If the expression is constant at runtime, return the type
     public static IAType constantRuntimeResultType(ILogicalExpression expr, 
IOptimizationContext context,
             IVariableTypeEnvironment typeEnvironment) throws 
AlgebricksException {
         Set<LogicalVariable> usedVariables = new HashSet<LogicalVariable>();
@@ -656,4 +661,24 @@ public class AccessMethodUtils {
         return (IAType) context.getExpressionTypeComputer().getType(expr, 
context.getMetadataProvider(),
                 typeEnvironment);
     }
+
+    //Get Variables used by afterSelectRefs that were created before the 
datasource
+    //If there are any, we should retain inputs
+    public static boolean retainInputs(List<LogicalVariable> 
dataSourceVariables, ILogicalOperator sourceOp,
+            List<Mutable<ILogicalOperator>> afterSelectRefs) throws 
AlgebricksException {
+        List<LogicalVariable> usedVars = new ArrayList<>();
+        List<LogicalVariable> producedVars = new ArrayList<>();
+        List<LogicalVariable> liveVars = new ArrayList<>();
+        VariableUtilities.getLiveVariables(sourceOp, liveVars);
+        for (Mutable<ILogicalOperator> opMutable : afterSelectRefs) {
+            ILogicalOperator op = opMutable.getValue();
+            VariableUtilities.getUsedVariables(op, usedVars);
+            VariableUtilities.getProducedVariables(op, producedVars);
+        }
+        usedVars.removeAll(producedVars);
+        usedVars.removeAll(dataSourceVariables);
+        usedVars.retainAll(liveVars);
+        return usedVars.isEmpty() ? false : true;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6b8a42f3/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/BTreeAccessMethod.java
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/BTreeAccessMethod.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/BTreeAccessMethod.java
index eb7d3a4..3035c76 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/BTreeAccessMethod.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/BTreeAccessMethod.java
@@ -120,13 +120,20 @@ public class BTreeAccessMethod implements IAccessMethod {
     }
 
     @Override
-    public boolean applySelectPlanTransformation(Mutable<ILogicalOperator> 
selectRef,
-            OptimizableOperatorSubTree subTree, Index chosenIndex, 
AccessMethodAnalysisContext analysisCtx,
-            IOptimizationContext context) throws AlgebricksException {
+    public boolean 
applySelectPlanTransformation(List<Mutable<ILogicalOperator>> afterSelectRefs,
+            Mutable<ILogicalOperator> selectRef, OptimizableOperatorSubTree 
subTree, Index chosenIndex,
+            AccessMethodAnalysisContext analysisCtx, IOptimizationContext 
context) throws AlgebricksException {
         SelectOperator select = (SelectOperator) selectRef.getValue();
         Mutable<ILogicalExpression> conditionRef = select.getCondition();
+
         ILogicalOperator primaryIndexUnnestOp = 
createSecondaryToPrimaryPlan(conditionRef, subTree, null, chosenIndex,
-                analysisCtx, false, false, false, context);
+                analysisCtx,
+                
AccessMethodUtils.retainInputs(subTree.getDataSourceVariables(), 
subTree.getDataSourceRef().getValue(),
+                        afterSelectRefs),
+                false, 
subTree.getDataSourceRef().getValue().getInputs().get(0).getValue()
+                        .getExecutionMode() == ExecutionMode.UNPARTITIONED,
+                context);
+
         if (primaryIndexUnnestOp == null) {
             return false;
         }
@@ -484,6 +491,18 @@ public class BTreeAccessMethod implements IAccessMethod {
                     
OperatorManipulationUtil.deepCopy(dataSourceOp.getInputs().get(0).getValue())));
             
assignConstantSearchKeys.setExecutionMode(dataSourceOp.getExecutionMode());
             inputOp = assignConstantSearchKeys;
+        } else if (probeSubTree == null) {
+            //nonpure case
+            //Make sure that the nonpure function is unpartitioned
+            ILogicalOperator checkOp = 
dataSourceOp.getInputs().get(0).getValue();
+            while (checkOp.getExecutionMode() != ExecutionMode.UNPARTITIONED) {
+                if (checkOp.getInputs().size() == 1) {
+                    checkOp = checkOp.getInputs().get(0).getValue();
+                } else {
+                    return null;
+                }
+            }
+            inputOp = dataSourceOp.getInputs().get(0).getValue();
         } else {
             // All index search keys are variables.
             inputOp = probeSubTree.getRoot();
@@ -694,8 +713,11 @@ public class BTreeAccessMethod implements IAccessMethod {
 
     private boolean probeIsOnLhs(IOptimizableFuncExpr optFuncExpr, 
OptimizableOperatorSubTree probeSubTree) {
         if (probeSubTree == null) {
+            if (optFuncExpr.getConstantExpressions().length == 0) {
+                return optFuncExpr.getLogicalExpr(0) == 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.getConstantAtRuntimeExpr(0);
+            return optFuncExpr.getFuncExpr().getArguments().get(0) == 
optFuncExpr.getConstantExpr(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);
@@ -711,10 +733,21 @@ public class BTreeAccessMethod implements IAccessMethod {
     }
 
     @Override
-    public boolean exprIsOptimizable(Index index, IOptimizableFuncExpr 
optFuncExpr) {
+    public boolean exprIsOptimizable(Index index, IOptimizableFuncExpr 
optFuncExpr) throws AlgebricksException {
         // If we are optimizing a join, check for the indexed nested-loop join 
hint.
         if (optFuncExpr.getNumLogicalVars() == 2) {
-            if 
(!optFuncExpr.getFuncExpr().getAnnotations().containsKey(IndexedNLJoinExpressionAnnotation.INSTANCE))
 {
+            if (optFuncExpr.getOperatorSubTree(0) == 
optFuncExpr.getOperatorSubTree(1)) {
+                if ((optFuncExpr.getSourceVar(0) == null && 
optFuncExpr.getFieldType(0) != null)
+                        || (optFuncExpr.getSourceVar(1) == null && 
optFuncExpr.getFieldType(1) != null)) {
+                    //We are in the select case (trees are the same, and one 
field comes from non-scan)
+                    //We can do the index search
+                } else {
+                    //One of the vars was from an assign rather than a scan
+                    //And we were unable to determine its type
+                    return false;
+                }
+            } else if (!optFuncExpr.getFuncExpr().getAnnotations()
+                    .containsKey(IndexedNLJoinExpressionAnnotation.INSTANCE)) {
                 return false;
             }
         }

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6b8a42f3/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IAccessMethod.java
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IAccessMethod.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IAccessMethod.java
index 5691d57..d249b96 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IAccessMethod.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IAccessMethod.java
@@ -30,7 +30,6 @@ import 
org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCa
 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.data.std.api.IDataOutputProvider;
 
 /**
  * Interface that an access method should implement to work with the rewrite
@@ -38,7 +37,7 @@ import org.apache.hyracks.data.std.api.IDataOutputProvider;
  * methods for analyzing a select/join condition, and for rewriting the plan
  * with a given index.
  */
-public interface IAccessMethod extends Comparable<IAccessMethod>{
+public interface IAccessMethod extends Comparable<IAccessMethod> {
 
     /**
      * @return A list of function identifiers that are optimizable by this
@@ -80,19 +79,17 @@ public interface IAccessMethod extends 
Comparable<IAccessMethod>{
 
     /**
      * Applies the plan transformation to use chosenIndex to optimize a 
selection query.
+     *
+     * @param afterSelectRefs
      */
-    public boolean applySelectPlanTransformation(Mutable<ILogicalOperator> 
selectRef,
-            OptimizableOperatorSubTree subTree, Index chosenIndex, 
AccessMethodAnalysisContext analysisCtx,
-            IOptimizationContext context) throws AlgebricksException;
+    public boolean 
applySelectPlanTransformation(List<Mutable<ILogicalOperator>> afterSelectRefs,
+            Mutable<ILogicalOperator> selectRef, OptimizableOperatorSubTree 
subTree, Index chosenIndex,
+            AccessMethodAnalysisContext analysisCtx, IOptimizationContext 
context) throws AlgebricksException;
 
     public ILogicalOperator 
createSecondaryToPrimaryPlan(Mutable<ILogicalExpression> conditionRef,
-            OptimizableOperatorSubTree indexSubTree,
-            OptimizableOperatorSubTree probeSubTree,
-            Index chosenIndex,
-            AccessMethodAnalysisContext analysisCtx,
-            boolean retainInput, boolean retainNull, boolean requiresBroadcast,
-            IOptimizationContext context)
-                    throws AlgebricksException;
+            OptimizableOperatorSubTree indexSubTree, 
OptimizableOperatorSubTree probeSubTree, Index chosenIndex,
+            AccessMethodAnalysisContext analysisCtx, boolean retainInput, 
boolean retainNull, boolean requiresBroadcast,
+            IOptimizationContext context) throws AlgebricksException;
 
     /**
      * Applies the plan transformation to use chosenIndex to optimize a join 
query.

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6b8a42f3/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IOptimizableFuncExpr.java
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IOptimizableFuncExpr.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IOptimizableFuncExpr.java
index b4f8c9f..05dc4a6 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IOptimizableFuncExpr.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IOptimizableFuncExpr.java
@@ -35,7 +35,7 @@ public interface IOptimizableFuncExpr {
 
     public int getNumLogicalVars();
 
-    public int getNumConstantAtRuntimeExpr();
+    public int getNumConstantExpr();
 
     public LogicalVariable getLogicalVar(int index);
 
@@ -55,7 +55,7 @@ public interface IOptimizableFuncExpr {
 
     public OptimizableOperatorSubTree getOperatorSubTree(int index);
 
-    public ILogicalExpression getConstantAtRuntimeExpr(int index);
+    public ILogicalExpression getConstantExpr(int index);
 
     public int findLogicalVar(LogicalVariable var);
 
@@ -75,5 +75,7 @@ public interface IOptimizableFuncExpr {
 
     IAType getConstantType(int index);
 
-    void setConstantAtRuntimeExpr(int index, ILogicalExpression expr);
+    void setConstantExpr(int index, ILogicalExpression expr);
+
+    ILogicalExpression[] getConstantExpressions();
 }

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6b8a42f3/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceLSMComponentFilterRule.java
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceLSMComponentFilterRule.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceLSMComponentFilterRule.java
index 02fb2a5..53f7a72 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceLSMComponentFilterRule.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceLSMComponentFilterRule.java
@@ -131,7 +131,7 @@ public class IntroduceLSMComponentFilterRule implements 
IAlgebraicRewriteRule {
         for (IOptimizableFuncExpr optFuncExpr : optFuncExprs) {
             ComparisonKind ck = AlgebricksBuiltinFunctions
                     
.getComparisonType(optFuncExpr.getFuncExpr().getFunctionIdentifier());
-            ILogicalExpression searchKeyExpr = 
optFuncExpr.getConstantAtRuntimeExpr(0);
+            ILogicalExpression searchKeyExpr = optFuncExpr.getConstantExpr(0);
             LogicalVariable var = context.newVar();
             assignKeyExprList.add(new 
MutableObject<ILogicalExpression>(searchKeyExpr));
             assignKeyVarList.add(var);

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6b8a42f3/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceSelectAccessMethodRule.java
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceSelectAccessMethodRule.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceSelectAccessMethodRule.java
index 434b961..1d332b6 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceSelectAccessMethodRule.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceSelectAccessMethodRule.java
@@ -25,6 +25,7 @@ import java.util.Map;
 import java.util.Optional;
 import java.util.TreeMap;
 
+import org.apache.asterix.algebra.operators.CommitOperator;
 import org.apache.asterix.metadata.declared.MetadataProvider;
 import org.apache.asterix.metadata.entities.Index;
 import org.apache.commons.lang3.mutable.Mutable;
@@ -42,6 +43,8 @@ import 
org.apache.hyracks.algebricks.core.algebra.expressions.IVariableTypeEnvir
 import 
org.apache.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression;
 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.AbstractLogicalOperator.ExecutionMode;
+import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.DelegateOperator;
 import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.IntersectOperator;
 import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.OrderOperator;
 import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.SelectOperator;
@@ -79,10 +82,11 @@ public class IntroduceSelectAccessMethodRule extends 
AbstractIntroduceAccessMeth
     // Operators representing the patterns to be matched:
     // These ops are set in matchesPattern()
     protected Mutable<ILogicalOperator> selectRef = null;
-    protected SelectOperator select = null;
+    protected SelectOperator selectOp = null;
     protected AbstractFunctionCallExpression selectCond = null;
     protected IVariableTypeEnvironment typeEnvironment = null;
     protected final OptimizableOperatorSubTree subTree = new 
OptimizableOperatorSubTree();
+    protected List<Mutable<ILogicalOperator>> afterSelectRefs = null;
 
     // Register access methods.
     protected static Map<FunctionIdentifier, List<IAccessMethod>> 
accessMethods = new HashMap<FunctionIdentifier, List<IAccessMethod>>();
@@ -93,46 +97,111 @@ public class IntroduceSelectAccessMethodRule extends 
AbstractIntroduceAccessMeth
         registerAccessMethod(InvertedIndexAccessMethod.INSTANCE, 
accessMethods);
     }
 
+    /**
+     * Recursively check the given plan from the root operator to transform a 
plan
+     * with SELECT operator into an index-utilized plan.
+     */
     @Override
     public boolean rewritePost(Mutable<ILogicalOperator> opRef, 
IOptimizationContext context)
             throws AlgebricksException {
         clear();
         setMetadataDeclarations(context);
 
-        // Match operator pattern and initialize operator members.
-        if (!matchesOperatorPattern(opRef, context)) {
+        AbstractLogicalOperator op = (AbstractLogicalOperator) 
opRef.getValue();
+        if (context.checkIfInDontApplySet(this, op)) {
             return false;
         }
 
-        // Analyze select condition.
-        Map<IAccessMethod, AccessMethodAnalysisContext> analyzedAMs = new 
TreeMap<IAccessMethod, AccessMethodAnalysisContext>();
-        if (!analyzeCondition(selectCond, subTree.getAssignsAndUnnests(), 
analyzedAMs, context, typeEnvironment)) {
+        //We start at the top of the plan
+        if (op.getOperatorTag() != LogicalOperatorTag.DISTRIBUTE_RESULT
+                && op.getOperatorTag() != LogicalOperatorTag.SINK
+                && op.getOperatorTag() != 
LogicalOperatorTag.DELEGATE_OPERATOR) {
             return false;
         }
-
-        // Set dataset and type metadata.
-        if (!subTree.setDatasetAndTypeMetadata((MetadataProvider) 
context.getMetadataProvider())) {
+        if (op.getOperatorTag() == LogicalOperatorTag.DELEGATE_OPERATOR
+                && !(((DelegateOperator) op).getDelegate() instanceof 
CommitOperator)) {
             return false;
         }
 
-        fillSubTreeIndexExprs(subTree, analyzedAMs, context);
-        pruneIndexCandidates(analyzedAMs, context, typeEnvironment);
+        afterSelectRefs = new ArrayList<>();
 
-        // Choose index to be applied.
-        List<Pair<IAccessMethod, Index>> chosenIndexes = 
chooseAllIndex(analyzedAMs);
-        if (chosenIndexes == null || chosenIndexes.size() == 0) {
-            context.addToDontApplySet(this, select);
+        // Recursively check the given plan whether the desired pattern exists 
in it.
+        // If so, try to optimize the plan.
+        boolean planTransformed = 
checkAndApplyTheSelectTransformationRule(opRef, context);
+
+        if (selectOp != null) {
+            // We found an optimization here. Don't need to optimize this 
operator again.
+            context.addToDontApplySet(this, selectOp);
+        }
+
+        if (!planTransformed) {
+            // We found an optimization here. Don't need to optimize this 
operator again.
             return false;
+        } else {
+            OperatorPropertiesUtil.typeOpRec(opRef, context);
+
         }
 
-        // Apply plan transformation using chosen index.
-        boolean res = intersectAllSecondaryIndexes(chosenIndexes, analyzedAMs, 
context);
+        return planTransformed;
+    }
 
-        if (res) {
-            OperatorPropertiesUtil.typeOpRec(opRef, context);
+    protected boolean 
checkAndApplyTheSelectTransformationRule(Mutable<ILogicalOperator> opRef,
+            IOptimizationContext context) throws AlgebricksException {
+        AbstractLogicalOperator op = (AbstractLogicalOperator) 
opRef.getValue();
+
+        // Match operator pattern and initialize operator members.
+        if (matchesOperatorPattern(opRef, context)) {
+            // Analyze select condition.
+            Map<IAccessMethod, AccessMethodAnalysisContext> analyzedAMs = new 
TreeMap<>();
+            if (!analyzeCondition(selectCond, subTree.getAssignsAndUnnests(), 
analyzedAMs, context, typeEnvironment)) {
+                return false;
+            }
+
+            // Set dataset and type metadata.
+            if (!subTree.setDatasetAndTypeMetadata((MetadataProvider) 
context.getMetadataProvider())) {
+                return false;
+            }
+
+            fillSubTreeIndexExprs(subTree, analyzedAMs, context);
+            pruneIndexCandidates(analyzedAMs, context, typeEnvironment);
+
+            // Choose index to be applied.
+            List<Pair<IAccessMethod, Index>> chosenIndexes = 
chooseAllIndex(analyzedAMs);
+            if (chosenIndexes == null || chosenIndexes.isEmpty()) {
+                context.addToDontApplySet(this, selectOp);
+                return false;
+            }
+
+            // Apply plan transformation using chosen index.
+            boolean res = intersectAllSecondaryIndexes(chosenIndexes, 
analyzedAMs, context);
+
+            context.addToDontApplySet(this, selectOp);
+            if (res) {
+                OperatorPropertiesUtil.typeOpRec(opRef, context);
+                return res;
+            }
+            selectRef = null;
+            selectOp = null;
+            afterSelectRefs.add(opRef);
+
+        } else {
+            // This is not a SELECT operator. Remember operators
+            afterSelectRefs.add(opRef);
+
+        }
+        // Recursively check the plan and try to optimize it.
+        boolean selectFoundAndOptimizationApplied = false;
+        for (Mutable<ILogicalOperator> inputOpRef : op.getInputs()) {
+            boolean foundHere = 
checkAndApplyTheSelectTransformationRule(inputOpRef, context);
+            if (foundHere) {
+                selectFoundAndOptimizationApplied = true;
+            }
         }
-        context.addToDontApplySet(this, select);
-        return res;
+
+        // Clean the path after SELECT operator by removing the current 
operator in the list.
+        afterSelectRefs.remove(opRef);
+        return selectFoundAndOptimizationApplied;
+
     }
 
     private boolean intersectAllSecondaryIndexes(List<Pair<IAccessMethod, 
Index>> chosenIndexes,
@@ -149,18 +218,22 @@ public class IntroduceSelectAccessMethodRule extends 
AbstractIntroduceAccessMeth
         }
         if (chosenIndex != null) {
             AccessMethodAnalysisContext analysisCtx = 
analyzedAMs.get(chosenIndex.first);
-            return chosenIndex.first.applySelectPlanTransformation(selectRef, 
subTree, chosenIndex.second, analysisCtx,
-                    context);
+            return 
chosenIndex.first.applySelectPlanTransformation(afterSelectRefs, selectRef, 
subTree,
+                    chosenIndex.second, analysisCtx, context);
         }
 
         // Intersect all secondary indexes, and postpone the primary index 
search.
-        Mutable<ILogicalExpression> conditionRef = select.getCondition();
+        Mutable<ILogicalExpression> conditionRef = selectOp.getCondition();
 
         List<ILogicalOperator> subRoots = new ArrayList<>();
         for (Pair<IAccessMethod, Index> pair : chosenIndexes) {
             AccessMethodAnalysisContext analysisCtx = 
analyzedAMs.get(pair.first);
             subRoots.add(pair.first.createSecondaryToPrimaryPlan(conditionRef, 
subTree, null, pair.second, analysisCtx,
-                    false, false, false, context));
+                    
AccessMethodUtils.retainInputs(subTree.getDataSourceVariables(),
+                            subTree.getDataSourceRef().getValue(), 
afterSelectRefs),
+                    false, 
subTree.getDataSourceRef().getValue().getInputs().get(0).getValue()
+                            .getExecutionMode() == ExecutionMode.UNPARTITIONED,
+                    context));
         }
         ILogicalOperator primaryUnnest = 
connectAll2ndarySearchPlanWithIntersect(subRoots, context);
 
@@ -217,11 +290,11 @@ public class IntroduceSelectAccessMethodRule extends 
AbstractIntroduceAccessMeth
         }
         // Set and analyze select.
         selectRef = opRef;
-        select = (SelectOperator) op1;
+        selectOp = (SelectOperator) op1;
 
         typeEnvironment = context.getOutputTypeEnvironment(op1);
         // Check that the select's condition is a function call.
-        ILogicalExpression condExpr = select.getCondition().getValue();
+        ILogicalExpression condExpr = selectOp.getCondition().getValue();
         if (condExpr.getExpressionTag() != LogicalExpressionTag.FUNCTION_CALL) 
{
             return false;
         }
@@ -236,8 +309,9 @@ public class IntroduceSelectAccessMethodRule extends 
AbstractIntroduceAccessMeth
     }
 
     private void clear() {
+        afterSelectRefs = null;
         selectRef = null;
-        select = null;
+        selectOp = null;
         selectCond = null;
     }
 }

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6b8a42f3/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/InvertedIndexAccessMethod.java
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/InvertedIndexAccessMethod.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/InvertedIndexAccessMethod.java
index e43af61..066757d 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/InvertedIndexAccessMethod.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/InvertedIndexAccessMethod.java
@@ -144,7 +144,7 @@ public class InvertedIndexAccessMethod implements 
IAccessMethod {
 
     public boolean analyzeGetItemFuncExpr(AbstractFunctionCallExpression 
funcExpr,
             List<AbstractLogicalOperator> assignsAndUnnests, 
AccessMethodAnalysisContext analysisCtx)
-            throws AlgebricksException {
+                    throws AlgebricksException {
         if (funcExpr.getFunctionIdentifier() != 
AsterixBuiltinFunctions.GET_ITEM) {
             return false;
         }
@@ -436,11 +436,15 @@ public class InvertedIndexAccessMethod implements 
IAccessMethod {
     }
 
     @Override
-    public boolean applySelectPlanTransformation(Mutable<ILogicalOperator> 
selectRef,
-            OptimizableOperatorSubTree subTree, Index chosenIndex, 
AccessMethodAnalysisContext analysisCtx,
-            IOptimizationContext context) throws AlgebricksException {
+    public boolean 
applySelectPlanTransformation(List<Mutable<ILogicalOperator>> afterSelectRefs,
+            Mutable<ILogicalOperator> selectRef, OptimizableOperatorSubTree 
subTree, Index chosenIndex,
+            AccessMethodAnalysisContext analysisCtx, IOptimizationContext 
context) throws AlgebricksException {
         ILogicalOperator indexPlanRootOp = createSecondaryToPrimaryPlan(null, 
subTree, null, chosenIndex, analysisCtx,
-                false, false, false, context);
+                
AccessMethodUtils.retainInputs(subTree.getDataSourceVariables(), 
subTree.getDataSourceRef().getValue(),
+                        afterSelectRefs),
+                false, 
subTree.getDataSourceRef().getValue().getInputs().get(0).getValue()
+                        .getExecutionMode() == ExecutionMode.UNPARTITIONED,
+                context);
         // Replace the datasource scan with the new plan rooted at 
primaryIndexUnnestMap.
         subTree.getDataSourceRef().setValue(indexPlanRootOp);
         return true;
@@ -737,7 +741,7 @@ public class InvertedIndexAccessMethod implements 
IAccessMethod {
                 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>(optFuncExpr.getConstantAtRuntimeExpr(0)));
+                isFilterableArgs.add(new 
MutableObject<ILogicalExpression>(optFuncExpr.getConstantExpr(0)));
                 isFilterableArgs.add(new MutableObject<ILogicalExpression>(
                         
AccessMethodUtils.createInt32Constant(chosenIndex.getGramLength())));
                 boolean usePrePost = optFuncExpr.containsPartialField() ? 
false : true;
@@ -754,7 +758,7 @@ public class InvertedIndexAccessMethod implements 
IAccessMethod {
                 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>(optFuncExpr.getConstantAtRuntimeExpr(0)));
+                isFilterableArgs.add(new 
MutableObject<ILogicalExpression>(optFuncExpr.getConstantExpr(0)));
                 isFilterableExpr = new ScalarFunctionCallExpression(
                         
FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.EDIT_DISTANCE_LIST_IS_FILTERABLE),
                         isFilterableArgs);
@@ -828,8 +832,9 @@ public class InvertedIndexAccessMethod implements 
IAccessMethod {
         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(((ConstantExpression) 
optFuncExpr
-                    
.getConstantAtRuntimeExpr(optFuncExpr.getNumConstantAtRuntimeExpr() - 
1)).getValue());
+            jobGenParams.setSimilarityThreshold(
+                    ((ConstantExpression) 
optFuncExpr.getConstantExpr(optFuncExpr.getNumConstantExpr() - 1))
+                            .getValue());
         }
         if (optFuncExpr.getFuncExpr().getFunctionIdentifier() == 
AsterixBuiltinFunctions.EDIT_DISTANCE_CHECK
                 || optFuncExpr.getFuncExpr()
@@ -840,19 +845,20 @@ public class InvertedIndexAccessMethod implements 
IAccessMethod {
                 
jobGenParams.setSearchModifierType(SearchModifierType.EDIT_DISTANCE);
             }
             // Add the similarity threshold which, by convention, is the last 
constant value.
-            jobGenParams.setSimilarityThreshold(((ConstantExpression) 
optFuncExpr
-                    
.getConstantAtRuntimeExpr(optFuncExpr.getNumConstantAtRuntimeExpr() - 
1)).getValue());
+            jobGenParams.setSimilarityThreshold(
+                    ((ConstantExpression) 
optFuncExpr.getConstantExpr(optFuncExpr.getNumConstantExpr() - 1))
+                            .getValue());
         }
     }
 
     private void addKeyVarsAndExprs(IOptimizableFuncExpr optFuncExpr, 
ArrayList<LogicalVariable> keyVarList,
             ArrayList<Mutable<ILogicalExpression>> keyExprList, 
IOptimizationContext context)
-            throws AlgebricksException {
+                    throws AlgebricksException {
         // For now we are assuming a single secondary index key.
         // 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>(optFuncExpr.getConstantAtRuntimeExpr(0)));
+        keyExprList.add(new 
MutableObject<ILogicalExpression>(optFuncExpr.getConstantExpr(0)));
         return;
     }
 
@@ -882,7 +888,7 @@ public class InvertedIndexAccessMethod implements 
IAccessMethod {
 
     private boolean isEditDistanceFuncOptimizable(Index index, 
IOptimizableFuncExpr optFuncExpr)
             throws AlgebricksException {
-        if (optFuncExpr.getNumConstantAtRuntimeExpr() == 1) {
+        if (optFuncExpr.getNumConstantExpr() == 1) {
             return isEditDistanceFuncJoinOptimizable(index, optFuncExpr);
         } else {
             return isEditDistanceFuncSelectOptimizable(index, optFuncExpr);
@@ -917,7 +923,7 @@ public class InvertedIndexAccessMethod implements 
IAccessMethod {
         // Check for panic in selection query.
         // TODO: Panic also depends on prePost which is currently hardcoded to 
be true.
         AsterixConstantValue listOrStrConstVal = (AsterixConstantValue) 
((ConstantExpression) optFuncExpr
-                .getConstantAtRuntimeExpr(0)).getValue();
+                .getConstantExpr(0)).getValue();
         IAObject listOrStrObj = listOrStrConstVal.getObject();
         ATypeTag typeTag = listOrStrObj.getType().getTypeTag();
 
@@ -925,8 +931,8 @@ public class InvertedIndexAccessMethod implements 
IAccessMethod {
             return false;
         }
 
-        AsterixConstantValue intConstVal = (AsterixConstantValue) 
((ConstantExpression) optFuncExpr
-                .getConstantAtRuntimeExpr(1)).getValue();
+        AsterixConstantValue intConstVal = (AsterixConstantValue) 
((ConstantExpression) optFuncExpr.getConstantExpr(1))
+                .getValue();
         IAObject intObj = intConstVal.getObject();
 
         AInt32 edThresh = null;
@@ -1084,8 +1090,8 @@ public class InvertedIndexAccessMethod implements 
IAccessMethod {
     }
 
     private boolean isContainsFuncSelectOptimizable(Index index, 
IOptimizableFuncExpr optFuncExpr) {
-        AsterixConstantValue strConstVal = (AsterixConstantValue) 
((ConstantExpression) optFuncExpr
-                .getConstantAtRuntimeExpr(0)).getValue();
+        AsterixConstantValue strConstVal = (AsterixConstantValue) 
((ConstantExpression) optFuncExpr.getConstantExpr(0))
+                .getValue();
         IAObject strObj = strConstVal.getObject();
         ATypeTag typeTag = strObj.getType().getTypeTag();
 

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6b8a42f3/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/OptimizableFuncExpr.java
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/OptimizableFuncExpr.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/OptimizableFuncExpr.java
index 2ecd504..d792e3d 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/OptimizableFuncExpr.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/OptimizableFuncExpr.java
@@ -39,8 +39,8 @@ public class OptimizableFuncExpr implements 
IOptimizableFuncExpr {
     protected final List<List<String>> fieldNames;
     protected final IAType[] fieldTypes;
     protected final OptimizableOperatorSubTree[] subTrees;
-    protected final ILogicalExpression[] constantAtRuntimeExpressions;
-    protected final IAType[] constantAtRuntimeExpressionTypes;
+    protected final ILogicalExpression[] constantExpressions;
+    protected final IAType[] constantExpressionTypes;
     protected boolean partialField;
 
     public OptimizableFuncExpr(AbstractFunctionCallExpression funcExpr, 
LogicalVariable[] logicalVars,
@@ -49,8 +49,8 @@ public class OptimizableFuncExpr implements 
IOptimizableFuncExpr {
         this.logicalVars = logicalVars;
         this.sourceVars = new LogicalVariable[logicalVars.length];
         this.logicalExprs = new ILogicalExpression[logicalVars.length];
-        this.constantAtRuntimeExpressionTypes = constantExpressionTypes;
-        this.constantAtRuntimeExpressions = constantExpressions;
+        this.constantExpressionTypes = constantExpressionTypes;
+        this.constantExpressions = constantExpressions;
         this.fieldNames = new ArrayList<List<String>>();
         for (int i = 0; i < logicalVars.length; i++) {
             fieldNames.add(new ArrayList<String>());
@@ -72,8 +72,8 @@ public class OptimizableFuncExpr implements 
IOptimizableFuncExpr {
         this.logicalVars = new LogicalVariable[] { logicalVar };
         this.sourceVars = new LogicalVariable[1];
         this.logicalExprs = new ILogicalExpression[1];
-        this.constantAtRuntimeExpressions = new ILogicalExpression[] { 
constantExpression };
-        this.constantAtRuntimeExpressionTypes = new IAType[] { 
constantExpressionType };
+        this.constantExpressions = new ILogicalExpression[] { 
constantExpression };
+        this.constantExpressionTypes = new IAType[] { constantExpressionType };
         this.fieldNames = new ArrayList<List<String>>();
         for (int i = 0; i < logicalVars.length; i++) {
             fieldNames.add(new ArrayList<String>());
@@ -98,8 +98,8 @@ public class OptimizableFuncExpr implements 
IOptimizableFuncExpr {
     }
 
     @Override
-    public int getNumConstantAtRuntimeExpr() {
-        return constantAtRuntimeExpressions.length;
+    public int getNumConstantExpr() {
+        return constantExpressions.length;
     }
 
     @Override
@@ -138,23 +138,28 @@ public class OptimizableFuncExpr implements 
IOptimizableFuncExpr {
     }
 
     @Override
-    public ILogicalExpression getConstantAtRuntimeExpr(int index) {
-        return constantAtRuntimeExpressions[index];
+    public ILogicalExpression getConstantExpr(int index) {
+        return constantExpressions[index];
+    }
+
+    @Override
+    public ILogicalExpression[] getConstantExpressions() {
+        return constantExpressions;
     }
 
     @Override
     public void setConstType(int index, IAType fieldType) {
-        constantAtRuntimeExpressionTypes[index] = fieldType;
+        constantExpressionTypes[index] = fieldType;
     }
 
     @Override
     public IAType getConstantType(int index) {
-        return constantAtRuntimeExpressionTypes[index];
+        return constantExpressionTypes[index];
     }
 
     @Override
-    public void setConstantAtRuntimeExpr(int index, ILogicalExpression expr) {
-        constantAtRuntimeExpressions[index] = expr;
+    public void setConstantExpr(int index, ILogicalExpression expr) {
+        constantExpressions[index] = expr;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6b8a42f3/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/OptimizableOperatorSubTree.java
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/OptimizableOperatorSubTree.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/OptimizableOperatorSubTree.java
index 75ee46b..1869d60 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/OptimizableOperatorSubTree.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/OptimizableOperatorSubTree.java
@@ -42,6 +42,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.metadata.IDataSource;
 import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
+import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator.ExecutionMode;
 import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractScanOperator;
 import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractUnnestOperator;
 import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.DataSourceScanOperator;
@@ -85,36 +86,50 @@ public class OptimizableOperatorSubTree {
         reset();
         rootRef = subTreeOpRef;
         root = subTreeOpRef.getValue();
+        boolean passedSource = false;
+        boolean result = false;
+        Mutable<ILogicalOperator> searchOpRef = subTreeOpRef;
         // Examine the op's children to match the expected patterns.
-        AbstractLogicalOperator subTreeOp = (AbstractLogicalOperator) 
subTreeOpRef.getValue();
+        AbstractLogicalOperator subTreeOp = (AbstractLogicalOperator) 
searchOpRef.getValue();
         do {
             // Skip select operator.
             if (subTreeOp.getOperatorTag() == LogicalOperatorTag.SELECT) {
-                subTreeOpRef = subTreeOp.getInputs().get(0);
-                subTreeOp = (AbstractLogicalOperator) subTreeOpRef.getValue();
+                searchOpRef = subTreeOp.getInputs().get(0);
+                subTreeOp = (AbstractLogicalOperator) searchOpRef.getValue();
             }
             // Check primary-index pattern.
             if (subTreeOp.getOperatorTag() != LogicalOperatorTag.ASSIGN
                     && subTreeOp.getOperatorTag() != 
LogicalOperatorTag.UNNEST) {
                 // Pattern may still match if we are looking for primary index 
matches as well.
-                return initializeDataSource(subTreeOpRef);
+                result = initializeDataSource(searchOpRef);
+                passedSource = true;
+                if (!subTreeOp.getInputs().isEmpty()) {
+                    searchOpRef = subTreeOp.getInputs().get(0);
+                    subTreeOp = (AbstractLogicalOperator) 
searchOpRef.getValue();
+                }
             }
             // Match (assign | unnest)+.
-            while ((subTreeOp.getOperatorTag() == LogicalOperatorTag.ASSIGN
-                    || subTreeOp.getOperatorTag() == 
LogicalOperatorTag.UNNEST)) {
-                if (!OperatorPropertiesUtil.isMovable(subTreeOp)) {
+            while (subTreeOp.getOperatorTag() == LogicalOperatorTag.ASSIGN
+                    || subTreeOp.getOperatorTag() == 
LogicalOperatorTag.UNNEST) {
+                if (!passedSource && 
!OperatorPropertiesUtil.isMovable(subTreeOp)) {
                     return false;
-                } else {
-                    getAssignsAndUnnestsRefs().add(subTreeOpRef);
-                    getAssignsAndUnnests().add(subTreeOp);
                 }
-                subTreeOpRef = subTreeOp.getInputs().get(0);
-                subTreeOp = (AbstractLogicalOperator) subTreeOpRef.getValue();
+                if (subTreeOp.getExecutionMode() != 
ExecutionMode.UNPARTITIONED) {
+                    //The unpartitioned ops should stay below the search
+                    assignsAndUnnestsRefs.add(searchOpRef);
+                }
+                assignsAndUnnests.add(subTreeOp);
+
+                searchOpRef = subTreeOp.getInputs().get(0);
+                subTreeOp = (AbstractLogicalOperator) searchOpRef.getValue();
+            }
+            if (passedSource) {
+                return result;
             }
         } while (subTreeOp.getOperatorTag() == LogicalOperatorTag.SELECT);
 
         // Match data source (datasource scan or primary index search).
-        return initializeDataSource(subTreeOpRef);
+        return initializeDataSource(searchOpRef);
     }
 
     private boolean initializeDataSource(Mutable<ILogicalOperator> 
subTreeOpRef) {
@@ -395,8 +410,8 @@ public class OptimizableOperatorSubTree {
                 case DATASOURCE_SCAN:
                 case EXTERNAL_SCAN:
                 case PRIMARY_INDEX_LOOKUP:
-                    AbstractScanOperator scanOp =
-                            (AbstractScanOperator) 
getIxJoinOuterAdditionalDataSourceRefs().get(idx).getValue();
+                    AbstractScanOperator scanOp = (AbstractScanOperator) 
getIxJoinOuterAdditionalDataSourceRefs()
+                            .get(idx).getValue();
                     return scanOp.getVariables();
                 case COLLECTION_SCAN:
                     return new ArrayList<>();

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6b8a42f3/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/RTreeAccessMethod.java
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/RTreeAccessMethod.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/RTreeAccessMethod.java
index c3c162e..eeaaa8d 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/RTreeAccessMethod.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/RTreeAccessMethod.java
@@ -95,12 +95,14 @@ public class RTreeAccessMethod implements IAccessMethod {
     }
 
     @Override
-    public boolean applySelectPlanTransformation(Mutable<ILogicalOperator> 
selectRef,
-            OptimizableOperatorSubTree subTree, Index chosenIndex, 
AccessMethodAnalysisContext analysisCtx,
-            IOptimizationContext context) throws AlgebricksException {
+    public boolean 
applySelectPlanTransformation(List<Mutable<ILogicalOperator>> afterSelectRefs,
+            Mutable<ILogicalOperator> selectRef, OptimizableOperatorSubTree 
subTree, Index chosenIndex,
+            AccessMethodAnalysisContext analysisCtx, IOptimizationContext 
context) throws AlgebricksException {
         // TODO: We can probably do something smarter here based on 
selectivity or MBR area.
         ILogicalOperator primaryIndexUnnestOp = 
createSecondaryToPrimaryPlan(subTree, null, chosenIndex, analysisCtx,
-                false, false, false, context);
+                
AccessMethodUtils.retainInputs(subTree.getDataSourceVariables(), 
subTree.getDataSourceRef().getValue(),
+                        afterSelectRefs),
+                false, false, context);
         if (primaryIndexUnnestOp == null) {
             return false;
         }

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6b8a42f3/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/global-datetime-no-index.aql
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/global-datetime-no-index.aql
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/global-datetime-no-index.aql
new file mode 100644
index 0000000..bd3f019
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/global-datetime-no-index.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     : Time should be unpartitioned and Broadcast to nodes
+ *  Expected Result : Success
+ *  Date            : 20th Oct 2016
+ */
+
+drop dataverse channels if exists;
+create dataverse channels;
+use dataverse channels;
+
+create type userLocation as {
+  userId: int,
+  stamp: datetime
+}
+
+create dataset Users(userLocation)
+primary key userId;
+
+let $time := current-datetime()
+for $result in dataset Users
+where $result.stamp = $time
+return $time
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6b8a42f3/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/global-datetime-use-index-return-time.aql
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/global-datetime-use-index-return-time.aql
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/global-datetime-use-index-return-time.aql
new file mode 100644
index 0000000..34c4e30
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/global-datetime-use-index-return-time.aql
@@ -0,0 +1,45 @@
+/*
+ * 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     : Time should be unpartitioned
+ *                  : but used by index and returned
+ *  Expected Result : Success
+ *  Date            : 20th Oct 2016
+ */
+
+drop dataverse channels if exists;
+create dataverse channels;
+use dataverse channels;
+
+create type userLocation as {
+  userId: int,
+  stamp: datetime
+}
+
+create dataset Users(userLocation)
+primary key stamp;
+
+let $time := current-datetime()
+for $result in dataset Users
+where $result.stamp = $time
+return {
+  "date":$time,
+  "result":$result
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6b8a42f3/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/global-datetime-use-index.aql
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/global-datetime-use-index.aql
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/global-datetime-use-index.aql
new file mode 100644
index 0000000..010ad6f
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/global-datetime-use-index.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     : Time should be unpartitioned
+ *                  : but used by index
+ *  Expected Result : Success
+ *  Date            : 20th Oct 2016
+ */
+
+drop dataverse channels if exists;
+create dataverse channels;
+use dataverse channels;
+
+create type userLocation as {
+  userId: int,
+  stamp: datetime
+}
+
+create dataset Users(userLocation)
+primary key stamp;
+
+let $time := current-datetime()
+for $result in dataset Users
+where $result.stamp = $time
+return $result
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6b8a42f3/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/keep-datetime-local.aql
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/keep-datetime-local.aql
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/keep-datetime-local.aql
new file mode 100644
index 0000000..bb0ffc1
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/keep-datetime-local.aql
@@ -0,0 +1,74 @@
+/*
+ * 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     : Time should remain partitoned
+ *                  : and be returned
+ *  Expected Result : Success
+ *  Date            : 20th Oct 2016
+ */
+
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+create type TwitterUserType as closed {
+    screen-name: string,
+    lang: string,
+    friends-count: int32,
+    statuses-count: int32,
+    name: string,
+    followers-count: int32
+}
+
+create type TweetMessageType as closed {
+    tweetid: int64,
+        user: TwitterUserType,
+        sender-location: point,
+    send-time: datetime,
+        referred-topics: {{ string }},
+    message-text: string,
+    countA: int32,
+    countB: int32
+}
+
+create dataset TweetMessages(TweetMessageType)
+primary key tweetid;
+
+create index twmSndLocIx on TweetMessages(sender-location) type rtree;
+create index msgCountAIx on TweetMessages(countA) type btree;
+create index msgCountBIx on TweetMessages(countB) type btree;
+create index msgTextIx on TweetMessages(message-text) type keyword;
+
+write output to 
asterix_nc1:"rttest/btree-index-join_leftouterjoin-probe-pidx-with-join-btree-sidx_01.adm";
+
+for $t1 in dataset('TweetMessages')
+let $time := current-datetime()
+where $t1.tweetid < int64("10")
+order by $t1.tweetid
+return {
+"time": $time,
+"tweetid1": $t1.tweetid,
+"count1":$t1.countA,
+"t2info": for $t2 in dataset('TweetMessages')
+          where $t1.countA /* +indexnl */= $t2.countB
+          order by $t2.tweetid
+          return {"tweetid2": $t2.tweetid,
+                  "count2":$t2.countB}
+};
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6b8a42f3/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/local-datetime-ignore-index.aql
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/local-datetime-ignore-index.aql
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/local-datetime-ignore-index.aql
new file mode 100644
index 0000000..1077257
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/local-datetime-ignore-index.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     : Time should remain partitoned
+ *                  : and therefore unusable by index
+ *  Expected Result : Success
+ *  Date            : 20th Oct 2016
+ */
+
+drop dataverse channels if exists;
+create dataverse channels;
+use dataverse channels;
+
+create type userLocation as {
+  userId: int,
+  stamp: datetime
+}
+
+create dataset Users(userLocation)
+primary key stamp;
+
+for $result in dataset Users
+let $time := current-datetime()
+where $result.stamp = $time
+return $result
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6b8a42f3/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/local-datetime-no-index.aql
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/local-datetime-no-index.aql
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/local-datetime-no-index.aql
new file mode 100644
index 0000000..5083aaa
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/local-datetime-no-index.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     : Time should remain partitoned
+ *                  : and be returned
+ *  Expected Result : Success
+ *  Date            : 20th Oct 2016
+ */
+
+drop dataverse channels if exists;
+create dataverse channels;
+use dataverse channels;
+
+create type userLocation as {
+  userId: int,
+  stamp: datetime
+}
+
+create dataset Users(userLocation)
+primary key userId;
+
+for $result in dataset Users
+let $time := current-datetime()
+where $result.stamp = $time
+return $time
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6b8a42f3/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/maintain-nonpure-location-in-join-cannot-index.aql
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/maintain-nonpure-location-in-join-cannot-index.aql
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/maintain-nonpure-location-in-join-cannot-index.aql
new file mode 100644
index 0000000..4a7b695
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/maintain-nonpure-location-in-join-cannot-index.aql
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+ /*
+ *  Description     : Time should remain partitoned
+ *  Expected Result : Success
+ *  Date            : 20th Oct 2016
+ */
+
+drop dataverse channels if exists;
+create dataverse channels;
+use dataverse channels;
+
+create type userLocation as {
+  id: int,
+  stamp: time
+}
+
+create dataset Users1(userLocation)
+primary key stamp;
+
+create dataset Users2(userLocation)
+primary key stamp;
+
+for $x in dataset Users1
+let $time := current-time()
+for $y in dataset Users2
+where $y.stamp > $time-time("123045678+0800")
+return {
+   "x_id": $x.id,
+   "y_id": $y.id
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6b8a42f3/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/query-ASTERIXDB-1608.aql
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/query-ASTERIXDB-1608.aql
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/query-ASTERIXDB-1608.aql
new file mode 100644
index 0000000..04620bd
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/query-ASTERIXDB-1608.aql
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ *  Description     : Check fix for ASTERIXDB-1608
+ *  Expected Result : Success
+ *  Date            : 20th Oct 2016
+ */
+
+
+drop dataverse test if exists;
+create dataverse test;
+
+for $x in range(1, 3)
+for $y in range(1, 3)
+return
+{"id": create-uuid(), "x": $x}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6b8a42f3/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index/btree-datetime-02.plan
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index/btree-datetime-02.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index/btree-datetime-02.plan
index a9e223a..a461461 100644
--- 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index/btree-datetime-02.plan
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index/btree-datetime-02.plan
@@ -1,8 +1,9 @@
 -- DISTRIBUTE_RESULT  |PARTITIONED|
   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
     -- STREAM_PROJECT  |PARTITIONED|
-      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-        -- BTREE_SEARCH  |PARTITIONED|
+      -- STREAM_SELECT  |PARTITIONED|
+        -- ASSIGN  |PARTITIONED|
           -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-            -- ASSIGN  |PARTITIONED|
-              -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
\ No newline at end of file
+            -- DATASOURCE_SCAN  |PARTITIONED|
+              -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6b8a42f3/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/global-datetime-no-index.plan
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/global-datetime-no-index.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/global-datetime-no-index.plan
new file mode 100644
index 0000000..82d3768
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/global-datetime-no-index.plan
@@ -0,0 +1,10 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- STREAM_PROJECT  |PARTITIONED|
+      -- STREAM_SELECT  |PARTITIONED|
+        -- STREAM_PROJECT  |PARTITIONED|
+          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+            -- DATASOURCE_SCAN  |PARTITIONED|
+              -- BROADCAST_EXCHANGE  |PARTITIONED|
+                -- ASSIGN  |UNPARTITIONED|
+                  -- EMPTY_TUPLE_SOURCE  |UNPARTITIONED|
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6b8a42f3/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/global-datetime-use-index-return-time.plan
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/global-datetime-use-index-return-time.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/global-datetime-use-index-return-time.plan
new file mode 100644
index 0000000..c6fd83e
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/global-datetime-use-index-return-time.plan
@@ -0,0 +1,12 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- STREAM_PROJECT  |PARTITIONED|
+      -- ASSIGN  |PARTITIONED|
+        -- STREAM_PROJECT  |PARTITIONED|
+          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+            -- BTREE_SEARCH  |PARTITIONED|
+              -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                -- STABLE_SORT [$$0(ASC)]  |PARTITIONED|
+                  -- HASH_PARTITION_EXCHANGE [$$0]  |PARTITIONED|
+                    -- ASSIGN  |UNPARTITIONED|
+                      -- EMPTY_TUPLE_SOURCE  |UNPARTITIONED|
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6b8a42f3/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/global-datetime-use-index.plan
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/global-datetime-use-index.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/global-datetime-use-index.plan
new file mode 100644
index 0000000..972e56a
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/global-datetime-use-index.plan
@@ -0,0 +1,10 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- STREAM_PROJECT  |PARTITIONED|
+      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+        -- BTREE_SEARCH  |PARTITIONED|
+          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+            -- STABLE_SORT [$$0(ASC)]  |PARTITIONED|
+              -- HASH_PARTITION_EXCHANGE [$$0]  |PARTITIONED|
+                -- ASSIGN  |UNPARTITIONED|
+                  -- EMPTY_TUPLE_SOURCE  |UNPARTITIONED|
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6b8a42f3/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/keep-datetime-local.plan
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/keep-datetime-local.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/keep-datetime-local.plan
new file mode 100644
index 0000000..5246d83
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/keep-datetime-local.plan
@@ -0,0 +1,36 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- STREAM_PROJECT  |PARTITIONED|
+      -- ASSIGN  |PARTITIONED|
+        -- SORT_MERGE_EXCHANGE [$$22(ASC) ]  |PARTITIONED|
+          -- STABLE_SORT [$$22(ASC)]  |PARTITIONED|
+            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+              -- STREAM_PROJECT  |PARTITIONED|
+                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                  -- PRE_CLUSTERED_GROUP_BY[$$30]  |PARTITIONED|
+                          {
+                            -- AGGREGATE  |LOCAL|
+                              -- STREAM_SELECT  |LOCAL|
+                                -- NESTED_TUPLE_SOURCE  |LOCAL|
+                          }
+                    -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                      -- STABLE_SORT [$$30(ASC), $$23(ASC)]  |PARTITIONED|
+                        -- HASH_PARTITION_EXCHANGE [$$30]  |PARTITIONED|
+                          -- HYBRID_HASH_JOIN [$$25][$$24]  |PARTITIONED|
+                            -- HASH_PARTITION_EXCHANGE [$$25]  |PARTITIONED|
+                              -- ASSIGN  |PARTITIONED|
+                                -- STREAM_SELECT  |PARTITIONED|
+                                  -- ASSIGN  |PARTITIONED|
+                                    -- STREAM_PROJECT  |PARTITIONED|
+                                      -- ASSIGN  |PARTITIONED|
+                                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                          -- DATASOURCE_SCAN  |PARTITIONED|
+                                            -- ONE_TO_ONE_EXCHANGE  
|PARTITIONED|
+                                              -- EMPTY_TUPLE_SOURCE  
|PARTITIONED|
+                            -- HASH_PARTITION_EXCHANGE [$$24]  |PARTITIONED|
+                              -- STREAM_PROJECT  |PARTITIONED|
+                                -- ASSIGN  |PARTITIONED|
+                                  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                    -- DATASOURCE_SCAN  |PARTITIONED|
+                                      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                        -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6b8a42f3/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/local-datetime-ignore-index.plan
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/local-datetime-ignore-index.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/local-datetime-ignore-index.plan
new file mode 100644
index 0000000..a461461
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/local-datetime-ignore-index.plan
@@ -0,0 +1,9 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- STREAM_PROJECT  |PARTITIONED|
+      -- STREAM_SELECT  |PARTITIONED|
+        -- ASSIGN  |PARTITIONED|
+          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+            -- DATASOURCE_SCAN  |PARTITIONED|
+              -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6b8a42f3/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/local-datetime-no-index.plan
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/local-datetime-no-index.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/local-datetime-no-index.plan
new file mode 100644
index 0000000..2d604a9
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/local-datetime-no-index.plan
@@ -0,0 +1,10 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- STREAM_PROJECT  |PARTITIONED|
+      -- STREAM_SELECT  |PARTITIONED|
+        -- ASSIGN  |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

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6b8a42f3/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/maintain-nonpure-location-in-join-cannot-index.plan
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/maintain-nonpure-location-in-join-cannot-index.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/maintain-nonpure-location-in-join-cannot-index.plan
new file mode 100644
index 0000000..fe2675b
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/maintain-nonpure-location-in-join-cannot-index.plan
@@ -0,0 +1,25 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- STREAM_PROJECT  |PARTITIONED|
+      -- ASSIGN  |PARTITIONED|
+        -- STREAM_PROJECT  |PARTITIONED|
+          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+            -- NESTED_LOOP  |PARTITIONED|
+              -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                -- STREAM_PROJECT  |PARTITIONED|
+                  -- ASSIGN  |PARTITIONED|
+                    -- ASSIGN  |PARTITIONED|
+                      -- STREAM_PROJECT  |PARTITIONED|
+                        -- ASSIGN  |PARTITIONED|
+                          -- STREAM_PROJECT  |PARTITIONED|
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              -- DATASOURCE_SCAN  |PARTITIONED|
+                                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                  -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
+              -- BROADCAST_EXCHANGE  |PARTITIONED|
+                -- STREAM_PROJECT  |PARTITIONED|
+                  -- ASSIGN  |PARTITIONED|
+                    -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                      -- DATASOURCE_SCAN  |PARTITIONED|
+                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                          -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/6b8a42f3/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/query-ASTERIXDB-1608.plan
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/query-ASTERIXDB-1608.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/query-ASTERIXDB-1608.plan
new file mode 100644
index 0000000..1864e29
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/query-ASTERIXDB-1608.plan
@@ -0,0 +1,13 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- STREAM_PROJECT  |PARTITIONED|
+      -- ASSIGN  |PARTITIONED|
+        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+          -- NESTED_LOOP  |PARTITIONED|
+            -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
+              -- UNNEST  |UNPARTITIONED|
+                -- EMPTY_TUPLE_SOURCE  |UNPARTITIONED|
+            -- BROADCAST_EXCHANGE  |PARTITIONED|
+              -- STREAM_PROJECT  |UNPARTITIONED|
+                -- UNNEST  |UNPARTITIONED|
+                  -- EMPTY_TUPLE_SOURCE  |UNPARTITIONED|
\ No newline at end of file

Reply via email to