You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@asterixdb.apache.org by bu...@apache.org on 2015/12/31 06:18:16 UTC
[1/4] incubator-asterixdb-hyracks git commit: Fix for ASTERIXDB-1018,
ASTERIXDB-1017, ASTERIXDB-1019, ASTERIXDB-1020, ASTERIXDB-1029, ASTERIXDB-1030,
ASTERIXDB-1034:
Repository: incubator-asterixdb-hyracks
Updated Branches:
refs/heads/master 834fc1438 -> 7dd479923
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/PushSubplanIntoGroupByRule.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/PushSubplanIntoGroupByRule.java b/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/PushSubplanIntoGroupByRule.java
new file mode 100644
index 0000000..74ff21f
--- /dev/null
+++ b/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/PushSubplanIntoGroupByRule.java
@@ -0,0 +1,209 @@
+/*
+
+ * 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.subplan;
+
+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.ListSet;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan;
+import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
+import org.apache.hyracks.algebricks.core.algebra.base.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.AggregateOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.GroupByOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.NestedTupleSourceOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.SubplanOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities;
+import org.apache.hyracks.algebricks.core.algebra.util.OperatorManipulationUtil;
+import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
+
+/**
+ * This rule pushes an array of subplans on top of a group-by into the
+ * nested plan of the group-by.
+ *
+ * @author yingyib
+ */
+
+public class PushSubplanIntoGroupByRule implements IAlgebraicRewriteRule {
+ /** Stores used variables above the current operator. */
+ private final Set<LogicalVariable> usedVarsSoFar = new HashSet<LogicalVariable>();
+
+ @Override
+ public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
+ throws AlgebricksException {
+ return false;
+ }
+
+ @Override
+ public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException {
+ ILogicalOperator parentOperator = opRef.getValue();
+ if (context.checkIfInDontApplySet(this, parentOperator)) {
+ return false;
+ }
+ context.addToDontApplySet(this, parentOperator);
+ VariableUtilities.getUsedVariables(parentOperator, usedVarsSoFar);
+ if (parentOperator.getInputs().size() <= 0) {
+ return false;
+ }
+ boolean changed = false;
+ GroupByOperator gby = null;
+ for (Mutable<ILogicalOperator> ref : parentOperator.getInputs()) {
+ AbstractLogicalOperator op = (AbstractLogicalOperator) ref.getValue();
+ /** Only processes subplan operator. */
+ List<SubplanOperator> subplans = new ArrayList<SubplanOperator>();
+ if (op.getOperatorTag() == LogicalOperatorTag.SUBPLAN) {
+ while (op.getOperatorTag() == LogicalOperatorTag.SUBPLAN) {
+ SubplanOperator currentSubplan = (SubplanOperator) op;
+ subplans.add(currentSubplan);
+ op = (AbstractLogicalOperator) op.getInputs().get(0).getValue();
+ }
+ /** Only processes the case a group-by operator is the input of the subplan operators. */
+ if (op.getOperatorTag() == LogicalOperatorTag.GROUP) {
+ gby = (GroupByOperator) op;
+ List<ILogicalPlan> newGbyNestedPlans = new ArrayList<ILogicalPlan>();
+ for (SubplanOperator subplan : subplans) {
+ List<ILogicalPlan> subplanNestedPlans = subplan.getNestedPlans();
+ List<ILogicalPlan> gbyNestedPlans = gby.getNestedPlans();
+ List<ILogicalPlan> subplanNestedPlansToRemove = new ArrayList<ILogicalPlan>();
+ for (ILogicalPlan subplanNestedPlan : subplanNestedPlans) {
+ List<Mutable<ILogicalOperator>> rootOpRefs = subplanNestedPlan.getRoots();
+ List<Mutable<ILogicalOperator>> rootOpRefsToRemove = new ArrayList<Mutable<ILogicalOperator>>();
+ for (Mutable<ILogicalOperator> rootOpRef : rootOpRefs) {
+ /** Gets free variables in the root operator of a nested plan and its descent. */
+ Set<LogicalVariable> freeVars = new ListSet<LogicalVariable>();
+ VariableUtilities.getUsedVariablesInDescendantsAndSelf(rootOpRef.getValue(), freeVars);
+ Set<LogicalVariable> producedVars = new ListSet<LogicalVariable>();
+ VariableUtilities.getProducedVariablesInDescendantsAndSelf(rootOpRef.getValue(),
+ producedVars);
+ freeVars.removeAll(producedVars);
+ /** * Checks whether the above freeVars are all contained in live variables * of one nested plan inside the group-by operator. * If yes, then the subplan can be pushed into the nested plan of the group-by. */
+ for (ILogicalPlan gbyNestedPlanOriginal : gbyNestedPlans) {
+ // add a subplan in the original gby
+ if (!newGbyNestedPlans.contains(gbyNestedPlanOriginal)) {
+ newGbyNestedPlans.add(gbyNestedPlanOriginal);
+ }
+
+ // add a pushed subplan
+ ILogicalPlan gbyNestedPlan = OperatorManipulationUtil.deepCopy(
+ gbyNestedPlanOriginal, context);
+ List<Mutable<ILogicalOperator>> gbyRootOpRefs = gbyNestedPlan.getRoots();
+ for (int rootIndex = 0; rootIndex < gbyRootOpRefs.size(); rootIndex++) {
+ //set the nts for a original subplan
+ Mutable<ILogicalOperator> originalGbyRootOpRef = gbyNestedPlanOriginal
+ .getRoots().get(rootIndex);
+ Mutable<ILogicalOperator> originalGbyNtsRef = downToNts(originalGbyRootOpRef);
+ NestedTupleSourceOperator originalNts = (NestedTupleSourceOperator) originalGbyNtsRef
+ .getValue();
+ originalNts.setDataSourceReference(new MutableObject<ILogicalOperator>(gby));
+
+ //push a new subplan if possible
+ Mutable<ILogicalOperator> gbyRootOpRef = gbyRootOpRefs.get(rootIndex);
+ Set<LogicalVariable> liveVars = new ListSet<LogicalVariable>();
+ VariableUtilities.getLiveVariables(gbyRootOpRef.getValue(), liveVars);
+ if (liveVars.containsAll(freeVars)) {
+ /** Does the actual push. */
+ Mutable<ILogicalOperator> ntsRef = downToNts(rootOpRef);
+ ntsRef.setValue(gbyRootOpRef.getValue());
+ // Removes unused vars.
+ AggregateOperator aggOp = (AggregateOperator) gbyRootOpRef.getValue();
+ for (int varIndex = aggOp.getVariables().size() - 1; varIndex >= 0; varIndex--) {
+ if (!freeVars.contains(aggOp.getVariables().get(varIndex))) {
+ aggOp.getVariables().remove(varIndex);
+ aggOp.getExpressions().remove(varIndex);
+ }
+ }
+
+ gbyRootOpRef.setValue(rootOpRef.getValue());
+ rootOpRefsToRemove.add(rootOpRef);
+
+ // Sets the nts for a new pushed plan.
+ Mutable<ILogicalOperator> oldGbyNtsRef = downToNts(gbyRootOpRef);
+ NestedTupleSourceOperator nts = (NestedTupleSourceOperator) oldGbyNtsRef
+ .getValue();
+ nts.setDataSourceReference(new MutableObject<ILogicalOperator>(gby));
+
+ newGbyNestedPlans.add(gbyNestedPlan);
+ changed = true;
+ continue;
+ }
+ }
+ }
+ }
+ rootOpRefs.removeAll(rootOpRefsToRemove);
+ if (rootOpRefs.size() == 0) {
+ subplanNestedPlansToRemove.add(subplanNestedPlan);
+ }
+ }
+ subplanNestedPlans.removeAll(subplanNestedPlansToRemove);
+ }
+ if (changed) {
+ ref.setValue(gby);
+ gby.getNestedPlans().clear();
+ gby.getNestedPlans().addAll(newGbyNestedPlans);
+ }
+ }
+ }
+ }
+ if (changed) {
+ cleanup(gby);
+ }
+ return changed;
+ }
+
+ /**
+ * Removes unused aggregation variables (and expressions)
+ *
+ * @param gby
+ * @throws AlgebricksException
+ */
+ private void cleanup(GroupByOperator gby) throws AlgebricksException {
+ for (ILogicalPlan nestedPlan : gby.getNestedPlans()) {
+ for (Mutable<ILogicalOperator> rootRef : nestedPlan.getRoots()) {
+ AggregateOperator aggOp = (AggregateOperator) rootRef.getValue();
+ for (int varIndex = aggOp.getVariables().size() - 1; varIndex >= 0; varIndex--) {
+ if (!usedVarsSoFar.contains(aggOp.getVariables().get(varIndex))) {
+ aggOp.getVariables().remove(varIndex);
+ aggOp.getExpressions().remove(varIndex);
+ }
+ }
+ }
+
+ }
+ }
+
+ private Mutable<ILogicalOperator> downToNts(Mutable<ILogicalOperator> opRef) {
+ Mutable<ILogicalOperator> currentOpRef = opRef;
+ while (currentOpRef.getValue().getInputs().size() > 0) {
+ currentOpRef = currentOpRef.getValue().getInputs().get(0);
+ }
+ return currentOpRef;
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/SubplanOutOfGroupRule.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/SubplanOutOfGroupRule.java b/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/SubplanOutOfGroupRule.java
new file mode 100644
index 0000000..0aba194
--- /dev/null
+++ b/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/SubplanOutOfGroupRule.java
@@ -0,0 +1,125 @@
+/*
+ * 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.subplan;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.commons.lang3.mutable.Mutable;
+import org.apache.commons.lang3.mutable.MutableObject;
+
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan;
+import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
+import org.apache.hyracks.algebricks.core.algebra.base.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.GroupByOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.SubplanOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities;
+import org.apache.hyracks.algebricks.core.algebra.util.OperatorPropertiesUtil;
+import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
+
+/**
+ * Looks for a nested group-by plan ending in
+ * subplan {
+ * ...
+ * }
+ * select (function-call: algebricks:not, Args:[function-call:
+ * algebricks:is-null, Args:[...]])
+ * nested tuple source -- |UNPARTITIONED|
+ */
+
+public class SubplanOutOfGroupRule 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 op0 = (AbstractLogicalOperator) opRef.getValue();
+ if (op0.getOperatorTag() != LogicalOperatorTag.GROUP) {
+ return false;
+ }
+ GroupByOperator gby = (GroupByOperator) op0;
+
+ Iterator<ILogicalPlan> plansIter = gby.getNestedPlans().iterator();
+ ILogicalPlan p = null;
+ while (plansIter.hasNext()) {
+ p = plansIter.next();
+ }
+ if (p == null) {
+ return false;
+ }
+ if (p.getRoots().size() != 1) {
+ return false;
+ }
+ Mutable<ILogicalOperator> op1Ref = p.getRoots().get(0);
+ AbstractLogicalOperator op1 = (AbstractLogicalOperator) op1Ref.getValue();
+ boolean found = false;
+ while (op1.getInputs().size() == 1) {
+ if (op1.getOperatorTag() == LogicalOperatorTag.SUBPLAN) {
+ SubplanOperator subplan = (SubplanOperator) op1;
+ AbstractLogicalOperator op2 = (AbstractLogicalOperator) subplan.getInputs().get(0).getValue();
+ if (OperatorPropertiesUtil.isNullTest(op2)) {
+ if (subplan.getNestedPlans().size() == 1) {
+ ILogicalPlan p1 = subplan.getNestedPlans().get(0);
+ if (p1.getRoots().size() == 1) {
+ AbstractLogicalOperator r1 = (AbstractLogicalOperator) p1.getRoots().get(0).getValue();
+ if (r1.getOperatorTag() == LogicalOperatorTag.INNERJOIN
+ || r1.getOperatorTag() == LogicalOperatorTag.LEFTOUTERJOIN) {
+ // now, check that it propagates all variables,
+ // so it can be pushed
+ List<LogicalVariable> op2Vars = new ArrayList<LogicalVariable>();
+ VariableUtilities.getLiveVariables(op2, op2Vars);
+ List<LogicalVariable> op1Vars = new ArrayList<LogicalVariable>();
+ VariableUtilities.getLiveVariables(subplan, op1Vars);
+ if (op1Vars.containsAll(op2Vars)) {
+ found = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ op1Ref = op1.getInputs().get(0);
+ op1 = (AbstractLogicalOperator) op1Ref.getValue();
+ }
+ if (!found) {
+ return false;
+ }
+
+ ILogicalOperator subplan = op1;
+ ILogicalOperator op2 = op1.getInputs().get(0).getValue();
+ op1Ref.setValue(op2);
+ Mutable<ILogicalOperator> opUnderRef = gby.getInputs().get(0);
+ ILogicalOperator opUnder = opUnderRef.getValue();
+ subplan.getInputs().clear();
+ subplan.getInputs().add(new MutableObject<ILogicalOperator>(opUnder));
+ opUnderRef.setValue(subplan);
+
+ return true;
+ }
+}
[2/4] incubator-asterixdb-hyracks git commit: Fix for ASTERIXDB-1018,
ASTERIXDB-1017, ASTERIXDB-1019, ASTERIXDB-1020, ASTERIXDB-1029, ASTERIXDB-1030,
ASTERIXDB-1034:
Posted by bu...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/PushSubplanIntoGroupByRule.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/PushSubplanIntoGroupByRule.java b/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/PushSubplanIntoGroupByRule.java
deleted file mode 100644
index 9dce6c9..0000000
--- a/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/PushSubplanIntoGroupByRule.java
+++ /dev/null
@@ -1,209 +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.ListSet;
-import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
-import org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan;
-import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
-import org.apache.hyracks.algebricks.core.algebra.base.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.AggregateOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.GroupByOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.NestedTupleSourceOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.SubplanOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities;
-import org.apache.hyracks.algebricks.core.algebra.util.OperatorManipulationUtil;
-import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
-
-/**
- * This rule pushes an array of subplans on top of a group-by into the
- * nested plan of the group-by.
- *
- * @author yingyib
- */
-
-public class PushSubplanIntoGroupByRule implements IAlgebraicRewriteRule {
- /** Stores used variables above the current operator. */
- private final Set<LogicalVariable> usedVarsSoFar = new HashSet<LogicalVariable>();
-
- @Override
- public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
- throws AlgebricksException {
- return false;
- }
-
- @Override
- public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException {
- ILogicalOperator parentOperator = opRef.getValue();
- if (context.checkIfInDontApplySet(this, parentOperator)) {
- return false;
- }
- context.addToDontApplySet(this, parentOperator);
- VariableUtilities.getUsedVariables(parentOperator, usedVarsSoFar);
- if (parentOperator.getInputs().size() <= 0) {
- return false;
- }
- boolean changed = false;
- GroupByOperator gby = null;
- for (Mutable<ILogicalOperator> ref : parentOperator.getInputs()) {
- AbstractLogicalOperator op = (AbstractLogicalOperator) ref.getValue();
- /** Only processes subplan operator. */
- List<SubplanOperator> subplans = new ArrayList<SubplanOperator>();
- if (op.getOperatorTag() == LogicalOperatorTag.SUBPLAN) {
- while (op.getOperatorTag() == LogicalOperatorTag.SUBPLAN) {
- SubplanOperator currentSubplan = (SubplanOperator) op;
- subplans.add(currentSubplan);
- op = (AbstractLogicalOperator) op.getInputs().get(0).getValue();
- }
- /** Only processes the case a group-by operator is the input of the subplan operators. */
- if (op.getOperatorTag() == LogicalOperatorTag.GROUP) {
- gby = (GroupByOperator) op;
- List<ILogicalPlan> newGbyNestedPlans = new ArrayList<ILogicalPlan>();
- for (SubplanOperator subplan : subplans) {
- List<ILogicalPlan> subplanNestedPlans = subplan.getNestedPlans();
- List<ILogicalPlan> gbyNestedPlans = gby.getNestedPlans();
- List<ILogicalPlan> subplanNestedPlansToRemove = new ArrayList<ILogicalPlan>();
- for (ILogicalPlan subplanNestedPlan : subplanNestedPlans) {
- List<Mutable<ILogicalOperator>> rootOpRefs = subplanNestedPlan.getRoots();
- List<Mutable<ILogicalOperator>> rootOpRefsToRemove = new ArrayList<Mutable<ILogicalOperator>>();
- for (Mutable<ILogicalOperator> rootOpRef : rootOpRefs) {
- /** Gets free variables in the root operator of a nested plan and its descent. */
- Set<LogicalVariable> freeVars = new ListSet<LogicalVariable>();
- VariableUtilities.getUsedVariablesInDescendantsAndSelf(rootOpRef.getValue(), freeVars);
- Set<LogicalVariable> producedVars = new ListSet<LogicalVariable>();
- VariableUtilities.getProducedVariablesInDescendantsAndSelf(rootOpRef.getValue(),
- producedVars);
- freeVars.removeAll(producedVars);
- /** * Checks whether the above freeVars are all contained in live variables * of one nested plan inside the group-by operator. * If yes, then the subplan can be pushed into the nested plan of the group-by. */
- for (ILogicalPlan gbyNestedPlanOriginal : gbyNestedPlans) {
- // add a subplan in the original gby
- if (!newGbyNestedPlans.contains(gbyNestedPlanOriginal)) {
- newGbyNestedPlans.add(gbyNestedPlanOriginal);
- }
-
- // add a pushed subplan
- ILogicalPlan gbyNestedPlan = OperatorManipulationUtil.deepCopy(
- gbyNestedPlanOriginal, context);
- List<Mutable<ILogicalOperator>> gbyRootOpRefs = gbyNestedPlan.getRoots();
- for (int rootIndex = 0; rootIndex < gbyRootOpRefs.size(); rootIndex++) {
- //set the nts for a original subplan
- Mutable<ILogicalOperator> originalGbyRootOpRef = gbyNestedPlanOriginal
- .getRoots().get(rootIndex);
- Mutable<ILogicalOperator> originalGbyNtsRef = downToNts(originalGbyRootOpRef);
- NestedTupleSourceOperator originalNts = (NestedTupleSourceOperator) originalGbyNtsRef
- .getValue();
- originalNts.setDataSourceReference(new MutableObject<ILogicalOperator>(gby));
-
- //push a new subplan if possible
- Mutable<ILogicalOperator> gbyRootOpRef = gbyRootOpRefs.get(rootIndex);
- Set<LogicalVariable> liveVars = new ListSet<LogicalVariable>();
- VariableUtilities.getLiveVariables(gbyRootOpRef.getValue(), liveVars);
- if (liveVars.containsAll(freeVars)) {
- /** Does the actual push. */
- Mutable<ILogicalOperator> ntsRef = downToNts(rootOpRef);
- ntsRef.setValue(gbyRootOpRef.getValue());
- // Removes unused vars.
- AggregateOperator aggOp = (AggregateOperator) gbyRootOpRef.getValue();
- for (int varIndex = aggOp.getVariables().size() - 1; varIndex >= 0; varIndex--) {
- if (!freeVars.contains(aggOp.getVariables().get(varIndex))) {
- aggOp.getVariables().remove(varIndex);
- aggOp.getExpressions().remove(varIndex);
- }
- }
-
- gbyRootOpRef.setValue(rootOpRef.getValue());
- rootOpRefsToRemove.add(rootOpRef);
-
- // Sets the nts for a new pushed plan.
- Mutable<ILogicalOperator> oldGbyNtsRef = downToNts(gbyRootOpRef);
- NestedTupleSourceOperator nts = (NestedTupleSourceOperator) oldGbyNtsRef
- .getValue();
- nts.setDataSourceReference(new MutableObject<ILogicalOperator>(gby));
-
- newGbyNestedPlans.add(gbyNestedPlan);
- changed = true;
- continue;
- }
- }
- }
- }
- rootOpRefs.removeAll(rootOpRefsToRemove);
- if (rootOpRefs.size() == 0) {
- subplanNestedPlansToRemove.add(subplanNestedPlan);
- }
- }
- subplanNestedPlans.removeAll(subplanNestedPlansToRemove);
- }
- if (changed) {
- ref.setValue(gby);
- gby.getNestedPlans().clear();
- gby.getNestedPlans().addAll(newGbyNestedPlans);
- }
- }
- }
- }
- if (changed) {
- cleanup(gby);
- }
- return changed;
- }
-
- /**
- * Removes unused aggregation variables (and expressions)
- *
- * @param gby
- * @throws AlgebricksException
- */
- private void cleanup(GroupByOperator gby) throws AlgebricksException {
- for (ILogicalPlan nestedPlan : gby.getNestedPlans()) {
- for (Mutable<ILogicalOperator> rootRef : nestedPlan.getRoots()) {
- AggregateOperator aggOp = (AggregateOperator) rootRef.getValue();
- for (int varIndex = aggOp.getVariables().size() - 1; varIndex >= 0; varIndex--) {
- if (!usedVarsSoFar.contains(aggOp.getVariables().get(varIndex))) {
- aggOp.getVariables().remove(varIndex);
- aggOp.getExpressions().remove(varIndex);
- }
- }
- }
-
- }
- }
-
- private Mutable<ILogicalOperator> downToNts(Mutable<ILogicalOperator> opRef) {
- Mutable<ILogicalOperator> currentOpRef = opRef;
- while (currentOpRef.getValue().getInputs().size() > 0) {
- currentOpRef = currentOpRef.getValue().getInputs().get(0);
- }
- return currentOpRef;
- }
-
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/SimpleUnnestToProductRule.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/SimpleUnnestToProductRule.java b/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/SimpleUnnestToProductRule.java
index 50b4ea9..21e9c06 100644
--- a/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/SimpleUnnestToProductRule.java
+++ b/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/SimpleUnnestToProductRule.java
@@ -36,7 +36,6 @@ import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogi
import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractScanOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.EmptyTupleSourceOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.InnerJoinOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.NestedTupleSourceOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities;
import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
@@ -80,19 +79,41 @@ public class SimpleUnnestToProductRule implements IAlgebraicRewriteRule {
Mutable<ILogicalOperator> tupleSourceOpRef = currentOpRef;
currentOpRef = opRef;
if (tupleSourceOpRef.getValue().getOperatorTag() == LogicalOperatorTag.NESTEDTUPLESOURCE) {
- NestedTupleSourceOperator nts = (NestedTupleSourceOperator) tupleSourceOpRef.getValue();
- // If the subplan input is a trivial plan, do not do the rewriting.
- if (nts.getSourceOperator().getOperatorTag() != LogicalOperatorTag.EMPTYTUPLESOURCE) {
- while (currentOpRef.getValue().getInputs().size() == 1
- && currentOpRef.getValue() instanceof AbstractScanOperator
- && descOrSelfIsSourceScan((AbstractLogicalOperator) currentOpRef.getValue())) {
- if (opsAreIndependent(currentOpRef.getValue(), tupleSourceOpRef.getValue())) {
- /** move down the boundary if the operator is independent of the tuple source */
- boundaryOpRef = currentOpRef.getValue().getInputs().get(0);
- } else {
- break;
- }
- currentOpRef = currentOpRef.getValue().getInputs().get(0);
+ while (currentOpRef.getValue().getInputs().size() == 1
+ /*
+ * When this rule is fired,
+ * Unnests with a dataset function have been rewritten to DataSourceScans and
+ * AccessMethod related rewriting hasn't been done. Therefore, we only need
+ * to check if currentOpRef holds a DataSourceScanOperator.
+ */
+ && currentOpRef.getValue().getOperatorTag() == LogicalOperatorTag.DATASOURCESCAN
+ && descOrSelfIsSourceScan((AbstractLogicalOperator) currentOpRef.getValue())) {
+ if (opsAreIndependent(currentOpRef.getValue(), tupleSourceOpRef.getValue())) {
+ /** move down the boundary if the operator is independent of the tuple source */
+ boundaryOpRef = currentOpRef.getValue().getInputs().get(0);
+ } else {
+ break;
+ }
+ currentOpRef = currentOpRef.getValue().getInputs().get(0);
+ }
+ } else {
+ //Move the boundary below any top const assigns.
+ boundaryOpRef = opRef.getValue().getInputs().get(0);
+ while (boundaryOpRef.getValue().getInputs().size() == 1
+ /*
+ * When this rule is fired,
+ * Unnests with a dataset function have been rewritten to DataSourceScans and
+ * AccessMethod related rewriting hasn't been done. Therefore, we only need
+ * to check if boundaryOpRef holds a DataSourceScanOperator.
+ */
+ && boundaryOpRef.getValue().getOperatorTag() != LogicalOperatorTag.DATASOURCESCAN) {
+ List<LogicalVariable> opUsedVars = new ArrayList<LogicalVariable>();
+ VariableUtilities.getUsedVariables(boundaryOpRef.getValue(), opUsedVars);
+ if (opUsedVars.size() == 0) {
+ // move down the boundary if the operator is a const assigns.
+ boundaryOpRef = boundaryOpRef.getValue().getInputs().get(0);
+ } else {
+ break;
}
}
}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/SubplanOutOfGroupRule.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/SubplanOutOfGroupRule.java b/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/SubplanOutOfGroupRule.java
deleted file mode 100644
index d0d3dd7..0000000
--- a/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/SubplanOutOfGroupRule.java
+++ /dev/null
@@ -1,125 +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.Iterator;
-import java.util.List;
-
-import org.apache.commons.lang3.mutable.Mutable;
-import org.apache.commons.lang3.mutable.MutableObject;
-
-import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
-import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
-import org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan;
-import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
-import org.apache.hyracks.algebricks.core.algebra.base.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.GroupByOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.SubplanOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities;
-import org.apache.hyracks.algebricks.core.algebra.util.OperatorPropertiesUtil;
-import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
-
-/**
- * Looks for a nested group-by plan ending in
- * subplan {
- * ...
- * }
- * select (function-call: algebricks:not, Args:[function-call:
- * algebricks:is-null, Args:[...]])
- * nested tuple source -- |UNPARTITIONED|
- */
-
-public class SubplanOutOfGroupRule 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 op0 = (AbstractLogicalOperator) opRef.getValue();
- if (op0.getOperatorTag() != LogicalOperatorTag.GROUP) {
- return false;
- }
- GroupByOperator gby = (GroupByOperator) op0;
-
- Iterator<ILogicalPlan> plansIter = gby.getNestedPlans().iterator();
- ILogicalPlan p = null;
- while (plansIter.hasNext()) {
- p = plansIter.next();
- }
- if (p == null) {
- return false;
- }
- if (p.getRoots().size() != 1) {
- return false;
- }
- Mutable<ILogicalOperator> op1Ref = p.getRoots().get(0);
- AbstractLogicalOperator op1 = (AbstractLogicalOperator) op1Ref.getValue();
- boolean found = false;
- while (op1.getInputs().size() == 1) {
- if (op1.getOperatorTag() == LogicalOperatorTag.SUBPLAN) {
- SubplanOperator subplan = (SubplanOperator) op1;
- AbstractLogicalOperator op2 = (AbstractLogicalOperator) subplan.getInputs().get(0).getValue();
- if (OperatorPropertiesUtil.isNullTest(op2)) {
- if (subplan.getNestedPlans().size() == 1) {
- ILogicalPlan p1 = subplan.getNestedPlans().get(0);
- if (p1.getRoots().size() == 1) {
- AbstractLogicalOperator r1 = (AbstractLogicalOperator) p1.getRoots().get(0).getValue();
- if (r1.getOperatorTag() == LogicalOperatorTag.INNERJOIN
- || r1.getOperatorTag() == LogicalOperatorTag.LEFTOUTERJOIN) {
- // now, check that it propagates all variables,
- // so it can be pushed
- List<LogicalVariable> op2Vars = new ArrayList<LogicalVariable>();
- VariableUtilities.getLiveVariables(op2, op2Vars);
- List<LogicalVariable> op1Vars = new ArrayList<LogicalVariable>();
- VariableUtilities.getLiveVariables(subplan, op1Vars);
- if (op1Vars.containsAll(op2Vars)) {
- found = true;
- break;
- }
- }
- }
- }
- }
- }
- op1Ref = op1.getInputs().get(0);
- op1 = (AbstractLogicalOperator) op1Ref.getValue();
- }
- if (!found) {
- return false;
- }
-
- ILogicalOperator subplan = op1;
- ILogicalOperator op2 = op1.getInputs().get(0).getValue();
- op1Ref.setValue(op2);
- Mutable<ILogicalOperator> opUnderRef = gby.getInputs().get(0);
- ILogicalOperator opUnder = opUnderRef.getValue();
- subplan.getInputs().clear();
- subplan.getInputs().add(new MutableObject<ILogicalOperator>(opUnder));
- opUnderRef.setValue(subplan);
-
- return true;
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/EliminateSubplanRule.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/EliminateSubplanRule.java b/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/EliminateSubplanRule.java
new file mode 100644
index 0000000..32c7e03
--- /dev/null
+++ b/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/EliminateSubplanRule.java
@@ -0,0 +1,129 @@
+/*
+ * 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.subplan;
+
+import java.util.LinkedList;
+
+import org.apache.commons.lang3.mutable.Mutable;
+import org.apache.commons.lang3.mutable.MutableObject;
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan;
+import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
+import org.apache.hyracks.algebricks.core.algebra.base.LogicalOperatorTag;
+import org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.InnerJoinOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.SubplanOperator;
+import org.apache.hyracks.algebricks.core.algebra.util.OperatorManipulationUtil;
+import org.apache.hyracks.algebricks.core.algebra.util.OperatorPropertiesUtil;
+import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
+
+public class EliminateSubplanRule implements IAlgebraicRewriteRule {
+
+ @Override
+ public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context) {
+ return false;
+ }
+
+ /**
+ * Eliminate Subplan above ETS
+ * and Subplan that has only ops. with one input and no free vars.
+ */
+ @Override
+ public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
+ throws AlgebricksException {
+ AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue();
+ if (op.getOperatorTag() != LogicalOperatorTag.SUBPLAN) {
+ return false;
+ }
+ SubplanOperator subplan = (SubplanOperator) op;
+
+ Mutable<ILogicalOperator> outerRef = subplan.getInputs().get(0);
+ AbstractLogicalOperator outerRefOp = (AbstractLogicalOperator) outerRef.getValue();
+ if (outerRefOp.getOperatorTag() == LogicalOperatorTag.EMPTYTUPLESOURCE) {
+ elimSubplanOverEts(opRef, context);
+ return true;
+ }
+ if (subplan.getNestedPlans().size() == 1 && subplan.getNestedPlans().get(0).getRoots().size() == 1
+ && !OperatorPropertiesUtil.hasFreeVariables(subplan)) {
+ if (elimOneSubplanWithNoFreeVars(opRef)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private boolean elimOneSubplanWithNoFreeVars(Mutable<ILogicalOperator> opRef) {
+ SubplanOperator subplan = (SubplanOperator) opRef.getValue();
+ AbstractLogicalOperator rootOp = (AbstractLogicalOperator) subplan.getNestedPlans().get(0).getRoots().get(0)
+ .getValue();
+ if (rootOp.getOperatorTag() == LogicalOperatorTag.EMPTYTUPLESOURCE
+ || rootOp.getOperatorTag() == LogicalOperatorTag.NESTEDTUPLESOURCE) {
+ opRef.setValue(subplan.getInputs().get(0).getValue());
+ return true;
+ } else {
+ AbstractLogicalOperator botOp = rootOp;
+ if (botOp.getInputs().size() != 1) {
+ return false;
+ }
+ do {
+ Mutable<ILogicalOperator> botRef = botOp.getInputs().get(0);
+ botOp = (AbstractLogicalOperator) botRef.getValue();
+ if (botOp.getOperatorTag() == LogicalOperatorTag.EMPTYTUPLESOURCE) {
+ botRef.setValue(subplan.getInputs().get(0).getValue());
+ opRef.setValue(rootOp);
+ return true;
+ }
+ } while (botOp.getInputs().size() == 1);
+ return false;
+ }
+ }
+
+ private void elimSubplanOverEts(Mutable<ILogicalOperator> opRef, IOptimizationContext ctx)
+ throws AlgebricksException {
+ SubplanOperator subplan = (SubplanOperator) opRef.getValue();
+ for (ILogicalPlan p : subplan.getNestedPlans()) {
+ for (Mutable<ILogicalOperator> r : p.getRoots()) {
+ OperatorManipulationUtil.ntsToEts(r, ctx);
+ }
+ }
+ LinkedList<Mutable<ILogicalOperator>> allRoots = subplan.allRootsInReverseOrder();
+ if (allRoots.size() == 1) {
+ opRef.setValue(allRoots.get(0).getValue());
+ } else {
+ ILogicalOperator topOp = null;
+ for (Mutable<ILogicalOperator> r : allRoots) {
+ if (topOp == null) {
+ topOp = r.getValue();
+ } else {
+ InnerJoinOperator j = new InnerJoinOperator(
+ new MutableObject<ILogicalExpression>(ConstantExpression.TRUE));
+ j.getInputs().add(new MutableObject<ILogicalOperator>(topOp));
+ j.getInputs().add(r);
+ ctx.setOutputTypeEnvironment(j, j.computeOutputTypeEnvironment(ctx));
+ topOp = j;
+ }
+ }
+ opRef.setValue(topOp);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/EliminateSubplanWithInputCardinalityOneRule.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/EliminateSubplanWithInputCardinalityOneRule.java b/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/EliminateSubplanWithInputCardinalityOneRule.java
new file mode 100644
index 0000000..f7b6dea
--- /dev/null
+++ b/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/EliminateSubplanWithInputCardinalityOneRule.java
@@ -0,0 +1,203 @@
+/*
+ * 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.subplan;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.commons.lang3.mutable.Mutable;
+
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.common.utils.ListSet;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan;
+import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
+import org.apache.hyracks.algebricks.core.algebra.base.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.SubplanOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities;
+import org.apache.hyracks.algebricks.core.algebra.util.OperatorPropertiesUtil;
+import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
+
+/**
+ * This rule eliminates a subplan with the following pattern:
+ * -- SUBPLAN
+ * -- OP (where OP produces exactly one tuple)
+ * The live variables at OP will not be used after SUBPLAN.
+ * Note: This rule must be applied after
+ * the RemoveRedundantVariablesRule (to avoid the lineage analysis of variable cardinality).
+ *
+ * @author yingyib
+ */
+public class EliminateSubplanWithInputCardinalityOneRule implements IAlgebraicRewriteRule {
+ /** The pointer to the topmost operator */
+ private Mutable<ILogicalOperator> rootRef;
+ /** Whether the rule has even been invoked */
+ private boolean invoked = false;
+
+ @Override
+ public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context) {
+ return false;
+ }
+
+ @Override
+ public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException {
+ if (!invoked) {
+ rootRef = opRef;
+ invoked = true;
+ }
+ AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue();
+ if (op.getInputs().size() <= 0) {
+ return false;
+ }
+ boolean changed = false;
+ for (Mutable<ILogicalOperator> subplanRef : op.getInputs()) {
+ AbstractLogicalOperator op1 = (AbstractLogicalOperator) subplanRef.getValue();
+ if (op1.getOperatorTag() != LogicalOperatorTag.SUBPLAN) {
+ continue;
+ }
+
+ SubplanOperator subplan = (SubplanOperator) op1;
+ Set<LogicalVariable> usedVarsUp = new ListSet<LogicalVariable>();
+ OperatorPropertiesUtil.getFreeVariablesInPath(rootRef.getValue(), subplan, usedVarsUp);
+ // TODO(buyingyi): figure out the rewriting for subplan operators with multiple subplans.
+ if (subplan.getNestedPlans().size() != 1) {
+ continue;
+ }
+
+ ILogicalOperator subplanInputOperator = subplan.getInputs().get(0).getValue();
+ Set<LogicalVariable> subplanInputVars = new ListSet<LogicalVariable>();
+ VariableUtilities.getLiveVariables(subplanInputOperator, subplanInputVars);
+ int subplanInputVarSize = subplanInputVars.size();
+ subplanInputVars.removeAll(usedVarsUp);
+ // Makes sure the free variables are only used in the subplan.
+ if (subplanInputVars.size() < subplanInputVarSize) {
+ continue;
+ }
+ Set<LogicalVariable> freeVars = new ListSet<LogicalVariable>();
+ OperatorPropertiesUtil.getFreeVariablesInSubplans(subplan, freeVars);
+ boolean cardinalityOne = isCardinalityOne(subplan.getInputs().get(0), freeVars);
+ if (cardinalityOne) {
+ /** If the cardinality of freeVars in the subplan is one, the subplan can be removed. */
+ ILogicalPlan plan = subplan.getNestedPlans().get(0);
+
+ List<Mutable<ILogicalOperator>> rootRefs = plan.getRoots();
+ // TODO(buyingyi): investigate the case of multi-root plans.
+ if (rootRefs.size() != 1) {
+ continue;
+ }
+ Set<Mutable<ILogicalOperator>> ntsSet = new ListSet<Mutable<ILogicalOperator>>();
+ findNts(rootRefs.get(0), ntsSet);
+
+ /** Replaces nts with the input operator of the subplan. */
+ for (Mutable<ILogicalOperator> nts : ntsSet) {
+ nts.setValue(subplanInputOperator);
+ }
+ subplanRef.setValue(rootRefs.get(0).getValue());
+ changed = true;
+ } else {
+ continue;
+ }
+ }
+ return changed;
+ }
+
+ /**
+ * Whether the cardinality of the input free variables are one.
+ *
+ * @param opRef
+ * the operator to be checked (including its input operators)
+ * @param freeVars
+ * variables to be checked for produced operators
+ * @return true if every input variable has cardinality one; false otherwise.
+ * @throws AlgebricksException
+ */
+ private boolean isCardinalityOne(Mutable<ILogicalOperator> opRef, Set<LogicalVariable> freeVars)
+ throws AlgebricksException {
+ Set<LogicalVariable> varsWithCardinalityOne = new ListSet<LogicalVariable>();
+ Set<LogicalVariable> varsLiveAtUnnestAndJoin = new ListSet<LogicalVariable>();
+ isCardinalityOne(opRef, freeVars, varsWithCardinalityOne, varsLiveAtUnnestAndJoin);
+ varsWithCardinalityOne.removeAll(varsLiveAtUnnestAndJoin);
+ return varsWithCardinalityOne.equals(freeVars);
+ }
+
+ /**
+ * Recursively adding variables which has cardinality one and in int the input free variable set.
+ *
+ * @param opRef
+ * , the current operator reference.
+ * @param freeVars
+ * , a set of variables.
+ * @param varsWithCardinalityOne
+ * , variables in the free variable set with cardinality one at the time they are created.
+ * @param varsLiveAtUnnestAndJoin
+ * , live variables at Unnest and Join. The cardinalities of those variables can become more than one
+ * even if their cardinalities were one at the time those variables were created.
+ * @throws AlgebricksException
+ */
+ private void isCardinalityOne(Mutable<ILogicalOperator> opRef, Set<LogicalVariable> freeVars,
+ Set<LogicalVariable> varsWithCardinalityOne, Set<LogicalVariable> varsLiveAtUnnestAndJoin)
+ throws AlgebricksException {
+ AbstractLogicalOperator operator = (AbstractLogicalOperator) opRef.getValue();
+ List<LogicalVariable> producedVars = new ArrayList<LogicalVariable>();
+ VariableUtilities.getProducedVariables(operator, producedVars);
+ if (operator.getOperatorTag() == LogicalOperatorTag.UNNEST
+ || operator.getOperatorTag() == LogicalOperatorTag.INNERJOIN
+ || operator.getOperatorTag() == LogicalOperatorTag.LEFTOUTERJOIN) {
+ VariableUtilities.getLiveVariables(operator, varsLiveAtUnnestAndJoin);
+ }
+ if (operator.getOperatorTag() == LogicalOperatorTag.AGGREGATE) {
+ for (LogicalVariable producedVar : producedVars) {
+ if (freeVars.contains(producedVar)) {
+ varsWithCardinalityOne.add(producedVar);
+ }
+ }
+ }
+ if (varsWithCardinalityOne.size() == freeVars.size()) {
+ return;
+ }
+ for (Mutable<ILogicalOperator> childRef : operator.getInputs()) {
+ isCardinalityOne(childRef, freeVars, varsWithCardinalityOne, varsLiveAtUnnestAndJoin);
+ }
+ }
+
+ /**
+ * Find the NestedTupleSource operator in the direct/undirect input operators of opRef.
+ *
+ * @param opRef
+ * , the current operator reference.
+ * @param ntsSet
+ * , the set NestedTupleSource operator references.
+ */
+ private void findNts(Mutable<ILogicalOperator> opRef, Set<Mutable<ILogicalOperator>> ntsSet) {
+ int childSize = opRef.getValue().getInputs().size();
+ if (childSize == 0) {
+ AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue();
+ if (op.getOperatorTag() == LogicalOperatorTag.NESTEDTUPLESOURCE) {
+ ntsSet.add(opRef);
+ }
+ return;
+ }
+ for (Mutable<ILogicalOperator> childRef : opRef.getValue().getInputs()) {
+ findNts(childRef, ntsSet);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/IntroduceGroupByForSubplanRule.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/IntroduceGroupByForSubplanRule.java b/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/IntroduceGroupByForSubplanRule.java
new file mode 100644
index 0000000..3e65d91
--- /dev/null
+++ b/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/IntroduceGroupByForSubplanRule.java
@@ -0,0 +1,337 @@
+/*
+ * 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.subplan;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+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.ListSet;
+import org.apache.hyracks.algebricks.common.utils.Pair;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan;
+import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
+import org.apache.hyracks.algebricks.core.algebra.base.LogicalOperatorTag;
+import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable;
+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.functions.AlgebricksBuiltinFunctions;
+import org.apache.hyracks.algebricks.core.algebra.functions.IFunctionInfo;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractBinaryJoinOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.AggregateOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.AssignOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.DataSourceScanOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.GroupByOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.NestedTupleSourceOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.ProjectOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.SelectOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.SubplanOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.UnnestOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities;
+import org.apache.hyracks.algebricks.core.algebra.plan.ALogicalPlanImpl;
+import org.apache.hyracks.algebricks.core.algebra.properties.FunctionalDependency;
+import org.apache.hyracks.algebricks.core.algebra.util.OperatorManipulationUtil;
+import org.apache.hyracks.algebricks.core.algebra.util.OperatorPropertiesUtil;
+import org.apache.hyracks.algebricks.core.config.AlgebricksConfig;
+import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
+import org.apache.hyracks.algebricks.rewriter.util.PhysicalOptimizationsUtil;
+
+/**
+ * The rule searches for SUBPLAN operator with a optional PROJECT operator and
+ * an AGGREGATE followed by a join operator.
+ *
+ * <pre>
+ * Before
+ *
+ * plan__parent
+ * SUBPLAN {
+ * PROJECT?
+ * AGGREGATE
+ * plan__nested_A
+ * INNER_JOIN | LEFT_OUTER_JOIN ($condition, $left, $right)
+ * plan__nested_B
+ * }
+ * plan__child
+ *
+ * where $condition does not equal a constant true.
+ *
+ * After (This is a general application of the rule, specifics may vary based on the query plan.)
+ *
+ * plan__parent
+ * GROUP_BY {
+ * PROJECT?
+ * AGGREGATE
+ * plan__nested_A
+ * SELECT( algebricks:not( is_null( $right ) ) )
+ * NESTED_TUPLE_SOURCE
+ * }
+ * SUBPLAN {
+ * INNER_JOIN | LEFT_OUTER_JOIN ($condition, $left, $right)
+ * plan__nested_B
+ * }
+ * plan__child
+ * </pre>
+ *
+ * @author prestonc
+ */
+
+public class IntroduceGroupByForSubplanRule 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 op0 = (AbstractLogicalOperator) opRef.getValue();
+ if (op0.getOperatorTag() != LogicalOperatorTag.SUBPLAN) {
+ return false;
+ }
+ SubplanOperator subplan = (SubplanOperator) op0;
+
+ Iterator<ILogicalPlan> plansIter = subplan.getNestedPlans().iterator();
+ ILogicalPlan p = null;
+ while (plansIter.hasNext()) {
+ p = plansIter.next();
+ }
+ if (p == null) {
+ return false;
+ }
+ if (p.getRoots().size() != 1) {
+ return false;
+ }
+ Mutable<ILogicalOperator> subplanRoot = p.getRoots().get(0);
+ AbstractLogicalOperator op1 = (AbstractLogicalOperator) subplanRoot.getValue();
+
+ Mutable<ILogicalOperator> botRef = subplanRoot;
+ AbstractLogicalOperator op2;
+ // Project is optional
+ if (op1.getOperatorTag() != LogicalOperatorTag.PROJECT) {
+ op2 = op1;
+ } else {
+ ProjectOperator project = (ProjectOperator) op1;
+ botRef = project.getInputs().get(0);
+ op2 = (AbstractLogicalOperator) botRef.getValue();
+ }
+ if (op2.getOperatorTag() != LogicalOperatorTag.AGGREGATE) {
+ return false;
+ }
+ AggregateOperator aggregate = (AggregateOperator) op2;
+
+ Set<LogicalVariable> free = new HashSet<LogicalVariable>();
+ VariableUtilities.getUsedVariables(aggregate, free);
+
+ Mutable<ILogicalOperator> op3Ref = aggregate.getInputs().get(0);
+ AbstractLogicalOperator op3 = (AbstractLogicalOperator) op3Ref.getValue();
+
+ while (op3.getInputs().size() == 1) {
+ Set<LogicalVariable> prod = new HashSet<LogicalVariable>();
+ VariableUtilities.getProducedVariables(op3, prod);
+ free.removeAll(prod);
+ VariableUtilities.getUsedVariables(op3, free);
+ botRef = op3Ref;
+ op3Ref = op3.getInputs().get(0);
+ op3 = (AbstractLogicalOperator) op3Ref.getValue();
+ }
+
+ if (op3.getOperatorTag() != LogicalOperatorTag.INNERJOIN
+ && op3.getOperatorTag() != LogicalOperatorTag.LEFTOUTERJOIN) {
+ return false;
+ }
+ AbstractBinaryJoinOperator join = (AbstractBinaryJoinOperator) op3;
+ if (join.getCondition().getValue() == ConstantExpression.TRUE) {
+ return false;
+ }
+ VariableUtilities.getUsedVariables(join, free);
+
+ AbstractLogicalOperator b0 = (AbstractLogicalOperator) join.getInputs().get(0).getValue();
+ // see if there's an NTS at the end of the pipeline
+ NestedTupleSourceOperator outerNts = getNts(b0);
+ if (outerNts == null) {
+ AbstractLogicalOperator b1 = (AbstractLogicalOperator) join.getInputs().get(1).getValue();
+ outerNts = getNts(b1);
+ if (outerNts == null) {
+ return false;
+ }
+ }
+
+ Set<LogicalVariable> pkVars = computeGbyVars(outerNts, free, context);
+ if (pkVars == null || pkVars.size() < 1) {
+ // there is no non-trivial primary key, group-by keys are all live variables
+ // that were produced by descendant or self
+ ILogicalOperator subplanInput = subplan.getInputs().get(0).getValue();
+ pkVars = new HashSet<LogicalVariable>();
+ //get live variables
+ VariableUtilities.getLiveVariables(subplanInput, pkVars);
+
+ //get produced variables
+ Set<LogicalVariable> producedVars = new HashSet<LogicalVariable>();
+ VariableUtilities.getProducedVariablesInDescendantsAndSelf(subplanInput, producedVars);
+
+ //retain the intersection
+ pkVars.retainAll(producedVars);
+ }
+ AlgebricksConfig.ALGEBRICKS_LOGGER.fine("Found FD for introducing group-by: " + pkVars);
+
+ Mutable<ILogicalOperator> rightRef = join.getInputs().get(1);
+ LogicalVariable testForNull = null;
+ AbstractLogicalOperator right = (AbstractLogicalOperator) rightRef.getValue();
+ switch (right.getOperatorTag()) {
+ case UNNEST: {
+ UnnestOperator innerUnnest = (UnnestOperator) right;
+ // Select [ $y != null ]
+ testForNull = innerUnnest.getVariable();
+ break;
+ }
+ case RUNNINGAGGREGATE: {
+ ILogicalOperator inputToRunningAggregate = right.getInputs().get(0).getValue();
+ Set<LogicalVariable> producedVars = new ListSet<LogicalVariable>();
+ VariableUtilities.getProducedVariables(inputToRunningAggregate, producedVars);
+ if (!producedVars.isEmpty()) {
+ // Select [ $y != null ]
+ testForNull = producedVars.iterator().next();
+ }
+ break;
+ }
+ case DATASOURCESCAN: {
+ DataSourceScanOperator innerScan = (DataSourceScanOperator) right;
+ // Select [ $y != null ]
+ if (innerScan.getVariables().size() == 1) {
+ testForNull = innerScan.getVariables().get(0);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ if (testForNull == null) {
+ testForNull = context.newVar();
+ AssignOperator tmpAsgn = new AssignOperator(testForNull,
+ new MutableObject<ILogicalExpression>(ConstantExpression.TRUE));
+ tmpAsgn.getInputs().add(new MutableObject<ILogicalOperator>(rightRef.getValue()));
+ rightRef.setValue(tmpAsgn);
+ context.computeAndSetTypeEnvironmentForOperator(tmpAsgn);
+ }
+
+ IFunctionInfo finfoEq = context.getMetadataProvider().lookupFunction(AlgebricksBuiltinFunctions.IS_NULL);
+ ILogicalExpression isNullTest = new ScalarFunctionCallExpression(finfoEq,
+ new MutableObject<ILogicalExpression>(new VariableReferenceExpression(testForNull)));
+ IFunctionInfo finfoNot = context.getMetadataProvider().lookupFunction(AlgebricksBuiltinFunctions.NOT);
+ ScalarFunctionCallExpression nonNullTest = new ScalarFunctionCallExpression(finfoNot,
+ new MutableObject<ILogicalExpression>(isNullTest));
+ SelectOperator selectNonNull = new SelectOperator(new MutableObject<ILogicalExpression>(nonNullTest), false,
+ null);
+ GroupByOperator g = new GroupByOperator();
+ Mutable<ILogicalOperator> newSubplanRef = new MutableObject<ILogicalOperator>(subplan);
+ NestedTupleSourceOperator nts = new NestedTupleSourceOperator(new MutableObject<ILogicalOperator>(g));
+ opRef.setValue(g);
+ selectNonNull.getInputs().add(new MutableObject<ILogicalOperator>(nts));
+
+ List<Mutable<ILogicalOperator>> prodInpList = botRef.getValue().getInputs();
+ prodInpList.clear();
+ prodInpList.add(new MutableObject<ILogicalOperator>(selectNonNull));
+
+ ILogicalPlan gPlan = new ALogicalPlanImpl(new MutableObject<ILogicalOperator>(subplanRoot.getValue()));
+ g.getNestedPlans().add(gPlan);
+ subplanRoot.setValue(op3Ref.getValue());
+ g.getInputs().add(newSubplanRef);
+
+ HashSet<LogicalVariable> underVars = new HashSet<LogicalVariable>();
+ VariableUtilities.getLiveVariables(subplan.getInputs().get(0).getValue(), underVars);
+ underVars.removeAll(pkVars);
+ Map<LogicalVariable, LogicalVariable> mappedVars = buildVarExprList(pkVars, context, g, g.getGroupByList());
+ context.updatePrimaryKeys(mappedVars);
+ for (LogicalVariable uv : underVars) {
+ g.getDecorList().add(new Pair<LogicalVariable, Mutable<ILogicalExpression>>(null,
+ new MutableObject<ILogicalExpression>(new VariableReferenceExpression(uv))));
+ }
+ OperatorPropertiesUtil.typeOpRec(subplanRoot, context);
+ OperatorPropertiesUtil.typeOpRec(gPlan.getRoots().get(0), context);
+ context.computeAndSetTypeEnvironmentForOperator(g);
+ return true;
+ }
+
+ private NestedTupleSourceOperator getNts(AbstractLogicalOperator op) {
+ AbstractLogicalOperator alo = op;
+ do {
+ if (alo.getOperatorTag() == LogicalOperatorTag.NESTEDTUPLESOURCE) {
+ return (NestedTupleSourceOperator) alo;
+ }
+ if (alo.getInputs().size() != 1) {
+ return null;
+ }
+ alo = (AbstractLogicalOperator) alo.getInputs().get(0).getValue();
+ } while (true);
+ }
+
+ protected Set<LogicalVariable> computeGbyVars(AbstractLogicalOperator op, Set<LogicalVariable> freeVars,
+ IOptimizationContext context) throws AlgebricksException {
+ PhysicalOptimizationsUtil.computeFDsAndEquivalenceClasses(op, context);
+ List<FunctionalDependency> fdList = context.getFDList(op);
+ if (fdList == null) {
+ return null;
+ }
+ // check if any of the FDs is a key
+ List<LogicalVariable> all = new ArrayList<LogicalVariable>();
+ VariableUtilities.getLiveVariables(op, all);
+ all.retainAll(freeVars);
+ for (FunctionalDependency fd : fdList) {
+ if (fd.getTail().containsAll(all)) {
+ return new HashSet<LogicalVariable>(fd.getHead());
+ }
+ }
+ return null;
+ }
+
+ private Map<LogicalVariable, LogicalVariable> buildVarExprList(Collection<LogicalVariable> vars,
+ IOptimizationContext context, GroupByOperator g,
+ List<Pair<LogicalVariable, Mutable<ILogicalExpression>>> outVeList) throws AlgebricksException {
+ Map<LogicalVariable, LogicalVariable> m = new HashMap<LogicalVariable, LogicalVariable>();
+ for (LogicalVariable ov : vars) {
+ LogicalVariable newVar = context.newVar();
+ ILogicalExpression varExpr = new VariableReferenceExpression(newVar);
+ outVeList.add(new Pair<LogicalVariable, Mutable<ILogicalExpression>>(ov,
+ new MutableObject<ILogicalExpression>(varExpr)));
+ for (ILogicalPlan p : g.getNestedPlans()) {
+ for (Mutable<ILogicalOperator> r : p.getRoots()) {
+ OperatorManipulationUtil.substituteVarRec((AbstractLogicalOperator) r.getValue(), ov, newVar, true,
+ context);
+ }
+ }
+ AbstractLogicalOperator opUnder = (AbstractLogicalOperator) g.getInputs().get(0).getValue();
+ OperatorManipulationUtil.substituteVarRec(opUnder, ov, newVar, true, context);
+ m.put(ov, newVar);
+ }
+ return m;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/IntroduceLeftOuterJoinForSubplanRule.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/IntroduceLeftOuterJoinForSubplanRule.java b/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/IntroduceLeftOuterJoinForSubplanRule.java
new file mode 100644
index 0000000..daf27ac
--- /dev/null
+++ b/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/IntroduceLeftOuterJoinForSubplanRule.java
@@ -0,0 +1,125 @@
+/*
+ * 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.subplan;
+
+import java.util.Iterator;
+
+import org.apache.commons.lang3.mutable.Mutable;
+
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan;
+import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
+import org.apache.hyracks.algebricks.core.algebra.base.LogicalOperatorTag;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.InnerJoinOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.LeftOuterJoinOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.SubplanOperator;
+import org.apache.hyracks.algebricks.core.algebra.util.OperatorPropertiesUtil;
+import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
+
+public class IntroduceLeftOuterJoinForSubplanRule 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 op0 = (AbstractLogicalOperator) opRef.getValue();
+ if (op0.getOperatorTag() != LogicalOperatorTag.SUBPLAN) {
+ return false;
+ }
+ SubplanOperator subplan = (SubplanOperator) op0;
+
+ Iterator<ILogicalPlan> plansIter = subplan.getNestedPlans().iterator();
+ ILogicalPlan p = null;
+ while (plansIter.hasNext()) {
+ p = plansIter.next();
+ }
+ if (p == null) {
+ return false;
+ }
+ if (p.getRoots().size() != 1) {
+ return false;
+ }
+ Mutable<ILogicalOperator> subplanRoot = p.getRoots().get(0);
+ AbstractLogicalOperator op1 = (AbstractLogicalOperator) subplanRoot.getValue();
+ Mutable<ILogicalOperator> opUnder = subplan.getInputs().get(0);
+
+ if (OperatorPropertiesUtil.isNullTest((AbstractLogicalOperator) opUnder.getValue())) {
+ return false;
+ }
+
+ switch (op1.getOperatorTag()) {
+ case INNERJOIN: {
+ InnerJoinOperator join = (InnerJoinOperator) op1;
+ Mutable<ILogicalOperator> leftRef = join.getInputs().get(0);
+ Mutable<ILogicalOperator> rightRef = join.getInputs().get(1);
+ Mutable<ILogicalOperator> ntsRef = getNtsAtEndOfPipeline(leftRef);
+ if (ntsRef == null) {
+ ntsRef = getNtsAtEndOfPipeline(rightRef);
+ if (ntsRef == null) {
+ return false;
+ } else {
+ Mutable<ILogicalOperator> t = leftRef;
+ leftRef = rightRef;
+ rightRef = t;
+ }
+ }
+ ntsRef.setValue(opUnder.getValue());
+ LeftOuterJoinOperator loj = new LeftOuterJoinOperator(join.getCondition());
+ loj.getInputs().add(leftRef);
+ loj.getInputs().add(rightRef);
+ opRef.setValue(loj);
+ context.computeAndSetTypeEnvironmentForOperator(loj);
+ return true;
+ }
+ case LEFTOUTERJOIN: {
+ LeftOuterJoinOperator join = (LeftOuterJoinOperator) op1;
+ Mutable<ILogicalOperator> leftRef = join.getInputs().get(0);
+ Mutable<ILogicalOperator> ntsRef = getNtsAtEndOfPipeline(leftRef);
+ if (ntsRef == null) {
+ return false;
+ }
+ ntsRef.setValue(opUnder.getValue());
+ opRef.setValue(join);
+ context.computeAndSetTypeEnvironmentForOperator(join);
+ return true;
+ }
+ default: {
+ return false;
+ }
+ }
+ }
+
+ private Mutable<ILogicalOperator> getNtsAtEndOfPipeline(Mutable<ILogicalOperator> opRef) {
+ AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue();
+ if (op.getOperatorTag() == LogicalOperatorTag.NESTEDTUPLESOURCE) {
+ return opRef;
+ }
+ if (op.getInputs().size() != 1) {
+ return null;
+ }
+ return getNtsAtEndOfPipeline(op.getInputs().get(0));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/MoveFreeVariableOperatorOutOfSubplanRule.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/MoveFreeVariableOperatorOutOfSubplanRule.java b/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/MoveFreeVariableOperatorOutOfSubplanRule.java
new file mode 100644
index 0000000..959466a
--- /dev/null
+++ b/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/MoveFreeVariableOperatorOutOfSubplanRule.java
@@ -0,0 +1,187 @@
+/*
+ * 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.subplan;
+
+import java.util.HashSet;
+import java.util.ListIterator;
+import java.util.Set;
+
+import org.apache.commons.lang3.mutable.Mutable;
+
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan;
+import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
+import org.apache.hyracks.algebricks.core.algebra.base.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.SubplanOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities;
+import org.apache.hyracks.algebricks.core.algebra.util.OperatorPropertiesUtil;
+import org.apache.hyracks.algebricks.rewriter.rules.AbstractDecorrelationRule;
+
+/**
+ * The rule searches for operators that can be moved outside the subplan.
+ *
+ * <pre>
+ * Before
+ *
+ * %PARENT_PLAN
+ * SUBPLAN{
+ * %NESTED_OPERATORS_B+
+ * ASSIGN || %SUBPLAN
+ * %NESTED_OPERATORS_A*
+ * NESTEDTUPLESOURCE
+ * }
+ * %CHILD_PLAN
+ *
+ * where
+ * %SUBPLAN has one nested plan with a root AGGREGATE operator.
+ *
+ * After
+ *
+ * %PARENT_PLAN
+ * SUBPLAN{
+ * %NESTED_OPERATORS_B+
+ * %NESTED_OPERATORS_A*
+ * NESTEDTUPLESOURCE
+ * }
+ * ASSIGN || %SUBPLAN
+ * %CHILD_PLAN
+ * </pre>
+ */
+public class MoveFreeVariableOperatorOutOfSubplanRule extends AbstractDecorrelationRule {
+
+ @Override
+ public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
+ throws AlgebricksException {
+ AbstractLogicalOperator op0 = (AbstractLogicalOperator) opRef.getValue();
+ if (op0.getOperatorTag() != LogicalOperatorTag.SUBPLAN) {
+ return false;
+ }
+ SubplanOperator subplan = (SubplanOperator) op0;
+
+ Mutable<ILogicalOperator> leftRef = subplan.getInputs().get(0);
+ if (((AbstractLogicalOperator) leftRef.getValue()).getOperatorTag() == LogicalOperatorTag.EMPTYTUPLESOURCE) {
+ return false;
+ }
+
+ ListIterator<ILogicalPlan> plansIter = subplan.getNestedPlans().listIterator();
+ ILogicalPlan p = null;
+ while (plansIter.hasNext()) {
+ p = plansIter.next();
+ }
+ if (p == null) {
+ return false;
+ }
+ if (p.getRoots().size() != 1) {
+ return false;
+ }
+ Mutable<ILogicalOperator> opRef1 = p.getRoots().get(0);
+
+ //The root operator will not be movable. Start with the second op
+ AbstractLogicalOperator op1 = (AbstractLogicalOperator) opRef1.getValue();
+ if (op1.getInputs().size() != 1) {
+ return false;
+ }
+ Mutable<ILogicalOperator> op2Ref = op1.getInputs().get(0);
+
+ //Get all variables that come from outside of the loop
+ Set<LogicalVariable> free = new HashSet<LogicalVariable>();
+ OperatorPropertiesUtil.getFreeVariablesInSelfOrDesc(op1, free);
+
+ while (op2Ref != null) {
+ //Get the operator that we want to look at
+ AbstractLogicalOperator op2 = (AbstractLogicalOperator) op2Ref.getValue();
+
+ //Make sure we are looking at subplan with a scan/join
+ if (op2.getInputs().size() != 1 || !descOrSelfIsScanOrJoin(op2)) {
+ return false;
+ }
+ boolean notApplicable = false;
+
+ //Get its used variables
+ Set<LogicalVariable> used = new HashSet<LogicalVariable>();
+
+ //not movable if the operator is not an assign or subplan
+ //Might be helpful in the future for other operations in the future
+ if (movableOperator(op2.getOperatorTag())) {
+ if (op2.getOperatorTag() == LogicalOperatorTag.ASSIGN) {
+ VariableUtilities.getUsedVariables(op2, used);
+ } else if (op2.getOperatorTag() == LogicalOperatorTag.SUBPLAN) {
+ // Nested plan must have an aggregate root.
+ ListIterator<ILogicalPlan> subplansIter = ((SubplanOperator) op2).getNestedPlans().listIterator();
+ ILogicalPlan plan = null;
+ while (subplansIter.hasNext()) {
+ plan = subplansIter.next();
+ }
+ if (plan == null) {
+ return false;
+ }
+ if (plan.getRoots().size() != 1) {
+ return false;
+ }
+ ILogicalOperator op3 = plan.getRoots().get(0).getValue();
+ if (op3.getOperatorTag() != LogicalOperatorTag.AGGREGATE) {
+ return false;
+ }
+ // Used variables do not include ones created in the subplan.
+ VariableUtilities.getUsedVariables(op2, used);
+ Set<LogicalVariable> subplanProducedAndDown = new HashSet<LogicalVariable>();
+ VariableUtilities.getProducedVariablesInDescendantsAndSelf(op3, subplanProducedAndDown);
+ used.removeAll(subplanProducedAndDown);
+ } else {
+ notApplicable = true;
+ }
+ } else {
+ notApplicable = true;
+ }
+
+ //Make sure that all of its used variables come from outside
+ for (LogicalVariable var : used) {
+ if (!free.contains(var)) {
+ notApplicable = true;
+ }
+ }
+
+ if (notApplicable) {
+ op2Ref = op2.getInputs().get(0);
+ } else {
+ //Make the input of op2 be the input of op1
+ op2Ref.setValue(op2.getInputs().get(0).getValue());
+
+ //Make the outside of the subplan the input of op2
+ Mutable<ILogicalOperator> outsideRef = op2.getInputs().get(0);
+ outsideRef.setValue(op0.getInputs().get(0).getValue());
+
+ //Make op2 the input of the subplan
+ Mutable<ILogicalOperator> op2OutsideRef = op0.getInputs().get(0);
+ op2OutsideRef.setValue(op2);
+
+ return true;
+ }
+
+ }
+ return false;
+ }
+
+ protected boolean movableOperator(LogicalOperatorTag operatorTag) {
+ return (operatorTag == LogicalOperatorTag.ASSIGN || operatorTag == LogicalOperatorTag.SUBPLAN);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/NestedSubplanToJoinRule.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/NestedSubplanToJoinRule.java b/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/NestedSubplanToJoinRule.java
new file mode 100644
index 0000000..35c7e4e
--- /dev/null
+++ b/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/subplan/NestedSubplanToJoinRule.java
@@ -0,0 +1,146 @@
+/*
+ * 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.subplan;
+
+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.core.algebra.base.ILogicalExpression;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan;
+import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
+import org.apache.hyracks.algebricks.core.algebra.base.LogicalOperatorTag;
+import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable;
+import org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractOperatorWithNestedPlans;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.EmptyTupleSourceOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.InnerJoinOperator;
+import org.apache.hyracks.algebricks.core.algebra.util.OperatorPropertiesUtil;
+import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
+
+/**
+ * replace Subplan operators with nested loop joins where the join condition is true, if the Subplan
+ * does not contain free variables (does not have correlations to the input stream).
+ *
+ * @author yingyib
+ */
+public class NestedSubplanToJoinRule 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 {
+ if (context.checkIfInDontApplySet(this, opRef.getValue()))
+ return false;
+ context.addToDontApplySet(this, opRef.getValue());
+
+ ILogicalOperator op1 = opRef.getValue();
+ if (op1.getInputs().size() == 0) {
+ return false;
+ }
+
+ boolean rewritten = false;
+ for (int index = 0; index < op1.getInputs().size(); index++) {
+ AbstractLogicalOperator child = (AbstractLogicalOperator) op1.getInputs().get(index).getValue();
+ if (child.getOperatorTag() != LogicalOperatorTag.SUBPLAN) {
+ continue;
+ }
+
+ AbstractOperatorWithNestedPlans subplan = (AbstractOperatorWithNestedPlans) child;
+ Set<LogicalVariable> freeVars = new HashSet<LogicalVariable>();
+ OperatorPropertiesUtil.getFreeVariablesInSubplans(subplan, freeVars);
+ if (!freeVars.isEmpty()) {
+ /**
+ * the subplan is correlated with the outer plan, other rules can deal with it
+ */
+ continue;
+ }
+
+ /** get the input operator of the subplan operator */
+ ILogicalOperator subplanInput = subplan.getInputs().get(0).getValue();
+ AbstractLogicalOperator subplanInputOp = (AbstractLogicalOperator) subplanInput;
+
+ /** If the other join branch is a trivial plan, do not do the rewriting. */
+ if (subplanInputOp.getOperatorTag() == LogicalOperatorTag.EMPTYTUPLESOURCE) {
+ continue;
+ }
+
+ /** get all nested top operators */
+ List<ILogicalPlan> nestedPlans = subplan.getNestedPlans();
+ List<Mutable<ILogicalOperator>> nestedRoots = new ArrayList<Mutable<ILogicalOperator>>();
+ for (ILogicalPlan nestedPlan : nestedPlans) {
+ nestedRoots.addAll(nestedPlan.getRoots());
+ }
+ if (nestedRoots.size() == 0) {
+ /** there is no nested top operators */
+ continue;
+ }
+
+ /**
+ * Expends the input and roots into a DAG of nested loop joins.
+ * Though joins should be left-outer joins, a left-outer join with condition TRUE is equivalent to an inner join.
+ **/
+ Mutable<ILogicalExpression> expr = new MutableObject<ILogicalExpression>(ConstantExpression.TRUE);
+ Mutable<ILogicalOperator> nestedRootRef = nestedRoots.get(0);
+ ILogicalOperator join = new InnerJoinOperator(expr, new MutableObject<ILogicalOperator>(subplanInput),
+ nestedRootRef);
+
+ /** rewrite the nested tuple source to be empty tuple source */
+ rewriteNestedTupleSource(nestedRootRef, context);
+
+ for (int i = 1; i < nestedRoots.size(); i++) {
+ join = new InnerJoinOperator(expr, new MutableObject<ILogicalOperator>(join), nestedRoots.get(i));
+ }
+ op1.getInputs().get(index).setValue(join);
+ context.computeAndSetTypeEnvironmentForOperator(join);
+ rewritten = true;
+ }
+ return rewritten;
+ }
+
+ /**
+ * rewrite NestedTupleSource operators to EmptyTupleSource operators
+ *
+ * @param nestedRootRef
+ */
+ private void rewriteNestedTupleSource(Mutable<ILogicalOperator> nestedRootRef, IOptimizationContext context)
+ throws AlgebricksException {
+ AbstractLogicalOperator nestedRoot = (AbstractLogicalOperator) nestedRootRef.getValue();
+ if (nestedRoot.getOperatorTag() == LogicalOperatorTag.NESTEDTUPLESOURCE) {
+ ILogicalOperator ets = new EmptyTupleSourceOperator();
+ nestedRootRef.setValue(ets);
+ context.computeAndSetTypeEnvironmentForOperator(ets);
+ }
+ List<Mutable<ILogicalOperator>> inputs = nestedRoot.getInputs();
+ for (Mutable<ILogicalOperator> input : inputs) {
+ rewriteNestedTupleSource(input, context);
+ }
+ }
+}
[4/4] incubator-asterixdb-hyracks git commit: Fix for ASTERIXDB-1018,
ASTERIXDB-1017, ASTERIXDB-1019, ASTERIXDB-1020, ASTERIXDB-1029, ASTERIXDB-1030,
ASTERIXDB-1034:
Posted by bu...@apache.org.
Fix for ASTERIXDB-1018, ASTERIXDB-1017, ASTERIXDB-1019,
ASTERIXDB-1020, ASTERIXDB-1029, ASTERIXDB-1030, ASTERIXDB-1034:
1. Let the keys of introduced nested group-bys (group-bys in a subplan) be only the
variables that are produced in the subplan;
2. In PushSelectIntoJoinRule, push independent operators (e.g., a current-datetime() call)
into the first branch from which the join condition refers some variables.
3. In SimpleUnnestToJoinRule, move the boundary between the two join branches of a added join
which results from pipelined datascans to be below operators that doesn't use any variables
(e.g., a current-datetime() call), therefore potentially, the upper (left) join branch
can be rewritten to index lookups.
Change-Id: I18cfa3875d676f71b26e91433ff101a7e725c890
Reviewed-on: https://asterix-gerrit.ics.uci.edu/488
Tested-by: Jenkins <je...@fulliautomatix.ics.uci.edu>
Reviewed-by: Yingyi Bu <bu...@gmail.com>
Project: http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/commit/7dd47992
Tree: http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/tree/7dd47992
Diff: http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/diff/7dd47992
Branch: refs/heads/master
Commit: 7dd4799235619eb8bba35b6aed65b8b4d8b6f113
Parents: 834fc14
Author: Yingyi Bu <yi...@couchbase.com>
Authored: Wed Dec 30 16:05:14 2015 -0800
Committer: Yingyi Bu <bu...@gmail.com>
Committed: Wed Dec 30 21:14:07 2015 -0800
----------------------------------------------------------------------
.../functions/AlgebricksBuiltinFunctions.java | 1 +
.../logical/AbstractLogicalOperator.java | 1 -
.../logical/DataSourceScanOperator.java | 1 -
.../logical/ExternalDataLookupOperator.java | 9 +-
.../operators/logical/ScriptOperator.java | 14 +-
.../operators/logical/UnnestMapOperator.java | 5 +-
.../visitors/EnforceVariablesVisitor.java | 391 ++++++++++++++
...pressionDeepCopyWithNewVariablesVisitor.java | 152 ++++++
...OperatorDeepCopyWithNewVariablesVisitor.java | 526 +++++++++++++++++++
.../visitors/SubstituteVariableVisitor.java | 30 +-
.../logical/visitors/VariableUtilities.java | 32 +-
.../physical/AbstractPhysicalOperator.java | 21 +-
.../operators/physical/SubplanPOperator.java | 9 +-
.../algebra/util/OperatorManipulationUtil.java | 18 +-
.../algebra/visitors/IQueryOperatorVisitor.java | 59 +++
.../rewriter/base/IAlgebraicRewriteRule.java | 32 +-
.../visitors/EnforceVariablesVisitorTest.java | 190 +++++++
.../piglet/rewriter/PigletRewriteRuleset.java | 2 +-
.../rewriter/rules/EliminateSubplanRule.java | 131 -----
...inateSubplanWithInputCardinalityOneRule.java | 203 -------
.../rewriter/rules/InlineVariablesRule.java | 13 +-
.../rewriter/rules/InsertOuterJoinRule.java | 125 -----
.../rules/IntroduceGroupByForSubplanRule.java | 327 ------------
...oveFreeVariableOperatorOutOfSubplanRule.java | 186 -------
.../rewriter/rules/NestedSubplanToJoinRule.java | 146 -----
.../rewriter/rules/PushSelectIntoJoinRule.java | 26 +-
.../rules/PushSubplanIntoGroupByRule.java | 209 --------
.../rules/SimpleUnnestToProductRule.java | 49 +-
.../rewriter/rules/SubplanOutOfGroupRule.java | 125 -----
.../rules/subplan/EliminateSubplanRule.java | 129 +++++
...inateSubplanWithInputCardinalityOneRule.java | 203 +++++++
.../subplan/IntroduceGroupByForSubplanRule.java | 337 ++++++++++++
.../IntroduceLeftOuterJoinForSubplanRule.java | 125 +++++
...oveFreeVariableOperatorOutOfSubplanRule.java | 187 +++++++
.../rules/subplan/NestedSubplanToJoinRule.java | 146 +++++
.../subplan/PushSubplanIntoGroupByRule.java | 209 ++++++++
.../rules/subplan/SubplanOutOfGroupRule.java | 125 +++++
37 files changed, 2967 insertions(+), 1527 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/functions/AlgebricksBuiltinFunctions.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/functions/AlgebricksBuiltinFunctions.java b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/functions/AlgebricksBuiltinFunctions.java
index 70342b6..874b751 100644
--- a/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/functions/AlgebricksBuiltinFunctions.java
+++ b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/functions/AlgebricksBuiltinFunctions.java
@@ -54,6 +54,7 @@ public class AlgebricksBuiltinFunctions {
public final static FunctionIdentifier IS_NULL = new FunctionIdentifier(ALGEBRICKS_NS, "is-null", 1);
private static final Map<FunctionIdentifier, ComparisonKind> comparisonFunctions = new HashMap<FunctionIdentifier, ComparisonKind>();
+
static {
comparisonFunctions.put(AlgebricksBuiltinFunctions.EQ, ComparisonKind.EQ);
comparisonFunctions.put(AlgebricksBuiltinFunctions.LE, ComparisonKind.LE);
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/AbstractLogicalOperator.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/AbstractLogicalOperator.java b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/AbstractLogicalOperator.java
index cfb64d4..5e9eef6 100644
--- a/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/AbstractLogicalOperator.java
+++ b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/AbstractLogicalOperator.java
@@ -69,7 +69,6 @@ public abstract class AbstractLogicalOperator implements ILogicalOperator {
public AbstractLogicalOperator() {
inputs = new ArrayList<Mutable<ILogicalOperator>>();
- // outputs = new ArrayList<LogicalOperatorReference>();
}
@Override
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/DataSourceScanOperator.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/DataSourceScanOperator.java b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/DataSourceScanOperator.java
index e88b0da..7d3306e 100644
--- a/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/DataSourceScanOperator.java
+++ b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/DataSourceScanOperator.java
@@ -23,7 +23,6 @@ import java.util.Collection;
import java.util.List;
import org.apache.commons.lang3.mutable.Mutable;
-
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
import org.apache.hyracks.algebricks.core.algebra.base.LogicalOperatorTag;
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/ExternalDataLookupOperator.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/ExternalDataLookupOperator.java b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/ExternalDataLookupOperator.java
index fde5fe7..60aec27 100644
--- a/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/ExternalDataLookupOperator.java
+++ b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/ExternalDataLookupOperator.java
@@ -21,14 +21,13 @@ package org.apache.hyracks.algebricks.core.algebra.operators.logical;
import java.util.ArrayList;
import java.util.List;
-import org.apache.hyracks.algebricks.core.algebra.metadata.IDataSource;
import org.apache.commons.lang3.mutable.Mutable;
-
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
import org.apache.hyracks.algebricks.core.algebra.base.LogicalOperatorTag;
import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable;
import org.apache.hyracks.algebricks.core.algebra.expressions.IVariableTypeEnvironment;
+import org.apache.hyracks.algebricks.core.algebra.metadata.IDataSource;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities;
import org.apache.hyracks.algebricks.core.algebra.properties.VariablePropagationPolicy;
import org.apache.hyracks.algebricks.core.algebra.typing.ITypingContext;
@@ -40,7 +39,7 @@ public class ExternalDataLookupOperator extends AbstractDataSourceOperator {
private final List<Object> variableTypes;
protected final Mutable<ILogicalExpression> expression;
- private final boolean propagateInput;
+ private boolean propagateInput;
public ExternalDataLookupOperator(List<LogicalVariable> variables, Mutable<ILogicalExpression> expression,
List<Object> variableTypes, boolean propagateInput, IDataSource<?> dataSource) {
@@ -85,6 +84,10 @@ public class ExternalDataLookupOperator extends AbstractDataSourceOperator {
return propagateInput;
}
+ public void setPropagateInput(boolean propagateInput) {
+ this.propagateInput = propagateInput;
+ }
+
@Override
public VariablePropagationPolicy getVariablePropagationPolicy() {
return new VariablePropagationPolicy() {
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/ScriptOperator.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/ScriptOperator.java b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/ScriptOperator.java
index ee2e7da..b04b28c 100644
--- a/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/ScriptOperator.java
+++ b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/ScriptOperator.java
@@ -18,7 +18,7 @@
*/
package org.apache.hyracks.algebricks.core.algebra.operators.logical;
-import java.util.ArrayList;
+import java.util.List;
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
import org.apache.hyracks.algebricks.common.utils.Pair;
@@ -34,22 +34,22 @@ import org.apache.hyracks.algebricks.core.algebra.visitors.ILogicalOperatorVisit
public class ScriptOperator extends AbstractLogicalOperator {
- private ArrayList<LogicalVariable> inputVariables;
- private ArrayList<LogicalVariable> outputVariables;
+ private List<LogicalVariable> inputVariables;
+ private List<LogicalVariable> outputVariables;
private IScriptDescription scriptDesc;
- public ScriptOperator(IScriptDescription scriptDesc, ArrayList<LogicalVariable> inputVariables,
- ArrayList<LogicalVariable> outputVariables) {
+ public ScriptOperator(IScriptDescription scriptDesc, List<LogicalVariable> inputVariables,
+ List<LogicalVariable> outputVariables) {
this.inputVariables = inputVariables;
this.outputVariables = outputVariables;
this.scriptDesc = scriptDesc;
}
- public ArrayList<LogicalVariable> getInputVariables() {
+ public List<LogicalVariable> getInputVariables() {
return inputVariables;
}
- public ArrayList<LogicalVariable> getOutputVariables() {
+ public List<LogicalVariable> getOutputVariables() {
return outputVariables;
}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/UnnestMapOperator.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/UnnestMapOperator.java b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/UnnestMapOperator.java
index 881f6ae..815c36c 100644
--- a/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/UnnestMapOperator.java
+++ b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/UnnestMapOperator.java
@@ -21,7 +21,6 @@ package org.apache.hyracks.algebricks.core.algebra.operators.logical;
import java.util.List;
import org.apache.commons.lang3.mutable.Mutable;
-
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
import org.apache.hyracks.algebricks.core.algebra.base.LogicalOperatorTag;
@@ -105,6 +104,10 @@ public class UnnestMapOperator extends AbstractUnnestOperator {
return propagateInput;
}
+ public void setPropagatesInput(boolean propagateInput) {
+ this.propagateInput = propagateInput;
+ }
+
public List<LogicalVariable> getMinFilterVars() {
return minFilterVars;
}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/EnforceVariablesVisitor.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/EnforceVariablesVisitor.java b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/EnforceVariablesVisitor.java
new file mode 100644
index 0000000..d8089bd
--- /dev/null
+++ b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/EnforceVariablesVisitor.java
@@ -0,0 +1,391 @@
+/*
+ * 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.core.algebra.operators.logical.visitors;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+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.Pair;
+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.ILogicalPlan;
+import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
+import org.apache.hyracks.algebricks.core.algebra.base.LogicalExpressionTag;
+import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable;
+import org.apache.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.AggregateOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.AssignOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.DataSourceScanOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.DistinctOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.EmptyTupleSourceOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.ExchangeOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.ExtensionOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.ExternalDataLookupOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.GroupByOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.InnerJoinOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.LeftOuterJoinOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.LimitOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.MaterializeOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.NestedTupleSourceOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.OrderOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.OuterUnnestOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.PartitioningSplitOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.ProjectOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.ReplicateOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.RunningAggregateOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.ScriptOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.SelectOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.SubplanOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.TokenizeOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.UnionAllOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.UnnestMapOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.UnnestOperator;
+import org.apache.hyracks.algebricks.core.algebra.plan.ALogicalPlanImpl;
+import org.apache.hyracks.algebricks.core.algebra.util.OperatorManipulationUtil;
+import org.apache.hyracks.algebricks.core.algebra.visitors.IQueryOperatorVisitor;
+
+/**
+ * This visitor is to add back variables that are killed in the query plan rooted at an input operator.
+ * After visiting, it also provides a variable map for variables that have been
+ * mapped in the query plan, e.g., by group-by, assign, and union.
+ */
+class EnforceVariablesVisitor implements IQueryOperatorVisitor<ILogicalOperator, Collection<LogicalVariable>> {
+ private final IOptimizationContext context;
+ private final Map<LogicalVariable, LogicalVariable> inputVarToOutputVarMap = new HashMap<>();
+
+ public EnforceVariablesVisitor(IOptimizationContext context) {
+ this.context = context;
+ }
+
+ public Map<LogicalVariable, LogicalVariable> getInputVariableToOutputVariableMap() {
+ return inputVarToOutputVarMap;
+ }
+
+ @Override
+ public ILogicalOperator visitAggregateOperator(AggregateOperator op, Collection<LogicalVariable> varsToRecover)
+ throws AlgebricksException {
+ return rewriteAggregateOperator(op, varsToRecover);
+ }
+
+ @Override
+ public ILogicalOperator visitRunningAggregateOperator(RunningAggregateOperator op,
+ Collection<LogicalVariable> varsToRecover) throws AlgebricksException {
+ return rewriteAggregateOperator(op, varsToRecover);
+ }
+
+ @Override
+ public ILogicalOperator visitEmptyTupleSourceOperator(EmptyTupleSourceOperator op,
+ Collection<LogicalVariable> varsToRecover) throws AlgebricksException {
+ return visitsInputs(op, varsToRecover);
+ }
+
+ @Override
+ public ILogicalOperator visitGroupByOperator(GroupByOperator op, Collection<LogicalVariable> varsToRecover)
+ throws AlgebricksException {
+ Set<LogicalVariable> liveVars = new HashSet<>();
+ VariableUtilities.getLiveVariables(op, liveVars);
+ varsToRecover.removeAll(liveVars);
+
+ // Maps group by key variables if the corresponding expressions are VariableReferenceExpressions.
+ for (Pair<LogicalVariable, Mutable<ILogicalExpression>> keyVarExprRef : op.getGroupByList()) {
+ ILogicalExpression expr = keyVarExprRef.second.getValue();
+ if (expr.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
+ VariableReferenceExpression varExpr = (VariableReferenceExpression) expr;
+ LogicalVariable sourceVar = varExpr.getVariableReference();
+ updateVarMapping(sourceVar, keyVarExprRef.first);
+ varsToRecover.remove(sourceVar);
+ }
+ }
+
+ for (LogicalVariable varToRecover : varsToRecover) {
+ // This limits the visitor can only be applied to a nested logical plan inside a Subplan operator,
+ // where the varsToRecover forms a candidate key which can uniquely identify a tuple out of the nested-tuple-source.
+ op.getDecorList().add(new Pair<LogicalVariable, Mutable<ILogicalExpression>>(null,
+ new MutableObject<ILogicalExpression>(new VariableReferenceExpression(varToRecover))));
+ }
+ return visitsInputs(op, varsToRecover);
+ }
+
+ @Override
+ public ILogicalOperator visitLimitOperator(LimitOperator op, Collection<LogicalVariable> varsToRecover)
+ throws AlgebricksException {
+ return visitsInputs(op, varsToRecover);
+ }
+
+ @Override
+ public ILogicalOperator visitInnerJoinOperator(InnerJoinOperator op, Collection<LogicalVariable> varsToRecover)
+ throws AlgebricksException {
+ return visitsInputs(op, varsToRecover);
+ }
+
+ @Override
+ public ILogicalOperator visitLeftOuterJoinOperator(LeftOuterJoinOperator op,
+ Collection<LogicalVariable> varsToRecover) throws AlgebricksException {
+ return visitsInputs(op, varsToRecover);
+ }
+
+ @Override
+ public ILogicalOperator visitNestedTupleSourceOperator(NestedTupleSourceOperator op,
+ Collection<LogicalVariable> varsToRecover) throws AlgebricksException {
+ return visitsInputs(op, varsToRecover);
+ }
+
+ @Override
+ public ILogicalOperator visitOrderOperator(OrderOperator op, Collection<LogicalVariable> varsToRecover)
+ throws AlgebricksException {
+ return visitsInputs(op, varsToRecover);
+ }
+
+ @Override
+ public ILogicalOperator visitAssignOperator(AssignOperator op, Collection<LogicalVariable> varsToRecover)
+ throws AlgebricksException {
+ List<Mutable<ILogicalExpression>> assignedExprRefs = op.getExpressions();
+ List<LogicalVariable> assignedVars = op.getVariables();
+
+ // Maps assigning variables if assignment expressions are VariableReferenceExpressions.
+ for (int index = 0; index < assignedVars.size(); ++index) {
+ ILogicalExpression expr = assignedExprRefs.get(index).getValue();
+ if (expr.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
+ VariableReferenceExpression varExpr = (VariableReferenceExpression) expr;
+ LogicalVariable sourceVar = varExpr.getVariableReference();
+ updateVarMapping(sourceVar, assignedVars.get(index));
+ varsToRecover.remove(sourceVar);
+ }
+ }
+ return visitsInputs(op, varsToRecover);
+ }
+
+ @Override
+ public ILogicalOperator visitSelectOperator(SelectOperator op, Collection<LogicalVariable> varsToRecover)
+ throws AlgebricksException {
+ return visitsInputs(op, varsToRecover);
+ }
+
+ @Override
+ public ILogicalOperator visitExtensionOperator(ExtensionOperator op, Collection<LogicalVariable> varsToRecover)
+ throws AlgebricksException {
+ return visitsInputs(op, varsToRecover);
+ }
+
+ @Override
+ public ILogicalOperator visitProjectOperator(ProjectOperator op, Collection<LogicalVariable> varsToRecover)
+ throws AlgebricksException {
+ varsToRecover.removeAll(op.getVariables());
+ // Adds all missing variables that should propagates up.
+ op.getVariables().addAll(varsToRecover);
+ return visitsInputs(op, varsToRecover);
+ }
+
+ @Override
+ public ILogicalOperator visitPartitioningSplitOperator(PartitioningSplitOperator op,
+ Collection<LogicalVariable> varsToRecover) throws AlgebricksException {
+ return visitsInputs(op, varsToRecover);
+ }
+
+ @Override
+ public ILogicalOperator visitReplicateOperator(ReplicateOperator op, Collection<LogicalVariable> varsToRecover)
+ throws AlgebricksException {
+ return visitsInputs(op, varsToRecover);
+ }
+
+ @Override
+ public ILogicalOperator visitMaterializeOperator(MaterializeOperator op, Collection<LogicalVariable> varsToRecover)
+ throws AlgebricksException {
+ return visitsInputs(op, varsToRecover);
+ }
+
+ @Override
+ public ILogicalOperator visitScriptOperator(ScriptOperator op, Collection<LogicalVariable> varsToRecover)
+ throws AlgebricksException {
+ throw new UnsupportedOperationException("Script operators in a subplan are not supported!");
+ }
+
+ @Override
+ public ILogicalOperator visitSubplanOperator(SubplanOperator op, Collection<LogicalVariable> varsToRecover)
+ throws AlgebricksException {
+ return visitsInputs(op, varsToRecover);
+ }
+
+ @Override
+ public ILogicalOperator visitUnionOperator(UnionAllOperator op, Collection<LogicalVariable> varsToRecover)
+ throws AlgebricksException {
+ // Update the variable mappings
+ List<Triple<LogicalVariable, LogicalVariable, LogicalVariable>> varTriples = op.getVariableMappings();
+ for (Triple<LogicalVariable, LogicalVariable, LogicalVariable> triple : varTriples) {
+ updateVarMapping(triple.second, triple.first);
+ updateVarMapping(triple.third, triple.first);
+ }
+ return visitsInputs(op, varsToRecover);
+ }
+
+ @Override
+ public ILogicalOperator visitUnnestOperator(UnnestOperator op, Collection<LogicalVariable> varsToRecover)
+ throws AlgebricksException {
+ return visitsInputs(op, varsToRecover);
+ }
+
+ @Override
+ public ILogicalOperator visitOuterUnnestOperator(OuterUnnestOperator op, Collection<LogicalVariable> varsToRecover)
+ throws AlgebricksException {
+ return visitsInputs(op, varsToRecover);
+ }
+
+ @Override
+ public ILogicalOperator visitUnnestMapOperator(UnnestMapOperator op, Collection<LogicalVariable> varsToRecover)
+ throws AlgebricksException {
+ Set<LogicalVariable> liveVars = new HashSet<>();
+ VariableUtilities.getLiveVariables(op, liveVars);
+ varsToRecover.remove(liveVars);
+ if (!varsToRecover.isEmpty()) {
+ op.setPropagatesInput(true);
+ return visitsInputs(op, varsToRecover);
+ }
+ return op;
+ }
+
+ @Override
+ public ILogicalOperator visitDataScanOperator(DataSourceScanOperator op, Collection<LogicalVariable> varsToRecover)
+ throws AlgebricksException {
+ return visitsInputs(op, varsToRecover);
+ }
+
+ @Override
+ public ILogicalOperator visitDistinctOperator(DistinctOperator op, Collection<LogicalVariable> varsToRecover)
+ throws AlgebricksException {
+ return visitsInputs(op, varsToRecover);
+ }
+
+ @Override
+ public ILogicalOperator visitExchangeOperator(ExchangeOperator op, Collection<LogicalVariable> varsToRecover)
+ throws AlgebricksException {
+ return visitsInputs(op, varsToRecover);
+ }
+
+ @Override
+ public ILogicalOperator visitExternalDataLookupOperator(ExternalDataLookupOperator op,
+ Collection<LogicalVariable> varsToRecover) throws AlgebricksException {
+ Set<LogicalVariable> liveVars = new HashSet<>();
+ VariableUtilities.getLiveVariables(op, liveVars);
+ varsToRecover.retainAll(liveVars);
+ if (!varsToRecover.isEmpty()) {
+ op.setPropagateInput(true);
+ return visitsInputs(op, varsToRecover);
+ }
+ return op;
+ }
+
+ @Override
+ public ILogicalOperator visitTokenizeOperator(TokenizeOperator op, Collection<LogicalVariable> varsToRecover)
+ throws AlgebricksException {
+ return visitsInputs(op, varsToRecover);
+ }
+
+ /**
+ * Wraps an AggregateOperator or RunningAggregateOperator with a group-by operator where
+ * the group-by keys are variables in varsToRecover.
+ * Note that the function here prevents this visitor being used to rewrite arbitrary query plans.
+ * Instead, it could only be used for rewriting a nested plan within a subplan operator.
+ *
+ * @param op
+ * the logical operator for aggregate or running aggregate.
+ * @param varsToRecover
+ * the set of variables that needs to preserve.
+ * @return the wrapped group-by operator if {@code varsToRecover} is not empty, and {@code op} otherwise.
+ * @throws AlgebricksException
+ */
+ private ILogicalOperator rewriteAggregateOperator(ILogicalOperator op, Collection<LogicalVariable> varsToRecover)
+ throws AlgebricksException {
+ Set<LogicalVariable> liveVars = new HashSet<>();
+ VariableUtilities.getLiveVariables(op, liveVars);
+ varsToRecover.removeAll(liveVars);
+
+ GroupByOperator gbyOp = new GroupByOperator();
+ for (LogicalVariable varToRecover : varsToRecover) {
+ // This limits the visitor can only be applied to a nested logical plan inside a Subplan operator,
+ // where the varsToRecover forms a candidate key which can uniquely identify a tuple out of the nested-tuple-source.
+ LogicalVariable newVar = context.newVar();
+ gbyOp.getGroupByList().add(new Pair<LogicalVariable, Mutable<ILogicalExpression>>(newVar,
+ new MutableObject<ILogicalExpression>(new VariableReferenceExpression(varToRecover))));
+ updateVarMapping(varToRecover, newVar);
+ }
+
+ NestedTupleSourceOperator nts = new NestedTupleSourceOperator(new MutableObject<ILogicalOperator>(gbyOp));
+ op.getInputs().clear();
+ op.getInputs().add(new MutableObject<ILogicalOperator>(nts));
+
+ ILogicalOperator inputOp = op.getInputs().get(0).getValue();
+ ILogicalPlan nestedPlan = new ALogicalPlanImpl();
+ nestedPlan.getRoots().add(new MutableObject<ILogicalOperator>(op));
+ gbyOp.getNestedPlans().add(nestedPlan);
+ gbyOp.getInputs().add(new MutableObject<ILogicalOperator>(inputOp));
+
+ OperatorManipulationUtil.computeTypeEnvironmentBottomUp(op, context);
+ return visitsInputs(gbyOp, varsToRecover);
+ }
+
+ private ILogicalOperator visitsInputs(ILogicalOperator op, Collection<LogicalVariable> varsToRecover)
+ throws AlgebricksException {
+ if (op.getInputs().size() == 0 || varsToRecover.isEmpty()) {
+ return op;
+ }
+ Set<LogicalVariable> producedVars = new HashSet<>();
+ VariableUtilities.getProducedVariables(op, producedVars);
+ varsToRecover.removeAll(producedVars);
+ if (!varsToRecover.isEmpty()) {
+ if (op.getInputs().size() == 1) {
+ // Deals with single input operators.
+ ILogicalOperator newOp = op.getInputs().get(0).getValue().accept(this, varsToRecover);
+ op.getInputs().get(0).setValue(newOp);
+ } else {
+ // Deals with multi-input operators.
+ for (Mutable<ILogicalOperator> childRef : op.getInputs()) {
+ ILogicalOperator child = childRef.getValue();
+ Set<LogicalVariable> varsToRecoverInChild = new HashSet<>();
+ VariableUtilities.getProducedVariablesInDescendantsAndSelf(child, varsToRecoverInChild);
+ // Obtains the variables that this particular child should propagate.
+ varsToRecoverInChild.retainAll(varsToRecover);
+ ILogicalOperator newChild = child.accept(this, varsToRecoverInChild);
+ childRef.setValue(newChild);
+ }
+ }
+ }
+ return op;
+ }
+
+ private void updateVarMapping(LogicalVariable oldVar, LogicalVariable newVar) {
+ if (oldVar.equals(newVar)) {
+ return;
+ }
+ LogicalVariable mappedVar = newVar;
+ if (inputVarToOutputVarMap.containsKey(newVar)) {
+ mappedVar = inputVarToOutputVarMap.get(newVar);
+ inputVarToOutputVarMap.remove(newVar);
+ }
+ inputVarToOutputVarMap.put(oldVar, mappedVar);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/LogicalExpressionDeepCopyWithNewVariablesVisitor.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/LogicalExpressionDeepCopyWithNewVariablesVisitor.java b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/LogicalExpressionDeepCopyWithNewVariablesVisitor.java
new file mode 100644
index 0000000..f0bcd34
--- /dev/null
+++ b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/LogicalExpressionDeepCopyWithNewVariablesVisitor.java
@@ -0,0 +1,152 @@
+/*
+ * 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.core.algebra.operators.logical.visitors;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang3.mutable.Mutable;
+import org.apache.commons.lang3.mutable.MutableObject;
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
+import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
+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.AggregateFunctionCallExpression;
+import org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
+import org.apache.hyracks.algebricks.core.algebra.expressions.IExpressionAnnotation;
+import org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression;
+import org.apache.hyracks.algebricks.core.algebra.expressions.StatefulFunctionCallExpression;
+import org.apache.hyracks.algebricks.core.algebra.expressions.UnnestingFunctionCallExpression;
+import org.apache.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression;
+import org.apache.hyracks.algebricks.core.algebra.visitors.ILogicalExpressionVisitor;
+
+public class LogicalExpressionDeepCopyWithNewVariablesVisitor
+ implements ILogicalExpressionVisitor<ILogicalExpression, Void> {
+ private final IOptimizationContext context;
+ private final Map<LogicalVariable, LogicalVariable> inVarMapping;
+ private final Map<LogicalVariable, LogicalVariable> outVarMapping;
+
+ public LogicalExpressionDeepCopyWithNewVariablesVisitor(IOptimizationContext context,
+ Map<LogicalVariable, LogicalVariable> inVarMapping, Map<LogicalVariable, LogicalVariable> variableMapping) {
+ this.context = context;
+ this.inVarMapping = inVarMapping;
+ this.outVarMapping = variableMapping;
+ }
+
+ public ILogicalExpression deepCopy(ILogicalExpression expr) throws AlgebricksException {
+ return expr.accept(this, null);
+ }
+
+ private void deepCopyAnnotations(AbstractFunctionCallExpression src, AbstractFunctionCallExpression dest) {
+ Map<Object, IExpressionAnnotation> srcAnnotations = src.getAnnotations();
+ Map<Object, IExpressionAnnotation> destAnnotations = dest.getAnnotations();
+ for (Object k : srcAnnotations.keySet()) {
+ IExpressionAnnotation annotation = srcAnnotations.get(k).copy();
+ destAnnotations.put(k, annotation);
+ }
+ }
+
+ private void deepCopyOpaqueParameters(AbstractFunctionCallExpression src, AbstractFunctionCallExpression dest) {
+ Object[] srcOpaqueParameters = src.getOpaqueParameters();
+ Object[] newOpaqueParameters = null;
+ if (srcOpaqueParameters != null) {
+ newOpaqueParameters = new Object[srcOpaqueParameters.length];
+ for (int i = 0; i < srcOpaqueParameters.length; i++) {
+ newOpaqueParameters[i] = srcOpaqueParameters[i];
+ }
+ }
+ dest.setOpaqueParameters(newOpaqueParameters);
+ }
+
+ public MutableObject<ILogicalExpression> deepCopyExpressionReference(Mutable<ILogicalExpression> exprRef)
+ throws AlgebricksException {
+ return new MutableObject<ILogicalExpression>(deepCopy(exprRef.getValue()));
+ }
+
+ // TODO return List<...>
+ public ArrayList<Mutable<ILogicalExpression>> deepCopyExpressionReferenceList(
+ List<Mutable<ILogicalExpression>> list) throws AlgebricksException {
+ ArrayList<Mutable<ILogicalExpression>> listCopy = new ArrayList<Mutable<ILogicalExpression>>(list.size());
+ for (Mutable<ILogicalExpression> exprRef : list) {
+ listCopy.add(deepCopyExpressionReference(exprRef));
+ }
+ return listCopy;
+ }
+
+ @Override
+ public ILogicalExpression visitAggregateFunctionCallExpression(AggregateFunctionCallExpression expr, Void arg)
+ throws AlgebricksException {
+ AggregateFunctionCallExpression exprCopy = new AggregateFunctionCallExpression(expr.getFunctionInfo(),
+ expr.isTwoStep(), deepCopyExpressionReferenceList(expr.getArguments()));
+ deepCopyAnnotations(expr, exprCopy);
+ deepCopyOpaqueParameters(expr, exprCopy);
+ return exprCopy;
+ }
+
+ @Override
+ public ILogicalExpression visitConstantExpression(ConstantExpression expr, Void arg) throws AlgebricksException {
+ return new ConstantExpression(expr.getValue());
+ }
+
+ @Override
+ public ILogicalExpression visitScalarFunctionCallExpression(ScalarFunctionCallExpression expr, Void arg)
+ throws AlgebricksException {
+ ScalarFunctionCallExpression exprCopy = new ScalarFunctionCallExpression(expr.getFunctionInfo(),
+ deepCopyExpressionReferenceList(expr.getArguments()));
+ deepCopyAnnotations(expr, exprCopy);
+ deepCopyOpaqueParameters(expr, exprCopy);
+ return exprCopy;
+
+ }
+
+ @Override
+ public ILogicalExpression visitStatefulFunctionCallExpression(StatefulFunctionCallExpression expr, Void arg)
+ throws AlgebricksException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ILogicalExpression visitUnnestingFunctionCallExpression(UnnestingFunctionCallExpression expr, Void arg)
+ throws AlgebricksException {
+ UnnestingFunctionCallExpression exprCopy = new UnnestingFunctionCallExpression(expr.getFunctionInfo(),
+ deepCopyExpressionReferenceList(expr.getArguments()));
+ deepCopyAnnotations(expr, exprCopy);
+ deepCopyOpaqueParameters(expr, exprCopy);
+ return exprCopy;
+ }
+
+ @Override
+ public ILogicalExpression visitVariableReferenceExpression(VariableReferenceExpression expr, Void arg)
+ throws AlgebricksException {
+ LogicalVariable var = expr.getVariableReference();
+ LogicalVariable givenVarReplacement = inVarMapping.get(var);
+ if (givenVarReplacement != null) {
+ outVarMapping.put(var, givenVarReplacement);
+ return new VariableReferenceExpression(givenVarReplacement);
+ }
+ LogicalVariable varCopy = outVarMapping.get(var);
+ if (varCopy == null) {
+ varCopy = context.newVar();
+ outVarMapping.put(var, varCopy);
+ }
+ return new VariableReferenceExpression(varCopy);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/LogicalOperatorDeepCopyWithNewVariablesVisitor.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/LogicalOperatorDeepCopyWithNewVariablesVisitor.java b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/LogicalOperatorDeepCopyWithNewVariablesVisitor.java
new file mode 100644
index 0000000..ec7d7fe
--- /dev/null
+++ b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/LogicalOperatorDeepCopyWithNewVariablesVisitor.java
@@ -0,0 +1,526 @@
+/*
+ * 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.core.algebra.operators.logical.visitors;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+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.Pair;
+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.ILogicalPlan;
+import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
+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.AggregateOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.AssignOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.DataSourceScanOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.DistinctOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.EmptyTupleSourceOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.ExchangeOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.ExtensionOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.ExternalDataLookupOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.GroupByOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.InnerJoinOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.LeftOuterJoinOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.LimitOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.MaterializeOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.NestedTupleSourceOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.OrderOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.OrderOperator.IOrder;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.OuterUnnestOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.PartitioningSplitOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.ProjectOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.ReplicateOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.RunningAggregateOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.ScriptOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.SelectOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.SubplanOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.TokenizeOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.UnionAllOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.UnnestMapOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.UnnestOperator;
+import org.apache.hyracks.algebricks.core.algebra.plan.ALogicalPlanImpl;
+import org.apache.hyracks.algebricks.core.algebra.properties.FunctionalDependency;
+import org.apache.hyracks.algebricks.core.algebra.util.OperatorManipulationUtil;
+import org.apache.hyracks.algebricks.core.algebra.visitors.IQueryOperatorVisitor;
+
+/**
+ * This visitor deep-copies a query plan but uses a new set of variables.
+ * Method getInputToOutputVariableMapping() will return a map that maps
+ * input variables to their corresponding output variables.
+ */
+public class LogicalOperatorDeepCopyWithNewVariablesVisitor
+ implements IQueryOperatorVisitor<ILogicalOperator, ILogicalOperator> {
+ private final IOptimizationContext context;
+ private final LogicalExpressionDeepCopyWithNewVariablesVisitor exprDeepCopyVisitor;
+
+ // Key: Variable in the original plan. Value: New variable replacing the
+ // original one in the copied plan.
+ private final Map<LogicalVariable, LogicalVariable> inputVarToOutputVarMapping;
+
+ // Key: New variable in the new plan. Value: The old variable in the original plan.
+ private final Map<LogicalVariable, LogicalVariable> outputVarToInputVarMapping;
+
+ /**
+ * @param IOptimizationContext,
+ * the optimization context
+ */
+ public LogicalOperatorDeepCopyWithNewVariablesVisitor(IOptimizationContext context) {
+ this.context = context;
+ this.inputVarToOutputVarMapping = new HashMap<>();
+ this.outputVarToInputVarMapping = new HashMap<>();
+ this.exprDeepCopyVisitor = new LogicalExpressionDeepCopyWithNewVariablesVisitor(context,
+ outputVarToInputVarMapping, inputVarToOutputVarMapping);
+ }
+
+ /**
+ * @param IOptimizationContext
+ * the optimization context
+ * @param inVarMapping
+ * Variable mapping keyed by variables in the original plan.
+ * Those variables are replaced by their corresponding value in
+ * the map in the copied plan.
+ */
+ public LogicalOperatorDeepCopyWithNewVariablesVisitor(IOptimizationContext context,
+ Map<LogicalVariable, LogicalVariable> inVarMapping) {
+ this.context = context;
+ this.inputVarToOutputVarMapping = inVarMapping;
+ this.outputVarToInputVarMapping = new HashMap<>();
+ exprDeepCopyVisitor = new LogicalExpressionDeepCopyWithNewVariablesVisitor(context, inVarMapping,
+ inputVarToOutputVarMapping);
+ }
+
+ private void copyAnnotations(ILogicalOperator src, ILogicalOperator dest) {
+ dest.getAnnotations().putAll(src.getAnnotations());
+ }
+
+ public ILogicalOperator deepCopy(ILogicalOperator op, ILogicalOperator arg) throws AlgebricksException {
+ ILogicalOperator opCopy = op.accept(this, arg);
+ OperatorManipulationUtil.computeTypeEnvironmentBottomUp(opCopy, context);
+ return opCopy;
+ }
+
+ private void deepCopyInputs(ILogicalOperator src, ILogicalOperator dest, ILogicalOperator arg)
+ throws AlgebricksException {
+ List<Mutable<ILogicalOperator>> inputs = src.getInputs();
+ List<Mutable<ILogicalOperator>> inputsCopy = dest.getInputs();
+ for (Mutable<ILogicalOperator> input : inputs) {
+ inputsCopy.add(deepCopyOperatorReference(input, arg));
+ }
+ }
+
+ private Mutable<ILogicalOperator> deepCopyOperatorReference(Mutable<ILogicalOperator> opRef, ILogicalOperator arg)
+ throws AlgebricksException {
+ return new MutableObject<ILogicalOperator>(deepCopy(opRef.getValue(), arg));
+ }
+
+ private List<Mutable<ILogicalOperator>> deepCopyOperatorReferenceList(List<Mutable<ILogicalOperator>> list,
+ ILogicalOperator arg) throws AlgebricksException {
+ List<Mutable<ILogicalOperator>> listCopy = new ArrayList<Mutable<ILogicalOperator>>(list.size());
+ for (Mutable<ILogicalOperator> opRef : list) {
+ listCopy.add(deepCopyOperatorReference(opRef, arg));
+ }
+ return listCopy;
+ }
+
+ private IOrder deepCopyOrder(IOrder order) {
+ switch (order.getKind()) {
+ case ASC:
+ case DESC:
+ return order;
+ case FUNCTIONCALL:
+ default:
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ private List<Pair<IOrder, Mutable<ILogicalExpression>>> deepCopyOrderExpressionReferencePairList(
+ List<Pair<IOrder, Mutable<ILogicalExpression>>> list) throws AlgebricksException {
+ ArrayList<Pair<IOrder, Mutable<ILogicalExpression>>> listCopy = new ArrayList<Pair<IOrder, Mutable<ILogicalExpression>>>(
+ list.size());
+ for (Pair<IOrder, Mutable<ILogicalExpression>> pair : list) {
+ listCopy.add(new Pair<OrderOperator.IOrder, Mutable<ILogicalExpression>>(deepCopyOrder(pair.first),
+ exprDeepCopyVisitor.deepCopyExpressionReference(pair.second)));
+ }
+ return listCopy;
+ }
+
+ private ILogicalPlan deepCopyPlan(ILogicalPlan plan, ILogicalOperator arg) throws AlgebricksException {
+ List<Mutable<ILogicalOperator>> rootsCopy = deepCopyOperatorReferenceList(plan.getRoots(), arg);
+ ILogicalPlan planCopy = new ALogicalPlanImpl(rootsCopy);
+ return planCopy;
+ }
+
+ private List<ILogicalPlan> deepCopyPlanList(List<ILogicalPlan> list, List<ILogicalPlan> listCopy,
+ ILogicalOperator arg) throws AlgebricksException {
+ for (ILogicalPlan plan : list) {
+ listCopy.add(deepCopyPlan(plan, arg));
+ }
+ return listCopy;
+ }
+
+ private LogicalVariable deepCopyVariable(LogicalVariable var) {
+ if (var == null) {
+ return null;
+ }
+ LogicalVariable givenVarReplacement = outputVarToInputVarMapping.get(var);
+ if (givenVarReplacement != null) {
+ inputVarToOutputVarMapping.put(var, givenVarReplacement);
+ return givenVarReplacement;
+ }
+ LogicalVariable varCopy = inputVarToOutputVarMapping.get(var);
+ if (varCopy == null) {
+ varCopy = context.newVar();
+ inputVarToOutputVarMapping.put(var, varCopy);
+ }
+ return varCopy;
+ }
+
+ private List<Pair<LogicalVariable, Mutable<ILogicalExpression>>> deepCopyVariableExpressionReferencePairList(
+ List<Pair<LogicalVariable, Mutable<ILogicalExpression>>> list) throws AlgebricksException {
+ List<Pair<LogicalVariable, Mutable<ILogicalExpression>>> listCopy = new ArrayList<Pair<LogicalVariable, Mutable<ILogicalExpression>>>(
+ list.size());
+ for (Pair<LogicalVariable, Mutable<ILogicalExpression>> pair : list) {
+ listCopy.add(new Pair<LogicalVariable, Mutable<ILogicalExpression>>(deepCopyVariable(pair.first),
+ exprDeepCopyVisitor.deepCopyExpressionReference(pair.second)));
+ }
+ return listCopy;
+ }
+
+ private List<LogicalVariable> deepCopyVariableList(List<LogicalVariable> list) {
+ ArrayList<LogicalVariable> listCopy = new ArrayList<LogicalVariable>(list.size());
+ for (LogicalVariable var : list) {
+ listCopy.add(deepCopyVariable(var));
+ }
+ return listCopy;
+ }
+
+ private void deepCopyInputsAnnotationsAndExecutionMode(ILogicalOperator op, ILogicalOperator arg,
+ AbstractLogicalOperator opCopy) throws AlgebricksException {
+ deepCopyInputs(op, opCopy, arg);
+ copyAnnotations(op, opCopy);
+ opCopy.setExecutionMode(op.getExecutionMode());
+ }
+
+ public void reset() {
+ inputVarToOutputVarMapping.clear();
+ outputVarToInputVarMapping.clear();
+ }
+
+ public void updatePrimaryKeys(IOptimizationContext context) {
+ for (Map.Entry<LogicalVariable, LogicalVariable> entry : inputVarToOutputVarMapping.entrySet()) {
+ List<LogicalVariable> primaryKey = context.findPrimaryKey(entry.getKey());
+ if (primaryKey != null) {
+ List<LogicalVariable> head = new ArrayList<LogicalVariable>();
+ for (LogicalVariable variable : primaryKey) {
+ head.add(inputVarToOutputVarMapping.get(variable));
+ }
+ List<LogicalVariable> tail = new ArrayList<LogicalVariable>(1);
+ tail.add(entry.getValue());
+ context.addPrimaryKey(new FunctionalDependency(head, tail));
+ }
+ }
+ }
+
+ public LogicalVariable varCopy(LogicalVariable var) throws AlgebricksException {
+ return inputVarToOutputVarMapping.get(var);
+ }
+
+ @Override
+ public ILogicalOperator visitAggregateOperator(AggregateOperator op, ILogicalOperator arg)
+ throws AlgebricksException {
+ AggregateOperator opCopy = new AggregateOperator(deepCopyVariableList(op.getVariables()),
+ exprDeepCopyVisitor.deepCopyExpressionReferenceList(op.getExpressions()));
+ deepCopyInputsAnnotationsAndExecutionMode(op, arg, opCopy);
+ return opCopy;
+ }
+
+ @Override
+ public ILogicalOperator visitAssignOperator(AssignOperator op, ILogicalOperator arg) throws AlgebricksException {
+ AssignOperator opCopy = new AssignOperator(deepCopyVariableList(op.getVariables()),
+ exprDeepCopyVisitor.deepCopyExpressionReferenceList(op.getExpressions()));
+ deepCopyInputsAnnotationsAndExecutionMode(op, arg, opCopy);
+ return opCopy;
+ }
+
+ @Override
+ public ILogicalOperator visitDataScanOperator(DataSourceScanOperator op, ILogicalOperator arg)
+ throws AlgebricksException {
+ DataSourceScanOperator opCopy = new DataSourceScanOperator(deepCopyVariableList(op.getVariables()),
+ op.getDataSource());
+ deepCopyInputsAnnotationsAndExecutionMode(op, arg, opCopy);
+ return opCopy;
+ }
+
+ @Override
+ public ILogicalOperator visitDistinctOperator(DistinctOperator op, ILogicalOperator arg)
+ throws AlgebricksException {
+ DistinctOperator opCopy = new DistinctOperator(
+ exprDeepCopyVisitor.deepCopyExpressionReferenceList(op.getExpressions()));
+ deepCopyInputsAnnotationsAndExecutionMode(op, arg, opCopy);
+ return opCopy;
+ }
+
+ @Override
+ public ILogicalOperator visitEmptyTupleSourceOperator(EmptyTupleSourceOperator op, ILogicalOperator arg) {
+ EmptyTupleSourceOperator opCopy = new EmptyTupleSourceOperator();
+ opCopy.setExecutionMode(op.getExecutionMode());
+ return opCopy;
+ }
+
+ @Override
+ public ILogicalOperator visitExchangeOperator(ExchangeOperator op, ILogicalOperator arg)
+ throws AlgebricksException {
+ ExchangeOperator opCopy = new ExchangeOperator();
+ deepCopyInputsAnnotationsAndExecutionMode(op, arg, opCopy);
+ return opCopy;
+ }
+
+ @Override
+ public ILogicalOperator visitGroupByOperator(GroupByOperator op, ILogicalOperator arg) throws AlgebricksException {
+ List<Pair<LogicalVariable, Mutable<ILogicalExpression>>> groupByListCopy = deepCopyVariableExpressionReferencePairList(
+ op.getGroupByList());
+ List<Pair<LogicalVariable, Mutable<ILogicalExpression>>> decorListCopy = deepCopyVariableExpressionReferencePairList(
+ op.getDecorList());
+ List<ILogicalPlan> nestedPlansCopy = new ArrayList<ILogicalPlan>();
+
+ GroupByOperator opCopy = new GroupByOperator(groupByListCopy, decorListCopy, nestedPlansCopy);
+ deepCopyPlanList(op.getNestedPlans(), nestedPlansCopy, opCopy);
+ deepCopyInputsAnnotationsAndExecutionMode(op, arg, opCopy);
+ return opCopy;
+ }
+
+ @Override
+ public ILogicalOperator visitInnerJoinOperator(InnerJoinOperator op, ILogicalOperator arg)
+ throws AlgebricksException {
+ InnerJoinOperator opCopy = new InnerJoinOperator(
+ exprDeepCopyVisitor.deepCopyExpressionReference(op.getCondition()),
+ deepCopyOperatorReference(op.getInputs().get(0), null),
+ deepCopyOperatorReference(op.getInputs().get(1), null));
+ copyAnnotations(op, opCopy);
+ opCopy.setExecutionMode(op.getExecutionMode());
+ return opCopy;
+ }
+
+ @Override
+ public ILogicalOperator visitLeftOuterJoinOperator(LeftOuterJoinOperator op, ILogicalOperator arg)
+ throws AlgebricksException {
+ LeftOuterJoinOperator opCopy = new LeftOuterJoinOperator(
+ exprDeepCopyVisitor.deepCopyExpressionReference(op.getCondition()),
+ deepCopyOperatorReference(op.getInputs().get(0), null),
+ deepCopyOperatorReference(op.getInputs().get(1), null));
+ copyAnnotations(op, opCopy);
+ opCopy.setExecutionMode(op.getExecutionMode());
+ return opCopy;
+ }
+
+ @Override
+ public ILogicalOperator visitLimitOperator(LimitOperator op, ILogicalOperator arg) throws AlgebricksException {
+ LimitOperator opCopy = new LimitOperator(exprDeepCopyVisitor.deepCopy(op.getMaxObjects().getValue()),
+ exprDeepCopyVisitor.deepCopy(op.getOffset().getValue()), op.isTopmostLimitOp());
+ deepCopyInputsAnnotationsAndExecutionMode(op, arg, opCopy);
+ return opCopy;
+ }
+
+ @Override
+ public ILogicalOperator visitNestedTupleSourceOperator(NestedTupleSourceOperator op, ILogicalOperator arg)
+ throws AlgebricksException {
+ NestedTupleSourceOperator opCopy = new NestedTupleSourceOperator(new MutableObject<ILogicalOperator>(arg));
+ deepCopyInputsAnnotationsAndExecutionMode(op, arg, opCopy);
+ return opCopy;
+ }
+
+ @Override
+ public ILogicalOperator visitOrderOperator(OrderOperator op, ILogicalOperator arg) throws AlgebricksException {
+ OrderOperator opCopy = new OrderOperator(deepCopyOrderExpressionReferencePairList(op.getOrderExpressions()));
+ deepCopyInputsAnnotationsAndExecutionMode(op, arg, opCopy);
+ return opCopy;
+ }
+
+ @Override
+ public ILogicalOperator visitPartitioningSplitOperator(PartitioningSplitOperator op, ILogicalOperator arg)
+ throws AlgebricksException {
+ PartitioningSplitOperator opCopy = new PartitioningSplitOperator(
+ exprDeepCopyVisitor.deepCopyExpressionReferenceList(op.getExpressions()), op.getDefaultBranchIndex());
+ return opCopy;
+ }
+
+ @Override
+ public ILogicalOperator visitProjectOperator(ProjectOperator op, ILogicalOperator arg) throws AlgebricksException {
+ ProjectOperator opCopy = new ProjectOperator(deepCopyVariableList(op.getVariables()));
+ deepCopyInputsAnnotationsAndExecutionMode(op, arg, opCopy);
+ return opCopy;
+ }
+
+ @Override
+ public ILogicalOperator visitReplicateOperator(ReplicateOperator op, ILogicalOperator arg)
+ throws AlgebricksException {
+ boolean[] outputMatFlags = op.getOutputMaterializationFlags();
+ boolean[] copiedOutputMatFlags = new boolean[outputMatFlags.length];
+ System.arraycopy(outputMatFlags, 0, copiedOutputMatFlags, 0, outputMatFlags.length);
+ ReplicateOperator opCopy = new ReplicateOperator(op.getOutputArity(), copiedOutputMatFlags);
+ deepCopyInputsAnnotationsAndExecutionMode(op, arg, opCopy);
+ return opCopy;
+ }
+
+ @Override
+ public ILogicalOperator visitMaterializeOperator(MaterializeOperator op, ILogicalOperator arg)
+ throws AlgebricksException {
+ MaterializeOperator opCopy = new MaterializeOperator();
+ deepCopyInputsAnnotationsAndExecutionMode(op, arg, opCopy);
+ return opCopy;
+ }
+
+ @Override
+ public ILogicalOperator visitRunningAggregateOperator(RunningAggregateOperator op, ILogicalOperator arg)
+ throws AlgebricksException {
+ RunningAggregateOperator opCopy = new RunningAggregateOperator(deepCopyVariableList(op.getVariables()),
+ exprDeepCopyVisitor.deepCopyExpressionReferenceList(op.getExpressions()));
+ deepCopyInputsAnnotationsAndExecutionMode(op, arg, opCopy);
+ return opCopy;
+ }
+
+ @Override
+ public ILogicalOperator visitScriptOperator(ScriptOperator op, ILogicalOperator arg) throws AlgebricksException {
+ ScriptOperator opCopy = new ScriptOperator(op.getScriptDescription(),
+ deepCopyVariableList(op.getInputVariables()), deepCopyVariableList(op.getOutputVariables()));
+ deepCopyInputsAnnotationsAndExecutionMode(op, arg, opCopy);
+ return opCopy;
+ }
+
+ @Override
+ public ILogicalOperator visitSelectOperator(SelectOperator op, ILogicalOperator arg) throws AlgebricksException {
+ SelectOperator opCopy = new SelectOperator(exprDeepCopyVisitor.deepCopyExpressionReference(op.getCondition()),
+ op.getRetainNull(), deepCopyVariable(op.getNullPlaceholderVariable()));
+ deepCopyInputsAnnotationsAndExecutionMode(op, arg, opCopy);
+ return opCopy;
+ }
+
+ @Override
+ public ILogicalOperator visitSubplanOperator(SubplanOperator op, ILogicalOperator arg) throws AlgebricksException {
+ List<ILogicalPlan> nestedPlansCopy = new ArrayList<ILogicalPlan>();
+ SubplanOperator opCopy = new SubplanOperator(nestedPlansCopy);
+ deepCopyPlanList(op.getNestedPlans(), nestedPlansCopy, opCopy);
+ deepCopyInputsAnnotationsAndExecutionMode(op, arg, opCopy);
+ return opCopy;
+ }
+
+ @Override
+ public ILogicalOperator visitUnionOperator(UnionAllOperator op, ILogicalOperator arg) throws AlgebricksException {
+ List<Mutable<ILogicalOperator>> copiedInputs = new ArrayList<>();
+ for (Mutable<ILogicalOperator> childRef : op.getInputs()) {
+ copiedInputs.add(deepCopyOperatorReference(childRef, null));
+ }
+ List<List<LogicalVariable>> liveVarsInInputs = new ArrayList<>();
+ for (Mutable<ILogicalOperator> inputOpRef : copiedInputs) {
+ List<LogicalVariable> liveVars = new ArrayList<>();
+ VariableUtilities.getLiveVariables(inputOpRef.getValue(), liveVars);
+ liveVarsInInputs.add(liveVars);
+ }
+ List<LogicalVariable> liveVarsInLeftInput = liveVarsInInputs.get(0);
+ List<LogicalVariable> liveVarsInRightInput = liveVarsInInputs.get(1);
+ List<Triple<LogicalVariable, LogicalVariable, LogicalVariable>> copiedTriples = new ArrayList<>();
+ int index = 0;
+ for (Triple<LogicalVariable, LogicalVariable, LogicalVariable> triple : op.getVariableMappings()) {
+ LogicalVariable producedVar = deepCopyVariable(triple.third);
+ Triple<LogicalVariable, LogicalVariable, LogicalVariable> copiedTriple = new Triple<>(
+ liveVarsInLeftInput.get(index), liveVarsInRightInput.get(index), producedVar);
+ copiedTriples.add(copiedTriple);
+ ++index;
+ }
+ UnionAllOperator opCopy = new UnionAllOperator(copiedTriples);
+ deepCopyInputsAnnotationsAndExecutionMode(op, arg, opCopy);
+ return opCopy;
+ }
+
+ @Override
+ public ILogicalOperator visitUnnestMapOperator(UnnestMapOperator op, ILogicalOperator arg)
+ throws AlgebricksException {
+ UnnestMapOperator opCopy = new UnnestMapOperator(deepCopyVariableList(op.getVariables()),
+ exprDeepCopyVisitor.deepCopyExpressionReference(op.getExpressionRef()), op.getVariableTypes(),
+ op.propagatesInput());
+ deepCopyInputsAnnotationsAndExecutionMode(op, arg, opCopy);
+ return opCopy;
+ }
+
+ @Override
+ public ILogicalOperator visitUnnestOperator(UnnestOperator op, ILogicalOperator arg) throws AlgebricksException {
+ UnnestOperator opCopy = new UnnestOperator(deepCopyVariable(op.getVariable()),
+ exprDeepCopyVisitor.deepCopyExpressionReference(op.getExpressionRef()),
+ deepCopyVariable(op.getPositionalVariable()), op.getPositionalVariableType(), op.getPositionWriter());
+ deepCopyInputsAnnotationsAndExecutionMode(op, arg, opCopy);
+ return opCopy;
+ }
+
+ @Override
+ public ILogicalOperator visitTokenizeOperator(TokenizeOperator op, ILogicalOperator arg)
+ throws AlgebricksException {
+ TokenizeOperator opCopy = new TokenizeOperator(op.getDataSourceIndex(),
+ exprDeepCopyVisitor.deepCopyExpressionReferenceList(op.getPrimaryKeyExpressions()),
+ exprDeepCopyVisitor.deepCopyExpressionReferenceList(op.getSecondaryKeyExpressions()),
+ this.deepCopyVariableList(op.getTokenizeVars()),
+ exprDeepCopyVisitor.deepCopyExpressionReference(op.getFilterExpression()), op.getOperation(),
+ op.isBulkload(), op.isPartitioned(), op.getTokenizeVarTypes());
+ deepCopyInputsAnnotationsAndExecutionMode(op, arg, opCopy);
+ return opCopy;
+ }
+
+ @Override
+ public ILogicalOperator visitExtensionOperator(ExtensionOperator op, ILogicalOperator arg)
+ throws AlgebricksException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ILogicalOperator visitExternalDataLookupOperator(ExternalDataLookupOperator op, ILogicalOperator arg)
+ throws AlgebricksException {
+ ExternalDataLookupOperator opCopy = new ExternalDataLookupOperator(deepCopyVariableList(op.getVariables()),
+ exprDeepCopyVisitor.deepCopyExpressionReference(op.getExpressionRef()), op.getVariableTypes(),
+ op.isPropagateInput(), op.getDataSource());
+ deepCopyInputsAnnotationsAndExecutionMode(op, arg, opCopy);
+ return opCopy;
+
+ }
+
+ @Override
+ public ILogicalOperator visitOuterUnnestOperator(OuterUnnestOperator op, ILogicalOperator arg)
+ throws AlgebricksException {
+ OuterUnnestOperator opCopy = new OuterUnnestOperator(deepCopyVariable(op.getVariable()),
+ exprDeepCopyVisitor.deepCopyExpressionReference(op.getExpressionRef()),
+ deepCopyVariable(op.getPositionalVariable()), op.getPositionalVariableType(), op.getPositionWriter());
+ deepCopyInputsAnnotationsAndExecutionMode(op, arg, opCopy);
+ return opCopy;
+ }
+
+ public Map<LogicalVariable, LogicalVariable> getOutputToInputVariableMapping() {
+ return outputVarToInputVarMapping;
+ }
+
+ public Map<LogicalVariable, LogicalVariable> getInputToOutputVariableMapping() {
+ return inputVarToOutputVarMapping;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/SubstituteVariableVisitor.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/SubstituteVariableVisitor.java b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/SubstituteVariableVisitor.java
index 2268a9e..ddcf6c8 100644
--- a/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/SubstituteVariableVisitor.java
+++ b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/SubstituteVariableVisitor.java
@@ -18,11 +18,9 @@
*/
package org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors;
-import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.mutable.Mutable;
-
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
import org.apache.hyracks.algebricks.common.utils.Pair;
import org.apache.hyracks.algebricks.common.utils.Triple;
@@ -31,7 +29,6 @@ import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
import org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan;
import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable;
import org.apache.hyracks.algebricks.core.algebra.expressions.IVariableTypeEnvironment;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractUnnestNonMapOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.AggregateOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.AssignOperator;
@@ -69,10 +66,10 @@ import org.apache.hyracks.algebricks.core.algebra.operators.logical.WriteOperato
import org.apache.hyracks.algebricks.core.algebra.operators.logical.WriteResultOperator;
import org.apache.hyracks.algebricks.core.algebra.properties.OrderColumn;
import org.apache.hyracks.algebricks.core.algebra.typing.ITypingContext;
-import org.apache.hyracks.algebricks.core.algebra.util.OperatorManipulationUtil;
import org.apache.hyracks.algebricks.core.algebra.visitors.ILogicalOperatorVisitor;
-public class SubstituteVariableVisitor implements ILogicalOperatorVisitor<Void, Pair<LogicalVariable, LogicalVariable>> {
+public class SubstituteVariableVisitor
+ implements ILogicalOperatorVisitor<Void, Pair<LogicalVariable, LogicalVariable>> {
private final boolean goThroughNts;
private final ITypingContext ctx;
@@ -149,7 +146,8 @@ public class SubstituteVariableVisitor implements ILogicalOperatorVisitor<Void,
}
@Override
- public Void visitEmptyTupleSourceOperator(EmptyTupleSourceOperator op, Pair<LogicalVariable, LogicalVariable> pair) {
+ public Void visitEmptyTupleSourceOperator(EmptyTupleSourceOperator op,
+ Pair<LogicalVariable, LogicalVariable> pair) {
// does not use any variable
return null;
}
@@ -167,8 +165,7 @@ public class SubstituteVariableVisitor implements ILogicalOperatorVisitor<Void,
subst(pair.first, pair.second, op.getDecorList());
for (ILogicalPlan p : op.getNestedPlans()) {
for (Mutable<ILogicalOperator> r : p.getRoots()) {
- OperatorManipulationUtil.substituteVarRec((AbstractLogicalOperator) r.getValue(), pair.first,
- pair.second, goThroughNts, ctx);
+ VariableUtilities.substituteVariablesInDescendantsAndSelf(r.getValue(), pair.first, pair.second, ctx);
}
}
substVarTypes(op, pair);
@@ -204,8 +201,8 @@ public class SubstituteVariableVisitor implements ILogicalOperatorVisitor<Void,
}
@Override
- public Void visitNestedTupleSourceOperator(NestedTupleSourceOperator op, Pair<LogicalVariable, LogicalVariable> pair)
- throws AlgebricksException {
+ public Void visitNestedTupleSourceOperator(NestedTupleSourceOperator op,
+ Pair<LogicalVariable, LogicalVariable> pair) throws AlgebricksException {
return null;
}
@@ -220,8 +217,8 @@ public class SubstituteVariableVisitor implements ILogicalOperatorVisitor<Void,
}
@Override
- public Void visitPartitioningSplitOperator(PartitioningSplitOperator op, Pair<LogicalVariable, LogicalVariable> pair)
- throws AlgebricksException {
+ public Void visitPartitioningSplitOperator(PartitioningSplitOperator op,
+ Pair<LogicalVariable, LogicalVariable> pair) throws AlgebricksException {
for (Mutable<ILogicalExpression> e : op.getExpressions()) {
e.getValue().substituteVar(pair.first, pair.second);
}
@@ -280,8 +277,7 @@ public class SubstituteVariableVisitor implements ILogicalOperatorVisitor<Void,
throws AlgebricksException {
for (ILogicalPlan p : op.getNestedPlans()) {
for (Mutable<ILogicalOperator> r : p.getRoots()) {
- OperatorManipulationUtil.substituteVarRec((AbstractLogicalOperator) r.getValue(), pair.first,
- pair.second, goThroughNts, ctx);
+ VariableUtilities.substituteVariablesInDescendantsAndSelf(r.getValue(), pair.first, pair.second, ctx);
}
}
return null;
@@ -369,7 +365,7 @@ public class SubstituteVariableVisitor implements ILogicalOperatorVisitor<Void,
}
}
- private void substInArray(ArrayList<LogicalVariable> varArray, LogicalVariable v1, LogicalVariable v2) {
+ private void substInArray(List<LogicalVariable> varArray, LogicalVariable v1, LogicalVariable v2) {
for (int i = 0; i < varArray.size(); i++) {
LogicalVariable v = varArray.get(i);
if (v == v1) {
@@ -403,8 +399,8 @@ public class SubstituteVariableVisitor implements ILogicalOperatorVisitor<Void,
}
@Override
- public Void visitIndexInsertDeleteOperator(IndexInsertDeleteOperator op, Pair<LogicalVariable, LogicalVariable> pair)
- throws AlgebricksException {
+ public Void visitIndexInsertDeleteOperator(IndexInsertDeleteOperator op,
+ Pair<LogicalVariable, LogicalVariable> pair) throws AlgebricksException {
for (Mutable<ILogicalExpression> e : op.getPrimaryKeyExpressions()) {
e.getValue().substituteVar(pair.first, pair.second);
}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/VariableUtilities.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/VariableUtilities.java b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/VariableUtilities.java
index a3ea549..70eb544 100644
--- a/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/VariableUtilities.java
+++ b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/VariableUtilities.java
@@ -21,15 +21,17 @@ package org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.mutable.Mutable;
-
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
import org.apache.hyracks.algebricks.common.utils.Pair;
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.LogicalVariable;
import org.apache.hyracks.algebricks.core.algebra.typing.ITypingContext;
+import org.apache.hyracks.algebricks.core.algebra.util.OperatorManipulationUtil;
import org.apache.hyracks.algebricks.core.algebra.visitors.ILogicalOperatorVisitor;
public class VariableUtilities {
@@ -98,4 +100,32 @@ public class VariableUtilities {
return varSet.equals(varArgSet);
}
+ /**
+ * Recursively modifies the query plan to make sure every variable in {@code varsToEnforce}
+ * be part of the output schema of {@code opRef}.
+ *
+ * @param opRef,
+ * the operator to enforce.
+ * @param varsToEnforce,
+ * the variables that needs to be live after the operator of {@code opRef}.
+ * @param context,
+ * the optimization context.
+ * @return a map that maps a variable in {@code varsToEnforce} to yet-another-variable if
+ * a mapping happens in the query plan under {@code opRef}, e.g., by grouping and assigning.
+ * @throws AlgebricksException
+ */
+ public static Map<LogicalVariable, LogicalVariable> enforceVariablesInDescendantsAndSelf(
+ Mutable<ILogicalOperator> opRef, Collection<LogicalVariable> varsToEnforce, IOptimizationContext context)
+ throws AlgebricksException {
+ Set<LogicalVariable> copiedVarsToEnforce = new HashSet<>();
+ copiedVarsToEnforce.addAll(varsToEnforce);
+ // Rewrites the query plan
+ EnforceVariablesVisitor visitor = new EnforceVariablesVisitor(context);
+ ILogicalOperator result = opRef.getValue().accept(visitor, copiedVarsToEnforce);
+ opRef.setValue(result);
+ // Re-computes the type environment bottom up.
+ OperatorManipulationUtil.computeTypeEnvironmentBottomUp(result, context);
+ return visitor.getInputVariableToOutputVariableMap();
+ }
+
}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/physical/AbstractPhysicalOperator.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/physical/AbstractPhysicalOperator.java b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/physical/AbstractPhysicalOperator.java
index 74200b4..27d06f0 100644
--- a/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/physical/AbstractPhysicalOperator.java
+++ b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/physical/AbstractPhysicalOperator.java
@@ -61,16 +61,19 @@ public abstract class AbstractPhysicalOperator implements IPhysicalOperator {
return getOperatorTag().toString();
}
+ @Override
public void setHostQueryContext(Object context) {
this.hostQueryContext = context;
}
+ @Override
public Object getHostQueryContext() {
return hostQueryContext;
}
protected PhysicalRequirements emptyUnaryRequirements() {
- StructuralPropertiesVector[] req = new StructuralPropertiesVector[] { StructuralPropertiesVector.EMPTY_PROPERTIES_VECTOR };
+ StructuralPropertiesVector[] req = new StructuralPropertiesVector[] {
+ StructuralPropertiesVector.EMPTY_PROPERTIES_VECTOR };
return new PhysicalRequirements(req, IPartitioningRequirementsCoordinator.NO_COORDINATION);
}
@@ -103,7 +106,8 @@ public abstract class AbstractPhysicalOperator implements IPhysicalOperator {
return new Pair<int[], int[]>(inputDependencyLabels, outputDependencyLabels);
}
- protected void contributeOpDesc(IHyracksJobBuilder builder, AbstractLogicalOperator op, IOperatorDescriptor opDesc) {
+ protected void contributeOpDesc(IHyracksJobBuilder builder, AbstractLogicalOperator op,
+ IOperatorDescriptor opDesc) {
if (op.getExecutionMode() == ExecutionMode.UNPARTITIONED) {
AlgebricksPartitionConstraint apc = new AlgebricksCountPartitionConstraint(1);
builder.contributeAlgebricksPartitionConstraint(opDesc, apc);
@@ -113,7 +117,7 @@ public abstract class AbstractPhysicalOperator implements IPhysicalOperator {
protected AlgebricksPipeline[] compileSubplans(IOperatorSchema outerPlanSchema,
AbstractOperatorWithNestedPlans npOp, IOperatorSchema opSchema, JobGenContext context)
- throws AlgebricksException {
+ throws AlgebricksException {
AlgebricksPipeline[] subplans = new AlgebricksPipeline[npOp.getNestedPlans().size()];
PlanCompiler pc = new PlanCompiler(context);
int i = 0;
@@ -124,7 +128,8 @@ public abstract class AbstractPhysicalOperator implements IPhysicalOperator {
}
private AlgebricksPipeline buildPipelineWithProjection(ILogicalPlan p, IOperatorSchema outerPlanSchema,
- AbstractOperatorWithNestedPlans npOp, IOperatorSchema opSchema, PlanCompiler pc) throws AlgebricksException {
+ AbstractOperatorWithNestedPlans npOp, IOperatorSchema opSchema, PlanCompiler pc)
+ throws AlgebricksException {
if (p.getRoots().size() > 1) {
throw new NotImplementedException("Nested plans with several roots are not supported.");
}
@@ -136,10 +141,8 @@ public abstract class AbstractPhysicalOperator implements IPhysicalOperator {
Map<OperatorDescriptorId, IOperatorDescriptor> opMap = nestedJob.getOperatorMap();
if (opMap.size() != 1) {
- throw new AlgebricksException(
- "Attempting to construct a nested plan with "
- + opMap.size()
- + " operator descriptors. Currently, nested plans can only consist in linear pipelines of Asterix micro operators.");
+ throw new AlgebricksException("Attempting to construct a nested plan with " + opMap.size()
+ + " operator descriptors. Currently, nested plans can only consist in linear pipelines of Asterix micro operators.");
}
for (OperatorDescriptorId oid : opMap.keySet()) {
@@ -158,4 +161,4 @@ public abstract class AbstractPhysicalOperator implements IPhysicalOperator {
throw new IllegalStateException();
}
-}
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/physical/SubplanPOperator.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/physical/SubplanPOperator.java b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/physical/SubplanPOperator.java
index ecb7186..617e7ec 100644
--- a/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/physical/SubplanPOperator.java
+++ b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/physical/SubplanPOperator.java
@@ -22,7 +22,6 @@ import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.mutable.Mutable;
-
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
import org.apache.hyracks.algebricks.common.exceptions.NotImplementedException;
import org.apache.hyracks.algebricks.core.algebra.base.IHyracksJobBuilder;
@@ -85,7 +84,7 @@ public class SubplanPOperator extends AbstractPhysicalOperator {
@Override
public void contributeRuntimeOperator(IHyracksJobBuilder builder, JobGenContext context, ILogicalOperator op,
IOperatorSchema opSchema, IOperatorSchema[] inputSchemas, IOperatorSchema outerPlanSchema)
- throws AlgebricksException {
+ throws AlgebricksException {
SubplanOperator subplan = (SubplanOperator) op;
if (subplan.getNestedPlans().size() != 1) {
throw new NotImplementedException("Subplan currently works only for one nested plan with one root.");
@@ -93,8 +92,8 @@ public class SubplanPOperator extends AbstractPhysicalOperator {
AlgebricksPipeline[] subplans = compileSubplans(inputSchemas[0], subplan, opSchema, context);
assert (subplans.length == 1);
AlgebricksPipeline np = subplans[0];
- RecordDescriptor inputRecordDesc = JobGenHelper.mkRecordDescriptor(context.getTypeEnvironment(op.getInputs().get(0).getValue()),
- inputSchemas[0], context);
+ RecordDescriptor inputRecordDesc = JobGenHelper.mkRecordDescriptor(
+ context.getTypeEnvironment(op.getInputs().get(0).getValue()), inputSchemas[0], context);
INullWriterFactory[] nullWriterFactories = new INullWriterFactory[np.getOutputWidth()];
for (int i = 0; i < nullWriterFactories.length; i++) {
nullWriterFactories[i] = context.getNullWriterFactory();
@@ -112,4 +111,4 @@ public class SubplanPOperator extends AbstractPhysicalOperator {
public boolean expensiveThanMaterialization() {
return true;
}
-}
+}
\ No newline at end of file
[3/4] incubator-asterixdb-hyracks git commit: Fix for ASTERIXDB-1018,
ASTERIXDB-1017, ASTERIXDB-1019, ASTERIXDB-1020, ASTERIXDB-1029, ASTERIXDB-1030,
ASTERIXDB-1034:
Posted by bu...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/util/OperatorManipulationUtil.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/util/OperatorManipulationUtil.java b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/util/OperatorManipulationUtil.java
index 61a191f..b4569e4 100644
--- a/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/util/OperatorManipulationUtil.java
+++ b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/util/OperatorManipulationUtil.java
@@ -23,7 +23,6 @@ import java.util.List;
import org.apache.commons.lang3.mutable.Mutable;
import org.apache.commons.lang3.mutable.MutableObject;
-
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
import org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan;
@@ -226,4 +225,21 @@ public class OperatorManipulationUtil {
return op.accept(visitor, null);
}
+ /**
+ * Compute type environment of a newly generated operator {@code op} and its input.
+ *
+ * @param op,
+ * the logical operator.
+ * @param context,the
+ * optimization context.
+ * @throws AlgebricksException
+ */
+ public static void computeTypeEnvironmentBottomUp(ILogicalOperator op, IOptimizationContext context)
+ throws AlgebricksException {
+ for (Mutable<ILogicalOperator> children : op.getInputs()) {
+ computeTypeEnvironmentBottomUp(children.getValue(), context);
+ }
+ context.computeAndSetTypeEnvironmentForOperator(op);
+ }
+
}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/visitors/IQueryOperatorVisitor.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/visitors/IQueryOperatorVisitor.java b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/visitors/IQueryOperatorVisitor.java
new file mode 100644
index 0000000..b5ce212
--- /dev/null
+++ b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/visitors/IQueryOperatorVisitor.java
@@ -0,0 +1,59 @@
+/*
+ * 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.core.algebra.visitors;
+
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.DistributeResultOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.IndexInsertDeleteOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.InsertDeleteOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.SinkOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.WriteOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.WriteResultOperator;
+
+public interface IQueryOperatorVisitor<R, T> extends ILogicalOperatorVisitor<R, T> {
+
+ @Override
+ public default R visitWriteOperator(WriteOperator op, T arg) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public default R visitDistributeResultOperator(DistributeResultOperator op, T arg) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public default R visitWriteResultOperator(WriteResultOperator op, T arg) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public default R visitInsertDeleteOperator(InsertDeleteOperator op, T arg) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public default R visitIndexInsertDeleteOperator(IndexInsertDeleteOperator op, T arg) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public default R visitSinkOperator(SinkOperator op, T arg) {
+ throw new UnsupportedOperationException();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/rewriter/base/IAlgebraicRewriteRule.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/rewriter/base/IAlgebraicRewriteRule.java b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/rewriter/base/IAlgebraicRewriteRule.java
index 83740de..128c372 100644
--- a/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/rewriter/base/IAlgebraicRewriteRule.java
+++ b/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/rewriter/base/IAlgebraicRewriteRule.java
@@ -24,8 +24,34 @@ import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
public interface IAlgebraicRewriteRule {
- public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException;
- public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
- throws AlgebricksException;
+ /**
+ * This method is invoked in pre-order traversal of a query plan.
+ *
+ * @param opRef,
+ * the reference of the current operator to look at,
+ * @param context
+ * the optimization context
+ * @return true if any change is introduced to the query plan; false otherwise.
+ * @throws AlgebricksException
+ */
+ public default boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
+ throws AlgebricksException {
+ return false;
+ }
+
+ /**
+ * This method is invoked in the post-order traversal of a query plan.
+ *
+ * @param opRef,
+ * the reference of the current operator to look at,
+ * @param context
+ * the optimization context
+ * @return true if any change is introduced to the query plan; false otherwise.
+ * @throws AlgebricksException
+ */
+ public default boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
+ throws AlgebricksException {
+ return false;
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-core/src/test/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/EnforceVariablesVisitorTest.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-core/src/test/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/EnforceVariablesVisitorTest.java b/algebricks/algebricks-core/src/test/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/EnforceVariablesVisitorTest.java
new file mode 100644
index 0000000..d0676cf
--- /dev/null
+++ b/algebricks/algebricks-core/src/test/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/EnforceVariablesVisitorTest.java
@@ -0,0 +1,190 @@
+/*
+ * 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.core.algebra.operators.logical.visitors;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.lang3.mutable.Mutable;
+import org.apache.commons.lang3.mutable.MutableObject;
+import org.apache.hyracks.algebricks.common.utils.Pair;
+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.LogicalVariable;
+import org.apache.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.AggregateOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.GroupByOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.ProjectOperator;
+import org.junit.Test;
+
+import junit.framework.Assert;
+
+public class EnforceVariablesVisitorTest {
+
+ /**
+ * Tests the processing of project operator in RecoverVariablesVisitor.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testProject() throws Exception {
+ // Constructs the input operator.
+ LogicalVariable var = new LogicalVariable(1);
+ List<LogicalVariable> inputVarList = new ArrayList<>();
+ inputVarList.add(var);
+ ProjectOperator projectOp = new ProjectOperator(inputVarList);
+
+ // Constructs the visitor.
+ IOptimizationContext mockedContext = mock(IOptimizationContext.class);
+ EnforceVariablesVisitor visitor = new EnforceVariablesVisitor(mockedContext);
+
+ // Calls the visitor.
+ LogicalVariable varToEnforce = new LogicalVariable(2);
+ ProjectOperator op = (ProjectOperator) projectOp.accept(visitor,
+ Arrays.asList(new LogicalVariable[] { varToEnforce }));
+
+ // Checks the result.
+ List<LogicalVariable> expectedVars = Arrays.asList(new LogicalVariable[] { var, varToEnforce });
+ Assert.assertEquals(expectedVars, op.getVariables());
+ Assert.assertTrue(visitor.getInputVariableToOutputVariableMap().isEmpty());
+ }
+
+ /**
+ * Tests the processing of group-by operator in RecoverVariablesVisitor.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testGroupby() throws Exception {
+ // Constructs the group-by operator.
+ LogicalVariable keyVar = new LogicalVariable(2);
+ LogicalVariable keyExprVar = new LogicalVariable(1);
+ GroupByOperator gbyOp = new GroupByOperator();
+ gbyOp.getGroupByList().add(new Pair<LogicalVariable, Mutable<ILogicalExpression>>(keyVar,
+ new MutableObject<ILogicalExpression>(new VariableReferenceExpression(keyExprVar))));
+
+ // Constructs the visitor.
+ IOptimizationContext mockedContext = mock(IOptimizationContext.class);
+ EnforceVariablesVisitor visitor = new EnforceVariablesVisitor(mockedContext);
+
+ // Calls the visitor.
+ LogicalVariable varToEnforce = new LogicalVariable(3);
+ Set<LogicalVariable> varsToEnforce = new HashSet<>();
+ varsToEnforce.add(keyExprVar);
+ varsToEnforce.add(varToEnforce);
+ GroupByOperator op = (GroupByOperator) gbyOp.accept(visitor, varsToEnforce);
+
+ // Checks the result.
+ Map<LogicalVariable, LogicalVariable> expectedVarMap = new HashMap<>();
+ expectedVarMap.put(keyExprVar, keyVar);
+ Assert.assertEquals(expectedVarMap, visitor.getInputVariableToOutputVariableMap());
+ VariableReferenceExpression decorVarExpr = (VariableReferenceExpression) op.getDecorList().get(0).second
+ .getValue();
+ Assert.assertEquals(decorVarExpr.getVariableReference(), varToEnforce);
+ }
+
+ /**
+ * Tests the processing of aggregate operator in RecoverVariablesVisitor.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testAggregate() throws Exception {
+ // Constructs the group-by operator.
+ List<LogicalVariable> aggVars = new ArrayList<>();
+ List<Mutable<ILogicalExpression>> aggExprRefs = new ArrayList<>();
+ AggregateOperator aggOp = new AggregateOperator(aggVars, aggExprRefs);
+
+ // Constructs the visitor.
+ LogicalVariable var = new LogicalVariable(3);
+ IOptimizationContext mockedContext = mock(IOptimizationContext.class);
+ when(mockedContext.newVar()).thenReturn(var);
+ EnforceVariablesVisitor visitor = new EnforceVariablesVisitor(mockedContext);
+
+ // Calls the visitor.
+ LogicalVariable varToEnforce = new LogicalVariable(2);
+ Set<LogicalVariable> varsToEnforce = new HashSet<>();
+ varsToEnforce.add(varToEnforce);
+ GroupByOperator op = (GroupByOperator) aggOp.accept(visitor, varsToEnforce);
+
+ // Checks the result.
+ Map<LogicalVariable, LogicalVariable> expectedVarMap = new HashMap<>();
+ expectedVarMap.put(varToEnforce, var);
+ Assert.assertEquals(expectedVarMap, visitor.getInputVariableToOutputVariableMap());
+ VariableReferenceExpression keyExpr = (VariableReferenceExpression) op.getGroupByList().get(0).second
+ .getValue();
+ Assert.assertEquals(keyExpr.getVariableReference(), varToEnforce);
+ LogicalVariable expectedGbyVar = op.getGroupByList().get(0).first;
+ Assert.assertEquals(expectedGbyVar, var);
+ }
+
+ /**
+ * Tests the processing of two serial group-by operators in RecoverVariablesVisitor.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testTwoGroupbys() throws Exception {
+ // Constructs the group-by operators.
+ LogicalVariable keyVar = new LogicalVariable(1);
+ LogicalVariable keyExprVar = new LogicalVariable(2);
+ GroupByOperator gbyOp = new GroupByOperator();
+ gbyOp.getGroupByList().add(new Pair<LogicalVariable, Mutable<ILogicalExpression>>(keyVar,
+ new MutableObject<ILogicalExpression>(new VariableReferenceExpression(keyExprVar))));
+ LogicalVariable keyVar2 = new LogicalVariable(2);
+ LogicalVariable keyExprVar2 = new LogicalVariable(3);
+ GroupByOperator gbyOp2 = new GroupByOperator();
+ gbyOp.getGroupByList().add(new Pair<LogicalVariable, Mutable<ILogicalExpression>>(keyVar2,
+ new MutableObject<ILogicalExpression>(new VariableReferenceExpression(keyExprVar2))));
+ gbyOp.getInputs().add(new MutableObject<ILogicalOperator>(gbyOp2));
+
+ // Constructs the visitor.
+ IOptimizationContext mockedContext = mock(IOptimizationContext.class);
+ EnforceVariablesVisitor visitor = new EnforceVariablesVisitor(mockedContext);
+
+ // Calls the visitor.
+ LogicalVariable varToEnforce = new LogicalVariable(4);
+ Set<LogicalVariable> varsToEnforce = new HashSet<>();
+ varsToEnforce.add(keyExprVar2);
+ varsToEnforce.add(varToEnforce);
+ GroupByOperator op = (GroupByOperator) gbyOp.accept(visitor, varsToEnforce);
+
+ // Checks the result.
+ Map<LogicalVariable, LogicalVariable> expectedVarMap = new HashMap<>();
+ expectedVarMap.put(keyExprVar2, keyVar);
+ Assert.assertEquals(expectedVarMap, visitor.getInputVariableToOutputVariableMap());
+ VariableReferenceExpression decorVarExpr = (VariableReferenceExpression) op.getDecorList().get(0).second
+ .getValue();
+ Assert.assertEquals(decorVarExpr.getVariableReference(), varToEnforce);
+ GroupByOperator op2 = (GroupByOperator) op.getInputs().get(0).getValue();
+ VariableReferenceExpression decorVarExpr2 = (VariableReferenceExpression) op2.getDecorList().get(0).second
+ .getValue();
+ Assert.assertEquals(decorVarExpr2.getVariableReference(), varToEnforce);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-examples/piglet-example/src/main/java/org/apache/hyracks/algebricks/examples/piglet/rewriter/PigletRewriteRuleset.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-examples/piglet-example/src/main/java/org/apache/hyracks/algebricks/examples/piglet/rewriter/PigletRewriteRuleset.java b/algebricks/algebricks-examples/piglet-example/src/main/java/org/apache/hyracks/algebricks/examples/piglet/rewriter/PigletRewriteRuleset.java
index 6ff1477..952c7c1 100644
--- a/algebricks/algebricks-examples/piglet-example/src/main/java/org/apache/hyracks/algebricks/examples/piglet/rewriter/PigletRewriteRuleset.java
+++ b/algebricks/algebricks-examples/piglet-example/src/main/java/org/apache/hyracks/algebricks/examples/piglet/rewriter/PigletRewriteRuleset.java
@@ -27,7 +27,6 @@ import org.apache.hyracks.algebricks.rewriter.rules.BreakSelectIntoConjunctsRule
import org.apache.hyracks.algebricks.rewriter.rules.ComplexJoinInferenceRule;
import org.apache.hyracks.algebricks.rewriter.rules.ConsolidateAssignsRule;
import org.apache.hyracks.algebricks.rewriter.rules.ConsolidateSelectsRule;
-import org.apache.hyracks.algebricks.rewriter.rules.EliminateSubplanRule;
import org.apache.hyracks.algebricks.rewriter.rules.EnforceStructuralPropertiesRule;
import org.apache.hyracks.algebricks.rewriter.rules.ExtractCommonOperatorsRule;
import org.apache.hyracks.algebricks.rewriter.rules.ExtractGbyExpressionsRule;
@@ -45,6 +44,7 @@ import org.apache.hyracks.algebricks.rewriter.rules.ReinferAllTypesRule;
import org.apache.hyracks.algebricks.rewriter.rules.RemoveUnusedAssignAndAggregateRule;
import org.apache.hyracks.algebricks.rewriter.rules.SetAlgebricksPhysicalOperatorsRule;
import org.apache.hyracks.algebricks.rewriter.rules.SetExecutionModeRule;
+import org.apache.hyracks.algebricks.rewriter.rules.subplan.EliminateSubplanRule;
public class PigletRewriteRuleset {
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/EliminateSubplanRule.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/EliminateSubplanRule.java b/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/EliminateSubplanRule.java
deleted file mode 100644
index 7327e94..0000000
--- a/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/EliminateSubplanRule.java
+++ /dev/null
@@ -1,131 +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.LinkedList;
-
-import org.apache.commons.lang3.mutable.Mutable;
-import org.apache.commons.lang3.mutable.MutableObject;
-
-import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
-import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
-import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
-import org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan;
-import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
-import org.apache.hyracks.algebricks.core.algebra.base.LogicalOperatorTag;
-import org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.LeftOuterJoinOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.SubplanOperator;
-import org.apache.hyracks.algebricks.core.algebra.util.OperatorManipulationUtil;
-import org.apache.hyracks.algebricks.core.algebra.util.OperatorPropertiesUtil;
-import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
-
-public class EliminateSubplanRule implements IAlgebraicRewriteRule {
-
- @Override
- public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context) {
- return false;
- }
-
- /**
- * Eliminate Subplan above ETS
- * and Subplan that has only ops. with one input and no free vars. (could we
- * modify it to consider free vars which are sources of Unnest or Assign, if
- * there are no aggregates?)
- */
- @Override
- public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException {
- AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue();
- if (op.getOperatorTag() != LogicalOperatorTag.SUBPLAN) {
- return false;
- }
- SubplanOperator subplan = (SubplanOperator) op;
-
- Mutable<ILogicalOperator> outerRef = subplan.getInputs().get(0);
- AbstractLogicalOperator outerRefOp = (AbstractLogicalOperator) outerRef.getValue();
- if (outerRefOp.getOperatorTag() == LogicalOperatorTag.EMPTYTUPLESOURCE) {
- elimSubplanOverEts(opRef, context);
- return true;
- }
- if (subplan.getNestedPlans().size() == 1 && subplan.getNestedPlans().get(0).getRoots().size() == 1
- && !OperatorPropertiesUtil.hasFreeVariables(subplan)) {
- if (elimOneSubplanWithNoFreeVars(opRef)) {
- return true;
- }
- }
-
- return false;
- }
-
- private boolean elimOneSubplanWithNoFreeVars(Mutable<ILogicalOperator> opRef) {
- SubplanOperator subplan = (SubplanOperator) opRef.getValue();
- AbstractLogicalOperator rootOp = (AbstractLogicalOperator) subplan.getNestedPlans().get(0).getRoots().get(0)
- .getValue();
- if (rootOp.getOperatorTag() == LogicalOperatorTag.EMPTYTUPLESOURCE
- || rootOp.getOperatorTag() == LogicalOperatorTag.NESTEDTUPLESOURCE) {
- opRef.setValue(subplan.getInputs().get(0).getValue());
- return true;
- } else {
- AbstractLogicalOperator botOp = rootOp;
- if (botOp.getInputs().size() != 1) {
- return false;
- }
- do {
- Mutable<ILogicalOperator> botRef = botOp.getInputs().get(0);
- botOp = (AbstractLogicalOperator) botRef.getValue();
- if (botOp.getOperatorTag() == LogicalOperatorTag.EMPTYTUPLESOURCE) {
- botRef.setValue(subplan.getInputs().get(0).getValue());
- opRef.setValue(rootOp);
- return true;
- }
- } while (botOp.getInputs().size() == 1);
- return false;
- }
- }
-
- private void elimSubplanOverEts(Mutable<ILogicalOperator> opRef, IOptimizationContext ctx)
- throws AlgebricksException {
- SubplanOperator subplan = (SubplanOperator) opRef.getValue();
- for (ILogicalPlan p : subplan.getNestedPlans()) {
- for (Mutable<ILogicalOperator> r : p.getRoots()) {
- OperatorManipulationUtil.ntsToEts(r, ctx);
- }
- }
- LinkedList<Mutable<ILogicalOperator>> allRoots = subplan.allRootsInReverseOrder();
- if (allRoots.size() == 1) {
- opRef.setValue(allRoots.get(0).getValue());
- } else {
- ILogicalOperator topOp = null;
- for (Mutable<ILogicalOperator> r : allRoots) {
- if (topOp == null) {
- topOp = r.getValue();
- } else {
- LeftOuterJoinOperator j = new LeftOuterJoinOperator(new MutableObject<ILogicalExpression>(
- ConstantExpression.TRUE));
- j.getInputs().add(new MutableObject<ILogicalOperator>(topOp));
- j.getInputs().add(r);
- ctx.setOutputTypeEnvironment(j, j.computeOutputTypeEnvironment(ctx));
- topOp = j;
- }
- }
- opRef.setValue(topOp);
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/EliminateSubplanWithInputCardinalityOneRule.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/EliminateSubplanWithInputCardinalityOneRule.java b/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/EliminateSubplanWithInputCardinalityOneRule.java
deleted file mode 100644
index df6e1ee..0000000
--- a/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/EliminateSubplanWithInputCardinalityOneRule.java
+++ /dev/null
@@ -1,203 +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.List;
-import java.util.Set;
-
-import org.apache.commons.lang3.mutable.Mutable;
-
-import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
-import org.apache.hyracks.algebricks.common.utils.ListSet;
-import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
-import org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan;
-import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
-import org.apache.hyracks.algebricks.core.algebra.base.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.SubplanOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities;
-import org.apache.hyracks.algebricks.core.algebra.util.OperatorPropertiesUtil;
-import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
-
-/**
- * This rule eliminates a subplan with the following pattern:
- * -- SUBPLAN
- * -- OP (where OP produces exactly one tuple)
- * The live variables at OP will not be used after SUBPLAN.
- * Note: This rule must be applied after
- * the RemoveRedundantVariablesRule (to avoid the lineage analysis of variable cardinality).
- *
- * @author yingyib
- */
-public class EliminateSubplanWithInputCardinalityOneRule implements IAlgebraicRewriteRule {
- /** The pointer to the topmost operator */
- private Mutable<ILogicalOperator> rootRef;
- /** Whether the rule has even been invoked */
- private boolean invoked = false;
-
- @Override
- public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context) {
- return false;
- }
-
- @Override
- public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException {
- if (!invoked) {
- rootRef = opRef;
- invoked = true;
- }
- AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue();
- if (op.getInputs().size() <= 0) {
- return false;
- }
- boolean changed = false;
- for (Mutable<ILogicalOperator> subplanRef : op.getInputs()) {
- AbstractLogicalOperator op1 = (AbstractLogicalOperator) subplanRef.getValue();
- if (op1.getOperatorTag() != LogicalOperatorTag.SUBPLAN) {
- continue;
- }
-
- SubplanOperator subplan = (SubplanOperator) op1;
- Set<LogicalVariable> usedVarsUp = new ListSet<LogicalVariable>();
- OperatorPropertiesUtil.getFreeVariablesInPath(rootRef.getValue(), subplan, usedVarsUp);
- // TODO(buyingyi): figure out the rewriting for subplan operators with multiple subplans.
- if (subplan.getNestedPlans().size() != 1) {
- continue;
- }
-
- ILogicalOperator subplanInputOperator = subplan.getInputs().get(0).getValue();
- Set<LogicalVariable> subplanInputVars = new ListSet<LogicalVariable>();
- VariableUtilities.getLiveVariables(subplanInputOperator, subplanInputVars);
- int subplanInputVarSize = subplanInputVars.size();
- subplanInputVars.removeAll(usedVarsUp);
- // Makes sure the free variables are only used in the subplan.
- if (subplanInputVars.size() < subplanInputVarSize) {
- continue;
- }
- Set<LogicalVariable> freeVars = new ListSet<LogicalVariable>();
- OperatorPropertiesUtil.getFreeVariablesInSubplans(subplan, freeVars);
- boolean cardinalityOne = isCardinalityOne(subplan.getInputs().get(0), freeVars);
- if (cardinalityOne) {
- /** If the cardinality of freeVars in the subplan is one, the subplan can be removed. */
- ILogicalPlan plan = subplan.getNestedPlans().get(0);
-
- List<Mutable<ILogicalOperator>> rootRefs = plan.getRoots();
- // TODO(buyingyi): investigate the case of multi-root plans.
- if (rootRefs.size() != 1) {
- continue;
- }
- Set<Mutable<ILogicalOperator>> ntsSet = new ListSet<Mutable<ILogicalOperator>>();
- findNts(rootRefs.get(0), ntsSet);
-
- /** Replaces nts with the input operator of the subplan. */
- for (Mutable<ILogicalOperator> nts : ntsSet) {
- nts.setValue(subplanInputOperator);
- }
- subplanRef.setValue(rootRefs.get(0).getValue());
- changed = true;
- } else {
- continue;
- }
- }
- return changed;
- }
-
- /**
- * Whether the cardinality of the input free variables are one.
- *
- * @param opRef
- * the operator to be checked (including its input operators)
- * @param freeVars
- * variables to be checked for produced operators
- * @return true if every input variable has cardinality one; false otherwise.
- * @throws AlgebricksException
- */
- private boolean isCardinalityOne(Mutable<ILogicalOperator> opRef, Set<LogicalVariable> freeVars)
- throws AlgebricksException {
- Set<LogicalVariable> varsWithCardinalityOne = new ListSet<LogicalVariable>();
- Set<LogicalVariable> varsLiveAtUnnestAndJoin = new ListSet<LogicalVariable>();
- isCardinalityOne(opRef, freeVars, varsWithCardinalityOne, varsLiveAtUnnestAndJoin);
- varsWithCardinalityOne.removeAll(varsLiveAtUnnestAndJoin);
- return varsWithCardinalityOne.equals(freeVars);
- }
-
- /**
- * Recursively adding variables which has cardinality one and in int the input free variable set.
- *
- * @param opRef
- * , the current operator reference.
- * @param freeVars
- * , a set of variables.
- * @param varsWithCardinalityOne
- * , variables in the free variable set with cardinality one at the time they are created.
- * @param varsLiveAtUnnestAndJoin
- * , live variables at Unnest and Join. The cardinalities of those variables can become more than one
- * even if their cardinalities were one at the time those variables were created.
- * @throws AlgebricksException
- */
- private void isCardinalityOne(Mutable<ILogicalOperator> opRef, Set<LogicalVariable> freeVars,
- Set<LogicalVariable> varsWithCardinalityOne, Set<LogicalVariable> varsLiveAtUnnestAndJoin)
- throws AlgebricksException {
- AbstractLogicalOperator operator = (AbstractLogicalOperator) opRef.getValue();
- List<LogicalVariable> producedVars = new ArrayList<LogicalVariable>();
- VariableUtilities.getProducedVariables(operator, producedVars);
- if (operator.getOperatorTag() == LogicalOperatorTag.UNNEST
- || operator.getOperatorTag() == LogicalOperatorTag.INNERJOIN
- || operator.getOperatorTag() == LogicalOperatorTag.LEFTOUTERJOIN) {
- VariableUtilities.getLiveVariables(operator, varsLiveAtUnnestAndJoin);
- }
- if (operator.getOperatorTag() == LogicalOperatorTag.AGGREGATE) {
- for (LogicalVariable producedVar : producedVars) {
- if (freeVars.contains(producedVar)) {
- varsWithCardinalityOne.add(producedVar);
- }
- }
- }
- if (varsWithCardinalityOne.size() == freeVars.size()) {
- return;
- }
- for (Mutable<ILogicalOperator> childRef : operator.getInputs()) {
- isCardinalityOne(childRef, freeVars, varsWithCardinalityOne, varsLiveAtUnnestAndJoin);
- }
- }
-
- /**
- * Find the NestedTupleSource operator in the direct/undirect input operators of opRef.
- *
- * @param opRef
- * , the current operator reference.
- * @param ntsSet
- * , the set NestedTupleSource operator references.
- */
- private void findNts(Mutable<ILogicalOperator> opRef, Set<Mutable<ILogicalOperator>> ntsSet) {
- int childSize = opRef.getValue().getInputs().size();
- if (childSize == 0) {
- AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue();
- if (op.getOperatorTag() == LogicalOperatorTag.NESTEDTUPLESOURCE) {
- ntsSet.add(opRef);
- }
- return;
- }
- for (Mutable<ILogicalOperator> childRef : opRef.getValue().getInputs()) {
- findNts(childRef, ntsSet);
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/InlineVariablesRule.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/InlineVariablesRule.java b/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/InlineVariablesRule.java
index 1ecb893..f2645f5 100644
--- a/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/InlineVariablesRule.java
+++ b/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/InlineVariablesRule.java
@@ -85,7 +85,8 @@ public class InlineVariablesRule implements IAlgebraicRewriteRule {
}
@Override
- public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException {
+ public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
+ throws AlgebricksException {
if (hasRun) {
return false;
}
@@ -145,7 +146,7 @@ public class InlineVariablesRule implements IAlgebraicRewriteRule {
List<Mutable<ILogicalExpression>> exprs = assignOp.getExpressions();
for (int i = 0; i < vars.size(); i++) {
ILogicalExpression expr = exprs.get(i).getValue();
- // Ignore functions that are either in the doNotInline set or are non-functional
+ // Ignore functions that are either in the doNotInline set or are non-functional
if (expr.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
AbstractFunctionCallExpression funcExpr = (AbstractFunctionCallExpression) expr;
if (doNotInlineFuncs.contains(funcExpr.getFunctionIdentifier())
@@ -174,6 +175,14 @@ public class InlineVariablesRule implements IAlgebraicRewriteRule {
}
}
+ // References to variables generated in the right branch of a left-outer-join cannot be inlined
+ // in operators above the left-outer-join.
+ if (op.getOperatorTag() == LogicalOperatorTag.LEFTOUTERJOIN) {
+ Set<LogicalVariable> rightLiveVars = new HashSet<LogicalVariable>();
+ VariableUtilities.getLiveVariables(op.getInputs().get(1).getValue(), rightLiveVars);
+ varAssignRhs.keySet().removeAll(rightLiveVars);
+ }
+
if (performBottomUpAction(op)) {
modified = true;
}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/InsertOuterJoinRule.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/InsertOuterJoinRule.java b/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/InsertOuterJoinRule.java
deleted file mode 100644
index b8c75bd..0000000
--- a/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/InsertOuterJoinRule.java
+++ /dev/null
@@ -1,125 +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.Iterator;
-
-import org.apache.commons.lang3.mutable.Mutable;
-
-import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
-import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
-import org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan;
-import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
-import org.apache.hyracks.algebricks.core.algebra.base.LogicalOperatorTag;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.InnerJoinOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.LeftOuterJoinOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.SubplanOperator;
-import org.apache.hyracks.algebricks.core.algebra.util.OperatorPropertiesUtil;
-import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
-
-public class InsertOuterJoinRule 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 op0 = (AbstractLogicalOperator) opRef.getValue();
- if (op0.getOperatorTag() != LogicalOperatorTag.SUBPLAN) {
- return false;
- }
- SubplanOperator subplan = (SubplanOperator) op0;
-
- Iterator<ILogicalPlan> plansIter = subplan.getNestedPlans().iterator();
- ILogicalPlan p = null;
- while (plansIter.hasNext()) {
- p = plansIter.next();
- }
- if (p == null) {
- return false;
- }
- if (p.getRoots().size() != 1) {
- return false;
- }
- Mutable<ILogicalOperator> subplanRoot = p.getRoots().get(0);
- AbstractLogicalOperator op1 = (AbstractLogicalOperator) subplanRoot.getValue();
- Mutable<ILogicalOperator> opUnder = subplan.getInputs().get(0);
-
- if (OperatorPropertiesUtil.isNullTest((AbstractLogicalOperator) opUnder.getValue())) {
- return false;
- }
-
- switch (op1.getOperatorTag()) {
- case INNERJOIN: {
- InnerJoinOperator join = (InnerJoinOperator) op1;
- Mutable<ILogicalOperator> leftRef = join.getInputs().get(0);
- Mutable<ILogicalOperator> rightRef = join.getInputs().get(1);
- Mutable<ILogicalOperator> ntsRef = getNtsAtEndOfPipeline(leftRef);
- if (ntsRef == null) {
- ntsRef = getNtsAtEndOfPipeline(rightRef);
- if (ntsRef == null) {
- return false;
- } else {
- Mutable<ILogicalOperator> t = leftRef;
- leftRef = rightRef;
- rightRef = t;
- }
- }
- ntsRef.setValue(opUnder.getValue());
- LeftOuterJoinOperator loj = new LeftOuterJoinOperator(join.getCondition());
- loj.getInputs().add(leftRef);
- loj.getInputs().add(rightRef);
- opRef.setValue(loj);
- context.computeAndSetTypeEnvironmentForOperator(loj);
- return true;
- }
- case LEFTOUTERJOIN: {
- LeftOuterJoinOperator join = (LeftOuterJoinOperator) op1;
- Mutable<ILogicalOperator> leftRef = join.getInputs().get(0);
- Mutable<ILogicalOperator> ntsRef = getNtsAtEndOfPipeline(leftRef);
- if (ntsRef == null) {
- return false;
- }
- ntsRef.setValue(opUnder.getValue());
- opRef.setValue(join);
- context.computeAndSetTypeEnvironmentForOperator(join);
- return true;
- }
- default: {
- return false;
- }
- }
- }
-
- private Mutable<ILogicalOperator> getNtsAtEndOfPipeline(Mutable<ILogicalOperator> opRef) {
- AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue();
- if (op.getOperatorTag() == LogicalOperatorTag.NESTEDTUPLESOURCE) {
- return opRef;
- }
- if (op.getInputs().size() != 1) {
- return null;
- }
- return getNtsAtEndOfPipeline(op.getInputs().get(0));
- }
-
-}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/IntroduceGroupByForSubplanRule.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/IntroduceGroupByForSubplanRule.java b/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/IntroduceGroupByForSubplanRule.java
deleted file mode 100644
index 67e8d42..0000000
--- a/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/IntroduceGroupByForSubplanRule.java
+++ /dev/null
@@ -1,327 +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.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-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.ListSet;
-import org.apache.hyracks.algebricks.common.utils.Pair;
-import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
-import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
-import org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan;
-import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
-import org.apache.hyracks.algebricks.core.algebra.base.LogicalOperatorTag;
-import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable;
-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.functions.AlgebricksBuiltinFunctions;
-import org.apache.hyracks.algebricks.core.algebra.functions.IFunctionInfo;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractBinaryJoinOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.AggregateOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.AssignOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.DataSourceScanOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.GroupByOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.NestedTupleSourceOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.ProjectOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.SelectOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.SubplanOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.UnnestOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities;
-import org.apache.hyracks.algebricks.core.algebra.plan.ALogicalPlanImpl;
-import org.apache.hyracks.algebricks.core.algebra.properties.FunctionalDependency;
-import org.apache.hyracks.algebricks.core.algebra.util.OperatorManipulationUtil;
-import org.apache.hyracks.algebricks.core.algebra.util.OperatorPropertiesUtil;
-import org.apache.hyracks.algebricks.core.config.AlgebricksConfig;
-import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
-import org.apache.hyracks.algebricks.rewriter.util.PhysicalOptimizationsUtil;
-
-/**
- * The rule searches for SUBPLAN operator with a optional PROJECT operator and
- * an AGGREGATE followed by a join operator.
- *
- * <pre>
- * Before
- *
- * plan__parent
- * SUBPLAN {
- * PROJECT?
- * AGGREGATE
- * plan__nested_A
- * INNER_JOIN | LEFT_OUTER_JOIN ($condition, $left, $right)
- * plan__nested_B
- * }
- * plan__child
- *
- * where $condition does not equal a constant true.
- *
- * After (This is a general application of the rule, specifics may vary based on the query plan.)
- *
- * plan__parent
- * GROUP_BY {
- * PROJECT?
- * AGGREGATE
- * plan__nested_A
- * SELECT( algebricks:not( is_null( $right ) ) )
- * NESTED_TUPLE_SOURCE
- * }
- * SUBPLAN {
- * INNER_JOIN | LEFT_OUTER_JOIN ($condition, $left, $right)
- * plan__nested_B
- * }
- * plan__child
- * </pre>
- *
- * @author prestonc
- */
-
-public class IntroduceGroupByForSubplanRule 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 op0 = (AbstractLogicalOperator) opRef.getValue();
- if (op0.getOperatorTag() != LogicalOperatorTag.SUBPLAN) {
- return false;
- }
- SubplanOperator subplan = (SubplanOperator) op0;
-
- Iterator<ILogicalPlan> plansIter = subplan.getNestedPlans().iterator();
- ILogicalPlan p = null;
- while (plansIter.hasNext()) {
- p = plansIter.next();
- }
- if (p == null) {
- return false;
- }
- if (p.getRoots().size() != 1) {
- return false;
- }
- Mutable<ILogicalOperator> subplanRoot = p.getRoots().get(0);
- AbstractLogicalOperator op1 = (AbstractLogicalOperator) subplanRoot.getValue();
-
- Mutable<ILogicalOperator> botRef = subplanRoot;
- AbstractLogicalOperator op2;
- // Project is optional
- if (op1.getOperatorTag() != LogicalOperatorTag.PROJECT) {
- op2 = op1;
- } else {
- ProjectOperator project = (ProjectOperator) op1;
- botRef = project.getInputs().get(0);
- op2 = (AbstractLogicalOperator) botRef.getValue();
- }
- if (op2.getOperatorTag() != LogicalOperatorTag.AGGREGATE) {
- return false;
- }
- AggregateOperator aggregate = (AggregateOperator) op2;
-
- Set<LogicalVariable> free = new HashSet<LogicalVariable>();
- VariableUtilities.getUsedVariables(aggregate, free);
-
- Mutable<ILogicalOperator> op3Ref = aggregate.getInputs().get(0);
- AbstractLogicalOperator op3 = (AbstractLogicalOperator) op3Ref.getValue();
-
- while (op3.getInputs().size() == 1) {
- Set<LogicalVariable> prod = new HashSet<LogicalVariable>();
- VariableUtilities.getProducedVariables(op3, prod);
- free.removeAll(prod);
- VariableUtilities.getUsedVariables(op3, free);
- botRef = op3Ref;
- op3Ref = op3.getInputs().get(0);
- op3 = (AbstractLogicalOperator) op3Ref.getValue();
- }
-
- if (op3.getOperatorTag() != LogicalOperatorTag.INNERJOIN
- && op3.getOperatorTag() != LogicalOperatorTag.LEFTOUTERJOIN) {
- return false;
- }
- AbstractBinaryJoinOperator join = (AbstractBinaryJoinOperator) op3;
- if (join.getCondition().getValue() == ConstantExpression.TRUE) {
- return false;
- }
- VariableUtilities.getUsedVariables(join, free);
-
- AbstractLogicalOperator b0 = (AbstractLogicalOperator) join.getInputs().get(0).getValue();
- // see if there's an NTS at the end of the pipeline
- NestedTupleSourceOperator outerNts = getNts(b0);
- if (outerNts == null) {
- AbstractLogicalOperator b1 = (AbstractLogicalOperator) join.getInputs().get(1).getValue();
- outerNts = getNts(b1);
- if (outerNts == null) {
- return false;
- }
- }
-
- Set<LogicalVariable> pkVars = computeGbyVars(outerNts, free, context);
- if (pkVars == null || pkVars.size() < 1) {
- // there is no non-trivial primary key, group-by keys are all live variables
- ILogicalOperator subplanInput = subplan.getInputs().get(0).getValue();
- pkVars = new HashSet<LogicalVariable>();
- VariableUtilities.getLiveVariables(subplanInput, pkVars);
- }
- AlgebricksConfig.ALGEBRICKS_LOGGER.fine("Found FD for introducing group-by: " + pkVars);
-
- Mutable<ILogicalOperator> rightRef = join.getInputs().get(1);
- LogicalVariable testForNull = null;
- AbstractLogicalOperator right = (AbstractLogicalOperator) rightRef.getValue();
- switch (right.getOperatorTag()) {
- case UNNEST: {
- UnnestOperator innerUnnest = (UnnestOperator) right;
- // Select [ $y != null ]
- testForNull = innerUnnest.getVariable();
- break;
- }
- case RUNNINGAGGREGATE: {
- ILogicalOperator inputToRunningAggregate = right.getInputs().get(0).getValue();
- Set<LogicalVariable> producedVars = new ListSet<LogicalVariable>();
- VariableUtilities.getProducedVariables(inputToRunningAggregate, producedVars);
- if (!producedVars.isEmpty()) {
- // Select [ $y != null ]
- testForNull = producedVars.iterator().next();
- }
- break;
- }
- case DATASOURCESCAN: {
- DataSourceScanOperator innerScan = (DataSourceScanOperator) right;
- // Select [ $y != null ]
- if (innerScan.getVariables().size() == 1) {
- testForNull = innerScan.getVariables().get(0);
- }
- break;
- }
- }
- if (testForNull == null) {
- testForNull = context.newVar();
- AssignOperator tmpAsgn = new AssignOperator(testForNull, new MutableObject<ILogicalExpression>(
- ConstantExpression.TRUE));
- tmpAsgn.getInputs().add(new MutableObject<ILogicalOperator>(rightRef.getValue()));
- rightRef.setValue(tmpAsgn);
- context.computeAndSetTypeEnvironmentForOperator(tmpAsgn);
- }
-
- IFunctionInfo finfoEq = context.getMetadataProvider().lookupFunction(AlgebricksBuiltinFunctions.IS_NULL);
- ILogicalExpression isNullTest = new ScalarFunctionCallExpression(finfoEq,
- new MutableObject<ILogicalExpression>(new VariableReferenceExpression(testForNull)));
- IFunctionInfo finfoNot = context.getMetadataProvider().lookupFunction(AlgebricksBuiltinFunctions.NOT);
- ScalarFunctionCallExpression nonNullTest = new ScalarFunctionCallExpression(finfoNot,
- new MutableObject<ILogicalExpression>(isNullTest));
- SelectOperator selectNonNull = new SelectOperator(new MutableObject<ILogicalExpression>(nonNullTest), false,
- null);
- GroupByOperator g = new GroupByOperator();
- Mutable<ILogicalOperator> newSubplanRef = new MutableObject<ILogicalOperator>(subplan);
- NestedTupleSourceOperator nts = new NestedTupleSourceOperator(new MutableObject<ILogicalOperator>(g));
- opRef.setValue(g);
- selectNonNull.getInputs().add(new MutableObject<ILogicalOperator>(nts));
-
- List<Mutable<ILogicalOperator>> prodInpList = botRef.getValue().getInputs();
- prodInpList.clear();
- prodInpList.add(new MutableObject<ILogicalOperator>(selectNonNull));
-
- ILogicalPlan gPlan = new ALogicalPlanImpl(new MutableObject<ILogicalOperator>(subplanRoot.getValue()));
- g.getNestedPlans().add(gPlan);
- subplanRoot.setValue(op3Ref.getValue());
- g.getInputs().add(newSubplanRef);
-
- HashSet<LogicalVariable> underVars = new HashSet<LogicalVariable>();
- VariableUtilities.getLiveVariables(subplan.getInputs().get(0).getValue(), underVars);
- underVars.removeAll(pkVars);
- Map<LogicalVariable, LogicalVariable> mappedVars = buildVarExprList(pkVars, context, g, g.getGroupByList());
- context.updatePrimaryKeys(mappedVars);
- for (LogicalVariable uv : underVars) {
- g.getDecorList().add(
- new Pair<LogicalVariable, Mutable<ILogicalExpression>>(null, new MutableObject<ILogicalExpression>(
- new VariableReferenceExpression(uv))));
- }
- OperatorPropertiesUtil.typeOpRec(subplanRoot, context);
- OperatorPropertiesUtil.typeOpRec(gPlan.getRoots().get(0), context);
- context.computeAndSetTypeEnvironmentForOperator(g);
- return true;
- }
-
- private NestedTupleSourceOperator getNts(AbstractLogicalOperator op) {
- AbstractLogicalOperator alo = op;
- do {
- if (alo.getOperatorTag() == LogicalOperatorTag.NESTEDTUPLESOURCE) {
- return (NestedTupleSourceOperator) alo;
- }
- if (alo.getInputs().size() != 1) {
- return null;
- }
- alo = (AbstractLogicalOperator) alo.getInputs().get(0).getValue();
- } while (true);
- }
-
- protected Set<LogicalVariable> computeGbyVars(AbstractLogicalOperator op, Set<LogicalVariable> freeVars,
- IOptimizationContext context) throws AlgebricksException {
- PhysicalOptimizationsUtil.computeFDsAndEquivalenceClasses(op, context);
- List<FunctionalDependency> fdList = context.getFDList(op);
- if (fdList == null) {
- return null;
- }
- // check if any of the FDs is a key
- List<LogicalVariable> all = new ArrayList<LogicalVariable>();
- VariableUtilities.getLiveVariables(op, all);
- all.retainAll(freeVars);
- for (FunctionalDependency fd : fdList) {
- if (fd.getTail().containsAll(all)) {
- return new HashSet<LogicalVariable>(fd.getHead());
- }
- }
- return null;
- }
-
- private Map<LogicalVariable, LogicalVariable> buildVarExprList(Collection<LogicalVariable> vars,
- IOptimizationContext context, GroupByOperator g,
- List<Pair<LogicalVariable, Mutable<ILogicalExpression>>> outVeList) throws AlgebricksException {
- Map<LogicalVariable, LogicalVariable> m = new HashMap<LogicalVariable, LogicalVariable>();
- for (LogicalVariable ov : vars) {
- LogicalVariable newVar = context.newVar();
- ILogicalExpression varExpr = new VariableReferenceExpression(newVar);
- outVeList.add(new Pair<LogicalVariable, Mutable<ILogicalExpression>>(ov,
- new MutableObject<ILogicalExpression>(varExpr)));
- for (ILogicalPlan p : g.getNestedPlans()) {
- for (Mutable<ILogicalOperator> r : p.getRoots()) {
- OperatorManipulationUtil.substituteVarRec((AbstractLogicalOperator) r.getValue(), ov, newVar, true,
- context);
- }
- }
- AbstractLogicalOperator opUnder = (AbstractLogicalOperator) g.getInputs().get(0).getValue();
- OperatorManipulationUtil.substituteVarRec(opUnder, ov, newVar, true, context);
- m.put(ov, newVar);
- }
- return m;
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/MoveFreeVariableOperatorOutOfSubplanRule.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/MoveFreeVariableOperatorOutOfSubplanRule.java b/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/MoveFreeVariableOperatorOutOfSubplanRule.java
deleted file mode 100644
index 06063b8..0000000
--- a/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/MoveFreeVariableOperatorOutOfSubplanRule.java
+++ /dev/null
@@ -1,186 +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.HashSet;
-import java.util.ListIterator;
-import java.util.Set;
-
-import org.apache.commons.lang3.mutable.Mutable;
-
-import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
-import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
-import org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan;
-import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
-import org.apache.hyracks.algebricks.core.algebra.base.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.SubplanOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities;
-import org.apache.hyracks.algebricks.core.algebra.util.OperatorPropertiesUtil;
-
-/**
- * The rule searches for operators that can be moved outside the subplan.
- *
- * <pre>
- * Before
- *
- * %PARENT_PLAN
- * SUBPLAN{
- * %NESTED_OPERATORS_B+
- * ASSIGN || %SUBPLAN
- * %NESTED_OPERATORS_A*
- * NESTEDTUPLESOURCE
- * }
- * %CHILD_PLAN
- *
- * where
- * %SUBPLAN has one nested plan with a root AGGREGATE operator.
- *
- * After
- *
- * %PARENT_PLAN
- * SUBPLAN{
- * %NESTED_OPERATORS_B+
- * %NESTED_OPERATORS_A*
- * NESTEDTUPLESOURCE
- * }
- * ASSIGN || %SUBPLAN
- * %CHILD_PLAN
- * </pre>
- */
-public class MoveFreeVariableOperatorOutOfSubplanRule extends AbstractDecorrelationRule {
-
- @Override
- public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
- throws AlgebricksException {
- AbstractLogicalOperator op0 = (AbstractLogicalOperator) opRef.getValue();
- if (op0.getOperatorTag() != LogicalOperatorTag.SUBPLAN) {
- return false;
- }
- SubplanOperator subplan = (SubplanOperator) op0;
-
- Mutable<ILogicalOperator> leftRef = subplan.getInputs().get(0);
- if (((AbstractLogicalOperator) leftRef.getValue()).getOperatorTag() == LogicalOperatorTag.EMPTYTUPLESOURCE) {
- return false;
- }
-
- ListIterator<ILogicalPlan> plansIter = subplan.getNestedPlans().listIterator();
- ILogicalPlan p = null;
- while (plansIter.hasNext()) {
- p = plansIter.next();
- }
- if (p == null) {
- return false;
- }
- if (p.getRoots().size() != 1) {
- return false;
- }
- Mutable<ILogicalOperator> opRef1 = p.getRoots().get(0);
-
- //The root operator will not be movable. Start with the second op
- AbstractLogicalOperator op1 = (AbstractLogicalOperator) opRef1.getValue();
- if (op1.getInputs().size() != 1) {
- return false;
- }
- Mutable<ILogicalOperator> op2Ref = op1.getInputs().get(0);
-
- //Get all variables that come from outside of the loop
- Set<LogicalVariable> free = new HashSet<LogicalVariable>();
- OperatorPropertiesUtil.getFreeVariablesInSelfOrDesc(op1, free);
-
- while (op2Ref != null) {
- //Get the operator that we want to look at
- AbstractLogicalOperator op2 = (AbstractLogicalOperator) op2Ref.getValue();
-
- //Make sure we are looking at subplan with a scan/join
- if (op2.getInputs().size() != 1 || !descOrSelfIsScanOrJoin(op2)) {
- return false;
- }
- boolean notApplicable = false;
-
- //Get its used variables
- Set<LogicalVariable> used = new HashSet<LogicalVariable>();
-
- //not movable if the operator is not an assign or subplan
- //Might be helpful in the future for other operations in the future
- if (movableOperator(op2.getOperatorTag())) {
- if (op2.getOperatorTag() == LogicalOperatorTag.ASSIGN) {
- VariableUtilities.getUsedVariables(op2, used);
- } else if (op2.getOperatorTag() == LogicalOperatorTag.SUBPLAN) {
- // Nested plan must have an aggregate root.
- ListIterator<ILogicalPlan> subplansIter = ((SubplanOperator) op2).getNestedPlans().listIterator();
- ILogicalPlan plan = null;
- while (subplansIter.hasNext()) {
- plan = subplansIter.next();
- }
- if (plan == null) {
- return false;
- }
- if (plan.getRoots().size() != 1) {
- return false;
- }
- ILogicalOperator op3 = plan.getRoots().get(0).getValue();
- if (op3.getOperatorTag() != LogicalOperatorTag.AGGREGATE) {
- return false;
- }
- // Used variables do not include ones created in the subplan.
- VariableUtilities.getUsedVariables(op2, used);
- Set<LogicalVariable> subplanProducedAndDown = new HashSet<LogicalVariable>();
- VariableUtilities.getProducedVariablesInDescendantsAndSelf(op3, subplanProducedAndDown);
- used.removeAll(subplanProducedAndDown);
- } else {
- notApplicable = true;
- }
- } else {
- notApplicable = true;
- }
-
- //Make sure that all of its used variables come from outside
- for (LogicalVariable var : used) {
- if (!free.contains(var)) {
- notApplicable = true;
- }
- }
-
- if (notApplicable) {
- op2Ref = op2.getInputs().get(0);
- } else {
- //Make the input of op2 be the input of op1
- op2Ref.setValue(op2.getInputs().get(0).getValue());
-
- //Make the outside of the subplan the input of op2
- Mutable<ILogicalOperator> outsideRef = op2.getInputs().get(0);
- outsideRef.setValue(op0.getInputs().get(0).getValue());
-
- //Make op2 the input of the subplan
- Mutable<ILogicalOperator> op2OutsideRef = op0.getInputs().get(0);
- op2OutsideRef.setValue(op2);
-
- return true;
- }
-
- }
- return false;
- }
-
- protected boolean movableOperator(LogicalOperatorTag operatorTag) {
- return (operatorTag == LogicalOperatorTag.ASSIGN || operatorTag == LogicalOperatorTag.SUBPLAN);
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/NestedSubplanToJoinRule.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/NestedSubplanToJoinRule.java b/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/NestedSubplanToJoinRule.java
deleted file mode 100644
index f8a93b0..0000000
--- a/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/NestedSubplanToJoinRule.java
+++ /dev/null
@@ -1,146 +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.core.algebra.base.ILogicalExpression;
-import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
-import org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan;
-import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
-import org.apache.hyracks.algebricks.core.algebra.base.LogicalOperatorTag;
-import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable;
-import org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractOperatorWithNestedPlans;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.EmptyTupleSourceOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.InnerJoinOperator;
-import org.apache.hyracks.algebricks.core.algebra.util.OperatorPropertiesUtil;
-import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
-
-/**
- * replace Subplan operators with nested loop joins where the join condition is true, if the Subplan
- * does not contain free variables (does not have correlations to the input stream).
- *
- * @author yingyib
- */
-public class NestedSubplanToJoinRule 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 {
- if (context.checkIfInDontApplySet(this, opRef.getValue()))
- return false;
- context.addToDontApplySet(this, opRef.getValue());
-
- ILogicalOperator op1 = opRef.getValue();
- if (op1.getInputs().size() == 0) {
- return false;
- }
-
- boolean rewritten = false;
- for (int index = 0; index < op1.getInputs().size(); index++) {
- AbstractLogicalOperator child = (AbstractLogicalOperator) op1.getInputs().get(index).getValue();
- if (child.getOperatorTag() != LogicalOperatorTag.SUBPLAN) {
- continue;
- }
-
- AbstractOperatorWithNestedPlans subplan = (AbstractOperatorWithNestedPlans) child;
- Set<LogicalVariable> freeVars = new HashSet<LogicalVariable>();
- OperatorPropertiesUtil.getFreeVariablesInSubplans(subplan, freeVars);
- if (!freeVars.isEmpty()) {
- /**
- * the subplan is correlated with the outer plan, other rules can deal with it
- */
- continue;
- }
-
- /** get the input operator of the subplan operator */
- ILogicalOperator subplanInput = subplan.getInputs().get(0).getValue();
- AbstractLogicalOperator subplanInputOp = (AbstractLogicalOperator) subplanInput;
-
- /** If the other join branch is a trivial plan, do not do the rewriting. */
- if (subplanInputOp.getOperatorTag() == LogicalOperatorTag.EMPTYTUPLESOURCE) {
- continue;
- }
-
- /** get all nested top operators */
- List<ILogicalPlan> nestedPlans = subplan.getNestedPlans();
- List<Mutable<ILogicalOperator>> nestedRoots = new ArrayList<Mutable<ILogicalOperator>>();
- for (ILogicalPlan nestedPlan : nestedPlans) {
- nestedRoots.addAll(nestedPlan.getRoots());
- }
- if (nestedRoots.size() == 0) {
- /** there is no nested top operators */
- continue;
- }
-
- /**
- * Expends the input and roots into a DAG of nested loop joins.
- * Though joins should be left-outer joins, a left-outer join with condition TRUE is equivalent to an inner join.
- **/
- Mutable<ILogicalExpression> expr = new MutableObject<ILogicalExpression>(ConstantExpression.TRUE);
- Mutable<ILogicalOperator> nestedRootRef = nestedRoots.get(0);
- ILogicalOperator join = new InnerJoinOperator(expr, new MutableObject<ILogicalOperator>(subplanInput),
- nestedRootRef);
-
- /** rewrite the nested tuple source to be empty tuple source */
- rewriteNestedTupleSource(nestedRootRef, context);
-
- for (int i = 1; i < nestedRoots.size(); i++) {
- join = new InnerJoinOperator(expr, new MutableObject<ILogicalOperator>(join), nestedRoots.get(i));
- }
- op1.getInputs().get(index).setValue(join);
- context.computeAndSetTypeEnvironmentForOperator(join);
- rewritten = true;
- }
- return rewritten;
- }
-
- /**
- * rewrite NestedTupleSource operators to EmptyTupleSource operators
- *
- * @param nestedRootRef
- */
- private void rewriteNestedTupleSource(Mutable<ILogicalOperator> nestedRootRef, IOptimizationContext context)
- throws AlgebricksException {
- AbstractLogicalOperator nestedRoot = (AbstractLogicalOperator) nestedRootRef.getValue();
- if (nestedRoot.getOperatorTag() == LogicalOperatorTag.NESTEDTUPLESOURCE) {
- ILogicalOperator ets = new EmptyTupleSourceOperator();
- nestedRootRef.setValue(ets);
- context.computeAndSetTypeEnvironmentForOperator(ets);
- }
- List<Mutable<ILogicalOperator>> inputs = nestedRoot.getInputs();
- for (Mutable<ILogicalOperator> input : inputs) {
- rewriteNestedTupleSource(input, context);
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb-hyracks/blob/7dd47992/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/PushSelectIntoJoinRule.java
----------------------------------------------------------------------
diff --git a/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/PushSelectIntoJoinRule.java b/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/PushSelectIntoJoinRule.java
index d6f1889..12e5ebe 100644
--- a/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/PushSelectIntoJoinRule.java
+++ b/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/PushSelectIntoJoinRule.java
@@ -28,7 +28,6 @@ import java.util.ListIterator;
import org.apache.commons.lang3.mutable.Mutable;
import org.apache.commons.lang3.mutable.MutableObject;
-
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
@@ -64,6 +63,7 @@ public class PushSelectIntoJoinRule implements IAlgebraicRewriteRule {
List<ILogicalOperator> pushedOnLeft = new ArrayList<ILogicalOperator>();
List<ILogicalOperator> pushedOnRight = new ArrayList<ILogicalOperator>();
+ List<ILogicalOperator> pushedOnEither = new ArrayList<ILogicalOperator>();
LinkedList<ILogicalOperator> notPushedStack = new LinkedList<ILogicalOperator>();
Collection<LogicalVariable> usedVars = new HashSet<LogicalVariable>();
Collection<LogicalVariable> producedVars = new HashSet<LogicalVariable>();
@@ -107,7 +107,9 @@ public class PushSelectIntoJoinRule implements IAlgebraicRewriteRule {
} else {
VariableUtilities.getUsedVariables(opIter, usedVars);
VariableUtilities.getProducedVariables(opIter, producedVars);
- if (joinLiveVarsLeft.containsAll(usedVars)) {
+ if (usedVars.size() == 0) {
+ pushedOnEither.add(opIter);
+ } else if (joinLiveVarsLeft.containsAll(usedVars)) {
pushedOnLeft.add(opIter);
liveInOpsToPushLeft.addAll(producedVars);
} else if (joinLiveVarsRight.containsAll(usedVars)) {
@@ -149,6 +151,12 @@ public class PushSelectIntoJoinRule implements IAlgebraicRewriteRule {
return false;
}
if (needToPushOps) {
+ //We should push independent ops into the first branch that the selection depends on
+ if (intersectsBranch[0]) {
+ pushOps(pushedOnEither, joinBranchLeftRef, context);
+ } else {
+ pushOps(pushedOnEither, joinBranchRightRef, context);
+ }
pushOps(pushedOnLeft, joinBranchLeftRef, context);
pushOps(pushedOnRight, joinBranchRightRef, context);
}
@@ -226,8 +234,8 @@ public class PushSelectIntoJoinRule implements IAlgebraicRewriteRule {
if (cond.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
AbstractFunctionCallExpression fcond = (AbstractFunctionCallExpression) cond;
if (fcond.getFunctionIdentifier().equals(AlgebricksBuiltinFunctions.AND)) {
- AbstractFunctionCallExpression newCond = new ScalarFunctionCallExpression(context
- .getMetadataProvider().lookupFunction(AlgebricksBuiltinFunctions.AND));
+ AbstractFunctionCallExpression newCond = new ScalarFunctionCallExpression(
+ context.getMetadataProvider().lookupFunction(AlgebricksBuiltinFunctions.AND));
newCond.getArguments().add(select.getCondition());
newCond.getArguments().addAll(fcond.getArguments());
join.getCondition().setValue(newCond);
@@ -235,9 +243,9 @@ public class PushSelectIntoJoinRule implements IAlgebraicRewriteRule {
}
}
if (!bAddedToConj) {
- AbstractFunctionCallExpression newCond = new ScalarFunctionCallExpression(context.getMetadataProvider()
- .lookupFunction(AlgebricksBuiltinFunctions.AND), select.getCondition(),
- new MutableObject<ILogicalExpression>(join.getCondition().getValue()));
+ AbstractFunctionCallExpression newCond = new ScalarFunctionCallExpression(
+ context.getMetadataProvider().lookupFunction(AlgebricksBuiltinFunctions.AND),
+ select.getCondition(), new MutableObject<ILogicalExpression>(join.getCondition().getValue()));
join.getCondition().setValue(newCond);
}
}
@@ -255,7 +263,7 @@ public class PushSelectIntoJoinRule implements IAlgebraicRewriteRule {
/**
* Whether the expression contains a not-null filtering
- *
+ *
* @param expr
* @return true if the expression contains a not-null filtering function call; false otherwise.
*/
@@ -288,7 +296,7 @@ public class PushSelectIntoJoinRule implements IAlgebraicRewriteRule {
/**
* Whether the expression contains a null filtering
- *
+ *
* @param expr
* @return true if the expression contains a null filtering function call; false otherwise.
*/