You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2014/08/17 02:22:27 UTC
[4/4] git commit: [OPTIQ-343] RelDecorrelator should build its own
mappings, not inherit from SqlToRelConverter
[OPTIQ-343] RelDecorrelator should build its own mappings, not inherit from SqlToRelConverter
Factor out CorrelatorRel.Correlation as a top-level class.
Add SqlExplainLevel.NON_COST_ATTRIBUTES, which includes "id".
Add RelShuttle.visit(CorrelatorRel).
Project: http://git-wip-us.apache.org/repos/asf/incubator-optiq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-optiq/commit/3055cc32
Tree: http://git-wip-us.apache.org/repos/asf/incubator-optiq/tree/3055cc32
Diff: http://git-wip-us.apache.org/repos/asf/incubator-optiq/diff/3055cc32
Branch: refs/heads/master
Commit: 3055cc32fe752069e0ed45fff0d46081514a2d69
Parents: 0ad346f
Author: Julian Hyde <jh...@apache.org>
Authored: Fri Aug 15 13:42:32 2014 -0700
Committer: Julian Hyde <ju...@gmail.com>
Committed: Sat Aug 16 17:05:23 2014 -0700
----------------------------------------------------------------------
.../optiq/prepare/OptiqMaterializer.java | 3 +
.../java/org/eigenbase/rel/Correlation.java | 76 +++
.../java/org/eigenbase/rel/CorrelatorRel.java | 53 +-
.../main/java/org/eigenbase/rel/RelJson.java | 6 +-
.../main/java/org/eigenbase/rel/RelShuttle.java | 2 +
.../java/org/eigenbase/rel/RelShuttleImpl.java | 4 +
.../java/org/eigenbase/rel/RelWriterImpl.java | 8 +-
.../rel/rules/NestedLoopsJoinRule.java | 8 +-
.../rel/rules/PushFilterPastJoinRule.java | 61 +-
.../org/eigenbase/relopt/hep/HepRelVertex.java | 4 +
.../java/org/eigenbase/sql/SqlExplainLevel.java | 5 +
.../org/eigenbase/sql2rel/RelDecorrelator.java | 575 ++++++++++++-------
.../sql2rel/RelStructuredTypeFlattener.java | 31 +-
.../eigenbase/sql2rel/SqlToRelConverter.java | 162 +-----
.../net/hydromatic/optiq/test/OptiqAssert.java | 18 +-
.../test/resources/mysql-foodmart-model.json | 15 +
.../hydromatic/optiq/impl/tpch/TpchTest.java | 53 +-
17 files changed, 593 insertions(+), 491 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/3055cc32/core/src/main/java/net/hydromatic/optiq/prepare/OptiqMaterializer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/prepare/OptiqMaterializer.java b/core/src/main/java/net/hydromatic/optiq/prepare/OptiqMaterializer.java
index c00f307..ae57392 100644
--- a/core/src/main/java/net/hydromatic/optiq/prepare/OptiqMaterializer.java
+++ b/core/src/main/java/net/hydromatic/optiq/prepare/OptiqMaterializer.java
@@ -146,6 +146,9 @@ class OptiqMaterializer extends OptiqPrepareImpl.OptiqPreparingStmt {
public RelNode visit(JoinRel join) {
return join;
}
+ public RelNode visit(CorrelatorRel correlator) {
+ return correlator;
+ }
public RelNode visit(UnionRel union) {
return union;
}
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/3055cc32/core/src/main/java/org/eigenbase/rel/Correlation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/Correlation.java b/core/src/main/java/org/eigenbase/rel/Correlation.java
new file mode 100644
index 0000000..fef30ee
--- /dev/null
+++ b/core/src/main/java/org/eigenbase/rel/Correlation.java
@@ -0,0 +1,76 @@
+/*
+// 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.eigenbase.rel;
+
+/**
+ * Describes the necessary parameters for an implementation in order to
+ * identify and set dynamic variables
+ */
+public class Correlation implements Cloneable, Comparable<Correlation> {
+ private final int id;
+ private final int offset;
+
+ /**
+ * Creates a correlation.
+ *
+ * @param id Identifier
+ * @param offset Offset
+ */
+ public Correlation(int id, int offset) {
+ this.id = id;
+ this.offset = offset;
+ }
+
+ /**
+ * Returns the identifier.
+ *
+ * @return identifier
+ */
+ public int getId() {
+ return id;
+ }
+
+ /**
+ * Returns this correlation's offset.
+ *
+ * @return offset
+ */
+ public int getOffset() {
+ return offset;
+ }
+
+ public String toString() {
+ return "var" + id + "=offset" + offset;
+ }
+
+ public int compareTo(Correlation other) {
+ return id - other.id;
+ }
+
+ @Override public int hashCode() {
+ return id;
+ }
+
+ @Override public boolean equals(Object obj) {
+ return this == obj
+ || obj instanceof Correlation
+ && this.id == ((Correlation) obj).id
+ && this.offset == ((Correlation) obj).offset;
+ }
+}
+
+// End Correlation.java
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/3055cc32/core/src/main/java/org/eigenbase/rel/CorrelatorRel.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/CorrelatorRel.java b/core/src/main/java/org/eigenbase/rel/CorrelatorRel.java
index cd25cf1..df9b2e3 100644
--- a/core/src/main/java/org/eigenbase/rel/CorrelatorRel.java
+++ b/core/src/main/java/org/eigenbase/rel/CorrelatorRel.java
@@ -133,6 +133,10 @@ public final class CorrelatorRel extends JoinRelBase {
this.joinType);
}
+ @Override public RelNode accept(RelShuttle shuttle) {
+ return shuttle.visit(this);
+ }
+
public RelWriter explainTerms(RelWriter pw) {
return super.explainTerms(pw)
.item("correlations", correlations);
@@ -146,55 +150,6 @@ public final class CorrelatorRel extends JoinRelBase {
public List<Correlation> getCorrelations() {
return correlations;
}
-
- //~ Inner Classes ----------------------------------------------------------
-
- /**
- * Describes the neccessary parameters for an implementation in order to
- * identify and set dynamic variables
- */
- public static class Correlation
- implements Cloneable, Comparable<Correlation> {
- private final int id;
- private final int offset;
-
- /**
- * Creates a correlation.
- *
- * @param id Identifier
- * @param offset Offset
- */
- public Correlation(int id, int offset) {
- this.id = id;
- this.offset = offset;
- }
-
- /**
- * Returns the identifier.
- *
- * @return identifier
- */
- public int getId() {
- return id;
- }
-
- /**
- * Returns this correlation's offset.
- *
- * @return offset
- */
- public int getOffset() {
- return offset;
- }
-
- public String toString() {
- return "var" + id + "=offset" + offset;
- }
-
- public int compareTo(Correlation other) {
- return id - other.id;
- }
- }
}
// End CorrelatorRel.java
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/3055cc32/core/src/main/java/org/eigenbase/rel/RelJson.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/RelJson.java b/core/src/main/java/org/eigenbase/rel/RelJson.java
index 740dcee..6305270 100644
--- a/core/src/main/java/org/eigenbase/rel/RelJson.java
+++ b/core/src/main/java/org/eigenbase/rel/RelJson.java
@@ -205,8 +205,8 @@ public class RelJson {
return value;
} else if (value instanceof RexNode) {
return toJson((RexNode) value);
- } else if (value instanceof CorrelatorRel.Correlation) {
- return toJson((CorrelatorRel.Correlation) value);
+ } else if (value instanceof Correlation) {
+ return toJson((Correlation) value);
} else if (value instanceof List) {
final List<Object> list = jsonBuilder.list();
for (Object o : (List) value) {
@@ -261,7 +261,7 @@ public class RelJson {
return map;
}
- private Object toJson(CorrelatorRel.Correlation node) {
+ private Object toJson(Correlation node) {
final Map<String, Object> map = jsonBuilder.map();
map.put("correlation", node.getId());
map.put("offset", node.getOffset());
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/3055cc32/core/src/main/java/org/eigenbase/rel/RelShuttle.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/RelShuttle.java b/core/src/main/java/org/eigenbase/rel/RelShuttle.java
index e505ced..7f0b76f 100644
--- a/core/src/main/java/org/eigenbase/rel/RelShuttle.java
+++ b/core/src/main/java/org/eigenbase/rel/RelShuttle.java
@@ -32,6 +32,8 @@ public interface RelShuttle {
RelNode visit(JoinRel join);
+ RelNode visit(CorrelatorRel correlator);
+
RelNode visit(UnionRel union);
RelNode visit(IntersectRel intersect);
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/3055cc32/core/src/main/java/org/eigenbase/rel/RelShuttleImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/RelShuttleImpl.java b/core/src/main/java/org/eigenbase/rel/RelShuttleImpl.java
index c5c06ef..2bba485 100644
--- a/core/src/main/java/org/eigenbase/rel/RelShuttleImpl.java
+++ b/core/src/main/java/org/eigenbase/rel/RelShuttleImpl.java
@@ -86,6 +86,10 @@ public class RelShuttleImpl implements RelShuttle {
return visitChildren(join);
}
+ public RelNode visit(CorrelatorRel correlator) {
+ return visitChildren(correlator);
+ }
+
public RelNode visit(UnionRel union) {
return visitChildren(union);
}
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/3055cc32/core/src/main/java/org/eigenbase/rel/RelWriterImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/RelWriterImpl.java b/core/src/main/java/org/eigenbase/rel/RelWriterImpl.java
index 178f64c..4816f40 100644
--- a/core/src/main/java/org/eigenbase/rel/RelWriterImpl.java
+++ b/core/src/main/java/org/eigenbase/rel/RelWriterImpl.java
@@ -98,16 +98,22 @@ public class RelWriterImpl implements RelWriter {
s.append(")");
}
}
- if (detailLevel == SqlExplainLevel.ALL_ATTRIBUTES) {
+ switch (detailLevel) {
+ case ALL_ATTRIBUTES:
s.append(": rowcount = ")
.append(RelMetadataQuery.getRowCount(rel))
.append(", cumulative cost = ")
.append(RelMetadataQuery.getCumulativeCost(rel));
+ }
+ switch (detailLevel) {
+ case NON_COST_ATTRIBUTES:
+ case ALL_ATTRIBUTES:
if (!withIdPrefix) {
// If we didn't print the rel id at the start of the line, print
// it at the end.
s.append(", id = ").append(rel.getId());
}
+ break;
}
pw.println(s);
spacer.add(2);
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/3055cc32/core/src/main/java/org/eigenbase/rel/rules/NestedLoopsJoinRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/rules/NestedLoopsJoinRule.java b/core/src/main/java/org/eigenbase/rel/rules/NestedLoopsJoinRule.java
index 9f1cd39..e31f427 100644
--- a/core/src/main/java/org/eigenbase/rel/rules/NestedLoopsJoinRule.java
+++ b/core/src/main/java/org/eigenbase/rel/rules/NestedLoopsJoinRule.java
@@ -25,6 +25,8 @@ import org.eigenbase.sql.fun.*;
import org.eigenbase.util.*;
import org.eigenbase.util.mapping.IntPair;
+import com.google.common.collect.Lists;
+
/**
* Rule which converts a {@link JoinRel} into a {@link CorrelatorRel}, which can
* then be implemented using nested loops.
@@ -83,8 +85,7 @@ public class NestedLoopsJoinRule extends RelOptRule {
RelNode right = join.getRight();
final RelNode left = join.getLeft();
final JoinInfo joinInfo = join.analyzeCondition();
- final List<CorrelatorRel.Correlation> correlationList =
- new ArrayList<CorrelatorRel.Correlation>();
+ final List<Correlation> correlationList = Lists.newArrayList();
if (joinInfo.leftKeys.size() > 0) {
final RelOptCluster cluster = join.getCluster();
final RexBuilder rexBuilder = cluster.getRexBuilder();
@@ -95,8 +96,7 @@ public class NestedLoopsJoinRule extends RelOptRule {
// Create correlation to say 'each row, set variable #id
// to the value of column #leftKey'.
- correlationList.add(
- new CorrelatorRel.Correlation(dynInId, p.source));
+ correlationList.add(new Correlation(dynInId, p.source));
condition =
RelOptUtil.andJoinFilters(
rexBuilder,
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/3055cc32/core/src/main/java/org/eigenbase/rel/rules/PushFilterPastJoinRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/rules/PushFilterPastJoinRule.java b/core/src/main/java/org/eigenbase/rel/rules/PushFilterPastJoinRule.java
index c1a19bd..7ecbd5b 100644
--- a/core/src/main/java/org/eigenbase/rel/rules/PushFilterPastJoinRule.java
+++ b/core/src/main/java/org/eigenbase/rel/rules/PushFilterPastJoinRule.java
@@ -21,7 +21,6 @@ import java.util.*;
import org.eigenbase.rel.*;
import org.eigenbase.relopt.*;
import org.eigenbase.rex.*;
-import org.eigenbase.util.Bug;
import org.eigenbase.util.Holder;
import com.google.common.collect.ImmutableList;
@@ -71,22 +70,12 @@ public abstract class PushFilterPastJoinRule extends RelOptRule {
final List<RexNode> joinFilters =
RelOptUtil.conjunctions(join.getCondition());
- if (filter == null) {
- // There is only the joinRel
- // make sure it does not match a cartesian product joinRel
- // (with "true" condition) otherwise this rule will be applied
- // again on the new cartesian product joinRel.
- boolean onlyTrueFilter = true;
- for (RexNode joinFilter : joinFilters) {
- if (!joinFilter.isAlwaysTrue()) {
- onlyTrueFilter = false;
- break;
- }
- }
-
- if (onlyTrueFilter) {
- return;
- }
+ // If there is only the joinRel,
+ // make sure it does not match a cartesian product joinRel
+ // (with "true" condition), otherwise this rule will be applied
+ // again on the new cartesian product joinRel.
+ if (filter == null && joinFilters.isEmpty()) {
+ return;
}
final List<RexNode> aboveFilters =
@@ -145,6 +134,14 @@ public abstract class PushFilterPastJoinRule extends RelOptRule {
return;
}
+ // if nothing actually got pushed and there is nothing leftover,
+ // then this rule is a no-op
+ if (joinFilters.isEmpty()
+ && leftFilters.isEmpty()
+ && rightFilters.isEmpty()) {
+ return;
+ }
+
// create FilterRels on top of the children if any filters were
// pushed to them
final RexBuilder rexBuilder = join.getCluster().getRexBuilder();
@@ -161,21 +158,18 @@ public abstract class PushFilterPastJoinRule extends RelOptRule {
// create the new join node referencing the new children and
// containing its new join filters (if there are any)
- RexNode joinFilter;
-
- if (joinFilters.size() == 0) {
- // if nothing actually got pushed and there is nothing leftover,
- // then this rule is a no-op
- if (leftFilters.isEmpty()
- && rightFilters.isEmpty()
- && joinTypeHolder.get() == join.getJoinType()) {
- return;
- }
- joinFilter = rexBuilder.makeLiteral(true);
- } else {
- joinFilter =
- RexUtil.composeConjunction(rexBuilder, joinFilters, true);
+ final RexNode joinFilter =
+ RexUtil.composeConjunction(rexBuilder, joinFilters, false);
+
+ // If nothing actually got pushed and there is nothing leftover,
+ // then this rule is a no-op
+ if (joinFilter.isAlwaysTrue()
+ && leftFilters.isEmpty()
+ && rightFilters.isEmpty()
+ && joinTypeHolder.get() == join.getJoinType()) {
+ return;
}
+
RelNode newJoinRel =
join.copy(
join.getCluster().traitSetOf(Convention.NONE),
@@ -185,11 +179,6 @@ public abstract class PushFilterPastJoinRule extends RelOptRule {
joinTypeHolder.get(),
join.isSemiJoinDone());
call.getPlanner().onCopy(join, newJoinRel);
-
- // The pushed filters are not exact copies of the original filter, but
- // telling the planner about them seems to help the RelDecorrelator more
- // often than not. The real solution is to fix OPTIQ-443.
- Bug.upgrade("OPTIQ-443");
if (!leftFilters.isEmpty()) {
call.getPlanner().onCopy(filter, leftRel);
}
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/3055cc32/core/src/main/java/org/eigenbase/relopt/hep/HepRelVertex.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/relopt/hep/HepRelVertex.java b/core/src/main/java/org/eigenbase/relopt/hep/HepRelVertex.java
index 61053c8..dc44875 100644
--- a/core/src/main/java/org/eigenbase/relopt/hep/HepRelVertex.java
+++ b/core/src/main/java/org/eigenbase/relopt/hep/HepRelVertex.java
@@ -48,6 +48,10 @@ public class HepRelVertex extends AbstractRelNode {
//~ Methods ----------------------------------------------------------------
+ @Override public void explain(RelWriter pw) {
+ currentRel.explain(pw);
+ }
+
@Override
public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) {
assert traitSet.equals(this.traitSet);
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/3055cc32/core/src/main/java/org/eigenbase/sql/SqlExplainLevel.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/sql/SqlExplainLevel.java b/core/src/main/java/org/eigenbase/sql/SqlExplainLevel.java
index d75a2ee..c50b5aa 100644
--- a/core/src/main/java/org/eigenbase/sql/SqlExplainLevel.java
+++ b/core/src/main/java/org/eigenbase/sql/SqlExplainLevel.java
@@ -38,6 +38,11 @@ public enum SqlExplainLevel implements SqlLiteral.SqlSymbol {
DIGEST_ATTRIBUTES,
/**
+ * Display all attributes, including id, except cost.
+ */
+ NON_COST_ATTRIBUTES,
+
+ /**
* Display all attributes, including cost.
*/
ALL_ATTRIBUTES;
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/3055cc32/core/src/main/java/org/eigenbase/sql2rel/RelDecorrelator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/sql2rel/RelDecorrelator.java b/core/src/main/java/org/eigenbase/sql2rel/RelDecorrelator.java
index 6d9a853..c47b760 100644
--- a/core/src/main/java/org/eigenbase/sql2rel/RelDecorrelator.java
+++ b/core/src/main/java/org/eigenbase/sql2rel/RelDecorrelator.java
@@ -21,7 +21,7 @@ import java.util.*;
import java.util.logging.*;
import org.eigenbase.rel.*;
-import org.eigenbase.rel.CorrelatorRel.Correlation;
+import org.eigenbase.rel.Correlation;
import org.eigenbase.rel.metadata.*;
import org.eigenbase.rel.rules.PushFilterPastJoinRule;
import org.eigenbase.relopt.*;
@@ -39,13 +39,24 @@ import net.hydromatic.linq4j.function.Function2;
import net.hydromatic.optiq.util.BitSets;
-import com.google.common.collect.ImmutableSet;
+import com.google.common.base.Supplier;
+import com.google.common.collect.*;
/**
- * RelDecorrelator replaces all correlated expressions(corExp) in a relational
+ * RelDecorrelator replaces all correlated expressions (corExp) in a relational
* expression (RelNode) tree with non-correlated expressions that are produced
* from joining the RelNode that produces the corExp with the RelNode that
* references it.
+ *
+ * <p>TODO:</p>
+ * <ul>
+ * <li>replace {@code CorelMap} constructor parameter with a RelNode
+ * <li>make {@link #currentRel} immutable (would require a fresh
+ * RelDecorrelator for each node being decorrelated)</li>
+ * <li>make fields of {@link CorelMap} immutable</li>
+ * <li>make sub-class rules static, and have them create their own
+ * de-correlator</li>
+ * </ul>
*/
public class RelDecorrelator implements ReflectiveVisitor {
//~ Static fields/initializers ---------------------------------------------
@@ -55,15 +66,8 @@ public class RelDecorrelator implements ReflectiveVisitor {
//~ Instance fields --------------------------------------------------------
- // maps built during translation
- private final Map<RelNode, SortedSet<CorrelatorRel.Correlation>>
- mapRefRelToCorVar;
-
- private final SortedMap<CorrelatorRel.Correlation, CorrelatorRel>
- mapCorVarToCorRel;
-
- private final Map<RexFieldAccess, CorrelatorRel.Correlation>
- mapFieldAccessToCorVar;
+ // map built during translation
+ private CorelMap cm;
private final DecorrelateRelVisitor decorrelateVisitor;
@@ -75,46 +79,80 @@ public class RelDecorrelator implements ReflectiveVisitor {
private final Context context;
// maps built during decorrelation
- private final Map<RelNode, RelNode> mapOldToNewRel;
+ private final Map<RelNode, RelNode> mapOldToNewRel = Maps.newHashMap();
// map rel to all the newly created correlated variables in its output
- private final Map<RelNode, SortedMap<CorrelatorRel.Correlation, Integer>>
- mapNewRelToMapCorVarToOutputPos;
+ private final Map<RelNode, SortedMap<Correlation, Integer>>
+ mapNewRelToMapCorVarToOutputPos = Maps.newHashMap();
// another map to map old input positions to new input positions
// this is from the view point of the parent rel of a new rel.
private final Map<RelNode, Map<Integer, Integer>>
- mapNewRelToMapOldToNewOutputPos;
+ mapNewRelToMapOldToNewOutputPos = Maps.newHashMap();
- private final HashSet<CorrelatorRel> generatedCorRels =
- new HashSet<CorrelatorRel>();
+ private final HashSet<CorrelatorRel> generatedCorRels = Sets.newHashSet();
//~ Constructors -----------------------------------------------------------
- public RelDecorrelator(
+ private RelDecorrelator(
RexBuilder rexBuilder,
- Map<RelNode, SortedSet<CorrelatorRel.Correlation>> mapRefRelToCorVar,
- SortedMap<CorrelatorRel.Correlation, CorrelatorRel> mapCorVarToCorRel,
- Map<RexFieldAccess, CorrelatorRel.Correlation> mapFieldAccessToCorVar,
+ CorelMap cm,
Context context) {
+ this.cm = cm;
this.rexBuilder = rexBuilder;
- this.mapRefRelToCorVar = mapRefRelToCorVar;
- this.mapCorVarToCorRel = mapCorVarToCorRel;
- this.mapFieldAccessToCorVar = mapFieldAccessToCorVar;
this.context = context;
decorrelateVisitor = new DecorrelateRelVisitor();
- mapOldToNewRel = new HashMap<RelNode, RelNode>();
- mapNewRelToMapCorVarToOutputPos =
- new HashMap<RelNode,
- SortedMap<CorrelatorRel.Correlation, Integer>>();
- mapNewRelToMapOldToNewOutputPos =
- new HashMap<RelNode, Map<Integer, Integer>>();
}
//~ Methods ----------------------------------------------------------------
- public RelNode decorrelate(RelNode root) {
+ /** Decorrelates a query.
+ *
+ * <p>This is the main entry point to {@code RelDecorrelator}.
+ *
+ * @param rootRel Root node of the query
+ * @return Equivalent query with all {@link CorrelatorRel} instances removed
+ */
+ public static RelNode decorrelateQuery(RelNode rootRel) {
+ final CorelMap corelMap = CorelMap.build(rootRel);
+ if (!corelMap.hasCorrelation()) {
+ return rootRel;
+ }
+
+ final RelOptCluster cluster = rootRel.getCluster();
+ final RexBuilder rexBuilder = cluster.getRexBuilder();
+ final RelDecorrelator decorrelator =
+ new RelDecorrelator(rexBuilder, corelMap,
+ cluster.getPlanner().getContext());
+
+
+ RelNode newRootRel = decorrelator.removeCorrelationViaRule(rootRel);
+
+ if (SQL2REL_LOGGER.isLoggable(Level.FINE)) {
+ SQL2REL_LOGGER.fine(
+ RelOptUtil.dumpPlan(
+ "Plan after removing CorrelatorRel",
+ newRootRel,
+ false,
+ SqlExplainLevel.EXPPLAN_ATTRIBUTES));
+ }
+
+ if (!decorrelator.cm.mapCorVarToCorRel.isEmpty()) {
+ newRootRel = decorrelator.decorrelate(newRootRel);
+ }
+
+ return newRootRel;
+ }
+
+ private void setCurrent(RelNode root, CorrelatorRel corRel) {
+ currentRel = corRel;
+ if (corRel != null) {
+ cm = CorelMap.build(Util.first(root, corRel));
+ }
+ }
+
+ private RelNode decorrelate(RelNode root) {
// first adjust count() expression if any
HepProgram program = HepProgram.builder()
.addRuleInstance(new AdjustProjectForCountAggregateRule(false))
@@ -146,16 +184,16 @@ public class RelDecorrelator implements ReflectiveVisitor {
private Function2<RelNode, RelNode, Void> createCopyHook() {
return new Function2<RelNode, RelNode, Void>() {
public Void apply(RelNode oldNode, RelNode newNode) {
- if (mapRefRelToCorVar.containsKey(oldNode)) {
- mapRefRelToCorVar.put(
- newNode, mapRefRelToCorVar.get(oldNode));
+ if (cm.mapRefRelToCorVar.containsKey(oldNode)) {
+ cm.mapRefRelToCorVar.putAll(newNode,
+ cm.mapRefRelToCorVar.get(oldNode));
}
if (oldNode instanceof CorrelatorRel
&& newNode instanceof CorrelatorRel) {
CorrelatorRel oldCor = (CorrelatorRel) oldNode;
for (Correlation c : oldCor.getCorrelations()) {
- if (mapCorVarToCorRel.get(c) == oldNode) {
- mapCorVarToCorRel.put(c, (CorrelatorRel) newNode);
+ if (cm.mapCorVarToCorRel.get(c) == oldNode) {
+ cm.mapCorVarToCorRel.put(c, (CorrelatorRel) newNode);
}
}
@@ -238,7 +276,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
if (rel.getInputs().size() > 0) {
List<RelNode> oldInputs = rel.getInputs();
- List<RelNode> newInputs = new ArrayList<RelNode>();
+ List<RelNode> newInputs = Lists.newArrayList();
for (int i = 0; i < oldInputs.size(); ++i) {
RelNode newInputRel = mapOldToNewRel.get(oldInputs.get(i));
if ((newInputRel == null)
@@ -257,10 +295,9 @@ public class RelDecorrelator implements ReflectiveVisitor {
}
}
- // the output position should not change since there're no corVars
+ // the output position should not change since there are no corVars
// coming from below.
- Map<Integer, Integer> mapOldToNewOutputPos =
- new HashMap<Integer, Integer>();
+ Map<Integer, Integer> mapOldToNewOutputPos = Maps.newHashMap();
for (int i = 0; i < rel.getRowType().getFieldCount(); i++) {
mapOldToNewOutputPos.put(i, i);
}
@@ -281,7 +318,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
//
// SortRel itself should not reference cor vars.
- assert !mapRefRelToCorVar.containsKey(rel);
+ assert !cm.mapRefRelToCorVar.containsKey(rel);
// SortRel only references field positions in collations field.
// The collations field in the newRel now need to refer to the
@@ -340,7 +377,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
//
// AggregaterRel itself should not reference cor vars.
- assert !mapRefRelToCorVar.containsKey(rel);
+ assert !cm.mapRefRelToCorVar.containsKey(rel);
RelNode oldChildRel = rel.getChild();
@@ -355,14 +392,12 @@ public class RelDecorrelator implements ReflectiveVisitor {
assert childMapOldToNewOutputPos != null;
// map from newChildRel
- Map<Integer, Integer> mapNewChildToProjOutputPos =
- new HashMap<Integer, Integer>();
+ Map<Integer, Integer> mapNewChildToProjOutputPos = Maps.newHashMap();
final int oldGroupKeyCount = rel.getGroupSet().cardinality();
// ProjectRel projects the original expressions,
// plus any correlated variables the child wants to pass along.
- final List<Pair<RexNode, String>> projects =
- new ArrayList<Pair<RexNode, String>>();
+ final List<Pair<RexNode, String>> projects = Lists.newArrayList();
List<RelDataTypeField> newChildOutput =
newChildRel.getRowType().getFieldList();
@@ -376,8 +411,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
mapNewChildToProjOutputPos.put(newChildPos, newPos);
}
- SortedMap<CorrelatorRel.Correlation, Integer> mapCorVarToOutputPos =
- new TreeMap<CorrelatorRel.Correlation, Integer>();
+ SortedMap<Correlation, Integer> mapCorVarToOutputPos = Maps.newTreeMap();
boolean produceCorVar =
mapNewRelToMapCorVarToOutputPos.containsKey(newChildRel);
@@ -385,13 +419,12 @@ public class RelDecorrelator implements ReflectiveVisitor {
// If child produces correlated variables, move them to the front,
// right after any existing groupby fields.
- SortedMap<CorrelatorRel.Correlation, Integer>
- childMapCorVarToOutputPos =
+ SortedMap<Correlation, Integer> childMapCorVarToOutputPos =
mapNewRelToMapCorVarToOutputPos.get(newChildRel);
// Now add the corVars from the child, starting from
// position oldGroupKeyCount.
- for (CorrelatorRel.Correlation corVar
+ for (Correlation corVar
: childMapCorVarToOutputPos.keySet()) {
int newChildPos = childMapCorVarToOutputPos.get(corVar);
projects.add(RexInputRef.of2(newChildPos, newChildOutput));
@@ -431,7 +464,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
// oldChildRel ----> newProjectRel
// |
// newChildRel
- Map<Integer, Integer> combinedMap = new HashMap<Integer, Integer>();
+ Map<Integer, Integer> combinedMap = Maps.newHashMap();
for (Integer oldChildPos : childMapOldToNewOutputPos.keySet()) {
combinedMap.put(
@@ -450,7 +483,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
}
// now it's time to rewrite AggregateRel
- List<AggregateCall> newAggCalls = new ArrayList<AggregateCall>();
+ List<AggregateCall> newAggCalls = Lists.newArrayList();
List<AggregateCall> oldAggCalls = rel.getAggCallList();
// AggregateRel.Call oldAggCall;
@@ -463,7 +496,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
++i;
List<Integer> oldAggArgs = oldAggCall.getArgList();
- List<Integer> aggArgs = new ArrayList<Integer>();
+ List<Integer> aggArgs = Lists.newArrayList();
// Adjust the aggregator argument positions.
// Note aggregator does not change input ordering, so the child
@@ -473,8 +506,9 @@ public class RelDecorrelator implements ReflectiveVisitor {
aggArgs.add(combinedMap.get(oldPos));
}
- newAggCalls.add(oldAggCall.adaptTo(newProjectRel, aggArgs,
- oldGroupKeyCount, newGroupKeyCount));
+ newAggCalls.add(
+ oldAggCall.adaptTo(newProjectRel, aggArgs,
+ oldGroupKeyCount, newGroupKeyCount));
// The old to new output position mapping will be the same as that
// of newProjectRel, plus any aggregates that the oldAgg produces.
@@ -529,20 +563,18 @@ public class RelDecorrelator implements ReflectiveVisitor {
mapNewRelToMapOldToNewOutputPos.get(newChildRel);
assert childMapOldToNewOutputPos != null;
- Map<Integer, Integer> mapOldToNewOutputPos =
- new HashMap<Integer, Integer>();
+ Map<Integer, Integer> mapOldToNewOutputPos = Maps.newHashMap();
boolean produceCorVar =
mapNewRelToMapCorVarToOutputPos.containsKey(newChildRel);
// ProjectRel projects the original expressions,
// plus any correlated variables the child wants to pass along.
- final List<Pair<RexNode, String>> projects =
- new ArrayList<Pair<RexNode, String>>();
+ final List<Pair<RexNode, String>> projects = Lists.newArrayList();
// If this ProjectRel has correlated reference, create value generator
// and produce the correlated variables in the new output.
- if (mapRefRelToCorVar.containsKey(rel)) {
+ if (cm.mapRefRelToCorVar.containsKey(rel)) {
decorrelateInputWithValueGenerator(rel);
// The old child should be mapped to the JoinRel created by
@@ -562,19 +594,17 @@ public class RelDecorrelator implements ReflectiveVisitor {
mapOldToNewOutputPos.put(newPos, newPos);
}
- SortedMap<CorrelatorRel.Correlation, Integer> mapCorVarToOutputPos =
- new TreeMap<CorrelatorRel.Correlation, Integer>();
+ SortedMap<Correlation, Integer> mapCorVarToOutputPos = Maps.newTreeMap();
// Project any correlated variables the child wants to pass along.
if (produceCorVar) {
- SortedMap<CorrelatorRel.Correlation, Integer>
- childMapCorVarToOutputPos =
+ SortedMap<Correlation, Integer> childMapCorVarToOutputPos =
mapNewRelToMapCorVarToOutputPos.get(newChildRel);
// propagate cor vars from the new child
List<RelDataTypeField> newChildOutput =
newChildRel.getRowType().getFieldList();
- for (CorrelatorRel.Correlation corVar
+ for (Correlation corVar
: childMapCorVarToOutputPos.keySet()) {
int corVarPos = childMapCorVarToOutputPos.get(corVar);
projects.add(RexInputRef.of2(corVarPos, newChildOutput));
@@ -609,16 +639,14 @@ public class RelDecorrelator implements ReflectiveVisitor {
* @return RelNode the root of the resultant RelNode tree
*/
private RelNode createValueGenerator(
- SortedSet<CorrelatorRel.Correlation> correlations,
+ Iterable<Correlation> correlations,
int valueGenFieldOffset,
- SortedMap<CorrelatorRel.Correlation, Integer> mapCorVarToOutputPos) {
+ SortedMap<Correlation, Integer> mapCorVarToOutputPos) {
RelNode resultRel = null;
- Map<RelNode, List<Integer>> mapNewInputRelToOutputPos =
- new HashMap<RelNode, List<Integer>>();
+ Map<RelNode, List<Integer>> mapNewInputRelToOutputPos = Maps.newHashMap();
- Map<RelNode, Integer> mapNewInputRelToNewOffset =
- new HashMap<RelNode, Integer>();
+ Map<RelNode, Integer> mapNewInputRelToNewOffset = Maps.newHashMap();
RelNode oldInputRel;
RelNode newInputRel;
@@ -626,16 +654,16 @@ public class RelDecorrelator implements ReflectiveVisitor {
// inputRel provides the definition of a correlated variable.
// Add to map all the referenced positions(relative to each input rel)
- for (CorrelatorRel.Correlation corVar : correlations) {
+ for (Correlation corVar : correlations) {
int oldCorVarOffset = corVar.getOffset();
- oldInputRel = mapCorVarToCorRel.get(corVar).getInput(0);
+ oldInputRel = cm.mapCorVarToCorRel.get(corVar).getInput(0);
assert oldInputRel != null;
newInputRel = mapOldToNewRel.get(oldInputRel);
assert newInputRel != null;
if (!mapNewInputRelToOutputPos.containsKey(newInputRel)) {
- newLocalOutputPosList = new ArrayList<Integer>();
+ newLocalOutputPosList = Lists.newArrayList();
} else {
newLocalOutputPosList =
mapNewInputRelToOutputPos.get(newInputRel);
@@ -659,12 +687,12 @@ public class RelDecorrelator implements ReflectiveVisitor {
// Project only the correlated fields out of each inputRel
// and join the projectRel together.
// To make sure the plan does not change in terms of join order,
- // join these rels based on their occurance in cor var list which
+ // join these rels based on their occurrence in cor var list which
// is sorted.
- Set<RelNode> joinedInputRelSet = new HashSet<RelNode>();
+ Set<RelNode> joinedInputRelSet = Sets.newHashSet();
- for (CorrelatorRel.Correlation corVar : correlations) {
- oldInputRel = mapCorVarToCorRel.get(corVar).getInput(0);
+ for (Correlation corVar : correlations) {
+ oldInputRel = cm.mapCorVarToCorRel.get(corVar).getInput(0);
assert oldInputRel != null;
newInputRel = mapOldToNewRel.get(oldInputRel);
assert newInputRel != null;
@@ -702,11 +730,11 @@ public class RelDecorrelator implements ReflectiveVisitor {
// referencing correlated variables.
int newOutputPos;
int newLocalOutputPos;
- for (CorrelatorRel.Correlation corVar : correlations) {
+ for (Correlation corVar : correlations) {
// The first child of a correlatorRel is always the rel defining
// the correlated variables.
newInputRel =
- mapOldToNewRel.get(mapCorVarToCorRel.get(corVar).getInput(0));
+ mapOldToNewRel.get(cm.mapCorVarToCorRel.get(corVar).getInput(0));
newLocalOutputPosList = mapNewInputRelToOutputPos.get(newInputRel);
Map<Integer, Integer> mapOldToNewOutputPos =
@@ -743,16 +771,14 @@ public class RelDecorrelator implements ReflectiveVisitor {
mapNewRelToMapOldToNewOutputPos.get(newChildRel);
assert childMapOldToNewOutputPos != null;
- SortedMap<CorrelatorRel.Correlation, Integer> mapCorVarToOutputPos =
- new TreeMap<CorrelatorRel.Correlation, Integer>();
+ SortedMap<Correlation, Integer> mapCorVarToOutputPos = Maps.newTreeMap();
if (mapNewRelToMapCorVarToOutputPos.containsKey(newChildRel)) {
mapCorVarToOutputPos.putAll(
mapNewRelToMapCorVarToOutputPos.get(newChildRel));
}
- SortedSet<CorrelatorRel.Correlation> corVarList =
- mapRefRelToCorVar.get(rel);
+ final Collection<Correlation> corVarList = cm.mapRefRelToCorVar.get(rel);
RelNode newLeftChildRel = newChildRel;
@@ -824,7 +850,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
// If this FilterRel has correlated reference, create value generator
// and produce the correlated variables in the new output.
- if (mapRefRelToCorVar.containsKey(rel)) {
+ if (cm.mapRefRelToCorVar.containsKey(rel)) {
decorrelateInputWithValueGenerator(rel);
// The old child should be mapped to the newly created JoinRel by
@@ -883,8 +909,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
return;
}
- SortedMap<CorrelatorRel.Correlation, Integer>
- rightChildMapCorVarToOutputPos =
+ SortedMap<Correlation, Integer> rightChildMapCorVarToOutputPos =
mapNewRelToMapCorVarToOutputPos.get(newRightRel);
if (rightChildMapCorVarToOutputPos == null) {
@@ -900,7 +925,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
assert rightChildMapOldToNewOutputPos != null;
- SortedMap<CorrelatorRel.Correlation, Integer> mapCorVarToOutputPos =
+ SortedMap<Correlation, Integer> mapCorVarToOutputPos =
rightChildMapCorVarToOutputPos;
assert rel.getCorrelations().size()
@@ -919,7 +944,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
int newLeftPos;
int newRightPos;
- for (CorrelatorRel.Correlation corVar : rel.getCorrelations()) {
+ for (Correlation corVar : rel.getCorrelations()) {
newLeftPos = leftChildMapOldToNewOutputPos.get(corVar.getOffset());
newRightPos = rightChildMapCorVarToOutputPos.get(corVar);
RexNode equi =
@@ -945,7 +970,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
// Update the output position for the cor vars: only pass on the cor
// vars that are not used in the join key.
- for (CorrelatorRel.Correlation corVar : mapCorVarToOutputPos.keySet()) {
+ for (Correlation corVar : mapCorVarToOutputPos.keySet()) {
int newPos = mapCorVarToOutputPos.get(corVar) + newLeftFieldCount;
mapCorVarToOutputPos.put(corVar, newPos);
}
@@ -959,8 +984,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
// Create the mapping between the output of the old correlation rel
// and the new join rel
- Map<Integer, Integer> mapOldToNewOutputPos =
- new HashMap<Integer, Integer>();
+ Map<Integer, Integer> mapOldToNewOutputPos = Maps.newHashMap();
int oldLeftFieldCount = oldLeftRel.getRowType().getFieldCount();
@@ -1028,8 +1052,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
mapNewRelToMapOldToNewOutputPos.get(newRightRel);
assert rightChildMapOldToNewOutputPos != null;
- SortedMap<CorrelatorRel.Correlation, Integer> mapCorVarToOutputPos =
- new TreeMap<CorrelatorRel.Correlation, Integer>();
+ SortedMap<Correlation, Integer> mapCorVarToOutputPos = Maps.newTreeMap();
final Set<String> variablesStopped = Collections.emptySet();
RelNode newRel =
@@ -1043,8 +1066,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
// Create the mapping between the output of the old correlation rel
// and the new join rel
- Map<Integer, Integer> mapOldToNewOutputPos =
- new HashMap<Integer, Integer>();
+ Map<Integer, Integer> mapOldToNewOutputPos = Maps.newHashMap();
int oldLeftFieldCount = oldLeftRel.getRowType().getFieldCount();
int newLeftFieldCount = newLeftRel.getRowType().getFieldCount();
@@ -1071,11 +1093,9 @@ public class RelDecorrelator implements ReflectiveVisitor {
// Right input positions are shifted by newLeftFieldCount.
int oldRightPos;
if (mapNewRelToMapCorVarToOutputPos.containsKey(newRightRel)) {
- SortedMap<CorrelatorRel.Correlation, Integer>
- rightChildMapCorVarToOutputPos =
+ SortedMap<Correlation, Integer> rightChildMapCorVarToOutputPos =
mapNewRelToMapCorVarToOutputPos.get(newRightRel);
- for (CorrelatorRel.Correlation corVar
- : rightChildMapCorVarToOutputPos.keySet()) {
+ for (Correlation corVar : rightChildMapCorVarToOutputPos.keySet()) {
oldRightPos = rightChildMapCorVarToOutputPos.get(corVar);
mapCorVarToOutputPos.put(
corVar,
@@ -1133,10 +1153,8 @@ public class RelDecorrelator implements ReflectiveVisitor {
newOrdinal += newLocalOrdinal;
- return new RexInputRef(
- newOrdinal,
- newInputRel.getRowType().getFieldList().get(newLocalOrdinal)
- .getType());
+ return new RexInputRef(newOrdinal,
+ newInputRel.getRowType().getFieldList().get(newLocalOrdinal).getType());
}
/**
@@ -1144,7 +1162,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
* for join output.
*
* @param joinRel Join
- * @param projRel the orginal projRel as the RHS input of the join.
+ * @param projRel the original projRel as the RHS input of the join.
* @param nullIndicatorPos Position of null indicator
* @return the subtree with the new ProjectRel at the root
*/
@@ -1165,8 +1183,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
true));
// now create the new project
- List<Pair<RexNode, String>> newProjExprs =
- new ArrayList<Pair<RexNode, String>>();
+ List<Pair<RexNode, String>> newProjExprs = Lists.newArrayList();
// project everything from the LHS and then those from the original
// projRel
@@ -1204,7 +1221,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
* for join output.
*
* @param corRel Correlator
- * @param projRel the orginal ProjectRel as the RHS input of the join
+ * @param projRel the original ProjectRel as the RHS input of the join
* @param isCount Positions which are calls to the <code>COUNT</code>
* aggregation function
* @return the subtree with the new ProjectRel at the root
@@ -1217,8 +1234,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
JoinRelType joinType = corRel.getJoinType();
// now create the new project
- List<Pair<RexNode, String>> newProjects =
- new ArrayList<Pair<RexNode, String>>();
+ List<Pair<RexNode, String>> newProjects = Lists.newArrayList();
// project everything from the LHS and then those from the original
// projRel
@@ -1252,7 +1268,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
* the correlated variables provided by corRel.
*
* @param corRel Correlator
- * @param projRel the orginal ProjectRel as the RHS input of the
+ * @param projRel the original ProjectRel as the RHS input of the
* join
* @param filterRel Filter
* @param correlatedJoinKeys Correlated join keys
@@ -1268,13 +1284,12 @@ public class RelDecorrelator implements ReflectiveVisitor {
// check that all correlated refs in the filter condition are
// used in the join(as field access).
- HashSet<CorrelatorRel.Correlation> corVarInFilter =
- new HashSet<CorrelatorRel.Correlation>();
- corVarInFilter.addAll(mapRefRelToCorVar.get(filterRel));
+ Set<Correlation> corVarInFilter =
+ Sets.newHashSet(cm.mapRefRelToCorVar.get(filterRel));
for (RexFieldAccess correlatedJoinKey : correlatedJoinKeys) {
corVarInFilter.remove(
- mapFieldAccessToCorVar.get(correlatedJoinKey));
+ cm.mapFieldAccessToCorVar.get(correlatedJoinKey));
}
if (!corVarInFilter.isEmpty()) {
@@ -1283,10 +1298,10 @@ public class RelDecorrelator implements ReflectiveVisitor {
// Check that the correlated variables referenced in these
// comparisons do come from the correlatorRel.
- corVarInFilter.addAll(mapRefRelToCorVar.get(filterRel));
+ corVarInFilter.addAll(cm.mapRefRelToCorVar.get(filterRel));
- for (CorrelatorRel.Correlation corVar : corVarInFilter) {
- if (mapCorVarToCorRel.get(corVar) != corRel) {
+ for (Correlation corVar : corVarInFilter) {
+ if (cm.mapCorVarToCorRel.get(corVar) != corRel) {
return false;
}
}
@@ -1295,11 +1310,9 @@ public class RelDecorrelator implements ReflectiveVisitor {
// if projRel has any correlated reference, make sure they are also
// provided by the current corRel. They will be projected out of the LHS
// of the corRel.
- if ((projRel != null) && mapRefRelToCorVar.containsKey(projRel)) {
- SortedSet<CorrelatorRel.Correlation> corVarInProj =
- mapRefRelToCorVar.get(projRel);
- for (CorrelatorRel.Correlation corVar : corVarInProj) {
- if (mapCorVarToCorRel.get(corVar) != corRel) {
+ if ((projRel != null) && cm.mapRefRelToCorVar.containsKey(projRel)) {
+ for (Correlation corVar : cm.mapRefRelToCorVar.get(projRel)) {
+ if (cm.mapCorVarToCorRel.get(corVar) != corRel) {
return false;
}
}
@@ -1313,15 +1326,10 @@ public class RelDecorrelator implements ReflectiveVisitor {
*
* @param corRel Correlator
*/
- private void removeCorVarFromTree(
- CorrelatorRel corRel) {
- HashSet<CorrelatorRel.Correlation> corVarSet =
- new HashSet<CorrelatorRel.Correlation>();
- corVarSet.addAll(mapCorVarToCorRel.keySet());
-
- for (CorrelatorRel.Correlation corVar : corVarSet) {
- if (mapCorVarToCorRel.get(corVar) == corRel) {
- mapCorVarToCorRel.remove(corVar);
+ private void removeCorVarFromTree(CorrelatorRel corRel) {
+ for (Correlation c : Lists.newArrayList(cm.mapCorVarToCorRel.keySet())) {
+ if (cm.mapCorVarToCorRel.get(c) == corRel) {
+ cm.mapCorVarToCorRel.remove(c);
}
}
}
@@ -1338,8 +1346,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
List<Pair<RexNode, String>> additionalExprs) {
final List<RelDataTypeField> fieldList =
childRel.getRowType().getFieldList();
- List<Pair<RexNode, String>> projects =
- new ArrayList<Pair<RexNode, String>>();
+ List<Pair<RexNode, String>> projects = Lists.newArrayList();
for (Ord<RelDataTypeField> field : Ord.zip(fieldList)) {
projects.add(
Pair.of(
@@ -1373,7 +1380,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
RelDecorrelator.this,
currentRel,
visitMethodName);
- currentRel = null;
+ setCurrent(null, null);
if (!found) {
decorrelateRelGeneric(p);
@@ -1399,14 +1406,12 @@ public class RelDecorrelator implements ReflectiveVisitor {
if ((newInputRel != null)
&& mapNewRelToMapCorVarToOutputPos.containsKey(newInputRel)) {
- SortedMap<CorrelatorRel.Correlation, Integer>
- childMapCorVarToOutputPos =
+ SortedMap<Correlation, Integer> childMapCorVarToOutputPos =
mapNewRelToMapCorVarToOutputPos.get(newInputRel);
if (childMapCorVarToOutputPos != null) {
// try to find in this input rel the position of cor var
- CorrelatorRel.Correlation corVar =
- mapFieldAccessToCorVar.get(fieldAccess);
+ Correlation corVar = cm.mapFieldAccessToCorVar.get(fieldAccess);
if (corVar != null) {
newInputPos = childMapCorVarToOutputPos.get(corVar);
@@ -1543,12 +1548,11 @@ public class RelDecorrelator implements ReflectiveVisitor {
// override RexShuttle
public RexNode visitFieldAccess(RexFieldAccess fieldAccess) {
- if (mapFieldAccessToCorVar.containsKey(fieldAccess)) {
+ if (cm.mapFieldAccessToCorVar.containsKey(fieldAccess)) {
// if it is a corVar, change it to be input ref.
- CorrelatorRel.Correlation corVar =
- mapFieldAccessToCorVar.get(fieldAccess);
+ Correlation corVar = cm.mapFieldAccessToCorVar.get(fieldAccess);
- // corVar offset shuold point to the leftInput of currentRel,
+ // corVar offset should point to the leftInput of currentRel,
// which is the CorrelatorRel.
RexNode newRexNode =
new RexInputRef(corVar.getOffset(), fieldAccess.getType());
@@ -1718,14 +1722,14 @@ public class RelDecorrelator implements ReflectiveVisitor {
// singleAggRel produces a nullable type, so create the new
// projection that casts proj expr to a nullable type.
+ final RelOptCluster cluster = projRel.getCluster();
RelNode newProjRel =
- CalcRel.createProject(
- aggRel,
- Collections.singletonList(
+ CalcRel.createProject(aggRel,
+ ImmutableList.of(
rexBuilder.makeCast(
- projRel.getCluster().getTypeFactory()
- .createTypeWithNullability(
- projExprs.get(0).getType(), true),
+ cluster.getTypeFactory().createTypeWithNullability(
+ projExprs.get(0).getType(),
+ true),
projExprs.get(0))),
null);
call.transformTo(newProjRel);
@@ -1753,7 +1757,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
RelNode rightInputRel = call.rel(4);
RelOptCluster cluster = corRel.getCluster();
- currentRel = corRel;
+ setCurrent(call.getPlanner().getRoot(), corRel);
// Check for this pattern.
// The pattern matching could be simplified if rules can be applied
@@ -1789,7 +1793,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
int nullIndicatorPos;
if ((rightInputRel instanceof FilterRel)
- && mapRefRelToCorVar.containsKey(rightInputRel)) {
+ && cm.mapRefRelToCorVar.containsKey(rightInputRel)) {
// rightInputRel has this shape:
//
// FilterRel (references corvar)
@@ -1817,8 +1821,8 @@ public class RelDecorrelator implements ReflectiveVisitor {
// filterInputRel) and correlatedJoinKeys. correlatedJoinKeys
// can be expressions, while rightJoinKeys need to be input
// refs. These comparisons are AND'ed together.
- List<RexNode> tmpRightJoinKeys = new ArrayList<RexNode>();
- List<RexNode> correlatedJoinKeys = new ArrayList<RexNode>();
+ List<RexNode> tmpRightJoinKeys = Lists.newArrayList();
+ List<RexNode> correlatedJoinKeys = Lists.newArrayList();
RelOptUtil.splitCorrelatedFilterCondition(
filterRel,
tmpRightJoinKeys,
@@ -1828,9 +1832,9 @@ public class RelDecorrelator implements ReflectiveVisitor {
// check that the columns referenced in these comparisons form
// an unique key of the filterInputRel
List<RexInputRef> rightJoinKeys = new ArrayList<RexInputRef>();
- for (int i = 0; i < tmpRightJoinKeys.size(); i++) {
- assert tmpRightJoinKeys.get(i) instanceof RexInputRef;
- rightJoinKeys.add((RexInputRef) tmpRightJoinKeys.get(i));
+ for (RexNode key : tmpRightJoinKeys) {
+ assert key instanceof RexInputRef;
+ rightJoinKeys.add((RexInputRef) key);
}
// check that the columns referenced in rightJoinKeys form an
@@ -1857,11 +1861,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
List<RexFieldAccess> correlatedKeyList =
visitor.getFieldAccessList();
- if (!checkCorVars(
- corRel,
- projRel,
- filterRel,
- correlatedKeyList)) {
+ if (!checkCorVars(corRel, projRel, filterRel, correlatedKeyList)) {
return;
}
@@ -1880,7 +1880,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
nullIndicatorPos =
leftInputRel.getRowType().getFieldCount()
+ rightJoinKeys.get(0).getIndex();
- } else if (mapRefRelToCorVar.containsKey(projRel)) {
+ } else if (cm.mapRefRelToCorVar.containsKey(projRel)) {
// check filter input contains no correlation
if (RelOptUtil.getVariablesUsed(rightInputRel).size() > 0) {
return;
@@ -1901,12 +1901,10 @@ public class RelDecorrelator implements ReflectiveVisitor {
// make the new projRel to provide a null indicator
rightInputRel =
- createProjectWithAdditionalExprs(
- rightInputRel,
- Collections.singletonList(
- Pair.of(
- (RexNode) rexBuilder.makeLiteral(true),
- "nullIndicator")));
+ createProjectWithAdditionalExprs(rightInputRel,
+ ImmutableList.of(
+ Pair.<RexNode, String>of(
+ rexBuilder.makeLiteral(true), "nullIndicator")));
// make the new aggRel
rightInputRel =
@@ -1933,10 +1931,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
ImmutableSet.<String>of());
RelNode newProjRel =
- projectJoinOutputWithNullability(
- joinRel,
- projRel,
- nullIndicatorPos);
+ projectJoinOutputWithNullability(joinRel, projRel, nullIndicatorPos);
call.transformTo(newProjRel);
@@ -1969,7 +1964,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
RelNode rightInputRel = call.rel(5);
RelOptCluster cluster = corRel.getCluster();
- currentRel = corRel;
+ setCurrent(call.getPlanner().getRoot(), corRel);
// check for this pattern
// The pattern matching could be simplified if rules can be applied
@@ -2003,7 +1998,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
List<RexNode> aggInputProjExprs = aggInputProjRel.getProjects();
List<AggregateCall> aggCalls = aggRel.getAggCallList();
- Set<Integer> isCountStar = new HashSet<Integer>();
+ Set<Integer> isCountStar = Sets.newHashSet();
// mark if agg produces count(*) which needs to reference the
// nullIndicator after the transformation.
@@ -2017,7 +2012,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
}
if ((rightInputRel instanceof FilterRel)
- && mapRefRelToCorVar.containsKey(rightInputRel)) {
+ && cm.mapRefRelToCorVar.containsKey(rightInputRel)) {
// rightInputRel has this shape:
//
// FilterRel (references corvar)
@@ -2041,8 +2036,8 @@ public class RelDecorrelator implements ReflectiveVisitor {
// filterInputRel) and correlatedJoinKeys. correlatedJoinKeys
// can only be RexFieldAccess, while rightJoinKeys can be
// expressions. These comparisons are AND'ed together.
- List<RexNode> rightJoinKeys = new ArrayList<RexNode>();
- List<RexNode> tmpCorrelatedJoinKeys = new ArrayList<RexNode>();
+ List<RexNode> rightJoinKeys = Lists.newArrayList();
+ List<RexNode> tmpCorrelatedJoinKeys = Lists.newArrayList();
RelOptUtil.splitCorrelatedFilterCondition(
filterRel,
rightJoinKeys,
@@ -2052,17 +2047,13 @@ public class RelDecorrelator implements ReflectiveVisitor {
// make sure the correlated reference forms a unique key check
// that the columns referenced in these comparisons form an
// unique key of the leftInputRel
- List<RexFieldAccess> correlatedJoinKeys =
- new ArrayList<RexFieldAccess>();
- List<RexInputRef> correlatedInputRefJoinKeys =
- new ArrayList<RexInputRef>();
+ List<RexFieldAccess> correlatedJoinKeys = Lists.newArrayList();
+ List<RexInputRef> correlatedInputRefJoinKeys = Lists.newArrayList();
for (RexNode joinKey : tmpCorrelatedJoinKeys) {
assert joinKey instanceof RexFieldAccess;
correlatedJoinKeys.add((RexFieldAccess) joinKey);
RexNode correlatedInputRef =
- removeCorrelationExpr(
- joinKey,
- false);
+ removeCorrelationExpr(joinKey, false);
assert correlatedInputRef instanceof RexInputRef;
correlatedInputRefJoinKeys.add(
(RexInputRef) correlatedInputRef);
@@ -2087,8 +2078,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
}
// check cor var references are valid
- if (!checkCorVars(
- corRel,
+ if (!checkCorVars(corRel,
aggInputProjRel,
filterRel,
correlatedJoinKeys)) {
@@ -2140,7 +2130,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
// first change the filter condition into a join condition
joinCond =
removeCorrelationExpr(filterRel.getCondition(), false);
- } else if (mapRefRelToCorVar.containsKey(aggInputProjRel)) {
+ } else if (cm.mapRefRelToCorVar.containsKey(aggInputProjRel)) {
// check rightInputRel contains no correlation
if (RelOptUtil.getVariablesUsed(rightInputRel).size() > 0) {
return;
@@ -2213,12 +2203,9 @@ public class RelDecorrelator implements ReflectiveVisitor {
leftInputFieldCount + aggInputProjExprs.size() + 1;
rightInputRel =
- createProjectWithAdditionalExprs(
- rightInputRel,
- Collections.singletonList(
- Pair.of(
- (RexNode) rexBuilder.makeLiteral(true),
- "nullIndicator")));
+ createProjectWithAdditionalExprs(rightInputRel,
+ ImmutableList.of(Pair.<RexNode, String>of(rexBuilder.makeLiteral(
+ true), "nullIndicator")));
JoinRel joinRel =
new JoinRel(
@@ -2242,8 +2229,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
true));
// first project all group-by keys plus the transformed agg input
- List<RexNode> joinOutputProjExprs =
- new ArrayList<RexNode>();
+ List<RexNode> joinOutputProjExprs = Lists.newArrayList();
// LOJ Join preserves LHS types
for (int i = 0; i < leftInputFieldCount; i++) {
@@ -2254,8 +2240,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
for (RexNode aggInputProjExpr : aggInputProjExprs) {
joinOutputProjExprs.add(
- removeCorrelationExpr(
- aggInputProjExpr,
+ removeCorrelationExpr(aggInputProjExpr,
joinType.generatesNullsOnRight(),
nullIndicator));
}
@@ -2275,7 +2260,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
final int groupCount = leftInputFieldCount;
- List<AggregateCall> newAggCalls = new ArrayList<AggregateCall>();
+ List<AggregateCall> newAggCalls = Lists.newArrayList();
k = -1;
for (AggregateCall aggCall : aggCalls) {
++k;
@@ -2287,7 +2272,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
// the null indicator is located at the end
newAggArgs = Collections.singletonList(nullIndicatorPos);
} else {
- newAggArgs = new ArrayList<Integer>();
+ newAggArgs = Lists.newArrayList();
for (Integer aggArg : aggArgs) {
newAggArgs.add(aggArg + groupCount);
@@ -2307,7 +2292,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
groupSet,
newAggCalls);
- List<RexNode> newAggOutputProjExprList = new ArrayList<RexNode>();
+ List<RexNode> newAggOutputProjExprList = Lists.newArrayList();
for (int i : BitSets.toIter(groupSet)) {
newAggOutputProjExprList.add(
rexBuilder.makeInputRef(newAggRel, i));
@@ -2370,8 +2355,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
aggRel = call.rel(2);
// Create identity projection
- List<Pair<RexNode, String>> projects =
- new ArrayList<Pair<RexNode, String>>();
+ List<Pair<RexNode, String>> projects = Lists.newArrayList();
final List<RelDataTypeField> fields =
aggRel.getRowType().getFieldList();
for (int i = 0; i < fields.size(); i++) {
@@ -2400,7 +2384,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
return;
}
- currentRel = corRel;
+ setCurrent(call.getPlanner().getRoot(), corRel);
// check for this pattern
// The pattern matching could be simplified if rules can be applied
@@ -2430,7 +2414,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
}
List<AggregateCall> aggCalls = aggRel.getAggCallList();
- Set<Integer> isCount = new HashSet<Integer>();
+ Set<Integer> isCount = Sets.newHashSet();
// remember the count() positions
int i = -1;
@@ -2466,12 +2450,9 @@ public class RelDecorrelator implements ReflectiveVisitor {
// need to update the mapCorVarToCorRel Update the output position
// for the cor vars: only pass on the cor vars that are not used in
// the join key.
- Set<CorrelatorRel.Correlation> corVars =
- new HashSet<CorrelatorRel.Correlation>();
- corVars.addAll(mapCorVarToCorRel.keySet());
- for (CorrelatorRel.Correlation corVar : corVars) {
- if (mapCorVarToCorRel.get(corVar) == corRel) {
- mapCorVarToCorRel.put(corVar, newCorRel);
+ for (Correlation c : Lists.newArrayList(cm.mapCorVarToCorRel.keySet())) {
+ if (cm.mapCorVarToCorRel.get(c) == corRel) {
+ cm.mapCorVarToCorRel.put(c, newCorRel);
}
}
@@ -2481,6 +2462,176 @@ public class RelDecorrelator implements ReflectiveVisitor {
call.transformTo(newOutputRel);
}
}
+
+ /** A map of the locations of {@link org.eigenbase.rel.CorrelatorRel} in
+ * a tree of {@link RelNode}s.
+ *
+ * <p>It is used to drive the decorrelation process.
+ * Treat it as immutable; rebuild if you modify the tree.
+ *
+ * <p>There are three maps:<ol>
+ *
+ * <li>mapRefRelToCorVars map a rel node to the correlated variables it
+ * references;
+ *
+ * <li>mapCorVarToCorRel maps a correlated variable to the correlatorRel
+ * providing it;
+ *
+ * <li>mapFieldAccessToCorVar maps a rex field access to
+ * the cor var it represents. Because typeFlattener does not clone or
+ * modify a correlated field access this map does not need to be
+ * updated.
+ *
+ * </ol> */
+ private static class CorelMap {
+ private final Multimap<RelNode, Correlation> mapRefRelToCorVar;
+ private final SortedMap<Correlation, CorrelatorRel> mapCorVarToCorRel;
+ private final Map<RexFieldAccess, Correlation> mapFieldAccessToCorVar;
+
+ // TODO: create immutable copies of all maps
+ private CorelMap(Multimap<RelNode, Correlation> mapRefRelToCorVar,
+ SortedMap<Correlation, CorrelatorRel> mapCorVarToCorRel,
+ Map<RexFieldAccess, Correlation> mapFieldAccessToCorVar) {
+ this.mapRefRelToCorVar = mapRefRelToCorVar;
+ this.mapCorVarToCorRel = mapCorVarToCorRel;
+ this.mapFieldAccessToCorVar = mapFieldAccessToCorVar;
+ }
+
+ @Override
+ public String toString() {
+ return "mapRefRelToCorVar=" + mapRefRelToCorVar
+ + "\nmapCorVarToCorRel=" + mapCorVarToCorRel
+ + "\nmapFieldAccessToCorVar=" + mapFieldAccessToCorVar
+ + "\n";
+ }
+
+ @Override public boolean equals(Object obj) {
+ return obj == this
+ || obj instanceof CorelMap
+ && mapRefRelToCorVar.equals(((CorelMap) obj).mapRefRelToCorVar)
+ && mapCorVarToCorRel.equals(((CorelMap) obj).mapCorVarToCorRel)
+ && mapFieldAccessToCorVar.equals(
+ ((CorelMap) obj).mapFieldAccessToCorVar);
+ }
+
+ @Override public int hashCode() {
+ return Util.hashV(mapRefRelToCorVar, mapCorVarToCorRel,
+ mapFieldAccessToCorVar);
+ }
+
+ /** Creates a CorelMap with given contents. */
+ public static CorelMap of(
+ SortedSetMultimap<RelNode, Correlation> mapRefRelToCorVar,
+ SortedMap<Correlation, CorrelatorRel> mapCorVarToCorRel,
+ Map<RexFieldAccess, Correlation> mapFieldAccessToCorVar) {
+ return new CorelMap(mapRefRelToCorVar, mapCorVarToCorRel,
+ mapFieldAccessToCorVar);
+ }
+
+ /** Creates a CorelMap by iterating over a {@link RelNode} tree. */
+ public static CorelMap build(RelNode rel) {
+ final SortedMap<Correlation, CorrelatorRel> mapCorVarToCorRel =
+ new TreeMap<Correlation, CorrelatorRel>();
+
+ final SortedSetMultimap<RelNode, Correlation> mapRefRelToCorVar =
+ Multimaps.newSortedSetMultimap(
+ Maps.<RelNode, Collection<Correlation>>newHashMap(),
+ new Supplier<TreeSet<Correlation>>() {
+ public TreeSet<Correlation> get() {
+ Bug.upgrade("use MultimapBuilder when we're on Guava-16");
+ return Sets.newTreeSet();
+ }
+ });
+
+ final Map<RexFieldAccess, Correlation> mapFieldAccessToCorVar =
+ new HashMap<RexFieldAccess, Correlation>();
+
+ final Map<String, Correlation> mapNameToCorVar = Maps.newHashMap();
+
+ final Holder<Integer> offset = Holder.of(0);
+ final RelShuttleImpl shuttle = new RelShuttleImpl() {
+ @Override
+ public RelNode visit(JoinRel join) {
+ return visitJoin(join);
+ }
+
+ @Override
+ protected RelNode visitChild(RelNode parent, int i, RelNode child) {
+ return super.visitChild(parent, i, stripHep(child));
+ }
+
+ @Override
+ public RelNode visit(CorrelatorRel correlator) {
+ for (Correlation c : correlator.getCorrelations()) {
+ mapNameToCorVar.put("$cor" + c.getId(), c);
+ mapCorVarToCorRel.put(c, correlator);
+ }
+ return visitJoin(correlator);
+ }
+
+ private JoinRelBase visitJoin(JoinRelBase join) {
+ join.getCondition().accept(rexVisitor(join));
+ final int x = offset.get();
+ visitChild(join, 0, join.getLeft());
+ offset.set(x + join.getLeft().getRowType().getFieldCount());
+ visitChild(join, 0, join.getRight());
+ offset.set(x);
+ return join;
+ }
+
+ @Override
+ public RelNode visit(final FilterRel filter) {
+ filter.getCondition().accept(rexVisitor(filter));
+ return super.visit(filter);
+ }
+
+ @Override
+ public RelNode visit(ProjectRel project) {
+ for (RexNode node : project.getProjects()) {
+ node.accept(rexVisitor(project));
+ }
+ return super.visit(project);
+ }
+
+ private RexVisitorImpl<Void> rexVisitor(final RelNode rel) {
+ return new RexVisitorImpl<Void>(true) {
+ @Override
+ public Void visitFieldAccess(RexFieldAccess fieldAccess) {
+ final RexNode ref = fieldAccess.getReferenceExpr();
+ if (ref instanceof RexCorrelVariable) {
+ final RexCorrelVariable var = (RexCorrelVariable) ref;
+ final Correlation correlation =
+ mapNameToCorVar.get(var.getName());
+ mapFieldAccessToCorVar.put(fieldAccess, correlation);
+ mapRefRelToCorVar.put(rel, correlation);
+ }
+ return super.visitFieldAccess(fieldAccess);
+ }
+ };
+ }
+ };
+ stripHep(rel).accept(shuttle);
+ return new CorelMap(mapRefRelToCorVar, mapCorVarToCorRel,
+ mapFieldAccessToCorVar);
+ }
+
+ private static RelNode stripHep(RelNode rel) {
+ if (rel instanceof HepRelVertex) {
+ HepRelVertex hepRelVertex = (HepRelVertex) rel;
+ rel = hepRelVertex.getCurrentRel();
+ }
+ return rel;
+ }
+
+ /**
+ * Returns whether there are any correlating variables in this statement.
+ *
+ * @return whether there are any correlating variables
+ */
+ public boolean hasCorrelation() {
+ return !mapCorVarToCorRel.isEmpty();
+ }
+ }
}
// End RelDecorrelator.java
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/3055cc32/core/src/main/java/org/eigenbase/sql2rel/RelStructuredTypeFlattener.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/sql2rel/RelStructuredTypeFlattener.java b/core/src/main/java/org/eigenbase/sql2rel/RelStructuredTypeFlattener.java
index cb6867e..45526c0 100644
--- a/core/src/main/java/org/eigenbase/sql2rel/RelStructuredTypeFlattener.java
+++ b/core/src/main/java/org/eigenbase/sql2rel/RelStructuredTypeFlattener.java
@@ -30,6 +30,8 @@ import org.eigenbase.util.mapping.Mappings;
import net.hydromatic.linq4j.function.Function1;
+import com.google.common.collect.*;
+
// TODO jvs 10-Feb-2005: factor out generic rewrite helper, with the
// ability to map between old and new rels and field ordinals. Also,
// for now need to prohibit queries which return UDT instances.
@@ -74,7 +76,7 @@ public class RelStructuredTypeFlattener implements ReflectiveVisitor {
private final RexBuilder rexBuilder;
private final RewriteRelVisitor visitor;
- private Map<RelNode, RelNode> oldToNewRelMap;
+ private final Map<RelNode, RelNode> oldToNewRelMap = Maps.newHashMap();
private RelNode currentRel;
private int iRestructureInput;
private RelDataType flattenedRootType;
@@ -94,23 +96,19 @@ public class RelStructuredTypeFlattener implements ReflectiveVisitor {
//~ Methods ----------------------------------------------------------------
public void updateRelInMap(
- Map<RelNode, SortedSet<CorrelatorRel.Correlation>> mapRefRelToCorVar) {
- Set<RelNode> oldRefRelSet = new HashSet<RelNode>();
- oldRefRelSet.addAll(mapRefRelToCorVar.keySet());
- for (RelNode rel : oldRefRelSet) {
+ SortedSetMultimap<RelNode, Correlation> mapRefRelToCorVar) {
+ for (RelNode rel : Lists.newArrayList(mapRefRelToCorVar.keySet())) {
if (oldToNewRelMap.containsKey(rel)) {
- SortedSet<CorrelatorRel.Correlation> corVarSet =
- new TreeSet<CorrelatorRel.Correlation>();
- corVarSet.addAll(mapRefRelToCorVar.get(rel));
- mapRefRelToCorVar.remove(rel);
- mapRefRelToCorVar.put(oldToNewRelMap.get(rel), corVarSet);
+ SortedSet<Correlation> corVarSet =
+ mapRefRelToCorVar.removeAll(rel);
+ mapRefRelToCorVar.putAll(oldToNewRelMap.get(rel), corVarSet);
}
}
}
public void updateRelInMap(
- SortedMap<CorrelatorRel.Correlation, CorrelatorRel> mapCorVarToCorRel) {
- for (CorrelatorRel.Correlation corVar : mapCorVarToCorRel.keySet()) {
+ SortedMap<Correlation, CorrelatorRel> mapCorVarToCorRel) {
+ for (Correlation corVar : mapCorVarToCorRel.keySet()) {
CorrelatorRel oldRel = mapCorVarToCorRel.get(corVar);
if (oldToNewRelMap.containsKey(oldRel)) {
RelNode newRel = oldToNewRelMap.get(oldRel);
@@ -122,7 +120,6 @@ public class RelStructuredTypeFlattener implements ReflectiveVisitor {
public RelNode rewrite(RelNode root, boolean restructure) {
// Perform flattening.
- oldToNewRelMap = new HashMap<RelNode, RelNode>();
visitor.visit(root, 0, null);
RelNode flattened = getNewForOldRel(root);
flattenedRootType = flattened.getRowType();
@@ -374,9 +371,9 @@ public class RelStructuredTypeFlattener implements ReflectiveVisitor {
}
public void rewriteRel(CorrelatorRel rel) {
- final List<CorrelatorRel.Correlation> newCorrelations =
- new ArrayList<CorrelatorRel.Correlation>();
- for (CorrelatorRel.Correlation c : rel.getCorrelations()) {
+ final List<Correlation> newCorrelations =
+ new ArrayList<Correlation>();
+ for (Correlation c : rel.getCorrelations()) {
RelDataType corrFieldType =
rel.getLeft().getRowType().getFieldList().get(c.getOffset())
.getType();
@@ -384,7 +381,7 @@ public class RelStructuredTypeFlattener implements ReflectiveVisitor {
throw Util.needToImplement("correlation on structured type");
}
newCorrelations.add(
- new CorrelatorRel.Correlation(
+ new Correlation(
c.getId(),
getNewForOldInput(c.getOffset())));
}
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/3055cc32/core/src/main/java/org/eigenbase/sql2rel/SqlToRelConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/sql2rel/SqlToRelConverter.java b/core/src/main/java/org/eigenbase/sql2rel/SqlToRelConverter.java
index a03eb1b..60cc363 100644
--- a/core/src/main/java/org/eigenbase/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/eigenbase/sql2rel/SqlToRelConverter.java
@@ -96,24 +96,6 @@ public class SqlToRelConverter {
private static final String CORREL_PREFIX = "$cor";
/**
- * Fields used in decorrelation.
- */
- private final Map<String, RelNode> mapCorrelToRefRel =
- new HashMap<String, RelNode>();
-
- private final SortedMap<CorrelatorRel.Correlation, CorrelatorRel>
- mapCorVarToCorRel =
- new TreeMap<CorrelatorRel.Correlation, CorrelatorRel>();
-
- private final Map<RelNode, SortedSet<CorrelatorRel.Correlation>>
- mapRefRelToCorVar =
- new HashMap<RelNode, SortedSet<CorrelatorRel.Correlation>>();
-
- private final Map<RexFieldAccess, CorrelatorRel.Correlation>
- mapFieldAccessToCorVar =
- new HashMap<RexFieldAccess, CorrelatorRel.Correlation>();
-
- /**
* Stack of names of datasets requested by the <code>
* TABLE(SAMPLE(<datasetName>, <query>))</code> construct.
*/
@@ -332,20 +314,7 @@ public class SqlToRelConverter {
boolean restructure) {
RelStructuredTypeFlattener typeFlattener =
new RelStructuredTypeFlattener(rexBuilder, createToRelContext());
- RelNode newRootRel = typeFlattener.rewrite(rootRel, restructure);
-
- // There are three maps constructed during convertQuery which need to to
- // be maintained for use in decorrelation. 1. mapRefRelToCorVar: - map a
- // rel node to the coorrelated variables it references 2.
- // mapCorVarToCorRel: - map a correlated variable to the correlatorRel
- // providing it 3. mapFieldAccessToCorVar: - map a rex field access to
- // the cor var it represents. because typeFlattener does not clone or
- // modify a correlated field access this map does not need to be
- // updated.
- typeFlattener.updateRelInMap(mapRefRelToCorVar);
- typeFlattener.updateRelInMap(mapCorVarToCorRel);
-
- return newRootRel;
+ return typeFlattener.rewrite(rootRel, restructure);
}
/**
@@ -357,10 +326,11 @@ public class SqlToRelConverter {
* @return New root relational expression after decorrelation
*/
public RelNode decorrelate(SqlNode query, RelNode rootRel) {
- RelNode result = rootRel;
- if (enableDecorrelation()
- && hasCorrelation()) {
- result = decorrelateQuery(result);
+ if (!enableDecorrelation()) {
+ return rootRel;
+ }
+ final RelNode result = decorrelateQuery(rootRel);
+ if (result != rootRel) {
checkConvertedType(query, result);
}
return result;
@@ -828,22 +798,9 @@ public class SqlToRelConverter {
// only allocate filter if the condition is not TRUE
if (!convertedWhere.isAlwaysTrue()) {
- RelNode inputRel = bb.root;
- Set<String> correlatedVariablesBefore =
- RelOptUtil.getVariablesUsed(inputRel);
-
bb.setRoot(
CalcRel.createFilter(bb.root, convertedWhere),
false);
- Set<String> correlatedVariables =
- RelOptUtil.getVariablesUsed(bb.root);
-
- correlatedVariables.removeAll(correlatedVariablesBefore);
-
- // Associate the correlated variables with the new filter rel.
- for (String correl : correlatedVariables) {
- mapCorrelToRefRel.put(correl, bb.root);
- }
}
}
@@ -1884,8 +1841,7 @@ public class SqlToRelConverter {
}
if (correlatedVariables.size() > 0) {
- List<CorrelatorRel.Correlation> correlations =
- new ArrayList<CorrelatorRel.Correlation>();
+ final List<Correlation> correlations = Lists.newArrayList();
for (String correlName : correlatedVariables) {
DeferredLookup lookup = mapCorrelToDeferred.get(correlName);
@@ -1952,42 +1908,23 @@ public class SqlToRelConverter {
}
}
- CorrelatorRel.Correlation newCorVar =
- new CorrelatorRel.Correlation(
+ Correlation newCorVar =
+ new Correlation(
getCorrelOrdinal(correlName),
pos);
correlations.add(newCorVar);
-
- mapFieldAccessToCorVar.put(fieldAccess, newCorVar);
-
- RelNode refRel = mapCorrelToRefRel.get(correlName);
-
- SortedSet<CorrelatorRel.Correlation> corVarList;
-
- if (!mapRefRelToCorVar.containsKey(refRel)) {
- corVarList = new TreeSet<CorrelatorRel.Correlation>();
- } else {
- corVarList = mapRefRelToCorVar.get(refRel);
- }
- corVarList.add(newCorVar);
- mapRefRelToCorVar.put(refRel, corVarList);
}
}
if (!correlations.isEmpty()) {
- CorrelatorRel rel =
- new CorrelatorRel(
- rightRel.getCluster(),
- leftRel,
- rightRel,
- joinCond,
- correlations,
- joinType);
- for (CorrelatorRel.Correlation correlation : correlations) {
- mapCorVarToCorRel.put(correlation, rel);
- }
- return rel;
+ return new CorrelatorRel(
+ rightRel.getCluster(),
+ leftRel,
+ rightRel,
+ joinCond,
+ correlations,
+ joinType);
}
}
@@ -2487,9 +2424,7 @@ public class SqlToRelConverter {
preNames = Collections.singletonList(null);
}
- RelNode inputRel = bb.root;
- Set<String> correlatedVariablesBefore =
- RelOptUtil.getVariablesUsed(inputRel);
+ final RelNode inputRel = bb.root;
// Project the expressions required by agg and having.
bb.setRoot(
@@ -2501,15 +2436,6 @@ public class SqlToRelConverter {
false);
bb.mapRootRelToFieldProjection.put(bb.root, groupExprProjection);
- Set<String> correlatedVariables =
- RelOptUtil.getVariablesUsed(bb.root);
- correlatedVariables.removeAll(correlatedVariablesBefore);
-
- // Associate the correlated variables with the new project rel.
- for (String correl : correlatedVariables) {
- mapCorrelToRefRel.put(correl, bb.root);
- }
-
// REVIEW jvs 31-Oct-2007: doesn't the declaration of
// monotonicity here assume sort-based aggregation at
// the physical level?
@@ -2752,41 +2678,8 @@ public class SqlToRelConverter {
return decorrelationEnabled;
}
- /**
- * Returns whether there are any correlating variables in this statement.
- *
- * @return whether there are any correlating variables
- */
- public boolean hasCorrelation() {
- return !mapCorVarToCorRel.isEmpty();
- }
-
protected RelNode decorrelateQuery(RelNode rootRel) {
- RelDecorrelator decorrelator =
- new RelDecorrelator(
- rexBuilder,
- mapRefRelToCorVar,
- mapCorVarToCorRel,
- mapFieldAccessToCorVar,
- cluster.getPlanner().getContext());
- boolean dumpPlan = SQL2REL_LOGGER.isLoggable(Level.FINE);
-
- RelNode newRootRel = decorrelator.removeCorrelationViaRule(rootRel);
-
- if (dumpPlan) {
- SQL2REL_LOGGER.fine(
- RelOptUtil.dumpPlan(
- "Plan after removing CorrelatorRel",
- newRootRel,
- false,
- SqlExplainLevel.EXPPLAN_ATTRIBUTES));
- }
-
- if (!mapCorVarToCorRel.isEmpty()) {
- newRootRel = decorrelator.decorrelate(newRootRel);
- }
-
- return newRootRel;
+ return RelDecorrelator.decorrelateQuery(rootRel);
}
/**
@@ -3380,14 +3273,6 @@ public class SqlToRelConverter {
selectList,
fieldNameList);
- Set<String> correlatedVariables =
- RelOptUtil.getVariablesUsed(projRel);
-
- // Associate the correlated variables with the new project rel.
- for (String correl : correlatedVariables) {
- mapCorrelToRefRel.put(correl, projRel);
- }
-
joinList.set(i, projRel);
}
}
@@ -3478,9 +3363,6 @@ public class SqlToRelConverter {
fieldNames = SqlValidatorUtil.uniquify(fieldNames);
RelNode inputRel = bb.root;
- Set<String> correlatedVariablesBefore =
- RelOptUtil.getVariablesUsed(inputRel);
-
bb.setRoot(
CalcRel.createProject(bb.root, exprs, fieldNames),
false);
@@ -3491,14 +3373,6 @@ public class SqlToRelConverter {
bb.columnMonotonicities.add(
selectItem.getMonotonicity(bb.scope));
}
-
- Set<String> correlatedVariables = RelOptUtil.getVariablesUsed(bb.root);
- correlatedVariables.removeAll(correlatedVariablesBefore);
-
- // Associate the correlated variables with the new project rel.
- for (String correl : correlatedVariables) {
- mapCorrelToRefRel.put(correl, bb.root);
- }
}
/**
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/3055cc32/core/src/test/java/net/hydromatic/optiq/test/OptiqAssert.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/net/hydromatic/optiq/test/OptiqAssert.java b/core/src/test/java/net/hydromatic/optiq/test/OptiqAssert.java
index b236144..6841c81 100644
--- a/core/src/test/java/net/hydromatic/optiq/test/OptiqAssert.java
+++ b/core/src/test/java/net/hydromatic/optiq/test/OptiqAssert.java
@@ -119,14 +119,9 @@ public class OptiqAssert {
return NopAssertQuery.of(sql);
}
- @Override
- public void connectThrows(String message) {
- // nothing
- }
-
- @Override
- public void connectThrows(Function1<Throwable, Void> exceptionChecker) {
- // nothing
+ @Override public AssertThat connectThrows(
+ Function1<Throwable, Void> exceptionChecker) {
+ return this;
}
@Override
@@ -761,13 +756,13 @@ public class OptiqAssert {
/** Asserts that there is an exception with the given message while
* creating a connection. */
- public void connectThrows(String message) {
- connectThrows(checkException(message));
+ public AssertThat connectThrows(String message) {
+ return connectThrows(checkException(message));
}
/** Asserts that there is an exception that matches the given predicate
* while creating a connection. */
- public void connectThrows(
+ public AssertThat connectThrows(
Function1<Throwable, Void> exceptionChecker) {
Throwable throwable;
try {
@@ -782,6 +777,7 @@ public class OptiqAssert {
throwable = e;
}
exceptionChecker.apply(throwable);
+ return this;
}
/** Creates a {@link OptiqConnection} and executes a callback. */
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/3055cc32/core/src/test/resources/mysql-foodmart-model.json
----------------------------------------------------------------------
diff --git a/core/src/test/resources/mysql-foodmart-model.json b/core/src/test/resources/mysql-foodmart-model.json
new file mode 100644
index 0000000..7c420ff
--- /dev/null
+++ b/core/src/test/resources/mysql-foodmart-model.json
@@ -0,0 +1,15 @@
+{
+ version: '1.0',
+ defaultSchema: 'foodmart',
+ schemas: [
+ {
+ type: 'jdbc',
+ name: 'foodmart',
+ jdbcUser: 'foodmart',
+ jdbcPassword: 'foodmart',
+ jdbcUrl: 'jdbc:mysql://localhost',
+ jdbcCatalog: 'foodmart',
+ jdbcSchema: null
+ }
+ ]
+}