[NO ISSUE][COMP] Expand plan sanity check

- user model changes: no
- storage format changes: no
- interface changes: no

Details:
- Visit function arguments when performing plan
  sanity check
- Fix optimizer rules that we producing shared
  expression references in function arguments

Change-Id: Ib575a55fcc02c431f4dab80215ab343996f8f7de
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/10684
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Dmitry Lychagin <dmitry.lychagin@couchbase.com>
Reviewed-by: Ali Alsuliman <ali.al.solaiman@gmail.com>
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceSecondaryIndexInsertDeleteRule.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceSecondaryIndexInsertDeleteRule.java
index ed35026..07247fb 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceSecondaryIndexInsertDeleteRule.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceSecondaryIndexInsertDeleteRule.java
@@ -462,7 +462,8 @@
                         AbstractFunctionCallExpression createMBR = new ScalarFunctionCallExpression(
                                 FunctionUtil.getFunctionInfo(BuiltinFunctions.CREATE_MBR));
                         createMBR.setSourceLocation(sourceLoc);
-                        createMBR.getArguments().add(beforeOpSecondaryExpressions.get(0));
+                        createMBR.getArguments().add(
+                                new MutableObject<>(beforeOpSecondaryExpressions.get(0).getValue().cloneExpression()));
                         createMBR.getArguments().add(new MutableObject<ILogicalExpression>(
                                 new ConstantExpression(new AsterixConstantValue(new AInt32(dimension)))));
                         createMBR.getArguments().add(new MutableObject<ILogicalExpression>(
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushAggFuncIntoStandaloneAggregateRule.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushAggFuncIntoStandaloneAggregateRule.java
index 70b5450..1dfa0eb 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushAggFuncIntoStandaloneAggregateRule.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushAggFuncIntoStandaloneAggregateRule.java
@@ -43,6 +43,7 @@
 import org.apache.hyracks.algebricks.core.algebra.operators.logical.AssignOperator;
 import org.apache.hyracks.algebricks.core.algebra.operators.logical.GroupByOperator;
 import org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities;
+import org.apache.hyracks.algebricks.core.algebra.util.OperatorManipulationUtil;
 import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
 
 /**
@@ -211,10 +212,12 @@
                         BuiltinFunctions.getAggregateFunction(assignScalarAggExpr.getFunctionIdentifier());
 
                 // Push the scalar aggregate function into the aggregate op.
-                int sz = assignScalarAggExpr.getArguments().size();
-                List<Mutable<ILogicalExpression>> aggArgs = new ArrayList<>(sz);
-                aggArgs.add(listifyCandidateExpr.getArguments().get(0));
-                aggArgs.addAll(assignScalarAggExpr.getArguments().subList(1, sz));
+                int nArgs = assignScalarAggExpr.getArguments().size();
+                List<Mutable<ILogicalExpression>> aggArgs = new ArrayList<>(nArgs);
+                aggArgs.add(
+                        new MutableObject<>(listifyCandidateExpr.getArguments().get(0).getValue().cloneExpression()));
+                aggArgs.addAll(OperatorManipulationUtil
+                        .cloneExpressions(assignScalarAggExpr.getArguments().subList(1, nArgs)));
                 AggregateFunctionCallExpression aggFuncExpr =
                         BuiltinFunctions.makeAggregateFunctionExpression(aggFuncIdent, aggArgs);
                 aggFuncExpr.setSourceLocation(assignScalarAggExpr.getSourceLocation());
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushAggregateIntoNestedSubplanRule.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushAggregateIntoNestedSubplanRule.java
index d5f7b0a..d2ac8e5 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushAggregateIntoNestedSubplanRule.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushAggregateIntoNestedSubplanRule.java
@@ -254,9 +254,9 @@
                     if (a1.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
                         LogicalVariable argVar = ((VariableReferenceExpression) a1).getVariableReference();
                         AbstractOperatorWithNestedPlans nspOp = nspWithAgg.get(argVar);
-
                         if (nspOp != null) {
-                            if (!aggregateExprToVarExpr.containsKey(expr)) {
+                            ILogicalExpression varExpr = aggregateExprToVarExpr.get(expr);
+                            if (varExpr == null) {
                                 LogicalVariable newVar = context.newVar();
                                 AggregateFunctionCallExpression aggFun =
                                         BuiltinFunctions.makeAggregateFunctionExpression(fi, fce.getArguments());
@@ -267,8 +267,7 @@
                                 aggregateExprToVarExpr.put(expr, newVarExpr);
                                 return new Pair<>(Boolean.TRUE, newVarExpr);
                             } else {
-                                ILogicalExpression varExpr = aggregateExprToVarExpr.get(expr);
-                                return new Pair<>(Boolean.TRUE, varExpr);
+                                return new Pair<>(Boolean.TRUE, varExpr.cloneExpression());
                             }
                         }
                     }
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 c1ae61e..80bf943 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
@@ -266,7 +266,7 @@
                     new ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(BuiltinFunctions.CREATE_MBR));
             createMBR.setSourceLocation(optFuncExpr.getFuncExpr().getSourceLocation());
             // Spatial object is the constant from the func expr we are optimizing.
-            createMBR.getArguments().add(new MutableObject<>(returnedSearchKeyExpr));
+            createMBR.getArguments().add(new MutableObject<>(returnedSearchKeyExpr.cloneExpression()));
             // The number of dimensions
             createMBR.getArguments().add(new MutableObject<ILogicalExpression>(
                     new ConstantExpression(new AsterixConstantValue(new AInt32(numDimensions)))));
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/temporal/TranslateIntervalExpressionRule.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/temporal/TranslateIntervalExpressionRule.java
index 5b85cb6..d7dcb0c 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/temporal/TranslateIntervalExpressionRule.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/temporal/TranslateIntervalExpressionRule.java
@@ -19,6 +19,7 @@
 package org.apache.asterix.optimizer.rules.temporal;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -47,15 +48,10 @@
  */
 public class TranslateIntervalExpressionRule implements IAlgebraicRewriteRule {
 
-    private static final Set<FunctionIdentifier> TRANSLATABLE_INTERVALS = new HashSet<>();
-    {
-        TRANSLATABLE_INTERVALS.add(BuiltinFunctions.INTERVAL_MEETS);
-        TRANSLATABLE_INTERVALS.add(BuiltinFunctions.INTERVAL_MET_BY);
-        TRANSLATABLE_INTERVALS.add(BuiltinFunctions.INTERVAL_STARTS);
-        TRANSLATABLE_INTERVALS.add(BuiltinFunctions.INTERVAL_STARTED_BY);
-        TRANSLATABLE_INTERVALS.add(BuiltinFunctions.INTERVAL_ENDS);
-        TRANSLATABLE_INTERVALS.add(BuiltinFunctions.INTERVAL_ENDED_BY);
-    }
+    private static final Set<FunctionIdentifier> TRANSLATABLE_INTERVALS =
+            new HashSet<>(Arrays.asList(BuiltinFunctions.INTERVAL_MEETS, BuiltinFunctions.INTERVAL_MET_BY,
+                    BuiltinFunctions.INTERVAL_STARTS, BuiltinFunctions.INTERVAL_STARTED_BY,
+                    BuiltinFunctions.INTERVAL_ENDS, BuiltinFunctions.INTERVAL_ENDED_BY));
 
     @Override
     public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
@@ -84,93 +80,94 @@
         if (!hasTranslatableInterval(funcExpr)) {
             return false;
         }
-
-        return translateIntervalExpression(exprRef, funcExpr);
+        ILogicalExpression newExpr = translateIntervalExpression(funcExpr);
+        if (newExpr == null) {
+            return false;
+        }
+        exprRef.setValue(newExpr);
+        return true;
     }
 
     private boolean hasTranslatableInterval(AbstractFunctionCallExpression funcExpr) {
-        if (TRANSLATABLE_INTERVALS.contains(funcExpr.getFunctionIdentifier())) {
-            return true;
-        }
-        return false;
+        return TRANSLATABLE_INTERVALS.contains(funcExpr.getFunctionIdentifier());
     }
 
-    private boolean translateIntervalExpression(Mutable<ILogicalExpression> exprRef,
-            AbstractFunctionCallExpression funcExpr) {
+    private ILogicalExpression translateIntervalExpression(AbstractFunctionCallExpression funcExpr) {
         // All interval relations are translated unless specified in a hint.
         // TODO A new strategy may be needed instead of just a simple translation.
         ILogicalExpression interval1 = funcExpr.getArguments().get(0).getValue();
         ILogicalExpression interval2 = funcExpr.getArguments().get(1).getValue();
         if (funcExpr.getFunctionIdentifier().equals(BuiltinFunctions.INTERVAL_MEETS)) {
-            exprRef.setValue(getEqualExpr(getIntervalEndExpr(interval1), getIntervalStartExpr(interval2)));
+            return getEqualExpr(getIntervalEndExpr(interval1), getIntervalStartExpr(interval2));
         } else if (funcExpr.getFunctionIdentifier().equals(BuiltinFunctions.INTERVAL_MET_BY)) {
-            exprRef.setValue(getEqualExpr(getIntervalStartExpr(interval1), getIntervalEndExpr(interval2)));
+            return getEqualExpr(getIntervalStartExpr(interval1), getIntervalEndExpr(interval2));
         } else if (funcExpr.getFunctionIdentifier().equals(BuiltinFunctions.INTERVAL_STARTS)) {
             ILogicalExpression startExpr =
                     getEqualExpr(getIntervalStartExpr(interval1), getIntervalStartExpr(interval2));
-            ILogicalExpression endExpr =
-                    getLessThanOrEqualExpr(getIntervalEndExpr(interval1), getIntervalEndExpr(interval2));
-            exprRef.setValue(getAndExpr(startExpr, endExpr));
+            ILogicalExpression endExpr = getLessThanOrEqualExpr(getIntervalEndExpr(interval1.cloneExpression()),
+                    getIntervalEndExpr(interval2.cloneExpression()));
+            return getAndExpr(startExpr, endExpr);
         } else if (funcExpr.getFunctionIdentifier().equals(BuiltinFunctions.INTERVAL_STARTED_BY)) {
             ILogicalExpression startExpr =
                     getEqualExpr(getIntervalStartExpr(interval1), getIntervalStartExpr(interval2));
-            ILogicalExpression endExpr =
-                    getLessThanOrEqualExpr(getIntervalEndExpr(interval2), getIntervalEndExpr(interval1));
-            exprRef.setValue(getAndExpr(startExpr, endExpr));
+            ILogicalExpression endExpr = getLessThanOrEqualExpr(getIntervalEndExpr(interval2.cloneExpression()),
+                    getIntervalEndExpr(interval1.cloneExpression()));
+            return getAndExpr(startExpr, endExpr);
         } else if (funcExpr.getFunctionIdentifier().equals(BuiltinFunctions.INTERVAL_ENDS)) {
             ILogicalExpression endExpr = getEqualExpr(getIntervalEndExpr(interval1), getIntervalEndExpr(interval2));
-            ILogicalExpression startExpr =
-                    getLessThanOrEqualExpr(getIntervalStartExpr(interval1), getIntervalStartExpr(interval2));
-            exprRef.setValue(getAndExpr(startExpr, endExpr));
+            ILogicalExpression startExpr = getLessThanOrEqualExpr(getIntervalStartExpr(interval1.cloneExpression()),
+                    getIntervalStartExpr(interval2.cloneExpression()));
+            return getAndExpr(startExpr, endExpr);
         } else if (funcExpr.getFunctionIdentifier().equals(BuiltinFunctions.INTERVAL_ENDED_BY)) {
             ILogicalExpression endExpr = getEqualExpr(getIntervalEndExpr(interval1), getIntervalEndExpr(interval2));
-            ILogicalExpression startExpr =
-                    getLessThanOrEqualExpr(getIntervalStartExpr(interval2), getIntervalStartExpr(interval1));
-            exprRef.setValue(getAndExpr(startExpr, endExpr));
+            ILogicalExpression startExpr = getLessThanOrEqualExpr(getIntervalStartExpr(interval2.cloneExpression()),
+                    getIntervalStartExpr(interval1.cloneExpression()));
+            return getAndExpr(startExpr, endExpr);
         } else if (funcExpr.getFunctionIdentifier().equals(BuiltinFunctions.INTERVAL_BEFORE)) {
-            exprRef.setValue(getLessThanExpr(getIntervalEndExpr(interval1), getIntervalStartExpr(interval2)));
+            return getLessThanExpr(getIntervalEndExpr(interval1), getIntervalStartExpr(interval2));
         } else if (funcExpr.getFunctionIdentifier().equals(BuiltinFunctions.INTERVAL_AFTER)) {
-            exprRef.setValue(getGreaterThanExpr(getIntervalStartExpr(interval1), getIntervalEndExpr(interval2)));
+            return getGreaterThanExpr(getIntervalStartExpr(interval1), getIntervalEndExpr(interval2));
         } else if (funcExpr.getFunctionIdentifier().equals(BuiltinFunctions.INTERVAL_OVERLAPS)) {
             ILogicalExpression expr1 =
                     getLessThanExpr(getIntervalStartExpr(interval1), getIntervalStartExpr(interval2));
-            ILogicalExpression expr2 = getGreaterThanExpr(getIntervalEndExpr(interval2), getIntervalEndExpr(interval1));
-            ILogicalExpression expr3 =
-                    getGreaterThanExpr(getIntervalEndExpr(interval1), getIntervalStartExpr(interval2));
-            exprRef.setValue(getAndExpr(getAndExpr(expr1, expr2), expr3));
+            ILogicalExpression expr2 = getGreaterThanExpr(getIntervalEndExpr(interval2.cloneExpression()),
+                    getIntervalEndExpr(interval1.cloneExpression()));
+            ILogicalExpression expr3 = getGreaterThanExpr(getIntervalEndExpr(interval1.cloneExpression()),
+                    getIntervalStartExpr(interval2.cloneExpression()));
+            return getAndExpr(getAndExpr(expr1, expr2), expr3);
         } else if (funcExpr.getFunctionIdentifier().equals(BuiltinFunctions.INTERVAL_OVERLAPPED_BY)) {
             ILogicalExpression expr1 =
                     getLessThanExpr(getIntervalStartExpr(interval2), getIntervalStartExpr(interval1));
-            ILogicalExpression expr2 = getGreaterThanExpr(getIntervalEndExpr(interval1), getIntervalEndExpr(interval2));
-            ILogicalExpression expr3 =
-                    getGreaterThanExpr(getIntervalEndExpr(interval2), getIntervalStartExpr(interval1));
-            exprRef.setValue(getAndExpr(getAndExpr(expr1, expr2), expr3));
+            ILogicalExpression expr2 = getGreaterThanExpr(getIntervalEndExpr(interval1.cloneExpression()),
+                    getIntervalEndExpr(interval2.cloneExpression()));
+            ILogicalExpression expr3 = getGreaterThanExpr(getIntervalEndExpr(interval2.cloneExpression()),
+                    getIntervalStartExpr(interval1.cloneExpression()));
+            return getAndExpr(getAndExpr(expr1, expr2), expr3);
         } else if (funcExpr.getFunctionIdentifier().equals(BuiltinFunctions.INTERVAL_OVERLAPPING)) {
             ILogicalExpression startExpr =
                     getLessThanOrEqualExpr(getIntervalStartExpr(interval1), getIntervalEndExpr(interval2));
-            ILogicalExpression endExpr =
-                    getGreaterThanOrEqualExpr(getIntervalEndExpr(interval1), getIntervalStartExpr(interval2));
-            ILogicalExpression startPointExpr =
-                    getNotEqualExpr(getIntervalEndExpr(interval1), getIntervalStartExpr(interval2));
-            ILogicalExpression endPointExpr =
-                    getNotEqualExpr(getIntervalStartExpr(interval1), getIntervalEndExpr(interval2));
-            exprRef.setValue(getAndExpr(getAndExpr(startExpr, endExpr), getAndExpr(startPointExpr, endPointExpr)));
+            ILogicalExpression endExpr = getGreaterThanOrEqualExpr(getIntervalEndExpr(interval1.cloneExpression()),
+                    getIntervalStartExpr(interval2.cloneExpression()));
+            ILogicalExpression startPointExpr = getNotEqualExpr(getIntervalEndExpr(interval1.cloneExpression()),
+                    getIntervalStartExpr(interval2.cloneExpression()));
+            ILogicalExpression endPointExpr = getNotEqualExpr(getIntervalStartExpr(interval1.cloneExpression()),
+                    getIntervalEndExpr(interval2.cloneExpression()));
+            return getAndExpr(getAndExpr(startExpr, endExpr), getAndExpr(startPointExpr, endPointExpr));
         } else if (funcExpr.getFunctionIdentifier().equals(BuiltinFunctions.INTERVAL_COVERS)) {
             ILogicalExpression startExpr =
                     getLessThanOrEqualExpr(getIntervalStartExpr(interval1), getIntervalStartExpr(interval2));
-            ILogicalExpression endExpr =
-                    getGreaterThanOrEqualExpr(getIntervalEndExpr(interval1), getIntervalEndExpr(interval2));
-            exprRef.setValue(getAndExpr(startExpr, endExpr));
+            ILogicalExpression endExpr = getGreaterThanOrEqualExpr(getIntervalEndExpr(interval1.cloneExpression()),
+                    getIntervalEndExpr(interval2.cloneExpression()));
+            return getAndExpr(startExpr, endExpr);
         } else if (funcExpr.getFunctionIdentifier().equals(BuiltinFunctions.INTERVAL_COVERED_BY)) {
             ILogicalExpression startExpr =
                     getLessThanOrEqualExpr(getIntervalStartExpr(interval2), getIntervalStartExpr(interval1));
-            ILogicalExpression endExpr =
-                    getGreaterThanOrEqualExpr(getIntervalEndExpr(interval2), getIntervalEndExpr(interval1));
-            exprRef.setValue(getAndExpr(startExpr, endExpr));
+            ILogicalExpression endExpr = getGreaterThanOrEqualExpr(getIntervalEndExpr(interval2.cloneExpression()),
+                    getIntervalEndExpr(interval1.cloneExpression()));
+            return getAndExpr(startExpr, endExpr);
         } else {
-            return false;
+            return null;
         }
-        return true;
     }
 
     private ILogicalExpression getAndExpr(ILogicalExpression arg1, ILogicalExpression arg2) {
@@ -211,7 +208,7 @@
 
     private ILogicalExpression getScalarExpr(FunctionIdentifier func, ILogicalExpression interval) {
         List<Mutable<ILogicalExpression>> intervalArg = new ArrayList<>();
-        intervalArg.add(new MutableObject<ILogicalExpression>(interval));
+        intervalArg.add(new MutableObject<>(interval));
         ScalarFunctionCallExpression fnExpr =
                 new ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(func), intervalArg);
         fnExpr.setSourceLocation(interval.getSourceLocation());
@@ -221,8 +218,8 @@
     private ILogicalExpression getScalarExpr(FunctionIdentifier func, ILogicalExpression interval1,
             ILogicalExpression interval2) {
         List<Mutable<ILogicalExpression>> intervalArg = new ArrayList<>();
-        intervalArg.add(new MutableObject<ILogicalExpression>(interval1));
-        intervalArg.add(new MutableObject<ILogicalExpression>(interval2));
+        intervalArg.add(new MutableObject<>(interval1));
+        intervalArg.add(new MutableObject<>(interval2));
         ScalarFunctionCallExpression fnExpr =
                 new ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(func), intervalArg);
         fnExpr.setSourceLocation(interval1.getSourceLocation());
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/util/IntervalJoinUtils.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/util/IntervalJoinUtils.java
index dbe1c9e..e10f9fb 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/util/IntervalJoinUtils.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/util/IntervalJoinUtils.java
@@ -216,16 +216,22 @@
     private static void insertPartitionSortKey(AbstractBinaryJoinOperator op, int branch,
             List<LogicalVariable> partitionVars, LogicalVariable intervalVar, IOptimizationContext context)
             throws AlgebricksException {
-        Mutable<ILogicalExpression> intervalExp = new MutableObject<>(new VariableReferenceExpression(intervalVar));
-
         List<Mutable<ILogicalExpression>> assignExps = new ArrayList<>();
         // Start partition
+        VariableReferenceExpression intervalVarRef1 = new VariableReferenceExpression(intervalVar);
+        intervalVarRef1.setSourceLocation(op.getSourceLocation());
         IFunctionInfo startFi = FunctionUtil.getFunctionInfo(BuiltinFunctions.ACCESSOR_TEMPORAL_INTERVAL_START);
-        ScalarFunctionCallExpression startPartitionExp = new ScalarFunctionCallExpression(startFi, intervalExp);
+        ScalarFunctionCallExpression startPartitionExp =
+                new ScalarFunctionCallExpression(startFi, new MutableObject<>(intervalVarRef1));
+        startPartitionExp.setSourceLocation(op.getSourceLocation());
         assignExps.add(new MutableObject<>(startPartitionExp));
         // End partition
+        VariableReferenceExpression intervalVarRef2 = new VariableReferenceExpression(intervalVar);
+        intervalVarRef2.setSourceLocation(op.getSourceLocation());
         IFunctionInfo endFi = FunctionUtil.getFunctionInfo(BuiltinFunctions.ACCESSOR_TEMPORAL_INTERVAL_END);
-        ScalarFunctionCallExpression endPartitionExp = new ScalarFunctionCallExpression(endFi, intervalExp);
+        ScalarFunctionCallExpression endPartitionExp =
+                new ScalarFunctionCallExpression(endFi, new MutableObject<>(intervalVarRef2));
+        endPartitionExp.setSourceLocation(op.getSourceLocation());
         assignExps.add(new MutableObject<>(endPartitionExp));
 
         AssignOperator ao = new AssignOperator(partitionVars, assignExps);
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
index 24e1db8..fd689a5 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
@@ -1972,10 +1972,10 @@
     protected Mutable<ILogicalExpression> generateAndNotIsUnknownWrap(ILogicalExpression logicalExpr) {
         SourceLocation sourceLoc = logicalExpr.getSourceLocation();
         List<Mutable<ILogicalExpression>> arguments = new ArrayList<>();
-        arguments.add(new MutableObject<>(logicalExpr));
+        arguments.add(new MutableObject<>(logicalExpr.cloneExpression()));
         ScalarFunctionCallExpression isUnknownExpr =
                 new ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(BuiltinFunctions.IS_UNKNOWN),
-                        new ArrayList<>(Collections.singletonList(new MutableObject<>(logicalExpr))));
+                        new ArrayList<>(Collections.singletonList(new MutableObject<>(logicalExpr.cloneExpression()))));
         isUnknownExpr.setSourceLocation(sourceLoc);
         ScalarFunctionCallExpression notExpr =
                 new ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(BuiltinFunctions.NOT),
diff --git a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/LogicalExpressionDeepCopyWithNewVariablesVisitor.java b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/LogicalExpressionDeepCopyWithNewVariablesVisitor.java
index 13a758c..fe3abf2 100644
--- a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/LogicalExpressionDeepCopyWithNewVariablesVisitor.java
+++ b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/LogicalExpressionDeepCopyWithNewVariablesVisitor.java
@@ -156,7 +156,9 @@
             throws AlgebricksException {
         LogicalVariable var = expr.getVariableReference();
         if (freeVars.contains(var)) {
-            return expr;
+            VariableReferenceExpression varRef = new VariableReferenceExpression(var);
+            copySourceLocation(expr, varRef);
+            return varRef;
         }
         LogicalVariable givenVarReplacement = inVarMapping.get(var);
         if (givenVarReplacement != null) {
diff --git a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/plan/PlanStructureVerifier.java b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/plan/PlanStructureVerifier.java
index 434b46e..a072d11 100644
--- a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/plan/PlanStructureVerifier.java
+++ b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/plan/PlanStructureVerifier.java
@@ -43,6 +43,7 @@
 import org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan;
 import org.apache.hyracks.algebricks.core.algebra.base.LogicalExpressionTag;
 import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable;
+import org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
 import org.apache.hyracks.algebricks.core.algebra.expressions.IVariableTypeEnvironment;
 import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractOperatorWithNestedPlans;
 import org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities;
@@ -303,6 +304,12 @@
                             PlanStabilityVerifier.printExpression(expr, prettyPrinter), firstOp, currentOp);
                 }
             }
+            if (expr.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
+                AbstractFunctionCallExpression callExpr = (AbstractFunctionCallExpression) expr;
+                for (Mutable<ILogicalExpression> argRef : callExpr.getArguments()) {
+                    transform(argRef);
+                }
+            }
             return false;
         }
     }
diff --git a/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/EnforceStructuralPropertiesRule.java b/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/EnforceStructuralPropertiesRule.java
index cf95d01..3ae1218 100644
--- a/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/EnforceStructuralPropertiesRule.java
+++ b/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/EnforceStructuralPropertiesRule.java
@@ -807,7 +807,7 @@
             fields.add(new MutableObject<>(varExprRef));
             // add the same field as input to the corresponding local function propagating the type of the field
             expr = new AggregateFunctionCallExpression(typeFun, false,
-                    Collections.singletonList(new MutableObject<>(varExprRef)));
+                    Collections.singletonList(new MutableObject<>(varExprRef.cloneExpression())));
             // add the type propagating function to the list of the local functions
             localOutVariable = context.newVar();
             localResultVariables.add(localOutVariable);
diff --git a/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/InlineAssignIntoAggregateRule.java b/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/InlineAssignIntoAggregateRule.java
index ed43f29..d966ed1 100644
--- a/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/InlineAssignIntoAggregateRule.java
+++ b/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/InlineAssignIntoAggregateRule.java
@@ -138,7 +138,7 @@
                 ILogicalExpression e = eRef.getValue();
                 Pair<Boolean, ILogicalExpression> p = e.accept(this, arg);
                 if (p.first) {
-                    eRef.setValue(p.second);
+                    eRef.setValue(p.second.cloneExpression());
                     changed = true;
                 }
             }