Steven Jacobs has uploaded a new change for review.

  https://asterix-gerrit.ics.uci.edu/1057

Change subject: Compile a plan that alligns with user query in the case of 
nonpure functions
......................................................................

Compile a plan that alligns with user query in the case of nonpure functions

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
---
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AbstractIntroduceAccessMethodRule.java
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/BTreeAccessMethod.java
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IOptimizableFuncExpr.java
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/OptimizableFuncExpr.java
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/OptimizableOperatorSubTree.java
A 
asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/global-datetime-no-index.aql
A 
asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/global-datetime-use-index.aql
A 
asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/local-datetime-ignore-index.aql
A 
asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/local-datetime-no-index.aql
M 
asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index/btree-datetime-02.plan
A 
asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/global-datetime-no-index.plan
A 
asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/global-datetime-use-index.plan
A 
asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/local-datetime-ignore-index.plan
A 
asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/local-datetime-no-index.plan
M 
asterixdb/asterix-app/src/test/resources/optimizerts/results/query_issue849.plan
M 
hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/util/OperatorManipulationUtil.java
M 
hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/InlineVariablesRule.java
M 
hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/SetExecutionModeRule.java
19 files changed, 421 insertions(+), 119 deletions(-)


  git pull ssh://asterix-gerrit.ics.uci.edu:29418/asterixdb 
refs/changes/57/1057/1

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 ed1803d..6e41273 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
@@ -1,18 +1,18 @@
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
+ * or more contributor license agreements. See the NOTICE file
  * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
+ * 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
+ * with the License. You may obtain a copy of the License at
  *
- *   http://www.apache.org/licenses/LICENSE-2.0
+ * 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
+ * KIND, either express or implied. See the License for the
  * specific language governing permissions and limitations
  * under the License.
  */
@@ -108,7 +108,7 @@
 
     protected void fillSubTreeIndexExprs(OptimizableOperatorSubTree subTree,
             Map<IAccessMethod, AccessMethodAnalysisContext> analyzedAMs, 
IOptimizationContext context)
-            throws AlgebricksException {
+                    throws AlgebricksException {
         Iterator<Map.Entry<IAccessMethod, AccessMethodAnalysisContext>> amIt = 
analyzedAMs.entrySet().iterator();
         // Check applicability of indexes by access method type.
         while (amIt.hasNext()) {
@@ -226,24 +226,24 @@
                     }
                     boolean typeMatch = true;
                     //Prune indexes based on field types
-                    List<IAType> indexedTypes = new ArrayList<IAType>();
+                    List<IAType> matchedTypes = new ArrayList<IAType>();
                     //retrieve types of expressions joined/selected with an 
indexed field
                     for (int j = 0; j < optFuncExpr.getNumLogicalVars(); j++) {
                         if (j != exprAndVarIdx.second) {
-                            indexedTypes.add(optFuncExpr.getFieldType(j));
+                            if (optFuncExpr.getFieldType(j) != null) {
+                                matchedTypes.add(optFuncExpr.getFieldType(j));
+                            }
                         }
                     }
 
-                    //add constants in case of select
-                    if (indexedTypes.size() < 2 && 
optFuncExpr.getNumLogicalVars() == 1
-                            && optFuncExpr.getNumConstantAtRuntimeExpr() > 0) {
-                        indexedTypes.add((IAType) 
AqlExpressionTypeComputer.INSTANCE.getType(
+                    if (matchedTypes.size() < 2 && 
optFuncExpr.getNumLogicalVars() == 1) {
+                        matchedTypes.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(
+                    matchedTypes.add((IAType) 
AqlExpressionTypeComputer.INSTANCE.getType(
                             optFuncExpr.getLogicalExpr(exprAndVarIdx.second), 
null, new IVariableTypeEnvironment() {
 
                                 @Override
@@ -257,7 +257,7 @@
                                 @Override
                                 public Object getVarType(LogicalVariable var, 
List<LogicalVariable> nonNullVariables,
                                         List<List<LogicalVariable>> 
correlatedNullableVariableLists)
-                                        throws AlgebricksException {
+                                                throws AlgebricksException {
                                     if 
(var.equals(optFuncExpr.getSourceVar(exprAndVarIdx.second))) {
                                         return keyType;
                                     }
@@ -285,9 +285,9 @@
                     boolean jaccardSimilarity = 
optFuncExpr.getFuncExpr().getFunctionIdentifier().getName()
                             .startsWith("similarity-jaccard-check");
 
-                    for (int j = 0; j < indexedTypes.size(); j++) {
-                        for (int k = j + 1; k < indexedTypes.size(); k++) {
-                            typeMatch &= isMatched(indexedTypes.get(j), 
indexedTypes.get(k), jaccardSimilarity);
+                    for (int j = 0; j < matchedTypes.size(); j++) {
+                        for (int k = j + 1; k < matchedTypes.size(); k++) {
+                            typeMatch &= isMatched(matchedTypes.get(j), 
matchedTypes.get(k), jaccardSimilarity);
                         }
                     }
 
@@ -435,7 +435,7 @@
     protected boolean fillIndexExprs(List<Index> datasetIndexes, List<String> 
fieldName, IAType fieldType,
             IOptimizableFuncExpr optFuncExpr, int matchedFuncExprIndex, int 
varIdx,
             OptimizableOperatorSubTree matchedSubTree, 
AccessMethodAnalysisContext analysisCtx)
-            throws AlgebricksException {
+                    throws AlgebricksException {
         List<Index> indexCandidates = new ArrayList<Index>();
         // Add an index to the candidates if one of the indexed fields is
         // fieldName
@@ -574,11 +574,12 @@
                     subTree.recordType, optVarIndex,
                     
optFuncExpr.getFuncExpr().getArguments().get(optVarIndex).getValue(), 
datasetRecordVar,
                     subTree.metaRecordType, datasetMetaVar);
+
             if (fieldName == null) {
                 continue;
             }
-            IAType fieldType = (IAType) 
context.getOutputTypeEnvironment(assignOp)
-                    .getType(optFuncExpr.getLogicalExpr(optVarIndex));
+
+            IAType fieldType = (IAType) 
context.getOutputTypeEnvironment(assignOp).getVarType(var);
             // Set the fieldName in the corresponding matched
             // function expression.
             optFuncExpr.setFieldName(optVarIndex, fieldName);
@@ -595,7 +596,7 @@
     private void matchVarsFromOptFuncExprToDataSourceScan(IOptimizableFuncExpr 
optFuncExpr, int optFuncExprIndex,
             List<Index> datasetIndexes, List<LogicalVariable> dsVarList, 
OptimizableOperatorSubTree subTree,
             AccessMethodAnalysisContext analysisCtx, IOptimizationContext 
context, boolean fromAdditionalDataSource)
-            throws AlgebricksException {
+                    throws AlgebricksException {
         for (int varIndex = 0; varIndex < dsVarList.size(); varIndex++) {
             LogicalVariable var = dsVarList.get(varIndex);
             int funcVarIndex = optFuncExpr.findLogicalVar(var);
@@ -666,7 +667,7 @@
     protected List<String> getFieldNameFromSubTree(IOptimizableFuncExpr 
optFuncExpr, OptimizableOperatorSubTree subTree,
             int opIndex, int assignVarIndex, ARecordType recordType, int 
funcVarIndex,
             ILogicalExpression parentFuncExpr, LogicalVariable recordVar, 
ARecordType metaType, LogicalVariable metaVar)
-            throws AlgebricksException {
+                    throws AlgebricksException {
         // Get expression corresponding to opVar at varIndex.
         AbstractLogicalExpression expr = null;
         AbstractFunctionCallExpression childFuncExpr = null;
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 db2c627..80ee907 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
@@ -1,18 +1,18 @@
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
+ * or more contributor license agreements. See the NOTICE file
  * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
+ * 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
+ * with the License. You may obtain a copy of the License at
  *
- *   http://www.apache.org/licenses/LICENSE-2.0
+ * 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
+ * KIND, either express or implied. See the License for the
  * specific language governing permissions and limitations
  * under the License.
  */
@@ -28,6 +28,7 @@
 import org.apache.asterix.common.config.DatasetConfig.DatasetType;
 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.external.indexing.IndexingConstants;
 import org.apache.asterix.lang.common.util.FunctionUtil;
 import org.apache.asterix.metadata.declared.AqlSourceId;
@@ -197,6 +198,7 @@
         } else {
             return false;
         }
+
         OptimizableFuncExpr newOptFuncExpr = new OptimizableFuncExpr(funcExpr,
                 new LogicalVariable[] { fieldVar1, fieldVar2 }, new 
ILogicalExpression[0], new IAType[0]);
         for (IOptimizableFuncExpr optFuncExpr : analysisCtx.matchedFuncExprs) {
@@ -303,19 +305,28 @@
     }
 
     /**
-     * Returns the search key expression which feeds a secondary-index search. 
If we are optimizing a selection query then this method returns
+     * 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.
+     * 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,
             OptimizableOperatorSubTree indexSubTree, 
OptimizableOperatorSubTree probeSubTree)
-            throws AlgebricksException {
+                    throws AlgebricksException {
         if (probeSubTree == null) {
             // We are optimizing a selection query. Search key is a constant.
             // Type Checking and type promotion is done here
             IAType fieldType = optFuncExpr.getFieldType(0);
+
+            if (optFuncExpr.getNumConstantAtRuntimeExpr() == 0) {
+                //We are looking at a nonpure case
+                //TODO: Right now we miss on type promotion for nonpure 
functions
+                return new Pair<ILogicalExpression, Boolean>(
+                        new 
VariableReferenceExpression(optFuncExpr.getLogicalVar(1)), false);
+            }
 
             ILogicalExpression constantAtRuntimeExpression = null;
             AsterixConstantValue constantValue = null;
@@ -399,7 +410,7 @@
     public static ILogicalOperator createSecondaryIndexUnnestMap(Dataset 
dataset, ARecordType recordType,
             ARecordType metaRecordType, Index index, ILogicalOperator inputOp, 
AccessMethodJobGenParams jobGenParams,
             IOptimizationContext context, boolean outputPrimaryKeysOnly, 
boolean retainInput, boolean retainNull)
-            throws AlgebricksException {
+                    throws AlgebricksException {
         // The job gen parameters are transferred to the actual job gen via 
the UnnestMapOperator's function arguments.
         ArrayList<Mutable<ILogicalExpression>> secondaryIndexFuncArgs = new 
ArrayList<Mutable<ILogicalExpression>>();
         jobGenParams.writeToFuncArgs(secondaryIndexFuncArgs);
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 4dc7bf4..e7aa59b 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
@@ -1,18 +1,18 @@
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
+ * or more contributor license agreements. See the NOTICE file
  * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
+ * 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
+ * with the License. You may obtain a copy of the License at
  *
- *   http://www.apache.org/licenses/LICENSE-2.0
+ * 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
+ * KIND, either express or implied. See the License for the
  * specific language governing permissions and limitations
  * under the License.
  */
@@ -102,6 +102,7 @@
     public boolean analyzeFuncExprArgs(AbstractFunctionCallExpression funcExpr,
             List<AbstractLogicalOperator> assignsAndUnnests, 
AccessMethodAnalysisContext analysisCtx,
             IOptimizationContext context, IVariableTypeEnvironment 
typeEnvironment) throws AlgebricksException {
+
         boolean matches = 
AccessMethodUtils.analyzeFuncExprArgsForOneConstAndVar(funcExpr, analysisCtx, 
context,
                 typeEnvironment);
         if (!matches) {
@@ -478,6 +479,18 @@
                     
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.root;
@@ -688,6 +701,9 @@
 
     private boolean probeIsOnLhs(IOptimizableFuncExpr optFuncExpr, 
OptimizableOperatorSubTree probeSubTree) {
         if (probeSubTree == null) {
+            if (optFuncExpr.getConstantAtRuntimeExpressions().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);
         } else {
@@ -708,6 +724,10 @@
     public boolean exprIsOptimizable(Index index, IOptimizableFuncExpr 
optFuncExpr) {
         // If we are optimizing a join, check for the indexed nested-loop join 
hint.
         if (optFuncExpr.getNumLogicalVars() == 2) {
+            if (optFuncExpr.getFieldType(0) == null || 
optFuncExpr.getFieldType(1) == null) {
+                //Nonpure nonjoin case
+                return true;
+            }
             if 
(!optFuncExpr.getFuncExpr().getAnnotations().containsKey(IndexedNLJoinExpressionAnnotation.INSTANCE))
 {
                 return false;
             }
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..fd3e4f4 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
@@ -1,18 +1,18 @@
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
+ * or more contributor license agreements. See the NOTICE file
  * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
+ * 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
+ * with the License. You may obtain a copy of the License at
  *
- *   http://www.apache.org/licenses/LICENSE-2.0
+ * 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
+ * KIND, either express or implied. See the License for the
  * specific language governing permissions and limitations
  * under the License.
  */
@@ -76,4 +76,6 @@
     IAType getConstantType(int index);
 
     void setConstantAtRuntimeExpr(int index, ILogicalExpression expr);
+
+    ILogicalExpression[] getConstantAtRuntimeExpressions();
 }
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..4b4084b 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
@@ -1,18 +1,18 @@
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
+ * or more contributor license agreements. See the NOTICE file
  * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
+ * 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
+ * with the License. You may obtain a copy of the License at
  *
- *   http://www.apache.org/licenses/LICENSE-2.0
+ * 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
+ * KIND, either express or implied. See the License for the
  * specific language governing permissions and limitations
  * under the License.
  */
@@ -143,6 +143,11 @@
     }
 
     @Override
+    public ILogicalExpression[] getConstantAtRuntimeExpressions() {
+        return constantAtRuntimeExpressions;
+    }
+
+    @Override
     public void setConstType(int index, IAType fieldType) {
         constantAtRuntimeExpressionTypes[index] = fieldType;
     }
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 d5a6f2b..7a849c8 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
@@ -1,18 +1,18 @@
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
+ * or more contributor license agreements. See the NOTICE file
  * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
+ * 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
+ * with the License. You may obtain a copy of the License at
  *
- *   http://www.apache.org/licenses/LICENSE-2.0
+ * 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
+ * KIND, either express or implied. See the License for the
  * specific language governing permissions and limitations
  * under the License.
  */
@@ -39,6 +39,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.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;
@@ -82,6 +83,8 @@
         reset();
         rootRef = subTreeOpRef;
         root = subTreeOpRef.getValue();
+        boolean exitLoop = false;
+        boolean result = false;
         // Examine the op's children to match the expected patterns.
         AbstractLogicalOperator subTreeOp = (AbstractLogicalOperator) 
subTreeOpRef.getValue();
         do {
@@ -94,20 +97,33 @@
             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(subTreeOpRef);
+                exitLoop = true;
+                if (!subTreeOp.getInputs().isEmpty()) {
+                    subTreeOpRef = subTreeOp.getInputs().get(0);
+                    subTreeOp = (AbstractLogicalOperator) 
subTreeOpRef.getValue();
+                }
             }
             // Match (assign | unnest)+.
             while ((subTreeOp.getOperatorTag() == LogicalOperatorTag.ASSIGN
-                    || subTreeOp.getOperatorTag() == 
LogicalOperatorTag.UNNEST)) {
+                    || subTreeOp.getOperatorTag() == LogicalOperatorTag.UNNEST
+                    || subTreeOp.getOperatorTag() == 
LogicalOperatorTag.EXCHANGE)) {
                 if (!OperatorPropertiesUtil.isMovable(subTreeOp)) {
                     return false;
-                } else {
-                    assignsAndUnnestsRefs.add(subTreeOpRef);
+                } else if (subTreeOp.getOperatorTag() == 
LogicalOperatorTag.ASSIGN
+                        || subTreeOp.getOperatorTag() == 
LogicalOperatorTag.UNNEST) {
+                    if (subTreeOp.getExecutionMode() != 
ExecutionMode.UNPARTITIONED) {
+                        //We won't need to move up the nonpure unpartitioned 
assigns
+                        assignsAndUnnestsRefs.add(subTreeOpRef);
+                    }
                     assignsAndUnnests.add(subTreeOp);
                 }
                 subTreeOpRef = subTreeOp.getInputs().get(0);
                 subTreeOp = (AbstractLogicalOperator) subTreeOpRef.getValue();
-            };
+            }
+            if (exitLoop) {
+                return result;
+            }
         } while (subTreeOp.getOperatorTag() == LogicalOperatorTag.SELECT);
 
         // Match data source (datasource scan or primary index search).
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..a637484
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/global-datetime-no-index.aql
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+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
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..0a1948e
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/global-datetime-use-index.aql
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+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
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..939bac0
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/local-datetime-ignore-index.aql
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+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
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..36d6530
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/nonpure/local-datetime-no-index.aql
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+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
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
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
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..0b2ff34
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/nonpure/global-datetime-use-index.plan
@@ -0,0 +1,8 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- STREAM_PROJECT  |PARTITIONED|
+      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+        -- BTREE_SEARCH  |PARTITIONED|
+          -- BROADCAST_EXCHANGE  |PARTITIONED|
+            -- ASSIGN  |UNPARTITIONED|
+              -- EMPTY_TUPLE_SOURCE  |UNPARTITIONED|
\ No newline at end of file
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
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
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/query_issue849.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/query_issue849.plan
index dd7b473..2ddb987 100644
--- 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/query_issue849.plan
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/query_issue849.plan
@@ -20,14 +20,10 @@
       -- ASSIGN  |PARTITIONED|
         -- STREAM_PROJECT  |PARTITIONED|
           -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-            -- HYBRID_HASH_JOIN [$$15][$$14]  |PARTITIONED|
-              -- HASH_PARTITION_EXCHANGE [$$15]  |PARTITIONED|
-                -- ASSIGN  |UNPARTITIONED|
-                  -- UNNEST  |UNPARTITIONED|
-                    -- EMPTY_TUPLE_SOURCE  |UNPARTITIONED|
+            -- BTREE_SEARCH  |PARTITIONED|
               -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                -- STREAM_PROJECT  |PARTITIONED|
-                  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                    -- DATASOURCE_SCAN  |PARTITIONED|
-                      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                        -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
+                -- STABLE_SORT [$$15(ASC)]  |PARTITIONED|
+                  -- HASH_PARTITION_EXCHANGE [$$15]  |PARTITIONED|
+                    -- ASSIGN  |UNPARTITIONED|
+                      -- UNNEST  |UNPARTITIONED|
+                        -- EMPTY_TUPLE_SOURCE  |UNPARTITIONED|
\ No newline at end of file
diff --git 
a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/util/OperatorManipulationUtil.java
 
b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/util/OperatorManipulationUtil.java
index 97aa853..dd11827 100644
--- 
a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/util/OperatorManipulationUtil.java
+++ 
b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/util/OperatorManipulationUtil.java
@@ -1,18 +1,18 @@
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
+ * or more contributor license agreements. See the NOTICE file
  * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
+ * 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
+ * with the License. You may obtain a copy of the License at
  *
- *   http://www.apache.org/licenses/LICENSE-2.0
+ * 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
+ * KIND, either express or implied. See the License for the
  * specific language governing permissions and limitations
  * under the License.
  */
@@ -25,20 +25,26 @@
 import org.apache.commons.lang3.mutable.Mutable;
 import org.apache.commons.lang3.mutable.MutableObject;
 import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
 import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
 import org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan;
 import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
+import org.apache.hyracks.algebricks.core.algebra.base.LogicalExpressionTag;
 import org.apache.hyracks.algebricks.core.algebra.base.LogicalOperatorTag;
 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.operators.logical.AbstractLogicalOperator;
 import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractOperatorWithNestedPlans;
 import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.AggregateOperator;
+import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.AssignOperator;
 import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.EmptyTupleSourceOperator;
+import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.ExchangeOperator;
 import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.LimitOperator;
 import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.NestedTupleSourceOperator;
 import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.SubplanOperator;
 import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.OperatorDeepCopyVisitor;
 import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities;
+import 
org.apache.hyracks.algebricks.core.algebra.operators.physical.BroadcastExchangePOperator;
 import org.apache.hyracks.algebricks.core.algebra.plan.ALogicalPlanImpl;
 import org.apache.hyracks.algebricks.core.algebra.typing.ITypingContext;
 
@@ -78,7 +84,82 @@
         return plan.getRoots().get(0).getValue();
     }
 
-    public static boolean setOperatorMode(AbstractLogicalOperator op) {
+    //returns an integer value
+    //TODO: Make this better before the commit!!!!
+    public static int planIsConstantPlanIsNonPure(AbstractLogicalOperator op) {
+        if (op.getInputs().size() > 1) {
+            return -1;
+        }
+        int result = 0;
+        if (op.getOperatorTag() == LogicalOperatorTag.ASSIGN) {
+            AssignOperator asOp = (AssignOperator) op;
+            result = checkAssignForNonPures(asOp);
+
+            if (result == -1) {
+                return result;
+            }
+
+            if (op.getInputs().size() == 1) {
+                if (op.getInputs().get(0).getValue().getOperatorTag() == 
LogicalOperatorTag.EMPTYTUPLESOURCE) {
+                    return result;
+                } else {
+                    int subResult = planIsConstantPlanIsNonPure(
+                            (AbstractLogicalOperator) 
op.getInputs().get(0).getValue());
+                    if (subResult == -1) {
+                        result = -1;
+                    } else if (subResult == 1 && result != -1) {
+                        result = 1;
+                    }
+
+                }
+            }
+
+        }
+        return result;
+    }
+
+    //return 1 for constants + nonpure only, 0 for constants only, -1 otherwise
+    private static int checkAssignForNonPures(AssignOperator asOp) {
+        int result = 0;
+        for (Mutable<ILogicalExpression> expr : asOp.getExpressions()) {
+            if (expr.getValue().getExpressionTag() == 
LogicalExpressionTag.FUNCTION_CALL) {
+                int subResult = 
checkFunctionForNonPures((AbstractFunctionCallExpression) expr.getValue());
+                if (subResult == -1) {
+                    result = -1;
+                } else if (subResult == 1 && result != -1) {
+                    result = 1;
+                }
+            } else if (expr.getValue().getExpressionTag() != 
LogicalExpressionTag.CONSTANT) {
+                return -1;
+            }
+        }
+        return result;
+    }
+
+    private static int checkFunctionForNonPures(AbstractFunctionCallExpression 
fExpr) {
+        if (!fExpr.getFunctionInfo().isFunctional()) {
+            return 1;
+
+        } else {
+            int result = 0;
+            for (Mutable<ILogicalExpression> expr : fExpr.getArguments()) {
+                if (expr.getValue().getExpressionTag() == 
LogicalExpressionTag.FUNCTION_CALL) {
+                    int subResult = 
checkFunctionForNonPures((AbstractFunctionCallExpression) expr.getValue());
+                    if (subResult == -1) {
+                        result = -1;
+                    } else if (subResult == 1 && result != -1) {
+                        result = 1;
+                    }
+                } else if (expr.getValue().getExpressionTag() != 
LogicalExpressionTag.CONSTANT) {
+                    return -1;
+                }
+            }
+            return result;
+        }
+    }
+
+    public static boolean setOperatorMode(AbstractLogicalOperator op, 
IOptimizationContext context)
+            throws AlgebricksException {
         boolean change = false;
         switch (op.getOperatorTag()) {
             case DATASOURCESCAN: {
@@ -89,6 +170,17 @@
                     if (child.getOperatorTag() == LogicalOperatorTag.EXCHANGE) 
{
                         break;
                     }
+                    int nonPureCheck = planIsConstantPlanIsNonPure(child);
+                    if (nonPureCheck == 1) {
+                        ExchangeOperator exchg = new ExchangeOperator();
+                        exchg.setPhysicalOperator(new 
BroadcastExchangePOperator(null));
+                        
exchg.setExecutionMode(AbstractLogicalOperator.ExecutionMode.PARTITIONED);
+                        exchg.getInputs().add(currentOp.getInputs().get(0));
+                        currentOp.getInputs().clear();
+                        currentOp.getInputs().add(new 
MutableObject<ILogicalOperator>(exchg));
+                        context.computeAndSetTypeEnvironmentForOperator(exchg);
+                        break;
+                    }
                     
child.setExecutionMode(AbstractLogicalOperator.ExecutionMode.PARTITIONED);
                     currentOp = child;
                 }
diff --git 
a/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/InlineVariablesRule.java
 
b/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/InlineVariablesRule.java
index b4ade4c..2dacca4 100644
--- 
a/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/InlineVariablesRule.java
+++ 
b/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/InlineVariablesRule.java
@@ -1,18 +1,18 @@
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
+ * or more contributor license agreements. See the NOTICE file
  * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
+ * 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
+ * with the License. You may obtain a copy of the License at
  *
- *   http://www.apache.org/licenses/LICENSE-2.0
+ * 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
+ * KIND, either express or implied. See the License for the
  * specific language governing permissions and limitations
  * under the License.
  */
@@ -118,25 +118,6 @@
         return false;
     }
 
-    /**
-     * An expression will be constant at runtime if it has:
-     * 1. A type
-     * 2. No free variables
-     *
-     * @param op
-     * @param funcExpr
-     * @param context
-     * @return whether a function is constant
-     * @throws AlgebricksException
-     */
-    public static boolean 
functionIsConstantAtRuntime(AbstractFunctionCallExpression funcExpr)
-            throws AlgebricksException {
-        //make sure that there are no variables in the expression
-        Set<LogicalVariable> usedVariables = new HashSet<>();
-        funcExpr.getUsedVariables(usedVariables);
-        return usedVariables.isEmpty();
-    }
-
     protected boolean inlineVariables(Mutable<ILogicalOperator> opRef, 
IOptimizationContext context)
             throws AlgebricksException {
         AbstractLogicalOperator op = (AbstractLogicalOperator) 
opRef.getValue();
@@ -151,8 +132,7 @@
                 // Ignore functions that are either in the doNotInline set or 
are non-functional
                 if (expr.getExpressionTag() == 
LogicalExpressionTag.FUNCTION_CALL) {
                     AbstractFunctionCallExpression funcExpr = 
(AbstractFunctionCallExpression) expr;
-                    if 
(doNotInlineFuncs.contains(funcExpr.getFunctionIdentifier()) || 
(!funcExpr.isFunctional()
-                            && 
!InlineVariablesRule.functionIsConstantAtRuntime(funcExpr))) {
+                    if 
(doNotInlineFuncs.contains(funcExpr.getFunctionIdentifier()) || 
!funcExpr.isFunctional()) {
                         continue;
                     }
                 }
diff --git 
a/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/SetExecutionModeRule.java
 
b/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/SetExecutionModeRule.java
index 63a33b5..13836bf 100644
--- 
a/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/SetExecutionModeRule.java
+++ 
b/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/SetExecutionModeRule.java
@@ -1,25 +1,25 @@
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
+ * or more contributor license agreements. See the NOTICE file
  * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
+ * 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
+ * with the License. You may obtain a copy of the License at
  *
- *   http://www.apache.org/licenses/LICENSE-2.0
+ * 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
+ * KIND, either express or implied. See the License for the
  * specific language governing permissions and limitations
  * under the License.
  */
 package org.apache.hyracks.algebricks.rewriter.rules;
 
 import org.apache.commons.lang3.mutable.Mutable;
-
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
 import org.apache.hyracks.algebricks.common.exceptions.NotImplementedException;
 import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
 import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
@@ -38,23 +38,24 @@
 public class SetExecutionModeRule implements IAlgebraicRewriteRule {
 
     @Override
-    public boolean rewritePost(Mutable<ILogicalOperator> opRef, 
IOptimizationContext context) {
+    public boolean rewritePost(Mutable<ILogicalOperator> opRef, 
IOptimizationContext context)
+            throws AlgebricksException {
         AbstractLogicalOperator op = (AbstractLogicalOperator) 
opRef.getValue();
-        boolean changed = OperatorManipulationUtil.setOperatorMode(op);
+        boolean changed = OperatorManipulationUtil.setOperatorMode(op, 
context);
         if (op.getExecutionMode() == 
AbstractLogicalOperator.ExecutionMode.UNPARTITIONED
                 || op.getExecutionMode() == 
AbstractLogicalOperator.ExecutionMode.LOCAL) {
             return changed;
         }
         switch (op.getOperatorTag()) {
-        // case DISTINCT:
-        // case AGGREGATE:
-        // case GROUP:
-        // case ORDER:
-        // case INNERJOIN:
-        // case LEFTOUTERJOIN: {
-        // op.setExecutionMode(ExecutionMode.GLOBAL);
-        // return true;
-        // }
+            // case DISTINCT:
+            // case AGGREGATE:
+            // case GROUP:
+            // case ORDER:
+            // case INNERJOIN:
+            // case LEFTOUTERJOIN: {
+            // op.setExecutionMode(ExecutionMode.GLOBAL);
+            // return true;
+            // }
 
             case PARTITIONINGSPLIT: {
                 throw new NotImplementedException();

-- 
To view, visit https://asterix-gerrit.ics.uci.edu/1057
To unsubscribe, visit https://asterix-gerrit.ics.uci.edu/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I2dec322b30835625430c06acd7626d902bada137
Gerrit-PatchSet: 1
Gerrit-Project: asterixdb
Gerrit-Branch: master
Gerrit-Owner: Steven Jacobs <sjaco...@ucr.edu>

Reply via email to