[ASTERIXDB-3341][COMP]: CBO choosing bad indexes (CH2 Q8)

Change-Id: Iee097528ef3792bfb55636a140e2519b67bcc29e
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/18102
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: <murali.krishna@couchbase.com>
Reviewed-by: Vijay Sarathy <vijay.sarathy@couchbase.com>
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 27bae51..894fd93 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
@@ -629,8 +629,8 @@
                     continue;
                 }
                 AbstractFunctionCallExpression argFuncExpr = (AbstractFunctionCallExpression) argExpr;
-                boolean matchFound = analyzeFunctionExprAndUpdateAnalyzedAM(argFuncExpr, assignsAndUnnests, analyzedAMs,
-                        context, typeEnvironment);
+                boolean matchFound = analyzeSelectOrJoinOpConditionAndUpdateAnalyzedAM(argFuncExpr, assignsAndUnnests,
+                        analyzedAMs, context, typeEnvironment);
                 found = found || matchFound;
             }
             return found;
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/EnumerateJoinsRule.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/EnumerateJoinsRule.java
index 187a8ee..980f281 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/EnumerateJoinsRule.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/EnumerateJoinsRule.java
@@ -420,7 +420,7 @@
         return nextOp;
     }
 
-    private ILogicalOperator findSelectOrDataScan(ILogicalOperator op) {
+    private ILogicalOperator findSelectOrUnnestOrDataScan(ILogicalOperator op) {
         LogicalOperatorTag tag;
         ILogicalOperator currentOp = op;
         while (true) {
@@ -431,7 +431,8 @@
             if (tag == LogicalOperatorTag.EMPTYTUPLESOURCE) {
                 return null; // if this happens, there is nothing we can do in CBO code since there is no datasourcescan
             }
-            if ((tag == LogicalOperatorTag.SELECT) || (tag == LogicalOperatorTag.DATASOURCESCAN)) {
+            if ((tag == LogicalOperatorTag.SELECT) || (tag == LogicalOperatorTag.UNNEST)
+                    || (tag == LogicalOperatorTag.DATASOURCESCAN)) {
                 return currentOp;
             }
 
@@ -685,7 +686,7 @@
                 EmptyTupleSourceOperator etsOp = etsDataSource.first;
                 DataSourceScanOperator dataSourceOp = etsDataSource.second;
                 if (op.getOperatorTag().equals(LogicalOperatorTag.DISTRIBUTE_RESULT)) {// single table query
-                    ILogicalOperator selectOp = findSelectOrDataScan(op);
+                    ILogicalOperator selectOp = findSelectOrUnnestOrDataScan(op);
                     if (selectOp == null) {
                         return false;
                     } else {
@@ -759,7 +760,7 @@
         afcExpr.removeAnnotation(HashJoinExpressionAnnotation.class);
     }
 
-    private void setAnnotation(AbstractFunctionCallExpression afcExpr, IExpressionAnnotation anno) {
+    protected static void setAnnotation(AbstractFunctionCallExpression afcExpr, IExpressionAnnotation anno) {
         FunctionIdentifier fi = afcExpr.getFunctionIdentifier();
         List<Mutable<ILogicalExpression>> arguments = afcExpr.getArguments();
 
@@ -829,7 +830,7 @@
     private void buildNewTree(PlanNode plan) {
         ILogicalOperator leftInput = plan.getLeafInput();
         skipAllIndexes(plan, leftInput);
-        ILogicalOperator selOp = findSelectOrDataScan(leftInput);
+        ILogicalOperator selOp = findSelectOrUnnestOrDataScan(leftInput);
         if (selOp != null) {
             addCardCostAnnotations(selOp, plan);
         }
@@ -936,7 +937,7 @@
             // leaf
             ILogicalOperator leftInput = leftPlan.getLeafInput();
             skipAllIndexes(leftPlan, leftInput);
-            ILogicalOperator selOp = findSelectOrDataScan(leftInput);
+            ILogicalOperator selOp = findSelectOrUnnestOrDataScan(leftInput);
             if (selOp != null) {
                 addCardCostAnnotations(selOp, leftPlan);
             }
@@ -956,7 +957,7 @@
             // leaf
             ILogicalOperator rightInput = rightPlan.getLeafInput();
             skipAllIndexes(rightPlan, rightInput);
-            ILogicalOperator selOp = findSelectOrDataScan(rightInput);
+            ILogicalOperator selOp = findSelectOrUnnestOrDataScan(rightInput);
             if (selOp != null) {
                 addCardCostAnnotations(selOp, rightPlan);
             }
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinEnum.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinEnum.java
index 7c7e20c..4d8ca67 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinEnum.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinEnum.java
@@ -967,7 +967,7 @@
         return null;
     }
 
-    private boolean findUnnestOp(ILogicalOperator op) {
+    protected boolean findUnnestOp(ILogicalOperator op) {
         ILogicalOperator currentOp = op;
         while (currentOp != null && currentOp.getOperatorTag() != LogicalOperatorTag.EMPTYTUPLESOURCE) {
             if (currentOp.getOperatorTag().equals(LogicalOperatorTag.UNNEST)) {
@@ -995,13 +995,16 @@
                 ILogicalOperator leafInput = findLeafInput(vars);
                 SelectOperator selOp;
                 if (leafInput.getOperatorTag().equals(LogicalOperatorTag.SELECT)) {
-                    selOp = (SelectOperator) leafInput;
+                    selOp = (SelectOperator) getStatsHandle().findSelectOpWithExpr(leafInput, exp);
+                    if (selOp == null) {
+                        selOp = (SelectOperator) leafInput;
+                    }
                 } else {
                     selOp = new SelectOperator(new MutableObject<>(exp));
                     selOp.getInputs().add(new MutableObject<>(leafInput));
                 }
                 sel = getStatsHandle().findSelectivityForThisPredicate(selOp, (AbstractFunctionCallExpression) exp,
-                        findUnnestOp(leafInput));
+                        findUnnestOp(selOp));
                 // Sometimes the sample query returns greater more rows than the sample size. Cap the selectivity to 0.9999
                 sel = Math.min(sel, 0.9999);
 
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinNode.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinNode.java
index b2ed5ed..52caaf3 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinNode.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinNode.java
@@ -617,7 +617,7 @@
             if (IndexCostInfo.get(i).second == -1.0) {
                 AbstractFunctionCallExpression afce = IndexCostInfo.get(i).third;
                 // this index has to be skipped, so find the corresponding expression
-                afce.putAnnotation(SkipSecondaryIndexSearchExpressionAnnotation
+                EnumerateJoinsRule.setAnnotation(afce, SkipSecondaryIndexSearchExpressionAnnotation
                         .newInstance(Collections.singleton(IndexCostInfo.get(i).first.getIndexName())));
             }
         }
@@ -650,13 +650,17 @@
                     sel = selectivityAnnotation.getSelectivity();
                 } else {
                     if (leafInput.getOperatorTag().equals(LogicalOperatorTag.SELECT)) {
-                        selOp = (SelectOperator) leafInput;
+                        selOp = (SelectOperator) joinEnum.getStatsHandle().findSelectOpWithExpr(leafInput, afce);
+                        if (selOp == null) {
+                            selOp = (SelectOperator) leafInput;
+                        }
                     } else {
                         selOp = new SelectOperator(new MutableObject<>(afce));
                         selOp.getInputs().add(new MutableObject<>(leafInput));
                     }
                     sel = joinEnum.getStatsHandle().findSelectivityForThisPredicate(selOp, afce,
-                            chosenIndex.getIndexType().equals(DatasetConfig.IndexType.ARRAY));
+                            chosenIndex.getIndexType().equals(DatasetConfig.IndexType.ARRAY)
+                                    || joinEnum.findUnnestOp(selOp));
                 }
                 IndexCostInfo.add(new Triple<>(chosenIndex, sel, afce));
             }
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/Stats.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/Stats.java
index 5d46f2e..63c67a5 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/Stats.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/Stats.java
@@ -313,7 +313,7 @@
     }
 
     private AggregateOperator findAggOp(ILogicalOperator op, ILogicalExpression exp) throws AlgebricksException {
-        /*private final */ ContainsExpressionVisitor visitor = new ContainsExpressionVisitor();
+        ContainsExpressionVisitor visitor = new ContainsExpressionVisitor();
         SubplanOperator subOp;
         while (op != null && op.getOperatorTag() != LogicalOperatorTag.EMPTYTUPLESOURCE) {
             if (op.getOperatorTag().equals(LogicalOperatorTag.SUBPLAN)) {
@@ -327,104 +327,70 @@
         return null;
     }
 
-    private SubplanOperator findSubplanWithExpr(ILogicalOperator op, ILogicalExpression exp)
+    protected SelectOperator findSelectOpWithExpr(ILogicalOperator op, ILogicalExpression exp)
             throws AlgebricksException {
-        /*private final */ ContainsExpressionVisitor visitor = new ContainsExpressionVisitor();
+        ContainsExpressionVisitor visitor = new ContainsExpressionVisitor();
         SubplanOperator subOp;
-        while (op != null && op.getOperatorTag() != LogicalOperatorTag.EMPTYTUPLESOURCE) {
-            if (op.getOperatorTag().equals(LogicalOperatorTag.SUBPLAN)) {
-                subOp = (SubplanOperator) op;
-                ILogicalOperator nextOp = subOp.getNestedPlans().get(0).getRoots().get(0).getValue();
-
-                while (nextOp != null) {
+        ILogicalOperator currentOp = op;
+        while (currentOp != null && currentOp.getOperatorTag() != LogicalOperatorTag.EMPTYTUPLESOURCE) {
+            if (currentOp.getOperatorTag().equals(LogicalOperatorTag.SELECT)) {
+                ILogicalOperator nextOp = currentOp.getInputs().get(0).getValue();
+                if (nextOp.getOperatorTag().equals(LogicalOperatorTag.SUBPLAN)) {
+                    subOp = (SubplanOperator) nextOp;
+                    ILogicalOperator childOp = subOp.getNestedPlans().get(0).getRoots().get(0).getValue();
+                    while (childOp != null) {
+                        visitor.setExpression(exp);
+                        if (childOp.acceptExpressionTransform(visitor)) {
+                            return (SelectOperator) currentOp;
+                        }
+                        if (childOp.getInputs().isEmpty()) {
+                            break;
+                        }
+                        childOp = childOp.getInputs().get(0).getValue();
+                    }
+                } else {
                     visitor.setExpression(exp);
-                    if (nextOp.acceptExpressionTransform(visitor)) {
-                        return subOp;
+                    if (currentOp.acceptExpressionTransform(visitor)) {
+                        return (SelectOperator) currentOp;
                     }
-
-                    if (nextOp.getInputs().isEmpty()) {
-                        break;
-                    }
-                    nextOp = nextOp.getInputs().get(0).getValue();
                 }
             }
-            op = op.getInputs().get(0).getValue();
+            currentOp = currentOp.getInputs().get(0).getValue();
         }
         return null;
     }
 
-    private List<ILogicalExpression> storeSubplanSelectsAndMakeThemTrue(ILogicalOperator op) {
+    // For the otherSelOp, leave the selection condition the same but all other selects and subplan selects should be marked true
+    private List<ILogicalExpression> storeSelectConditionsAndMakeThemTrue(ILogicalOperator op,
+            SelectOperator otherSelOp) {
         List<ILogicalExpression> selExprs = new ArrayList<>();
-        while (op != null && op.getOperatorTag() != LogicalOperatorTag.EMPTYTUPLESOURCE) {
-            if (op.getOperatorTag().equals(LogicalOperatorTag.SELECT)) {
-                if (op.getInputs().get(0).getValue().getOperatorTag().equals(LogicalOperatorTag.SUBPLAN)) {
-                    SelectOperator selOp = (SelectOperator) op;
+        ILogicalOperator currentOp = op;
+        while (currentOp != null && currentOp.getOperatorTag() != LogicalOperatorTag.EMPTYTUPLESOURCE) {
+            if (currentOp.getOperatorTag().equals(LogicalOperatorTag.SELECT)) {
+                SelectOperator selOp = (SelectOperator) currentOp;
+                if (selOp != otherSelOp) {
                     selExprs.add(selOp.getCondition().getValue());
                     selOp.getCondition().setValue(ConstantExpression.TRUE);
                 }
             }
-            op = op.getInputs().get(0).getValue();
+            currentOp = currentOp.getInputs().get(0).getValue();
         }
         return selExprs;
     }
 
-    private void restoreAllSubplanSelects(ILogicalOperator op, List<ILogicalExpression> selExprs) {
+    private void restoreAllSelectConditions(ILogicalOperator op, List<ILogicalExpression> selExprs,
+            ILogicalOperator otherSelOp) {
         int i = 0;
-        while (op != null && op.getOperatorTag() != LogicalOperatorTag.EMPTYTUPLESOURCE) {
-            if (op.getOperatorTag().equals(LogicalOperatorTag.SELECT)) {
-                if (op.getInputs().get(0).getValue().getOperatorTag().equals(LogicalOperatorTag.SUBPLAN)) {
-                    SelectOperator selOp = (SelectOperator) op;
+        ILogicalOperator currentOp = op;
+        while (currentOp != null && currentOp.getOperatorTag() != LogicalOperatorTag.EMPTYTUPLESOURCE) {
+            if (currentOp.getOperatorTag().equals(LogicalOperatorTag.SELECT)) {
+                SelectOperator selOp = (SelectOperator) currentOp;
+                if (selOp != otherSelOp) {
                     selOp.getCondition().setValue(selExprs.get(i));
                     i++;
                 }
             }
-            op = op.getInputs().get(0).getValue();
-        }
-    }
-
-    // For the SubOp subplan, leave the selection condition the same but all other selects and subsplan selects should be marked true
-    private List<ILogicalExpression> storeSubplanSelectsAndMakeThemTrue(ILogicalOperator op, SubplanOperator subOp) {
-        List<ILogicalExpression> selExprs = new ArrayList<>();
-        while (op != null && op.getOperatorTag() != LogicalOperatorTag.EMPTYTUPLESOURCE) {
-            if (op.getOperatorTag().equals(LogicalOperatorTag.SELECT)) {
-                ILogicalOperator op2 = op.getInputs().get(0).getValue();
-                if (op2.getOperatorTag().equals(LogicalOperatorTag.SUBPLAN)) {
-                    SubplanOperator subOp2 = (SubplanOperator) op2;
-                    if (subOp2 != subOp) {
-                        SelectOperator selOp = (SelectOperator) op;
-                        selExprs.add(selOp.getCondition().getValue());
-                        selOp.getCondition().setValue(ConstantExpression.TRUE);
-                    } // else leave expression as is.
-                } else { // a non subplan select
-                    SelectOperator selOp = (SelectOperator) op;
-                    selExprs.add(selOp.getCondition().getValue());
-                    selOp.getCondition().setValue(ConstantExpression.TRUE);
-                }
-            }
-            op = op.getInputs().get(0).getValue();
-        }
-        return selExprs;
-    }
-
-    private void restoreAllSubplanSelectConditions(ILogicalOperator op, List<ILogicalExpression> selExprs,
-            SubplanOperator subOp) {
-        int i = 0;
-        while (op != null && op.getOperatorTag() != LogicalOperatorTag.EMPTYTUPLESOURCE) {
-            if (op.getOperatorTag().equals(LogicalOperatorTag.SELECT)) {
-                ILogicalOperator op2 = op.getInputs().get(0).getValue();
-                if (op2.getOperatorTag().equals(LogicalOperatorTag.SUBPLAN)) {
-                    SubplanOperator subOp2 = (SubplanOperator) op2;
-                    if (subOp2 != subOp) {
-                        SelectOperator selOp = (SelectOperator) op;
-                        selOp.getCondition().setValue(selExprs.get(i));
-                        i++;
-                    }
-                } else { // a non subplan select
-                    SelectOperator selOp = (SelectOperator) op;
-                    selOp.getCondition().setValue(selExprs.get(i));
-                }
-            }
-            op = op.getInputs().get(0).getValue();
+            currentOp = currentOp.getInputs().get(0).getValue();
         }
     }
 
@@ -465,56 +431,39 @@
 
         List<ILogicalOperator> subPlans = countOps(selOp, LogicalOperatorTag.SUBPLAN);
         int numSubplans = subPlans.size();
+        List<ILogicalOperator> selOps = countOps(selOp, LogicalOperatorTag.SELECT);
+        int numSelects = selOps.size();
+        int nonSubplanSelects = numSelects - numSubplans;
+
         List<List<IAObject>> result;
-
-        // insert this in place of the scandatasourceOp.
         parent.getInputs().get(0).setValue(deepCopyofScan);
-        if (numSubplans == 0) { // just switch the predicates; the simplest case. There should be no other case if subplans were canonical
-            ILogicalExpression saveExprs = selOp.getCondition().getValue();
-            selOp.getCondition().setValue(exp);
-            result = runSamplingQuery(optCtx, selOp);
-            selOp.getCondition().setValue(saveExprs);
-        } else {
-            List<ILogicalOperator> selOps = countOps(selOp, LogicalOperatorTag.SELECT);
-            int numSelects = selOps.size();
-            int nonSubplanSelects = numSelects - numSubplans;
-
-            if (numSubplans == 1 && nonSubplanSelects == 0) {
-                AggregateOperator aggOp = findAggOp(selOp, exp);
-                if (aggOp.getExpressions().size() > 1) {
-                    // ANY and EVERY IN query; for selectivity purposes, we need to transform this into a ANY IN query
-                    SelectOperator newSelOp = (SelectOperator) OperatorManipulationUtil.bottomUpCopyOperators(selOp);
-                    aggOp = findAggOp(newSelOp, exp);
-                    ILogicalOperator input = aggOp.getInputs().get(0).getValue();
-                    SelectOperator condition = (SelectOperator) OperatorManipulationUtil
-                            .bottomUpCopyOperators(AbstractOperatorFromSubplanRewrite.getSelectFromPlan(aggOp));
-                    //push this condition below aggOp.
-                    aggOp.getInputs().get(0).setValue(condition);
-                    condition.getInputs().get(0).setValue(input);
-                    ILogicalExpression newExp2 = newSelOp.getCondition().getValue();
-                    if (newExp2.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
-                        AbstractFunctionCallExpression afce = (AbstractFunctionCallExpression) newExp2;
-                        afce.getArguments().get(1).setValue(ConstantExpression.TRUE);
-                    }
-                    result = runSamplingQuery(optCtx, newSelOp); // no need to switch anything
-                } else
-                    result = runSamplingQuery(optCtx, selOp);
-            } else { // the painful part; have to find where exp that is passed in is coming from. >= 1 and >= 1 case
-                // Assumption is that there is exaclty one select condition above each subplan.
-                // This was ensured before this routine is called
-                SubplanOperator subOp = findSubplanWithExpr(selOp, exp);
-                if (subOp == null) { // the exp is not coming from a subplan
-                    List<ILogicalExpression> selExprs;
-                    selExprs = storeSubplanSelectsAndMakeThemTrue(selOp); // all these will be marked true and will be resorted later.
-                    result = runSamplingQuery(optCtx, selOp);
-                    restoreAllSubplanSelects(selOp, selExprs);
-                } else { // found the matching subPlan oper. Only keep this predicate and make all others true and then restore them.
-                    List<ILogicalExpression> selExprs;
-                    selExprs = storeSubplanSelectsAndMakeThemTrue(selOp, subOp); // all these will be marked true and will be resorted later.
-                    result = runSamplingQuery(optCtx, selOp);
-                    restoreAllSubplanSelectConditions(selOp, selExprs, subOp);
+        if (numSubplans == 1 && nonSubplanSelects == 0) {
+            AggregateOperator aggOp = findAggOp(selOp, exp);
+            if (aggOp.getExpressions().size() > 1) {
+                // ANY and EVERY IN query; for selectivity purposes, we need to transform this into a ANY IN query
+                SelectOperator newSelOp = (SelectOperator) OperatorManipulationUtil.bottomUpCopyOperators(selOp);
+                aggOp = findAggOp(newSelOp, exp);
+                ILogicalOperator input = aggOp.getInputs().get(0).getValue();
+                SelectOperator condition = (SelectOperator) OperatorManipulationUtil
+                        .bottomUpCopyOperators(AbstractOperatorFromSubplanRewrite.getSelectFromPlan(aggOp));
+                //push this condition below aggOp.
+                aggOp.getInputs().get(0).setValue(condition);
+                condition.getInputs().get(0).setValue(input);
+                ILogicalExpression newExp2 = newSelOp.getCondition().getValue();
+                if (newExp2.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
+                    AbstractFunctionCallExpression afce = (AbstractFunctionCallExpression) newExp2;
+                    afce.getArguments().get(1).setValue(ConstantExpression.TRUE);
                 }
+                result = runSamplingQuery(optCtx, newSelOp); // no need to switch anything
+            } else {
+                result = runSamplingQuery(optCtx, selOp);
             }
+        } else {
+            SelectOperator selOp2 = findSelectOpWithExpr(selOp, exp);
+            List<ILogicalExpression> selExprs;
+            selExprs = storeSelectConditionsAndMakeThemTrue(selOp, selOp2); // all these will be marked true and will be resorted later.
+            result = runSamplingQuery(optCtx, selOp);
+            restoreAllSelectConditions(selOp, selExprs, selOp2);
         }
 
         double predicateCardinality = findPredicateCardinality(result, false);
@@ -534,10 +483,12 @@
             // SELECT count(*) as revenue
             // FROM   orders o, o.o_orderline ol
             // WHERE  TRUE;
-            ILogicalExpression saveExprs = selOp.getCondition().getValue();
-            selOp.getCondition().setValue(ConstantExpression.TRUE);
+
+            // Replace ALL SELECTS with TRUE
+            List<ILogicalExpression> selExprs;
+            selExprs = storeSelectConditionsAndMakeThemTrue(selOp, null); // all these will be marked true and will be resorted later.
             result = runSamplingQuery(optCtx, selOp);
-            selOp.getCondition().setValue(saveExprs);
+            restoreAllSelectConditions(selOp, selExprs, null);
             sampleCard = findPredicateCardinality(result, false);
         }
         // switch  the scanOp back
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/array-index/atomic-and-array-queries/query4.plan b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/array-index/atomic-and-array-queries/query4.plan
new file mode 100644
index 0000000..6d57ef0
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/array-index/atomic-and-array-queries/query4.plan
@@ -0,0 +1,22 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- STREAM_PROJECT  |PARTITIONED|
+      -- ASSIGN  |PARTITIONED|
+        -- STREAM_PROJECT  |PARTITIONED|
+          -- STREAM_SELECT  |PARTITIONED|
+            -- STREAM_PROJECT  |PARTITIONED|
+              -- SUBPLAN  |PARTITIONED|
+                      {
+                        -- AGGREGATE  |LOCAL|
+                          -- STREAM_SELECT  |LOCAL|
+                            -- ASSIGN  |LOCAL|
+                              -- UNNEST  |LOCAL|
+                                -- NESTED_TUPLE_SOURCE  |LOCAL|
+                      }
+                -- STREAM_SELECT  |PARTITIONED|
+                  -- ASSIGN  |PARTITIONED|
+                    -- STREAM_PROJECT  |PARTITIONED|
+                      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                        -- DATASOURCE_SCAN (TestDataverse.Dataset1)  |PARTITIONED|
+                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                            -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/array-index/atomic-and-array-queries/query5.plan b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/array-index/atomic-and-array-queries/query5.plan
new file mode 100644
index 0000000..9f3e9a0
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/array-index/atomic-and-array-queries/query5.plan
@@ -0,0 +1,31 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- STREAM_PROJECT  |PARTITIONED|
+      -- ASSIGN  |PARTITIONED|
+        -- STREAM_PROJECT  |PARTITIONED|
+          -- STREAM_SELECT  |PARTITIONED|
+            -- STREAM_PROJECT  |PARTITIONED|
+              -- SUBPLAN  |PARTITIONED|
+                      {
+                        -- AGGREGATE  |LOCAL|
+                          -- STREAM_SELECT  |LOCAL|
+                            -- SUBPLAN  |LOCAL|
+                                    {
+                                      -- AGGREGATE  |LOCAL|
+                                        -- STREAM_SELECT  |LOCAL|
+                                          -- ASSIGN  |LOCAL|
+                                            -- UNNEST  |LOCAL|
+                                              -- NESTED_TUPLE_SOURCE  |LOCAL|
+                                    }
+                              -- STREAM_SELECT  |LOCAL|
+                                -- ASSIGN  |LOCAL|
+                                  -- UNNEST  |LOCAL|
+                                    -- NESTED_TUPLE_SOURCE  |LOCAL|
+                      }
+                -- STREAM_SELECT  |PARTITIONED|
+                  -- ASSIGN  |PARTITIONED|
+                    -- STREAM_PROJECT  |PARTITIONED|
+                      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                        -- DATASOURCE_SCAN (TestDataverse.Dataset1)  |PARTITIONED|
+                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                            -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/array-index/select-quantified-queries/use-case-1/query2.plan b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/array-index/select-quantified-queries/use-case-1/query2.plan
new file mode 100644
index 0000000..1658a86
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/array-index/select-quantified-queries/use-case-1/query2.plan
@@ -0,0 +1,23 @@
+-- DISTRIBUTE_RESULT  |UNPARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
+    -- STREAM_PROJECT  |UNPARTITIONED|
+      -- ASSIGN  |UNPARTITIONED|
+        -- AGGREGATE  |UNPARTITIONED|
+          -- RANDOM_MERGE_EXCHANGE  |PARTITIONED|
+            -- AGGREGATE  |PARTITIONED|
+              -- STREAM_SELECT  |PARTITIONED|
+                -- STREAM_PROJECT  |PARTITIONED|
+                  -- SUBPLAN  |PARTITIONED|
+                          {
+                            -- AGGREGATE  |LOCAL|
+                              -- STREAM_SELECT  |LOCAL|
+                                -- UNNEST  |LOCAL|
+                                  -- NESTED_TUPLE_SOURCE  |LOCAL|
+                          }
+                    -- STREAM_PROJECT  |PARTITIONED|
+                      -- ASSIGN  |PARTITIONED|
+                        -- STREAM_PROJECT  |PARTITIONED|
+                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                            -- DATASOURCE_SCAN (TestYelp.YelpCheckin)  |PARTITIONED|
+                              -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/array-index/select-quantified-queries/use-case-1/query4.plan b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/array-index/select-quantified-queries/use-case-1/query4.plan
new file mode 100644
index 0000000..2d561f4
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/array-index/select-quantified-queries/use-case-1/query4.plan
@@ -0,0 +1,22 @@
+-- DISTRIBUTE_RESULT  |UNPARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
+    -- STREAM_PROJECT  |UNPARTITIONED|
+      -- ASSIGN  |UNPARTITIONED|
+        -- AGGREGATE  |UNPARTITIONED|
+          -- RANDOM_MERGE_EXCHANGE  |PARTITIONED|
+            -- AGGREGATE  |PARTITIONED|
+              -- STREAM_SELECT  |PARTITIONED|
+                -- STREAM_PROJECT  |PARTITIONED|
+                  -- SUBPLAN  |PARTITIONED|
+                          {
+                            -- AGGREGATE  |LOCAL|
+                              -- UNNEST  |LOCAL|
+                                -- NESTED_TUPLE_SOURCE  |LOCAL|
+                          }
+                    -- STREAM_PROJECT  |PARTITIONED|
+                      -- ASSIGN  |PARTITIONED|
+                        -- STREAM_PROJECT  |PARTITIONED|
+                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                            -- DATASOURCE_SCAN (TestYelp.YelpCheckin)  |PARTITIONED|
+                              -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/array-index/select-quantified-queries/use-case-2/query2.plan b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/array-index/select-quantified-queries/use-case-2/query2.plan
new file mode 100644
index 0000000..1658a86
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/array-index/select-quantified-queries/use-case-2/query2.plan
@@ -0,0 +1,23 @@
+-- DISTRIBUTE_RESULT  |UNPARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
+    -- STREAM_PROJECT  |UNPARTITIONED|
+      -- ASSIGN  |UNPARTITIONED|
+        -- AGGREGATE  |UNPARTITIONED|
+          -- RANDOM_MERGE_EXCHANGE  |PARTITIONED|
+            -- AGGREGATE  |PARTITIONED|
+              -- STREAM_SELECT  |PARTITIONED|
+                -- STREAM_PROJECT  |PARTITIONED|
+                  -- SUBPLAN  |PARTITIONED|
+                          {
+                            -- AGGREGATE  |LOCAL|
+                              -- STREAM_SELECT  |LOCAL|
+                                -- UNNEST  |LOCAL|
+                                  -- NESTED_TUPLE_SOURCE  |LOCAL|
+                          }
+                    -- STREAM_PROJECT  |PARTITIONED|
+                      -- ASSIGN  |PARTITIONED|
+                        -- STREAM_PROJECT  |PARTITIONED|
+                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                            -- DATASOURCE_SCAN (TestYelp.YelpCheckin)  |PARTITIONED|
+                              -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/array-index/select-quantified-queries/use-case-2/query3.plan b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/array-index/select-quantified-queries/use-case-2/query3.plan
new file mode 100644
index 0000000..2d561f4
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/array-index/select-quantified-queries/use-case-2/query3.plan
@@ -0,0 +1,22 @@
+-- DISTRIBUTE_RESULT  |UNPARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
+    -- STREAM_PROJECT  |UNPARTITIONED|
+      -- ASSIGN  |UNPARTITIONED|
+        -- AGGREGATE  |UNPARTITIONED|
+          -- RANDOM_MERGE_EXCHANGE  |PARTITIONED|
+            -- AGGREGATE  |PARTITIONED|
+              -- STREAM_SELECT  |PARTITIONED|
+                -- STREAM_PROJECT  |PARTITIONED|
+                  -- SUBPLAN  |PARTITIONED|
+                          {
+                            -- AGGREGATE  |LOCAL|
+                              -- UNNEST  |LOCAL|
+                                -- NESTED_TUPLE_SOURCE  |LOCAL|
+                          }
+                    -- STREAM_PROJECT  |PARTITIONED|
+                      -- ASSIGN  |PARTITIONED|
+                        -- STREAM_PROJECT  |PARTITIONED|
+                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                            -- DATASOURCE_SCAN (TestYelp.YelpCheckin)  |PARTITIONED|
+                              -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/array-index/select-quantified-queries/use-case-3/query3.plan b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/array-index/select-quantified-queries/use-case-3/query3.plan
new file mode 100644
index 0000000..7e503bb
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/array-index/select-quantified-queries/use-case-3/query3.plan
@@ -0,0 +1,21 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- STREAM_PROJECT  |PARTITIONED|
+      -- ASSIGN  |PARTITIONED|
+        -- STREAM_PROJECT  |PARTITIONED|
+          -- STREAM_SELECT  |PARTITIONED|
+            -- STREAM_PROJECT  |PARTITIONED|
+              -- SUBPLAN  |PARTITIONED|
+                      {
+                        -- AGGREGATE  |LOCAL|
+                          -- ASSIGN  |LOCAL|
+                            -- UNNEST  |LOCAL|
+                              -- NESTED_TUPLE_SOURCE  |LOCAL|
+                      }
+                -- STREAM_PROJECT  |PARTITIONED|
+                  -- ASSIGN  |PARTITIONED|
+                    -- STREAM_PROJECT  |PARTITIONED|
+                      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                        -- DATASOURCE_SCAN (TestYelp.YelpCheckin)  |PARTITIONED|
+                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                            -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/constant_folding/constant_folding.3.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/constant_folding/constant_folding.3.plan
index e24b70a..3028a95 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/constant_folding/constant_folding.3.plan
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/constant_folding/constant_folding.3.plan
@@ -1,14 +1,14 @@
-distribute result [$$15] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+distribute result [$$15] [cardinality: 0.0, op-cost: 0.0, total-cost: 33.22]
 -- DISTRIBUTE_RESULT  |UNPARTITIONED|
-  exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+  exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 33.22]
   -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
-    assign [$$15] <- [true] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+    assign [$$15] <- [true] [cardinality: 0.0, op-cost: 0.0, total-cost: 33.22]
     -- ASSIGN  |UNPARTITIONED|
-      project ([]) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+      project ([]) [cardinality: 0.0, op-cost: 0.0, total-cost: 33.22]
       -- STREAM_PROJECT  |UNPARTITIONED|
-        exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+        exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 33.22]
         -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
-          order (ASC, $$x) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+          order (ASC, $$x) [cardinality: 0.0, op-cost: 33.22, total-cost: 33.22]
           -- STABLE_SORT [$$x(ASC)]  |UNPARTITIONED|
             exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
             -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/constant_folding/constant_folding.5.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/constant_folding/constant_folding.5.plan
index 0d3b661..c5d8eb3 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/constant_folding/constant_folding.5.plan
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/constant_folding/constant_folding.5.plan
@@ -1,14 +1,14 @@
-distribute result [$$15] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+distribute result [$$15] [cardinality: 0.0, op-cost: 0.0, total-cost: 33.22]
 -- DISTRIBUTE_RESULT  |UNPARTITIONED|
-  exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+  exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 33.22]
   -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
-    project ([$$15]) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+    project ([$$15]) [cardinality: 0.0, op-cost: 0.0, total-cost: 33.22]
     -- STREAM_PROJECT  |UNPARTITIONED|
-      assign [$$15] <- [le($$x, 2)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+      assign [$$15] <- [le($$x, 2)] [cardinality: 0.0, op-cost: 0.0, total-cost: 33.22]
       -- ASSIGN  |UNPARTITIONED|
-        exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+        exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 33.22]
         -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
-          order (ASC, $$x) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+          order (ASC, $$x) [cardinality: 0.0, op-cost: 33.22, total-cost: 33.22]
           -- STABLE_SORT [$$x(ASC)]  |UNPARTITIONED|
             exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
             -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/constant_folding/constant_folding.6.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/constant_folding/constant_folding.6.plan
index cc40968..3cb126f 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/constant_folding/constant_folding.6.plan
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/constant_folding/constant_folding.6.plan
@@ -1,14 +1,14 @@
-distribute result [$$15] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+distribute result [$$15] [cardinality: 0.0, op-cost: 0.0, total-cost: 33.22]
 -- DISTRIBUTE_RESULT  |UNPARTITIONED|
-  exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+  exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 33.22]
   -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
-    project ([$$15]) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+    project ([$$15]) [cardinality: 0.0, op-cost: 0.0, total-cost: 33.22]
     -- STREAM_PROJECT  |UNPARTITIONED|
-      assign [$$15] <- [or(null, le($$x, 2))] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+      assign [$$15] <- [or(null, le($$x, 2))] [cardinality: 0.0, op-cost: 0.0, total-cost: 33.22]
       -- ASSIGN  |UNPARTITIONED|
-        exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+        exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 33.22]
         -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
-          order (ASC, $$x) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+          order (ASC, $$x) [cardinality: 0.0, op-cost: 33.22, total-cost: 33.22]
           -- STABLE_SORT [$$x(ASC)]  |UNPARTITIONED|
             exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
             -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/constant_folding/constant_folding.7.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/constant_folding/constant_folding.7.plan
index 9ea5c09..c8c68c9 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/constant_folding/constant_folding.7.plan
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/constant_folding/constant_folding.7.plan
@@ -1,14 +1,14 @@
-distribute result [$$17] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+distribute result [$$17] [cardinality: 0.0, op-cost: 0.0, total-cost: 33.22]
 -- DISTRIBUTE_RESULT  |UNPARTITIONED|
-  exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+  exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 33.22]
   -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
-    assign [$$17] <- [true] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+    assign [$$17] <- [true] [cardinality: 0.0, op-cost: 0.0, total-cost: 33.22]
     -- ASSIGN  |UNPARTITIONED|
-      project ([]) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+      project ([]) [cardinality: 0.0, op-cost: 0.0, total-cost: 33.22]
       -- STREAM_PROJECT  |UNPARTITIONED|
-        exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+        exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 33.22]
         -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
-          order (ASC, $$x) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+          order (ASC, $$x) [cardinality: 0.0, op-cost: 33.22, total-cost: 33.22]
           -- STABLE_SORT [$$x(ASC)]  |UNPARTITIONED|
             exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
             -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/column/filter/not-in_every/not-in_every.201.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/column/filter/not-in_every/not-in_every.201.plan
index b1b4bc2..1d6e680 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/column/filter/not-in_every/not-in_every.201.plan
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/column/filter/not-in_every/not-in_every.201.plan
@@ -49,7 +49,7 @@
                             -- BROADCAST_EXCHANGE  |PARTITIONED|
                               assign [$$23] <- [true] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                               -- ASSIGN  |UNPARTITIONED|
-                                unnest $#1 <- scan-collection(array: [ "1", "2", "3" ]) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                unnest $#1 <- scan-collection(array: [ "1", "2", "3" ]) [cardinality: 1.0, op-cost: 1.0, total-cost: 1.0]
                                 -- UNNEST  |UNPARTITIONED|
                                   empty-tuple-source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                                   -- EMPTY_TUPLE_SOURCE  |UNPARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/column/pushdown/array-access-pushdown/array-access-pushdown.008.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/column/pushdown/array-access-pushdown/array-access-pushdown.008.plan
index 8631f06..491db48 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/column/pushdown/array-access-pushdown/array-access-pushdown.008.plan
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/column/pushdown/array-access-pushdown/array-access-pushdown.008.plan
@@ -1,16 +1,16 @@
-distribute result [$$28] [cardinality: 2.0, op-cost: 0.0, total-cost: 4.0]
+distribute result [$$28] [cardinality: 2.0, op-cost: 0.0, total-cost: 2.0]
 -- DISTRIBUTE_RESULT  |PARTITIONED|
-  exchange [cardinality: 2.0, op-cost: 0.0, total-cost: 4.0]
+  exchange [cardinality: 2.0, op-cost: 0.0, total-cost: 2.0]
   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-    project ([$$28]) [cardinality: 2.0, op-cost: 0.0, total-cost: 4.0]
+    project ([$$28]) [cardinality: 2.0, op-cost: 0.0, total-cost: 2.0]
     -- STREAM_PROJECT  |PARTITIONED|
-      assign [$$28] <- [{"display_url": $$urls.getField("display_url")}] [cardinality: 2.0, op-cost: 0.0, total-cost: 4.0]
+      assign [$$28] <- [{"display_url": $$urls.getField("display_url")}] [cardinality: 2.0, op-cost: 0.0, total-cost: 2.0]
       -- ASSIGN  |PARTITIONED|
-        project ([$$urls]) [cardinality: 2.0, op-cost: 0.0, total-cost: 4.0]
+        project ([$$urls]) [cardinality: 2.0, op-cost: 0.0, total-cost: 2.0]
         -- STREAM_PROJECT  |PARTITIONED|
-          exchange [cardinality: 2.0, op-cost: 0.0, total-cost: 4.0]
+          exchange [cardinality: 2.0, op-cost: 0.0, total-cost: 2.0]
           -- SORT_MERGE_EXCHANGE [$$30(ASC) ]  |PARTITIONED|
-            order (ASC, $$30) [cardinality: 2.0, op-cost: 2.0, total-cost: 4.0]
+            order (ASC, $$30) [cardinality: 2.0, op-cost: 0.0, total-cost: 2.0]
             -- STABLE_SORT [$$30(ASC)]  |PARTITIONED|
               exchange [cardinality: 2.0, op-cost: 0.0, total-cost: 2.0]
               -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/column/pushdown/other-pushdowns/other-pushdowns.014.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/column/pushdown/other-pushdowns/other-pushdowns.014.plan
index d3f44d6..2182bcc 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/column/pushdown/other-pushdowns/other-pushdowns.014.plan
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/column/pushdown/other-pushdowns/other-pushdowns.014.plan
@@ -93,7 +93,7 @@
                                                 -- ASSIGN  |PARTITIONED|
                                                   project ([$$ht2]) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                                                   -- STREAM_PROJECT  |PARTITIONED|
-                                                    unnest $$ht2 <- scan-collection($$108) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                                    unnest $$ht2 <- scan-collection($$108) [cardinality: 1.0, op-cost: 2.0, total-cost: 2.0]
                                                     -- UNNEST  |PARTITIONED|
                                                       project ([$$108]) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                                                       -- STREAM_PROJECT  |PARTITIONED|