Ali Alsuliman has uploaded this change for review. ( 
https://asterix-gerrit.ics.uci.edu/3399


Change subject: [ASTERIXDB-2289][COMP] Fix field access with UNION and CASE
......................................................................

[ASTERIXDB-2289][COMP] Fix field access with UNION and CASE

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

Details:
This patch fixes field access in the presense of UNION and CASE.
For CASE scenario, push-down-field-access rule throws an exception
if the field access has potentially two sources and it could not
push down the field access to left or right branch. The exception
thinks that the field access has no source when in reality it has
but there were two potential sources because of CASE. Don't throw
an exception if the field access is a valid one and return false
(i.e. field access was not push) instead of throwing an exception.
For UNION, if there is an assign operator above UNION, the optimizer
will move the assign operator under UNION into both branches. If
the assign operator has field access by index, the index is based on
the output record of the union operator which could be different from
the field index in left and right branches. The fix is to convert
the index into a named field, and then move the assign operator.
The optimizer will fire by-name-to-by-index rule after this and
replace the name with the correct index for each record of left and
right branch. by-name-to-by-index rule is already a required rule
to be fired after push-assign-under-union rule.

Change-Id: I911e4e9018c15e8f226e46fa610d222eb2301fcd
---
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java
A 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushAssignBelowUnionAllRule.java
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushFieldAccessRule.java
A 
asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/field_access/field_access.1.ddl.sqlpp
A 
asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/field_access/field_access.2.update.sqlpp
A 
asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/field_access/field_access.3.query.sqlpp
A 
asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/field_access/field_access.4.query.sqlpp
A 
asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/field_access/field_access.5.query.sqlpp
A 
asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/field_access/field_access.6.query.sqlpp
A 
asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/field_access/field_access.7.query.sqlpp
A 
asterixdb/asterix-app/src/test/resources/runtimets/results/misc/field_access/field_access.3.adm
A 
asterixdb/asterix-app/src/test/resources/runtimets/results/misc/field_access/field_access.4.adm
A 
asterixdb/asterix-app/src/test/resources/runtimets/results/misc/field_access/field_access.5.adm
A 
asterixdb/asterix-app/src/test/resources/runtimets/results/misc/field_access/field_access.6.adm
A 
asterixdb/asterix-app/src/test/resources/runtimets/results/misc/field_access/field_access.7.adm
D 
hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/PushAssignBelowUnionAllRule.java
16 files changed, 537 insertions(+), 174 deletions(-)



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

diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java
index e4c35e4..79f565f 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java
@@ -66,6 +66,7 @@
 import org.apache.asterix.optimizer.rules.NestGroupByRule;
 import 
org.apache.asterix.optimizer.rules.PushAggFuncIntoStandaloneAggregateRule;
 import org.apache.asterix.optimizer.rules.PushAggregateIntoNestedSubplanRule;
+import org.apache.asterix.optimizer.rules.PushAssignBelowUnionAllRule;
 import org.apache.asterix.optimizer.rules.PushFieldAccessRule;
 import org.apache.asterix.optimizer.rules.PushGroupByThroughProduct;
 import org.apache.asterix.optimizer.rules.PushLimitIntoOrderByRule;
@@ -117,7 +118,6 @@
 import org.apache.hyracks.algebricks.rewriter.rules.IntroduceProjectsRule;
 import 
org.apache.hyracks.algebricks.rewriter.rules.IsolateHyracksOperatorsRule;
 import org.apache.hyracks.algebricks.rewriter.rules.PullSelectOutOfEqJoin;
-import 
org.apache.hyracks.algebricks.rewriter.rules.PushAssignBelowUnionAllRule;
 import org.apache.hyracks.algebricks.rewriter.rules.PushGroupByIntoSortRule;
 import 
org.apache.hyracks.algebricks.rewriter.rules.PushMapOperatorDownThroughProductRule;
 import 
org.apache.hyracks.algebricks.rewriter.rules.PushNestedOrderByUnderPreSortedGroupByRule;
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushAssignBelowUnionAllRule.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushAssignBelowUnionAllRule.java
new file mode 100644
index 0000000..552b691
--- /dev/null
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushAssignBelowUnionAllRule.java
@@ -0,0 +1,245 @@
+/*
+ * 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.
+ */
+package org.apache.asterix.optimizer.rules;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.asterix.lang.common.util.FunctionUtil;
+import org.apache.asterix.om.base.AString;
+import org.apache.asterix.om.constants.AsterixConstantValue;
+import org.apache.asterix.om.functions.BuiltinFunctions;
+import org.apache.asterix.om.types.ARecordType;
+import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.om.types.IAType;
+import org.apache.asterix.om.utils.ConstantExpressionUtil;
+import org.apache.commons.lang3.mutable.Mutable;
+import org.apache.commons.lang3.mutable.MutableObject;
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.common.exceptions.NotImplementedException;
+import org.apache.hyracks.algebricks.common.utils.Triple;
+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.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.expressions.ConstantExpression;
+import 
org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression;
+import 
org.apache.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression;
+import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
+import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.AssignOperator;
+import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.UnionAllOperator;
+import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities;
+import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
+
+/**
+ * <pre>
+ * Pushes an AssignOperator below a UnionAll operator by creating an new 
AssignOperator below each of
+ * the UnionAllOperator's branches with appropriate variable replacements.
+ * This rule can help to enable other rules that are difficult to fire across 
a UnionAllOperator,
+ * for example, eliminating common sub-expressions.
+ * Example:
+ * Before plan:
+ * ...
+ * assign [$$20, $$21] <- [funcA($$3), funcB($$6)]
+ * union ($$1, $$2, $$3) ($$4, $$5, $$6)
+ * union_branch_0
+ * ...
+ * union_branch_1
+ * ...
+ * After plan:
+ * ...
+ * union ($$1, $$2, $$3) ($$4, $$5, $$6) ($$22, $$24, $$20) ($$23, $$25, $$21)
+ * assign [$$22, $$23] <- [funcA($$1), funcB($$4)]
+ * union_branch_0
+ * ...
+ * assign [$$24, $$25] <- [funcA($$2), funcB($$5)]
+ * union_branch_1
+ * ...
+ * </pre>
+ * Post-requirements:
+ * <ol>
+ * <li>{@link ByNameToByIndexFieldAccessRule} should be fired.</li>
+ * </ol>
+ */
+public class PushAssignBelowUnionAllRule implements IAlgebraicRewriteRule {
+
+    @Override
+    public boolean rewritePre(Mutable<ILogicalOperator> opRef, 
IOptimizationContext context)
+            throws AlgebricksException {
+        return false;
+    }
+
+    @Override
+    public boolean rewritePost(Mutable<ILogicalOperator> opRef, 
IOptimizationContext context)
+            throws AlgebricksException {
+        AbstractLogicalOperator op = (AbstractLogicalOperator) 
opRef.getValue();
+        if (!op.hasInputs()) {
+            return false;
+        }
+
+        boolean modified = false;
+        for (int i = 0; i < op.getInputs().size(); i++) {
+            AbstractLogicalOperator childOp = (AbstractLogicalOperator) 
op.getInputs().get(i).getValue();
+            if (childOp.getOperatorTag() != LogicalOperatorTag.ASSIGN) {
+                continue;
+            }
+            AssignOperator assignOp = (AssignOperator) childOp;
+            for (Mutable<ILogicalExpression> expr : assignOp.getExpressions()) 
{
+                if (!expr.getValue().isFunctional()) {
+                    return false;
+                }
+            }
+
+            AbstractLogicalOperator childOfChildOp = (AbstractLogicalOperator) 
assignOp.getInputs().get(0).getValue();
+            if (childOfChildOp.getOperatorTag() != 
LogicalOperatorTag.UNIONALL) {
+                continue;
+            }
+            UnionAllOperator unionOp = (UnionAllOperator) childOfChildOp;
+
+            Set<LogicalVariable> assignUsedVars = new HashSet<>();
+            VariableUtilities.getUsedVariables(assignOp, assignUsedVars);
+
+            List<LogicalVariable> assignVars = assignOp.getVariables();
+
+            AssignOperator[] newAssignOps = new AssignOperator[2];
+            for (int j = 0; j < unionOp.getInputs().size(); j++) {
+                newAssignOps[j] = createAssignBelowUnionAllBranch(unionOp, j, 
assignOp, assignUsedVars, context);
+            }
+            // Add original assign variables to the union variable mappings.
+            for (int j = 0; j < assignVars.size(); j++) {
+                LogicalVariable first = newAssignOps[0].getVariables().get(j);
+                LogicalVariable second = newAssignOps[1].getVariables().get(j);
+                Triple<LogicalVariable, LogicalVariable, LogicalVariable> 
varMapping =
+                        new Triple<>(first, second, assignVars.get(j));
+                unionOp.getVariableMappings().add(varMapping);
+            }
+            context.computeAndSetTypeEnvironmentForOperator(unionOp);
+
+            // Remove original assign operator.
+            op.getInputs().set(i, assignOp.getInputs().get(0));
+            context.computeAndSetTypeEnvironmentForOperator(op);
+            modified = true;
+        }
+
+        return modified;
+    }
+
+    private AssignOperator createAssignBelowUnionAllBranch(UnionAllOperator 
unionOp, int inputIndex,
+            AssignOperator originalAssignOp, Set<LogicalVariable> 
assignUsedVars, IOptimizationContext context)
+            throws AlgebricksException {
+        AssignOperator newAssignOp = cloneAssignOperator(originalAssignOp, 
context, unionOp);
+        newAssignOp.getInputs().add(new 
MutableObject<>(unionOp.getInputs().get(inputIndex).getValue()));
+        unionOp.getInputs().get(inputIndex).setValue(newAssignOp);
+        int numVarMappings = unionOp.getVariableMappings().size();
+        for (int i = 0; i < numVarMappings; i++) {
+            Triple<LogicalVariable, LogicalVariable, LogicalVariable> 
varMapping = unionOp.getVariableMappings().get(i);
+            if (assignUsedVars.contains(varMapping.third)) {
+                LogicalVariable replacementVar;
+                if (inputIndex == 0) {
+                    replacementVar = varMapping.first;
+                } else {
+                    replacementVar = varMapping.second;
+                }
+                VariableUtilities.substituteVariables(newAssignOp, 
varMapping.third, replacementVar, context);
+            }
+        }
+        context.computeAndSetTypeEnvironmentForOperator(newAssignOp);
+        return newAssignOp;
+    }
+
+    /**
+     * Clones the given assign operator changing the returned variables to be 
new ones.
+     * Also, leaves the inputs of the clone clear.
+     */
+    private AssignOperator cloneAssignOperator(AssignOperator assignOp, 
IOptimizationContext context,
+            UnionAllOperator unionOp) throws AlgebricksException {
+        List<LogicalVariable> vars = new ArrayList<>();
+        List<Mutable<ILogicalExpression>> exprs = new ArrayList<>();
+        int numVars = assignOp.getVariables().size();
+        for (int i = 0; i < numVars; i++) {
+            vars.add(context.newVar());
+            ILogicalExpression clonedExpression = 
assignOp.getExpressions().get(i).getValue().cloneExpression();
+            exprs.add(new MutableObject<>(modifyExpression(clonedExpression, 
unionOp, context)));
+        }
+        AssignOperator assignCloneOp = new AssignOperator(vars, exprs);
+        assignCloneOp.setSourceLocation(assignOp.getSourceLocation());
+        assignCloneOp.setExecutionMode(assignOp.getExecutionMode());
+        return assignCloneOp;
+    }
+
+    private ILogicalExpression modifyExpression(ILogicalExpression expression, 
UnionAllOperator unionOp,
+            IOptimizationContext context) throws AlgebricksException {
+        switch (expression.getExpressionTag()) {
+            case CONSTANT:
+            case VARIABLE:
+                return expression;
+            case FUNCTION_CALL:
+                AbstractFunctionCallExpression functionCall = 
(AbstractFunctionCallExpression) expression;
+                List<Mutable<ILogicalExpression>> arguments = 
functionCall.getArguments();
+                for (int i = 0, size = arguments.size(); i < size; i++) {
+                    ILogicalExpression newArgExpr = 
modifyExpression(arguments.get(i).getValue(), unionOp, context);
+                    arguments.get(i).setValue(newArgExpr);
+                }
+                return changeFieldIndexToFieldName(functionCall, unionOp, 
context);
+            default:
+                throw new NotImplementedException();
+        }
+    }
+
+    private static ILogicalExpression 
changeFieldIndexToFieldName(AbstractFunctionCallExpression functionCall,
+            UnionAllOperator unionOp, IOptimizationContext context) throws 
AlgebricksException {
+        if 
(!functionCall.getFunctionIdentifier().equals(BuiltinFunctions.FIELD_ACCESS_BY_INDEX))
 {
+            return functionCall;
+        }
+        // the record variable in the field access should match the output 
variable from union, i.e. $2.getField
+        ILogicalExpression recordExpr = 
functionCall.getArguments().get(0).getValue();
+        if (recordExpr.getExpressionTag() != LogicalExpressionTag.VARIABLE) {
+            return functionCall;
+        }
+        Integer fieldIndex = 
ConstantExpressionUtil.getIntArgument(functionCall, 1);
+        if (fieldIndex == null) {
+            return functionCall;
+        }
+        LogicalVariable recordVar = ((VariableReferenceExpression) 
recordExpr).getVariableReference();
+        AbstractFunctionCallExpression newFunctionCall = functionCall;
+        for (Triple<LogicalVariable, LogicalVariable, LogicalVariable> 
variableMapping : unionOp
+                .getVariableMappings()) {
+            if (variableMapping.third.equals(recordVar)) {
+                IAType type = (IAType) 
context.getOutputTypeEnvironment(unionOp).getVarType(variableMapping.third);
+                if (type.getTypeTag() != ATypeTag.OBJECT) {
+                    continue;
+                }
+                ARecordType unionOutputType = (ARecordType) type;
+                String fieldName = unionOutputType.getFieldNames()[fieldIndex];
+                newFunctionCall = new ScalarFunctionCallExpression(
+                        
FunctionUtil.getFunctionInfo(BuiltinFunctions.FIELD_ACCESS_BY_NAME),
+                        functionCall.getArguments().get(0),
+                        new MutableObject<>(new ConstantExpression(new 
AsterixConstantValue(new AString(fieldName)))));
+                
newFunctionCall.setSourceLocation(functionCall.getSourceLocation());
+                return newFunctionCall;
+            }
+        }
+        return newFunctionCall;
+    }
+}
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushFieldAccessRule.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushFieldAccessRule.java
index 421b00d..0c3a163 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushFieldAccessRule.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushFieldAccessRule.java
@@ -69,6 +69,8 @@

 public class PushFieldAccessRule implements IAlgebraicRewriteRule {

+    private final HashSet<LogicalVariable> allLiveVariables = new HashSet<>();
+
     @Override
     public boolean rewritePre(Mutable<ILogicalOperator> opRef, 
IOptimizationContext context) {
         return false;
@@ -234,8 +236,7 @@
                     LogicalVariable oldVar = assignOp.getVariables().get(0);
                     VariableReferenceExpression v2Ref = new 
VariableReferenceExpression(v2);
                     v2Ref.setSourceLocation(g.getSourceLocation());
-                    g.getDecorList().add(new Pair<LogicalVariable, 
Mutable<ILogicalExpression>>(oldVar,
-                            new MutableObject<ILogicalExpression>(v2Ref)));
+                    g.getDecorList().add(new Pair<>(oldVar, new 
MutableObject<>(v2Ref)));
                     changed = true;
                     assignOp.getVariables().set(0, v2);
                     VariableUtilities.substituteVariables(assignOp, m.first, 
m.second, context);
@@ -255,6 +256,7 @@
                 pushAccessDown(opRef, inputOp, childOfSubplan, context, 
finalAnnot);
                 return true;
             }
+            allLiveVariables.clear();
             if (inputOp.getInputs().size() == 1 && !inputOp.hasNestedPlans()) {
                 pushAccessDown(opRef, inputOp, inputOp.getInputs().get(0), 
context, finalAnnot);
                 return true;
@@ -262,6 +264,7 @@
                 for (Mutable<ILogicalOperator> inp : inputOp.getInputs()) {
                     HashSet<LogicalVariable> v2 = new HashSet<>();
                     VariableUtilities.getLiveVariables(inp.getValue(), v2);
+                    allLiveVariables.addAll(v2);
                     if (v2.containsAll(usedInAccess)) {
                         pushAccessDown(opRef, inputOp, inp, context, 
finalAnnot);
                         return true;
@@ -274,6 +277,7 @@
                     for (Mutable<ILogicalOperator> root : plan.getRoots()) {
                         HashSet<LogicalVariable> v2 = new HashSet<>();
                         VariableUtilities.getLiveVariables(root.getValue(), 
v2);
+                        allLiveVariables.addAll(v2);
                         if (v2.containsAll(usedInAccess)) {
                             pushAccessDown(opRef, inputOp, root, context, 
finalAnnot);
                             return true;
@@ -281,8 +285,12 @@
                     }
                 }
             }
+            if (allLiveVariables.containsAll(usedInAccess)) {
+                // all field accesses in the assign operator have 
corresponding sources, but push down is not possible
+                return false;
+            }
             throw new CompilationException(ErrorCode.COMPILATION_ERROR, 
assignOp.getSourceLocation(),
-                    "Field access " + 
assignOp.getExpressions().get(0).getValue() + " doesn't correspond to any 
input");
+                    "Could not resolve field access " + 
assignOp.getExpressions().get(0).getValue());
         } else {
             // check if the accessed field is one of the partitioning key 
fields. If yes, we can equate the 2 variables
             if (inputOp.getOperatorTag() == LogicalOperatorTag.DATASOURCESCAN) 
{
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/field_access/field_access.1.ddl.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/field_access/field_access.1.ddl.sqlpp
new file mode 100644
index 0000000..692d0fd
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/field_access/field_access.1.ddl.sqlpp
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+// testing fix for ASTERIXDB-2288 and ASTERIXDB-2289 related to field access 
with CASE and UNION
+DROP DATAVERSE TinySocial IF EXISTS;
+CREATE DATAVERSE TinySocial;
+USE TinySocial;
+
+CREATE TYPE ChirpUserType AS {
+    screenName: string,
+    lang: string,
+    friendsCount: int,
+    statusesCount: int,
+    name: string,
+    followersCount: int
+};
+
+CREATE TYPE EmploymentType AS {
+    organizationName: string,
+    startDate: date,
+    endDate: date?
+};
+
+CREATE TYPE GleambookUserType AS {
+    id: int,
+    alias: string,
+    name: string,
+    userSince: datetime,
+    friendIds: {{ int }},
+    employment: [EmploymentType]
+};
+
+CREATE DATASET GleambookUsers(GleambookUserType) PRIMARY KEY id;
+CREATE DATASET ChirpUsers(ChirpUserType) PRIMARY KEY screenName;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/field_access/field_access.2.update.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/field_access/field_access.2.update.sqlpp
new file mode 100644
index 0000000..fe7c165
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/field_access/field_access.2.update.sqlpp
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// testing fix for ASTERIXDB-2288 and ASTERIXDB-2289 related to field access 
with CASE and UNION
+USE TinySocial;
+
+INSERT INTO ChirpUsers
+([
+{"screenName":"NathanGiesen@211","lang":"en","friendsCount":18,"statusesCount":473,"name":"Nathan
 Giesen","followersCount":49416},
+{"screenName":"ColineGeyer@63","lang":"en","friendsCount":121,"statusesCount":362,"name":"Coline
 Geyer","followersCount":17159},
+{"screenName":"NilaMilliron_tw","lang":"en","friendsCount":445,"statusesCount":164,"name":"Nila
 Milliron","followersCount":22649},
+{"screenName":"ChangEwing_573","lang":"en","friendsCount":182,"statusesCount":394,"name":"Chang
 Ewing","followersCount":32136}
+]);
+
+INSERT INTO GleambookUsers
+([
+{"id":1,"alias":"Margarita","name":"MargaritaStoddard","nickname":"Mags","userSince":datetime("2012-08-20T10:10:00"),"friendIds":{{2,3,6,10}},"employment":[{"organizationName":"Codetechno","startDate":date("2006-08-06")},{"organizationName":"geomedia","startDate":date("2010-06-17"),"endDate":date("2010-01-26")}],"gender":"F"},
+{"id":2,"alias":"Isbel","name":"IsbelDull","nickname":"Izzy","userSince":datetime("2011-01-22T10:10:00"),"friendIds":{{1,4}},"employment":[{"organizationName":"Hexviafind","startDate":date("2010-04-27")}]},
+{"id":3,"alias":"Emory","name":"EmoryUnk","userSince":datetime("2012-07-10T10:10:00"),"friendIds":{{1,5,8,9}},"employment":[{"organizationName":"geomedia","startDate":date("2010-06-17"),"endDate":date("2010-01-26")}]},
+{"id":4,"alias":"Nicholas","name":"NicholasStroh","userSince":datetime("2010-12-27T10:10:00"),"friendIds":{{2}},"employment":[{"organizationName":"Zamcorporation","startDate":date("2010-06-08")}]},
+{"id":5,"alias":"Von","name":"VonKemble","userSince":datetime("2010-01-05T10:10:00"),"friendIds":{{3,6,10}},"employment":[{"organizationName":"Kongreen","startDate":date("2010-11-27")}]},
+{"id":6,"alias":"Willis","name":"WillisWynne","userSince":datetime("2005-01-17T10:10:00"),"friendIds":{{1,3,7}},"employment":[{"organizationName":"jaydax","startDate":date("2009-05-15")}]},
+{"id":7,"alias":"Suzanna","name":"SuzannaTillson","userSince":datetime("2012-08-07T10:10:00"),"friendIds":{{6}},"employment":[{"organizationName":"Labzatron","startDate":date("2011-04-19")}]},
+{"id":8,"alias":"Nila","name":"NilaMilliron","userSince":datetime("2008-01-01T10:10:00"),"friendIds":{{3}},"employment":[{"organizationName":"Plexlane","startDate":date("2010-02-28")}]},
+{"id":9,"alias":"Woodrow","name":"WoodrowNehling","nickname":"Woody","userSince":datetime("2005-09-20T10:10:00"),"friendIds":{{3,10}},"employment":[{"organizationName":"Zuncan","startDate":date("2003-04-22"),"endDate":date("2009-12-13")}]},
+{"id":10,"alias":"Bram","name":"BramHatch","userSince":datetime("2010-10-16T10:10:00"),"friendIds":{{1,5,9}},"employment":[{"organizationName":"physcane","startDate":date("2007-06-05"),"endDate":date("2011-11-05")}]}
+]);
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/field_access/field_access.3.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/field_access/field_access.3.query.sqlpp
new file mode 100644
index 0000000..727faa2
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/field_access/field_access.3.query.sqlpp
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+// testing fix for ASTERIXDB-2288 and ASTERIXDB-2289 related to field access 
with CASE and UNION
+USE TinySocial;
+
+SELECT (CASE WHEN g.id = 6 THEN g ELSE u END).name as name
+FROM ChirpUsers u JOIN GleambookUsers g ON u.name < g.name WHERE u.screenName 
= "ChangEwing_573"
+ORDER BY name;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/field_access/field_access.4.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/field_access/field_access.4.query.sqlpp
new file mode 100644
index 0000000..78a19f2
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/field_access/field_access.4.query.sqlpp
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+// testing fix for ASTERIXDB-2288 and ASTERIXDB-2289 related to field access 
with CASE and UNION
+USE TinySocial;
+
+SELECT VALUE a FROM (SELECT VALUE c FROM ChirpUsers c UNION ALL SELECT VALUE g 
FROM GleambookUsers g) AS a
+ORDER BY a.name;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/field_access/field_access.5.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/field_access/field_access.5.query.sqlpp
new file mode 100644
index 0000000..7e60d2d
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/field_access/field_access.5.query.sqlpp
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+// testing fix for ASTERIXDB-2288 and ASTERIXDB-2289 related to field access 
with CASE and UNION
+USE TinySocial;
+
+SELECT name FROM (SELECT VALUE c FROM ChirpUsers c UNION ALL SELECT VALUE g 
FROM GleambookUsers g) AS a
+ORDER BY name;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/field_access/field_access.6.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/field_access/field_access.6.query.sqlpp
new file mode 100644
index 0000000..b3c44d3
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/field_access/field_access.6.query.sqlpp
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+// testing fix for ASTERIXDB-2288 and ASTERIXDB-2289 related to field access 
with CASE and UNION
+USE TinySocial;
+
+SELECT name, string_length(name) as len
+FROM (SELECT VALUE c FROM ChirpUsers c UNION ALL SELECT VALUE g FROM 
GleambookUsers g) AS a
+ORDER BY name;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/field_access/field_access.7.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/field_access/field_access.7.query.sqlpp
new file mode 100644
index 0000000..e7729ba
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/field_access/field_access.7.query.sqlpp
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+// testing fix for ASTERIXDB-2288 and ASTERIXDB-2289 related to field access 
with CASE and UNION
+USE TinySocial;
+
+SELECT alias FROM (SELECT VALUE c FROM ChirpUsers c UNION ALL SELECT VALUE g 
FROM GleambookUsers g) AS a
+ORDER BY alias;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/field_access/field_access.3.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/field_access/field_access.3.adm
new file mode 100644
index 0000000..ec27645
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/field_access/field_access.3.adm
@@ -0,0 +1,9 @@
+{ "name": "Chang Ewing" }
+{ "name": "Chang Ewing" }
+{ "name": "Chang Ewing" }
+{ "name": "Chang Ewing" }
+{ "name": "Chang Ewing" }
+{ "name": "Chang Ewing" }
+{ "name": "Chang Ewing" }
+{ "name": "Chang Ewing" }
+{ "name": "WillisWynne" }
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/field_access/field_access.4.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/field_access/field_access.4.adm
new file mode 100644
index 0000000..bfbb1bd
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/field_access/field_access.4.adm
@@ -0,0 +1,14 @@
+{ "name": "BramHatch", "id": 10, "alias": "Bram", "userSince": 
datetime("2010-10-16T10:10:00.000Z"), "friendIds": {{ 1, 5, 9 }}, "employment": 
[ { "organizationName": "physcane", "startDate": date("2007-06-05"), "endDate": 
date("2011-11-05") } ] }
+{ "name": "Chang Ewing", "screenName": "ChangEwing_573", "lang": "en", 
"friendsCount": 182, "statusesCount": 394, "followersCount": 32136 }
+{ "name": "Coline Geyer", "screenName": "ColineGeyer@63", "lang": "en", 
"friendsCount": 121, "statusesCount": 362, "followersCount": 17159 }
+{ "name": "EmoryUnk", "id": 3, "alias": "Emory", "userSince": 
datetime("2012-07-10T10:10:00.000Z"), "friendIds": {{ 1, 5, 8, 9 }}, 
"employment": [ { "organizationName": "geomedia", "startDate": 
date("2010-06-17"), "endDate": date("2010-01-26") } ] }
+{ "name": "IsbelDull", "id": 2, "alias": "Isbel", "userSince": 
datetime("2011-01-22T10:10:00.000Z"), "friendIds": {{ 1, 4 }}, "employment": [ 
{ "organizationName": "Hexviafind", "startDate": date("2010-04-27") } ], 
"nickname": "Izzy" }
+{ "name": "MargaritaStoddard", "id": 1, "alias": "Margarita", "userSince": 
datetime("2012-08-20T10:10:00.000Z"), "friendIds": {{ 2, 3, 6, 10 }}, 
"employment": [ { "organizationName": "Codetechno", "startDate": 
date("2006-08-06") }, { "organizationName": "geomedia", "startDate": 
date("2010-06-17"), "endDate": date("2010-01-26") } ], "nickname": "Mags", 
"gender": "F" }
+{ "name": "Nathan Giesen", "screenName": "NathanGiesen@211", "lang": "en", 
"friendsCount": 18, "statusesCount": 473, "followersCount": 49416 }
+{ "name": "NicholasStroh", "id": 4, "alias": "Nicholas", "userSince": 
datetime("2010-12-27T10:10:00.000Z"), "friendIds": {{ 2 }}, "employment": [ { 
"organizationName": "Zamcorporation", "startDate": date("2010-06-08") } ] }
+{ "name": "Nila Milliron", "screenName": "NilaMilliron_tw", "lang": "en", 
"friendsCount": 445, "statusesCount": 164, "followersCount": 22649 }
+{ "name": "NilaMilliron", "id": 8, "alias": "Nila", "userSince": 
datetime("2008-01-01T10:10:00.000Z"), "friendIds": {{ 3 }}, "employment": [ { 
"organizationName": "Plexlane", "startDate": date("2010-02-28") } ] }
+{ "name": "SuzannaTillson", "id": 7, "alias": "Suzanna", "userSince": 
datetime("2012-08-07T10:10:00.000Z"), "friendIds": {{ 6 }}, "employment": [ { 
"organizationName": "Labzatron", "startDate": date("2011-04-19") } ] }
+{ "name": "VonKemble", "id": 5, "alias": "Von", "userSince": 
datetime("2010-01-05T10:10:00.000Z"), "friendIds": {{ 3, 6, 10 }}, 
"employment": [ { "organizationName": "Kongreen", "startDate": 
date("2010-11-27") } ] }
+{ "name": "WillisWynne", "id": 6, "alias": "Willis", "userSince": 
datetime("2005-01-17T10:10:00.000Z"), "friendIds": {{ 1, 3, 7 }}, "employment": 
[ { "organizationName": "jaydax", "startDate": date("2009-05-15") } ] }
+{ "name": "WoodrowNehling", "id": 9, "alias": "Woodrow", "userSince": 
datetime("2005-09-20T10:10:00.000Z"), "friendIds": {{ 3, 10 }}, "employment": [ 
{ "organizationName": "Zuncan", "startDate": date("2003-04-22"), "endDate": 
date("2009-12-13") } ], "nickname": "Woody" }
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/field_access/field_access.5.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/field_access/field_access.5.adm
new file mode 100644
index 0000000..8660d98
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/field_access/field_access.5.adm
@@ -0,0 +1,14 @@
+{ "name": "BramHatch" }
+{ "name": "Chang Ewing" }
+{ "name": "Coline Geyer" }
+{ "name": "EmoryUnk" }
+{ "name": "IsbelDull" }
+{ "name": "MargaritaStoddard" }
+{ "name": "Nathan Giesen" }
+{ "name": "NicholasStroh" }
+{ "name": "Nila Milliron" }
+{ "name": "NilaMilliron" }
+{ "name": "SuzannaTillson" }
+{ "name": "VonKemble" }
+{ "name": "WillisWynne" }
+{ "name": "WoodrowNehling" }
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/field_access/field_access.6.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/field_access/field_access.6.adm
new file mode 100644
index 0000000..4af8057
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/field_access/field_access.6.adm
@@ -0,0 +1,14 @@
+{ "name": "BramHatch", "len": 9 }
+{ "name": "Chang Ewing", "len": 11 }
+{ "name": "Coline Geyer", "len": 12 }
+{ "name": "EmoryUnk", "len": 8 }
+{ "name": "IsbelDull", "len": 9 }
+{ "name": "MargaritaStoddard", "len": 17 }
+{ "name": "Nathan Giesen", "len": 13 }
+{ "name": "NicholasStroh", "len": 13 }
+{ "name": "Nila Milliron", "len": 13 }
+{ "name": "NilaMilliron", "len": 12 }
+{ "name": "SuzannaTillson", "len": 14 }
+{ "name": "VonKemble", "len": 9 }
+{ "name": "WillisWynne", "len": 11 }
+{ "name": "WoodrowNehling", "len": 14 }
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/field_access/field_access.7.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/field_access/field_access.7.adm
new file mode 100644
index 0000000..ea37f8c
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/field_access/field_access.7.adm
@@ -0,0 +1,14 @@
+{  }
+{  }
+{  }
+{  }
+{ "alias": "Bram" }
+{ "alias": "Emory" }
+{ "alias": "Isbel" }
+{ "alias": "Margarita" }
+{ "alias": "Nicholas" }
+{ "alias": "Nila" }
+{ "alias": "Suzanna" }
+{ "alias": "Von" }
+{ "alias": "Willis" }
+{ "alias": "Woodrow" }
\ No newline at end of file
diff --git 
a/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/PushAssignBelowUnionAllRule.java
 
b/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/PushAssignBelowUnionAllRule.java
deleted file mode 100644
index f432c9f..0000000
--- 
a/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/PushAssignBelowUnionAllRule.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * 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.
- */
-package org.apache.hyracks.algebricks.rewriter.rules;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import org.apache.commons.lang3.mutable.Mutable;
-import org.apache.commons.lang3.mutable.MutableObject;
-import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
-import org.apache.hyracks.algebricks.common.utils.Triple;
-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.IOptimizationContext;
-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.operators.logical.AbstractLogicalOperator;
-import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.AssignOperator;
-import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.UnionAllOperator;
-import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities;
-import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
-
-/**
- * Pushes an AssignOperator below a UnionAll operator by creating an new 
AssignOperator below each of
- * the UnionAllOperator's branches with appropriate variable replacements.
- * This rule can help to enable other rules that are difficult to fire across 
a UnionAllOperator,
- * for example, eliminating common sub-expressions.
- * Example:
- * Before plan:
- * ...
- * assign [$$20, $$21] <- [funcA($$3), funcB($$6)]
- * union ($$1, $$2, $$3) ($$4, $$5, $$6)
- * union_branch_0
- * ...
- * union_branch_1
- * ...
- * After plan:
- * ...
- * union ($$1, $$2, $$3) ($$4, $$5, $$6) ($$22, $$24, $$20) ($$23, $$25, $$21)
- * assign [$$22, $$23] <- [funcA($$1), funcB($$4)]
- * union_branch_0
- * ...
- * assign [$$24, $$25] <- [funcA($$2), funcB($$5)]
- * union_branch_1
- * ...
- */
-public class PushAssignBelowUnionAllRule implements IAlgebraicRewriteRule {
-
-    @Override
-    public boolean rewritePre(Mutable<ILogicalOperator> opRef, 
IOptimizationContext context)
-            throws AlgebricksException {
-        return false;
-    }
-
-    @Override
-    public boolean rewritePost(Mutable<ILogicalOperator> opRef, 
IOptimizationContext context)
-            throws AlgebricksException {
-        AbstractLogicalOperator op = (AbstractLogicalOperator) 
opRef.getValue();
-        if (!op.hasInputs()) {
-            return false;
-        }
-
-        boolean modified = false;
-        for (int i = 0; i < op.getInputs().size(); i++) {
-            AbstractLogicalOperator childOp = (AbstractLogicalOperator) 
op.getInputs().get(i).getValue();
-            if (childOp.getOperatorTag() != LogicalOperatorTag.ASSIGN) {
-                continue;
-            }
-            AssignOperator assignOp = (AssignOperator) childOp;
-            for (Mutable<ILogicalExpression> expr : assignOp.getExpressions()) 
{
-                if (!expr.getValue().isFunctional()) {
-                    return false;
-                }
-            }
-
-            AbstractLogicalOperator childOfChildOp = (AbstractLogicalOperator) 
assignOp.getInputs().get(0).getValue();
-            if (childOfChildOp.getOperatorTag() != 
LogicalOperatorTag.UNIONALL) {
-                continue;
-            }
-            UnionAllOperator unionOp = (UnionAllOperator) childOfChildOp;
-
-            Set<LogicalVariable> assignUsedVars = new 
HashSet<LogicalVariable>();
-            VariableUtilities.getUsedVariables(assignOp, assignUsedVars);
-
-            List<LogicalVariable> assignVars = assignOp.getVariables();
-
-            AssignOperator[] newAssignOps = new AssignOperator[2];
-            for (int j = 0; j < unionOp.getInputs().size(); j++) {
-                newAssignOps[j] = createAssignBelowUnionAllBranch(unionOp, j, 
assignOp, assignUsedVars, context);
-            }
-            // Add original assign variables to the union variable mappings.
-            for (int j = 0; j < assignVars.size(); j++) {
-                LogicalVariable first = newAssignOps[0].getVariables().get(j);
-                LogicalVariable second = newAssignOps[1].getVariables().get(j);
-                Triple<LogicalVariable, LogicalVariable, LogicalVariable> 
varMapping =
-                        new Triple<LogicalVariable, LogicalVariable, 
LogicalVariable>(first, second, assignVars.get(j));
-                unionOp.getVariableMappings().add(varMapping);
-            }
-            context.computeAndSetTypeEnvironmentForOperator(unionOp);
-
-            // Remove original assign operator.
-            op.getInputs().set(i, assignOp.getInputs().get(0));
-            context.computeAndSetTypeEnvironmentForOperator(op);
-            modified = true;
-        }
-
-        return modified;
-    }
-
-    private AssignOperator createAssignBelowUnionAllBranch(UnionAllOperator 
unionOp, int inputIndex,
-            AssignOperator originalAssignOp, Set<LogicalVariable> 
assignUsedVars, IOptimizationContext context)
-            throws AlgebricksException {
-        AssignOperator newAssignOp = cloneAssignOperator(originalAssignOp, 
context);
-        newAssignOp.getInputs()
-                .add(new 
MutableObject<ILogicalOperator>(unionOp.getInputs().get(inputIndex).getValue()));
-        unionOp.getInputs().get(inputIndex).setValue(newAssignOp);
-        int numVarMappings = unionOp.getVariableMappings().size();
-        for (int i = 0; i < numVarMappings; i++) {
-            Triple<LogicalVariable, LogicalVariable, LogicalVariable> 
varMapping = unionOp.getVariableMappings().get(i);
-            if (assignUsedVars.contains(varMapping.third)) {
-                LogicalVariable replacementVar;
-                if (inputIndex == 0) {
-                    replacementVar = varMapping.first;
-                } else {
-                    replacementVar = varMapping.second;
-                }
-                VariableUtilities.substituteVariables(newAssignOp, 
varMapping.third, replacementVar, context);
-            }
-        }
-        context.computeAndSetTypeEnvironmentForOperator(newAssignOp);
-        return newAssignOp;
-    }
-
-    /**
-     * Clones the given assign operator changing the returned variables to be 
new ones.
-     * Also, leaves the inputs of the clone clear.
-     */
-    private AssignOperator cloneAssignOperator(AssignOperator assignOp, 
IOptimizationContext context) {
-        List<LogicalVariable> vars = new ArrayList<LogicalVariable>();
-        List<Mutable<ILogicalExpression>> exprs = new 
ArrayList<Mutable<ILogicalExpression>>();
-        int numVars = assignOp.getVariables().size();
-        for (int i = 0; i < numVars; i++) {
-            vars.add(context.newVar());
-            exprs.add(new MutableObject<ILogicalExpression>(
-                    
assignOp.getExpressions().get(i).getValue().cloneExpression()));
-        }
-        AssignOperator assignCloneOp = new AssignOperator(vars, exprs);
-        assignCloneOp.setSourceLocation(assignOp.getSourceLocation());
-        assignCloneOp.setExecutionMode(assignOp.getExecutionMode());
-        return assignCloneOp;
-    }
-}

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

Gerrit-Project: asterixdb
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I911e4e9018c15e8f226e46fa610d222eb2301fcd
Gerrit-Change-Number: 3399
Gerrit-PatchSet: 1
Gerrit-Owner: Ali Alsuliman <ali.al.solai...@gmail.com>

Reply via email to