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/07/03 06:56:15 UTC

[1/2] git commit: [OPTIQ-327] Rules should use base class to find rule match & use factory for object creation

Repository: incubator-optiq
Updated Branches:
  refs/heads/master 0bf85206b -> c34c14487


[OPTIQ-327] Rules should use base class to find rule match & use factory for object creation


Project: http://git-wip-us.apache.org/repos/asf/incubator-optiq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-optiq/commit/e5188ec8
Tree: http://git-wip-us.apache.org/repos/asf/incubator-optiq/tree/e5188ec8
Diff: http://git-wip-us.apache.org/repos/asf/incubator-optiq/diff/e5188ec8

Branch: refs/heads/master
Commit: e5188ec851e2513f7cd915b7917d605071567426
Parents: 0bf8520
Author: Julian Hyde <ju...@gmail.com>
Authored: Wed Jul 2 16:36:38 2014 -0700
Committer: Julian Hyde <ju...@gmail.com>
Committed: Wed Jul 2 21:30:07 2014 -0700

----------------------------------------------------------------------
 .../hydromatic/optiq/impl/jdbc/JdbcRules.java   |  3 +-
 .../hydromatic/optiq/rules/java/JavaRules.java  |  3 +-
 .../java/org/eigenbase/rel/CorrelatorRel.java   |  2 +-
 .../main/java/org/eigenbase/rel/JoinRel.java    | 26 ++-----
 .../java/org/eigenbase/rel/JoinRelBase.java     | 19 ++++-
 .../java/org/eigenbase/rel/RelFactories.java    | 53 ++++++++++++-
 .../org/eigenbase/rel/RelImplementorImpl.java   |  2 +-
 .../rel/rules/AddRedundantSemiJoinRule.java     | 23 +++---
 .../rel/rules/ConvertMultiJoinRule.java         | 59 +++++++-------
 .../rel/rules/ExtractJoinFilterRule.java        | 38 +++++----
 .../org/eigenbase/rel/rules/LoptJoinTree.java   |  8 +-
 .../rel/rules/LoptOptimizeJoinRule.java         | 28 +++----
 .../rel/rules/PullUpProjectsAboveJoinRule.java  |  6 +-
 .../rel/rules/PushFilterPastJoinRule.java       | 22 +++---
 .../rel/rules/PushJoinThroughJoinRule.java      | 33 ++++----
 .../rel/rules/PushJoinThroughUnionRule.java     | 38 ++++-----
 .../rel/rules/PushProjectPastJoinRule.java      | 37 ++++-----
 .../rel/rules/PushSemiJoinPastJoinRule.java     | 58 +++++++-------
 .../rel/rules/ReduceExpressionsRule.java        | 12 +--
 .../rel/rules/RemoveDistinctAggregateRule.java  | 82 ++++++++++----------
 .../org/eigenbase/rel/rules/SemiJoinRel.java    |  2 +-
 .../org/eigenbase/rel/rules/SwapJoinRule.java   |  2 +-
 .../org/eigenbase/sql2rel/RelFieldTrimmer.java  |  2 +-
 23 files changed, 303 insertions(+), 255 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/e5188ec8/core/src/main/java/net/hydromatic/optiq/impl/jdbc/JdbcRules.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/impl/jdbc/JdbcRules.java b/core/src/main/java/net/hydromatic/optiq/impl/jdbc/JdbcRules.java
index a98d427..9009dad 100644
--- a/core/src/main/java/net/hydromatic/optiq/impl/jdbc/JdbcRules.java
+++ b/core/src/main/java/net/hydromatic/optiq/impl/jdbc/JdbcRules.java
@@ -200,7 +200,8 @@ public class JdbcRules {
 
     @Override
     public JdbcJoinRel copy(RelTraitSet traitSet, RexNode conditionExpr,
-        RelNode left, RelNode right, JoinRelType joinType) {
+        RelNode left, RelNode right, JoinRelType joinType,
+        boolean semiJoinDone) {
       try {
         return new JdbcJoinRel(getCluster(), traitSet, left, right,
             conditionExpr, this.joinType, variablesStopped);

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/e5188ec8/core/src/main/java/net/hydromatic/optiq/rules/java/JavaRules.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/rules/java/JavaRules.java b/core/src/main/java/net/hydromatic/optiq/rules/java/JavaRules.java
index 3b17701..2e4a69b 100644
--- a/core/src/main/java/net/hydromatic/optiq/rules/java/JavaRules.java
+++ b/core/src/main/java/net/hydromatic/optiq/rules/java/JavaRules.java
@@ -157,7 +157,8 @@ public class JavaRules {
 
     @Override
     public EnumerableJoinRel copy(RelTraitSet traitSet, RexNode conditionExpr,
-        RelNode left, RelNode right, JoinRelType joinType) {
+        RelNode left, RelNode right, JoinRelType joinType,
+        boolean semiJoinDone) {
       try {
         return new EnumerableJoinRel(getCluster(), traitSet, left, right,
             conditionExpr, joinType, variablesStopped);

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/e5188ec8/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 100f1f6..20999c9 100644
--- a/core/src/main/java/org/eigenbase/rel/CorrelatorRel.java
+++ b/core/src/main/java/org/eigenbase/rel/CorrelatorRel.java
@@ -124,7 +124,7 @@ public final class CorrelatorRel extends JoinRelBase {
 
   @Override
   public CorrelatorRel copy(RelTraitSet traitSet, RexNode conditionExpr,
-      RelNode left, RelNode right, JoinRelType joinType) {
+      RelNode left, RelNode right, JoinRelType joinType, boolean semiJoinDone) {
     assert traitSet.containsIfApplicable(Convention.NONE);
     return new CorrelatorRel(
         getCluster(),

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/e5188ec8/core/src/main/java/org/eigenbase/rel/JoinRel.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/JoinRel.java b/core/src/main/java/org/eigenbase/rel/JoinRel.java
index e062d62..fe20153 100644
--- a/core/src/main/java/org/eigenbase/rel/JoinRel.java
+++ b/core/src/main/java/org/eigenbase/rel/JoinRel.java
@@ -137,17 +137,17 @@ public final class JoinRel extends JoinRelBase {
 
   @Override
   public JoinRel copy(RelTraitSet traitSet, RexNode conditionExpr, RelNode left,
-      RelNode right, JoinRelType joinType) {
+      RelNode right, JoinRelType joinType, boolean semiJoinDone) {
     assert traitSet.containsIfApplicable(Convention.NONE);
     return new JoinRel(
         getCluster(),
         left,
         right,
         conditionExpr,
-        this.joinType,
+        joinType,
         this.variablesStopped,
-        this.semiJoinDone,
-        systemFieldList);
+        semiJoinDone,
+        this.systemFieldList);
   }
 
   @Override
@@ -156,23 +156,13 @@ public final class JoinRel extends JoinRelBase {
   }
 
   public RelWriter explainTerms(RelWriter pw) {
-    // NOTE jvs 14-Mar-2006: Do it this way so that semijoin state
-    // don't clutter things up in optimizers that don't use semijoins
-    if (!semiJoinDone) {
-      return super.explainTerms(pw);
-    }
+    // Don't ever print semiJoinDone=false. This way, we
+    // don't clutter things up in optimizers that don't use semi-joins.
     return super.explainTerms(pw)
-        .item("semiJoinDone", semiJoinDone);
+        .itemIf("semiJoinDone", semiJoinDone, semiJoinDone);
   }
 
-  /**
-   * Returns whether this JoinRel has already spawned a {@link
-   * org.eigenbase.rel.rules.SemiJoinRel} via {@link
-   * org.eigenbase.rel.rules.AddRedundantSemiJoinRule}.
-   *
-   * @return whether this join has already spawned a semi join
-   */
-  public boolean isSemiJoinDone() {
+  @Override public boolean isSemiJoinDone() {
     return semiJoinDone;
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/e5188ec8/core/src/main/java/org/eigenbase/rel/JoinRelBase.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/JoinRelBase.java b/core/src/main/java/org/eigenbase/rel/JoinRelBase.java
index 2aff371..799b2e1 100644
--- a/core/src/main/java/org/eigenbase/rel/JoinRelBase.java
+++ b/core/src/main/java/org/eigenbase/rel/JoinRelBase.java
@@ -220,6 +220,19 @@ public abstract class JoinRelBase extends AbstractRelNode {
   }
 
   /**
+   * Returns whether this JoinRel has already spawned a
+   * {@link org.eigenbase.rel.rules.SemiJoinRel} via
+   * {@link org.eigenbase.rel.rules.AddRedundantSemiJoinRule}.
+   *
+   * <p>The base implementation returns false.</p>
+   *
+   * @return whether this join has already spawned a semi join
+   */
+  public boolean isSemiJoinDone() {
+    return false;
+  }
+
+  /**
    * Returns a list of system fields that will be prefixed to
    * output row type.
    *
@@ -348,7 +361,7 @@ public abstract class JoinRelBase extends AbstractRelNode {
   public final JoinRelBase copy(RelTraitSet traitSet, List<RelNode> inputs) {
     assert inputs.size() == 2;
     return copy(traitSet, getCondition(), inputs.get(0), inputs.get(1),
-        joinType);
+        joinType, isSemiJoinDone());
   }
 
   /**
@@ -361,10 +374,12 @@ public abstract class JoinRelBase extends AbstractRelNode {
    * @param left          Left input
    * @param right         Right input
    * @param joinType      Join type
+   * @param semiJoinDone  Whether this join has been translated to a
+   *                      semi-join
    * @return Copy of this join
    */
   public abstract JoinRelBase copy(RelTraitSet traitSet, RexNode conditionExpr,
-      RelNode left, RelNode right, JoinRelType joinType);
+      RelNode left, RelNode right, JoinRelType joinType, boolean semiJoinDone);
 }
 
 // End JoinRelBase.java

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/e5188ec8/core/src/main/java/org/eigenbase/rel/RelFactories.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/RelFactories.java b/core/src/main/java/org/eigenbase/rel/RelFactories.java
index d664d46..155fd5d 100644
--- a/core/src/main/java/org/eigenbase/rel/RelFactories.java
+++ b/core/src/main/java/org/eigenbase/rel/RelFactories.java
@@ -20,18 +20,24 @@ package org.eigenbase.rel;
 
 import java.util.AbstractList;
 import java.util.List;
+import java.util.Set;
 
+import org.eigenbase.relopt.RelOptCluster;
+import org.eigenbase.reltype.RelDataTypeField;
 import org.eigenbase.rex.RexNode;
 
+import com.google.common.collect.ImmutableList;
+
 /**
  * Contains factory interface and default implementation for creating various
  * rel nodes.
  */
 public class RelFactories {
-
   public static final ProjectFactory DEFAULT_PROJECT_FACTORY =
       new ProjectFactoryImpl();
 
+  public static final JoinFactory DEFAULT_JOIN_FACTORY = new JoinFactoryImpl();
+
   private RelFactories() {
   }
 
@@ -60,11 +66,48 @@ public class RelFactories {
   }
 
   /**
+   * Can create a {@link org.eigenbase.rel.JoinRelBase} of the appropriate type
+   * for this rule's calling convention.
+   */
+  public interface JoinFactory {
+    /**
+     * Creates a join.
+     *
+     * @param left             Left input
+     * @param right            Right input
+     * @param condition        Join condition
+     * @param joinType         Join type
+     * @param variablesStopped Set of names of variables which are set by the
+     *                         LHS and used by the RHS and are not available to
+     *                         nodes above this JoinRel in the tree
+     * @param semiJoinDone     Whether this join has been translated to a
+     *                         semi-join
+     */
+    RelNode createJoin(RelNode left, RelNode right, RexNode condition,
+        JoinRelType joinType, Set<String> variablesStopped,
+        boolean semiJoinDone);
+  }
+
+  /**
+   * Implementation of {@link JoinFactory} that returns vanilla
+   * {@link JoinRel}.
+   */
+  private static class JoinFactoryImpl implements JoinFactory {
+    public RelNode createJoin(RelNode left, RelNode right, RexNode condition,
+        JoinRelType joinType, Set<String> variablesStopped,
+        boolean semiJoinDone) {
+      final RelOptCluster cluster = left.getCluster();
+      return new JoinRel(cluster, left, right, condition, joinType,
+          variablesStopped, semiJoinDone, ImmutableList.<RelDataTypeField>of());
+    }
+  }
+
+  /**
    * Creates a relational expression that projects the given fields of the
    * input.
-   * <p>
-   * Optimizes if the fields are the identity projection.
-   * </p>
+   *
+   * <p>Optimizes if the fields are the identity projection.
+   *
    * @param factory
    *          ProjectFactory
    * @param child
@@ -104,3 +147,5 @@ public class RelFactories {
   }
 
 }
+
+// End RelFactories.java

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/e5188ec8/core/src/main/java/org/eigenbase/rel/RelImplementorImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/RelImplementorImpl.java b/core/src/main/java/org/eigenbase/rel/RelImplementorImpl.java
index a854c51..ac40c90 100644
--- a/core/src/main/java/org/eigenbase/rel/RelImplementorImpl.java
+++ b/core/src/main/java/org/eigenbase/rel/RelImplementorImpl.java
@@ -106,7 +106,7 @@ public class RelImplementorImpl implements RelImplementor {
       RelNode rel,
       int offset,
       int[] offsets) {
-    if (rel instanceof JoinRel) {
+    if (rel instanceof JoinRelBase) {
       // no variable here -- go deeper
       List<RelNode> inputs = rel.getInputs();
       for (RelNode input : inputs) {

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/e5188ec8/core/src/main/java/org/eigenbase/rel/rules/AddRedundantSemiJoinRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/rules/AddRedundantSemiJoinRule.java b/core/src/main/java/org/eigenbase/rel/rules/AddRedundantSemiJoinRule.java
index 10cf24e..b3c7a0a 100644
--- a/core/src/main/java/org/eigenbase/rel/rules/AddRedundantSemiJoinRule.java
+++ b/core/src/main/java/org/eigenbase/rel/rules/AddRedundantSemiJoinRule.java
@@ -23,27 +23,30 @@ import org.eigenbase.rel.*;
 import org.eigenbase.relopt.*;
 
 /**
- * Rule to add a semijoin into a joinrel. Transformation is as follows:
+ * Rule to add a semi-join into a join. Transformation is as follows:
  *
  * <p>JoinRel(X, Y) &rarr; JoinRel(SemiJoinRel(X, Y), Y)
+ *
+ * <p>The constructor is parameterized to allow any sub-class of
+ * {@link JoinRelBase}, not just {@link JoinRel}.</p>
  */
 public class AddRedundantSemiJoinRule extends RelOptRule {
   public static final AddRedundantSemiJoinRule INSTANCE =
-      new AddRedundantSemiJoinRule();
+      new AddRedundantSemiJoinRule(JoinRel.class);
 
   //~ Constructors -----------------------------------------------------------
 
   /**
    * Creates an AddRedundantSemiJoinRule.
    */
-  private AddRedundantSemiJoinRule() {
-    super(operand(JoinRel.class, any()));
+  private AddRedundantSemiJoinRule(Class<? extends JoinRelBase> clazz) {
+    super(operand(clazz, any()));
   }
 
   //~ Methods ----------------------------------------------------------------
 
   public void onMatch(RelOptRuleCall call) {
-    JoinRel origJoinRel = call.rel(0);
+    JoinRelBase origJoinRel = call.rel(0);
     if (origJoinRel.isSemiJoinDone()) {
       return;
     }
@@ -76,15 +79,13 @@ public class AddRedundantSemiJoinRule extends RelOptRule {
             rightKeys);
 
     RelNode newJoinRel =
-        new JoinRel(
-            origJoinRel.getCluster(),
+        origJoinRel.copy(
+            origJoinRel.getTraitSet(),
+            origJoinRel.getCondition(),
             semiJoin,
             origJoinRel.getRight(),
-            origJoinRel.getCondition(),
             JoinRelType.INNER,
-            Collections.<String>emptySet(),
-            true,
-            origJoinRel.getSystemFieldList());
+            true);
 
     call.transformTo(newJoinRel);
   }

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/e5188ec8/core/src/main/java/org/eigenbase/rel/rules/ConvertMultiJoinRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/rules/ConvertMultiJoinRule.java b/core/src/main/java/org/eigenbase/rel/rules/ConvertMultiJoinRule.java
index f43dc1e..d661851 100644
--- a/core/src/main/java/org/eigenbase/rel/rules/ConvertMultiJoinRule.java
+++ b/core/src/main/java/org/eigenbase/rel/rules/ConvertMultiJoinRule.java
@@ -31,9 +31,9 @@ import org.eigenbase.util.Pair;
  * input in an outer join, i.e., either input in a full outer join, the right
  * hand side of a left outer join, or the left hand side of a right outer join.
  *
- * <p>Join conditions are also pulled up from the inputs into the topmost {@link
- * MultiJoinRel}, unless the input corresponds to a null generating input in an
- * outer join,
+ * <p>Join conditions are also pulled up from the inputs into the topmost
+ * {@link MultiJoinRel},
+ * unless the input corresponds to a null generating input in an outer join,
  *
  * <p>Outer join information is also stored in the {@link MultiJoinRel}. A
  * boolean flag indicates if the join is a full outer join, and in the case of
@@ -62,20 +62,22 @@ import org.eigenbase.util.Pair;
  *      inner MultiJoinRel and right outer join on input#0 in the second inner
  *      MultiJoinRel
  * </pre>
+ *
+ * <p>The constructor is parameterized to allow any sub-class of
+ * {@link JoinRelBase}, not just {@link JoinRel}.</p>
  */
 public class ConvertMultiJoinRule extends RelOptRule {
   public static final ConvertMultiJoinRule INSTANCE =
-      new ConvertMultiJoinRule();
+      new ConvertMultiJoinRule(JoinRel.class);
 
   //~ Constructors -----------------------------------------------------------
 
   /**
    * Creates a ConvertMultiJoinRule.
    */
-  private ConvertMultiJoinRule() {
+  public ConvertMultiJoinRule(Class<? extends JoinRelBase> clazz) {
     super(
-        operand(
-            JoinRel.class,
+        operand(clazz,
             operand(RelNode.class, any()),
             operand(RelNode.class, any())));
   }
@@ -83,10 +85,10 @@ public class ConvertMultiJoinRule extends RelOptRule {
   //~ Methods ----------------------------------------------------------------
 
   public void onMatch(RelOptRuleCall call) {
-    JoinRel origJoinRel = call.rel(0);
+    final JoinRelBase origJoin = call.rel(0);
 
-    RelNode left = call.rel(1);
-    RelNode right = call.rel(2);
+    final RelNode left = call.rel(1);
+    final RelNode right = call.rel(2);
 
     // combine the children MultiJoinRel inputs into an array of inputs
     // for the new MultiJoinRel
@@ -94,7 +96,7 @@ public class ConvertMultiJoinRule extends RelOptRule {
     List<int[]> joinFieldRefCountsList = new ArrayList<int[]>();
     List<RelNode> newInputs =
         combineInputs(
-            origJoinRel,
+            origJoin,
             left,
             right,
             projFieldsList,
@@ -106,7 +108,7 @@ public class ConvertMultiJoinRule extends RelOptRule {
     final List<Pair<JoinRelType, RexNode>> joinSpecs =
         new ArrayList<Pair<JoinRelType, RexNode>>();
     combineOuterJoins(
-        origJoinRel,
+        origJoin,
         newInputs,
         left,
         right,
@@ -118,29 +120,28 @@ public class ConvertMultiJoinRule extends RelOptRule {
     // pull up the join filters from the children MultiJoinRels and
     // combine them with the join filter associated with this JoinRel to
     // form the join filter for the new MultiJoinRel
-    RexNode newJoinFilter = combineJoinFilters(origJoinRel, left, right);
+    RexNode newJoinFilter = combineJoinFilters(origJoin, left, right);
 
     // add on the join field reference counts for the join condition
     // associated with this JoinRel
     Map<Integer, int[]> newJoinFieldRefCountsMap =
         new HashMap<Integer, int[]>();
-    addOnJoinFieldRefCounts(
-        newInputs,
-        origJoinRel.getRowType().getFieldCount(),
-        origJoinRel.getCondition(),
+    addOnJoinFieldRefCounts(newInputs,
+        origJoin.getRowType().getFieldCount(),
+        origJoin.getCondition(),
         joinFieldRefCountsList,
         newJoinFieldRefCountsMap);
 
     RexNode newPostJoinFilter =
-        combinePostJoinFilters(origJoinRel, left, right);
+        combinePostJoinFilters(origJoin, left, right);
 
     RelNode multiJoin =
         new MultiJoinRel(
-            origJoinRel.getCluster(),
+            origJoin.getCluster(),
             newInputs,
             newJoinFilter,
-            origJoinRel.getRowType(),
-            origJoinRel.getJoinType() == JoinRelType.FULL,
+            origJoin.getRowType(),
+            origJoin.getJoinType() == JoinRelType.FULL,
             newOuterJoinConds,
             joinTypes,
             projFieldsList,
@@ -163,7 +164,7 @@ public class ConvertMultiJoinRule extends RelOptRule {
    * @return combined left and right inputs in an array
    */
   private List<RelNode> combineInputs(
-      JoinRel join,
+      JoinRelBase join,
       RelNode left,
       RelNode right,
       List<BitSet> projFieldsList,
@@ -245,7 +246,7 @@ public class ConvertMultiJoinRule extends RelOptRule {
    *                       copied
    */
   private void combineOuterJoins(
-      JoinRel joinRel,
+      JoinRelBase joinRel,
       List<RelNode> combinedInputs,
       RelNode left,
       RelNode right,
@@ -361,12 +362,12 @@ public class ConvertMultiJoinRule extends RelOptRule {
    * outer join
    *
    * @param joinRel join rel
-   * @param left    left child of the joinrel
-   * @param right   right child of the joinrel
-   * @return combined join filters AND'd together
+   * @param left    left child of the join
+   * @param right   right child of the join
+   * @return combined join filters AND-ed together
    */
   private RexNode combineJoinFilters(
-      JoinRel joinRel,
+      JoinRelBase joinRel,
       RelNode left,
       RelNode right) {
     RexBuilder rexBuilder = joinRel.getCluster().getRexBuilder();
@@ -432,7 +433,7 @@ public class ConvertMultiJoinRule extends RelOptRule {
    * @return the adjusted right filter
    */
   private RexNode shiftRightFilter(
-      JoinRel joinRel,
+      JoinRelBase joinRel,
       RelNode left,
       MultiJoinRel right,
       RexNode rightFilter) {
@@ -517,7 +518,7 @@ public class ConvertMultiJoinRule extends RelOptRule {
    * @return combined post-join filters AND'd together
    */
   private RexNode combinePostJoinFilters(
-      JoinRel joinRel,
+      JoinRelBase joinRel,
       RelNode left,
       RelNode right) {
     RexNode rightPostJoinFilter = null;

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/e5188ec8/core/src/main/java/org/eigenbase/rel/rules/ExtractJoinFilterRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/rules/ExtractJoinFilterRule.java b/core/src/main/java/org/eigenbase/rel/rules/ExtractJoinFilterRule.java
index 5653a76..478f1b7 100644
--- a/core/src/main/java/org/eigenbase/rel/rules/ExtractJoinFilterRule.java
+++ b/core/src/main/java/org/eigenbase/rel/rules/ExtractJoinFilterRule.java
@@ -17,11 +17,8 @@
 */
 package org.eigenbase.rel.rules;
 
-import java.util.*;
-
 import org.eigenbase.rel.*;
 import org.eigenbase.relopt.*;
-import org.eigenbase.reltype.RelDataTypeField;
 
 /**
  * Rule to convert an {@link JoinRel inner join} to a {@link FilterRel filter}
@@ -30,37 +27,40 @@ import org.eigenbase.reltype.RelDataTypeField;
  * <p>One benefit of this transformation is that after it, the join condition
  * can be combined with conditions and expressions above the join. It also makes
  * the <code>FennelCartesianJoinRule</code> applicable.
+ *
+ * <p>The constructor is parameterized to allow any sub-class of
+ * {@link JoinRelBase}, not just {@link JoinRel}.</p>
  */
 public final class ExtractJoinFilterRule extends RelOptRule {
   //~ Static fields/initializers ---------------------------------------------
 
   /** The singleton. */
   public static final ExtractJoinFilterRule INSTANCE =
-      new ExtractJoinFilterRule();
+      new ExtractJoinFilterRule(JoinRel.class);
 
   //~ Constructors -----------------------------------------------------------
 
   /**
    * Creates an ExtractJoinFilterRule.
    */
-  private ExtractJoinFilterRule() {
-    super(operand(JoinRel.class, any()));
+  public ExtractJoinFilterRule(Class<? extends JoinRelBase> clazz) {
+    super(operand(clazz, any()));
   }
 
   //~ Methods ----------------------------------------------------------------
 
   public void onMatch(RelOptRuleCall call) {
-    JoinRel joinRel = call.rel(0);
+    final JoinRelBase join = call.rel(0);
 
-    if (joinRel.getJoinType() != JoinRelType.INNER) {
+    if (join.getJoinType() != JoinRelType.INNER) {
       return;
     }
 
-    if (joinRel.getCondition().isAlwaysTrue()) {
+    if (join.getCondition().isAlwaysTrue()) {
       return;
     }
 
-    if (!joinRel.getSystemFieldList().isEmpty()) {
+    if (!join.getSystemFieldList().isEmpty()) {
       // FIXME Enable this rule for joins with system fields
       return;
     }
@@ -69,20 +69,18 @@ public final class ExtractJoinFilterRule extends RelOptRule {
     // preserve attribute semiJoinDone here.
 
     RelNode cartesianJoinRel =
-        new JoinRel(
-            joinRel.getCluster(),
-            joinRel.getLeft(),
-            joinRel.getRight(),
-            joinRel.getCluster().getRexBuilder().makeLiteral(true),
-            joinRel.getJoinType(),
-            Collections.<String>emptySet(),
-            joinRel.isSemiJoinDone(),
-            Collections.<RelDataTypeField>emptyList());
+        join.copy(
+            join.getTraitSet(),
+            join.getCluster().getRexBuilder().makeLiteral(true),
+            join.getLeft(),
+            join.getRight(),
+            join.getJoinType(),
+            join.isSemiJoinDone());
 
     RelNode filterRel =
         CalcRel.createFilter(
             cartesianJoinRel,
-            joinRel.getCondition());
+            join.getCondition());
 
     call.transformTo(filterRel);
   }

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/e5188ec8/core/src/main/java/org/eigenbase/rel/rules/LoptJoinTree.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/rules/LoptJoinTree.java b/core/src/main/java/org/eigenbase/rel/rules/LoptJoinTree.java
index fffe59e..a274ab9 100644
--- a/core/src/main/java/org/eigenbase/rel/rules/LoptJoinTree.java
+++ b/core/src/main/java/org/eigenbase/rel/rules/LoptJoinTree.java
@@ -22,8 +22,8 @@ import java.util.*;
 import org.eigenbase.rel.*;
 
 /**
- * Utility class used to store a {@link JoinRel} tree and the factors that make
- * up the tree.
+ * Utility class used to store a {@link JoinRelBase} tree and the factors that
+ * make up the tree.
  *
  * <p>Because {@link RelNode}s can be duplicated in a query
  * when you have a self-join, factor ids are needed to distinguish between the
@@ -112,14 +112,14 @@ public class LoptJoinTree {
 
   public LoptJoinTree getLeft() {
     return new LoptJoinTree(
-        ((JoinRel) joinTree).getLeft(),
+        ((JoinRelBase) joinTree).getLeft(),
         factorTree.getLeft(),
         factorTree.getLeft().getParent().isRemovableSelfJoin());
   }
 
   public LoptJoinTree getRight() {
     return new LoptJoinTree(
-        ((JoinRel) joinTree).getRight(),
+        ((JoinRelBase) joinTree).getRight(),
         factorTree.getRight(),
         factorTree.getRight().getParent().isRemovableSelfJoin());
   }

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/e5188ec8/core/src/main/java/org/eigenbase/rel/rules/LoptOptimizeJoinRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/rules/LoptOptimizeJoinRule.java b/core/src/main/java/org/eigenbase/rel/rules/LoptOptimizeJoinRule.java
index 46115cb..77437c1 100644
--- a/core/src/main/java/org/eigenbase/rel/rules/LoptOptimizeJoinRule.java
+++ b/core/src/main/java/org/eigenbase/rel/rules/LoptOptimizeJoinRule.java
@@ -30,6 +30,7 @@ import org.eigenbase.util.mapping.IntPair;
 
 import net.hydromatic.optiq.util.BitSets;
 
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
 
 /**
@@ -40,11 +41,14 @@ import com.google.common.collect.Lists;
  */
 public class LoptOptimizeJoinRule extends RelOptRule {
   public static final LoptOptimizeJoinRule INSTANCE =
-      new LoptOptimizeJoinRule();
+      new LoptOptimizeJoinRule(RelFactories.DEFAULT_JOIN_FACTORY);
+
+  private final RelFactories.JoinFactory joinFactory;
 
   /** Creates a LoptOptimizeJoinRule. */
-  private LoptOptimizeJoinRule() {
+  public LoptOptimizeJoinRule(RelFactories.JoinFactory joinFactory) {
     super(operand(MultiJoinRel.class, any()));
+    this.joinFactory = joinFactory;
   }
 
   //~ Methods ----------------------------------------------------------------
@@ -802,8 +806,8 @@ public class LoptOptimizeJoinRule extends RelOptRule {
     // full outer joins were already optimized in a prior instantiation
     // of this rule; therefore we should never see a join input that's
     // a full outer join
-    if (rel instanceof JoinRel) {
-      assert ((JoinRel) rel).getJoinType() != JoinRelType.FULL;
+    if (rel instanceof JoinRelBase) {
+      assert ((JoinRelBase) rel).getJoinType() != JoinRelType.FULL;
       return true;
     } else {
       return false;
@@ -949,7 +953,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
     // the cost of each JoinRel that appears above that RelNode.
     int width = tree.getRowType().getFieldCount();
     if (isJoinTree(tree)) {
-      JoinRel joinRel = (JoinRel) tree;
+      JoinRelBase joinRel = (JoinRelBase) tree;
       width +=
           rowWidthCost(joinRel.getLeft())
               + rowWidthCost(joinRel.getRight());
@@ -990,7 +994,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
     int childNo = -1;
     LoptJoinTree left = joinTree.getLeft();
     LoptJoinTree right = joinTree.getRight();
-    JoinRel joinRel = (JoinRel) joinTree.getJoinTree();
+    JoinRelBase joinRel = (JoinRelBase) joinTree.getJoinTree();
     JoinRelType joinType = joinRel.getJoinType();
 
     // can't push factors pass self-joins because in order to later remove
@@ -1063,7 +1067,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
     // pushdown of the new factor as well as any swapping that may have
     // been done during the pushdown
     RexNode newCondition =
-        ((JoinRel) joinTree.getJoinTree()).getCondition();
+        ((JoinRelBase) joinTree.getJoinTree()).getCondition();
     newCondition =
         adjustFilter(
             multiJoin,
@@ -1734,15 +1738,13 @@ public class LoptOptimizeJoinRule extends RelOptRule {
     }
 
     RelNode joinTree =
-        new JoinRel(
-            multiJoin.getMultiJoinRel().getCluster(),
+        joinFactory.createJoin(
             left.getJoinTree(),
             right.getJoinTree(),
             condition,
             joinType,
-            Collections.<String>emptySet(),
-            true,
-            Collections.<RelDataTypeField>emptyList());
+            ImmutableSet.<String>of(),
+            true);
 
     // if this is a left or right outer join, and additional filters can
     // be applied to the resulting join, then they need to be applied
@@ -1964,7 +1966,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
    *
    * @return true if the join is removable
    */
-  public static boolean isRemovableSelfJoin(JoinRel joinRel) {
+  public static boolean isRemovableSelfJoin(JoinRelBase joinRel) {
     final RelNode left = joinRel.getLeft();
     final RelNode right = joinRel.getRight();
 

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/e5188ec8/core/src/main/java/org/eigenbase/rel/rules/PullUpProjectsAboveJoinRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/rules/PullUpProjectsAboveJoinRule.java b/core/src/main/java/org/eigenbase/rel/rules/PullUpProjectsAboveJoinRule.java
index 67f979b..792598a 100644
--- a/core/src/main/java/org/eigenbase/rel/rules/PullUpProjectsAboveJoinRule.java
+++ b/core/src/main/java/org/eigenbase/rel/rules/PullUpProjectsAboveJoinRule.java
@@ -189,8 +189,10 @@ public class PullUpProjectsAboveJoinRule extends RelOptRule {
     RexNode newCondition =
         mergedProgram.expandLocalRef(
             mergedProgram.getCondition());
-    JoinRelBase newJoinRel = joinRel.copy(joinRel.getTraitSet(), newCondition,
-            leftJoinChild, rightJoinChild, joinRel.getJoinType());
+    JoinRelBase newJoinRel =
+        joinRel.copy(joinRel.getTraitSet(), newCondition,
+            leftJoinChild, rightJoinChild, joinRel.getJoinType(),
+            joinRel.isSemiJoinDone());
 
     // expand out the new projection expressions; if the join is an
     // outer join, modify the expressions to reference the join output

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/e5188ec8/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 4b91552..f9b6f06 100644
--- a/core/src/main/java/org/eigenbase/rel/rules/PushFilterPastJoinRule.java
+++ b/core/src/main/java/org/eigenbase/rel/rules/PushFilterPastJoinRule.java
@@ -34,23 +34,23 @@ public abstract class PushFilterPastJoinRule extends RelOptRule {
       new PushFilterPastJoinRule(
           operand(
               FilterRel.class,
-              operand(JoinRel.class, any())),
+              operand(JoinRelBase.class, any())),
           "PushFilterPastJoinRule:filter") {
         @Override
         public void onMatch(RelOptRuleCall call) {
           FilterRel filter = call.rel(0);
-          JoinRel join = call.rel(1);
+          JoinRelBase join = call.rel(1);
           perform(call, filter, join);
         }
       };
 
   public static final PushFilterPastJoinRule JOIN =
       new PushFilterPastJoinRule(
-          operand(JoinRel.class, any()),
+          operand(JoinRelBase.class, any()),
           "PushFilterPastJoinRule:no-filter") {
         @Override
         public void onMatch(RelOptRuleCall call) {
-          JoinRel join = call.rel(0);
+          JoinRelBase join = call.rel(0);
           perform(call, null, join);
         }
       };
@@ -169,12 +169,14 @@ public abstract class PushFilterPastJoinRule extends RelOptRule {
       joinFilter =
           RexUtil.composeConjunction(rexBuilder, joinFilters, true);
     }
-    RelNode newJoinRel = join.copy(
-      join.getCluster().traitSetOf(Convention.NONE),
-      joinFilter,
-      leftRel,
-      rightRel,
-      join.getJoinType());
+    RelNode newJoinRel =
+        join.copy(
+            join.getCluster().traitSetOf(Convention.NONE),
+            joinFilter,
+            leftRel,
+            rightRel,
+            join.getJoinType(),
+            join.isSemiJoinDone());
     call.getPlanner().onCopy(join, newJoinRel);
 
     // create a FilterRel on top of the join if needed

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/e5188ec8/core/src/main/java/org/eigenbase/rel/rules/PushJoinThroughJoinRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/rules/PushJoinThroughJoinRule.java b/core/src/main/java/org/eigenbase/rel/rules/PushJoinThroughJoinRule.java
index b29a1b6..17f4fab 100644
--- a/core/src/main/java/org/eigenbase/rel/rules/PushJoinThroughJoinRule.java
+++ b/core/src/main/java/org/eigenbase/rel/rules/PushJoinThroughJoinRule.java
@@ -51,13 +51,19 @@ import net.hydromatic.optiq.util.BitSets;
  * ({@code ON TRUE}). After the rule, each join has one condition.</p>
  */
 public class PushJoinThroughJoinRule extends RelOptRule {
-
+  /** Instance of the rule that works on logical joins only, and pushes to the
+   * right. */
   public static final RelOptRule RIGHT =
       new PushJoinThroughJoinRule(
-          "PushJoinThroughJoinRule:right", true, JoinRel.class);
+          "PushJoinThroughJoinRule:right", true, JoinRel.class,
+          RelFactories.DEFAULT_PROJECT_FACTORY);
+
+  /** Instance of the rule that works on logical joins only, and pushes to the
+   * left. */
   public static final RelOptRule LEFT =
       new PushJoinThroughJoinRule(
-          "PushJoinThroughJoinRule:left", false, JoinRel.class);
+          "PushJoinThroughJoinRule:left", false, JoinRel.class,
+          RelFactories.DEFAULT_PROJECT_FACTORY);
 
   private final boolean right;
 
@@ -66,15 +72,8 @@ public class PushJoinThroughJoinRule extends RelOptRule {
   /**
    * Creates a PushJoinThroughJoinRule.
    */
-  private PushJoinThroughJoinRule(String description, boolean right,
-      Class<? extends JoinRelBase> clazz) {
-    this(description, right, clazz, RelFactories.DEFAULT_PROJECT_FACTORY);
-  }
-
-  public PushJoinThroughJoinRule(
-      String description,
-      boolean right,
-      Class<? extends JoinRelBase> clazz, ProjectFactory pFactory) {
+  public PushJoinThroughJoinRule(String description, boolean right,
+      Class<? extends JoinRelBase> clazz, ProjectFactory projectFactory) {
     super(
         operand(
             clazz,
@@ -82,7 +81,7 @@ public class PushJoinThroughJoinRule extends RelOptRule {
             operand(RelNode.class, any())),
         description);
     this.right = right;
-    projectFactory = pFactory;
+    this.projectFactory = projectFactory;
   }
 
   @Override
@@ -168,7 +167,7 @@ public class PushJoinThroughJoinRule extends RelOptRule {
         RexUtil.composeConjunction(rexBuilder, newBottomList, false);
     final JoinRelBase newBottomJoin =
         bottomJoin.copy(bottomJoin.getTraitSet(), newBottomCondition, relA,
-            relC, bottomJoin.getJoinType());
+            relC, bottomJoin.getJoinType(), bottomJoin.isSemiJoinDone());
 
     // target: | A       | C      | B |
     // source: | A       | B | C      |
@@ -188,7 +187,7 @@ public class PushJoinThroughJoinRule extends RelOptRule {
     @SuppressWarnings("SuspiciousNameCombination")
     final JoinRelBase newTopJoin =
         topJoin.copy(topJoin.getTraitSet(), newTopCondition, newBottomJoin,
-            relB, topJoin.getJoinType());
+            relB, topJoin.getJoinType(), topJoin.isSemiJoinDone());
 
     assert !Mappings.isIdentity(topMapping);
     final RelNode newProject = RelFactories.createProject(projectFactory,
@@ -276,7 +275,7 @@ public class PushJoinThroughJoinRule extends RelOptRule {
         RexUtil.composeConjunction(rexBuilder, newBottomList, false);
     final JoinRelBase newBottomJoin =
         bottomJoin.copy(bottomJoin.getTraitSet(), newBottomCondition, relC,
-            relB, bottomJoin.getJoinType());
+            relB, bottomJoin.getJoinType(), bottomJoin.isSemiJoinDone());
 
     // target: | C      | B | A       |
     // source: | A       | B | C      |
@@ -296,7 +295,7 @@ public class PushJoinThroughJoinRule extends RelOptRule {
     @SuppressWarnings("SuspiciousNameCombination")
     final JoinRelBase newTopJoin =
         topJoin.copy(topJoin.getTraitSet(), newTopCondition, newBottomJoin,
-            relA, topJoin.getJoinType());
+            relA, topJoin.getJoinType(), topJoin.isSemiJoinDone());
 
     final RelNode newProject = RelFactories.createProject(projectFactory,
         newTopJoin, Mappings.asList(topMapping));

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/e5188ec8/core/src/main/java/org/eigenbase/rel/rules/PushJoinThroughUnionRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/rules/PushJoinThroughUnionRule.java b/core/src/main/java/org/eigenbase/rel/rules/PushJoinThroughUnionRule.java
index fdf2ba4..f056197 100644
--- a/core/src/main/java/org/eigenbase/rel/rules/PushJoinThroughUnionRule.java
+++ b/core/src/main/java/org/eigenbase/rel/rules/PushJoinThroughUnionRule.java
@@ -22,8 +22,6 @@ import java.util.*;
 import org.eigenbase.rel.*;
 import org.eigenbase.relopt.*;
 
-import com.google.common.collect.ImmutableSet;
-
 /**
  * PushJoinThroughUnionRule implements the rule for pushing a
  * {@link JoinRel} past a non-distinct {@link UnionRel}.
@@ -31,27 +29,25 @@ import com.google.common.collect.ImmutableSet;
 public class PushJoinThroughUnionRule extends RelOptRule {
   public static final PushJoinThroughUnionRule LEFT_UNION =
       new PushJoinThroughUnionRule(
-          operand(JoinRel.class,
-              operand(UnionRel.class, any()),
+          operand(JoinRelBase.class,
+              operand(UnionRelBase.class, any()),
               operand(RelNode.class, any())),
           "union on left");
 
   public static final PushJoinThroughUnionRule RIGHT_UNION =
       new PushJoinThroughUnionRule(
-          operand(JoinRel.class,
+          operand(JoinRelBase.class,
               operand(RelNode.class, any()),
-              operand(UnionRel.class, any())),
+              operand(UnionRelBase.class, any())),
           "union on right");
 
   private PushJoinThroughUnionRule(RelOptRuleOperand operand, String id) {
-    super(
-        operand,
-        "PushJoinThroughUnionRule: " + id);
+    super(operand, "PushJoinThroughUnionRule: " + id);
   }
 
   public void onMatch(RelOptRuleCall call) {
-    JoinRel joinRel = call.rel(0);
-    UnionRel unionRel;
+    final JoinRelBase join = call.rel(0);
+    final UnionRelBase unionRel;
     RelNode otherInput;
     boolean unionOnLeft;
     if (call.rel(1) instanceof UnionRel) {
@@ -66,7 +62,7 @@ public class PushJoinThroughUnionRule extends RelOptRule {
     if (!unionRel.all) {
       return;
     }
-    if (!joinRel.getVariablesStopped().isEmpty()) {
+    if (!join.getVariablesStopped().isEmpty()) {
       return;
     }
     // The UNION ALL cannot be on the null generating side
@@ -74,16 +70,15 @@ public class PushJoinThroughUnionRule extends RelOptRule {
     // rows for the other side for join keys which lack a match
     // in one or both branches of the union)
     if (unionOnLeft) {
-      if (joinRel.getJoinType().generatesNullsOnLeft()) {
+      if (join.getJoinType().generatesNullsOnLeft()) {
         return;
       }
     } else {
-      if (joinRel.getJoinType().generatesNullsOnRight()) {
+      if (join.getJoinType().generatesNullsOnRight()) {
         return;
       }
     }
     List<RelNode> newUnionInputs = new ArrayList<RelNode>();
-    RelOptCluster cluster = unionRel.getCluster();
     for (RelNode input : unionRel.getInputs()) {
       RelNode joinLeft;
       RelNode joinRight;
@@ -95,15 +90,16 @@ public class PushJoinThroughUnionRule extends RelOptRule {
         joinRight = input;
       }
       newUnionInputs.add(
-          new JoinRel(
-              cluster,
+          join.copy(
+              join.getTraitSet(),
+              join.getCondition(),
               joinLeft,
               joinRight,
-              joinRel.getCondition(),
-              joinRel.getJoinType(),
-              ImmutableSet.<String>of()));
+              join.getJoinType(),
+              join.isSemiJoinDone()));
     }
-    UnionRel newUnionRel = new UnionRel(cluster, newUnionInputs, true);
+    final SetOpRel newUnionRel =
+        unionRel.copy(unionRel.getTraitSet(), newUnionInputs, true);
     call.transformTo(newUnionRel);
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/e5188ec8/core/src/main/java/org/eigenbase/rel/rules/PushProjectPastJoinRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/rules/PushProjectPastJoinRule.java b/core/src/main/java/org/eigenbase/rel/rules/PushProjectPastJoinRule.java
index 2cfceca..54181a5 100644
--- a/core/src/main/java/org/eigenbase/rel/rules/PushProjectPastJoinRule.java
+++ b/core/src/main/java/org/eigenbase/rel/rules/PushProjectPastJoinRule.java
@@ -51,9 +51,8 @@ public class PushProjectPastJoinRule extends RelOptRule {
   private PushProjectPastJoinRule(
       PushProjector.ExprCondition preserveExprCondition) {
     super(
-        operand(
-            ProjectRel.class,
-            operand(JoinRel.class, any())));
+        operand(ProjectRel.class,
+            operand(JoinRelBase.class, any())));
     this.preserveExprCondition = preserveExprCondition;
   }
 
@@ -62,7 +61,7 @@ public class PushProjectPastJoinRule extends RelOptRule {
   // implement RelOptRule
   public void onMatch(RelOptRuleCall call) {
     ProjectRel origProj = call.rel(0);
-    JoinRel joinRel = call.rel(1);
+    final JoinRelBase join = call.rel(1);
 
     // locate all fields referenced in the projection and join condition;
     // determine which inputs are referenced in the projection and
@@ -71,8 +70,8 @@ public class PushProjectPastJoinRule extends RelOptRule {
     PushProjector pushProject =
         new PushProjector(
             origProj,
-            joinRel.getCondition(),
-            joinRel,
+            join.getCondition(),
+            join,
             preserveExprCondition);
     if (pushProject.locateAllRefs()) {
       return;
@@ -82,45 +81,43 @@ public class PushProjectPastJoinRule extends RelOptRule {
     // fields referenced on each side
     RelNode leftProjRel =
         pushProject.createProjectRefsAndExprs(
-            joinRel.getLeft(),
+            join.getLeft(),
             true,
             false);
     RelNode rightProjRel =
         pushProject.createProjectRefsAndExprs(
-            joinRel.getRight(),
+            join.getRight(),
             true,
             true);
 
     // convert the join condition to reference the projected columns
     RexNode newJoinFilter = null;
     int[] adjustments = pushProject.getAdjustments();
-    if (joinRel.getCondition() != null) {
+    if (join.getCondition() != null) {
       List<RelDataTypeField> projJoinFieldList =
           new ArrayList<RelDataTypeField>();
       projJoinFieldList.addAll(
-          joinRel.getSystemFieldList());
+          join.getSystemFieldList());
       projJoinFieldList.addAll(
           leftProjRel.getRowType().getFieldList());
       projJoinFieldList.addAll(
           rightProjRel.getRowType().getFieldList());
       newJoinFilter =
           pushProject.convertRefsAndExprs(
-              joinRel.getCondition(),
+              join.getCondition(),
               projJoinFieldList,
               adjustments);
     }
 
-    // create a new joinrel with the projected children
-    JoinRel newJoinRel =
-        new JoinRel(
-            joinRel.getCluster(),
+    // create a new join with the projected children
+    JoinRelBase newJoinRel =
+        join.copy(
+            join.getTraitSet(),
+            newJoinFilter,
             leftProjRel,
             rightProjRel,
-            newJoinFilter,
-            joinRel.getJoinType(),
-            Collections.<String>emptySet(),
-            joinRel.isSemiJoinDone(),
-            joinRel.getSystemFieldList());
+            join.getJoinType(),
+            join.isSemiJoinDone());
 
     // put the original project on top of the join, converting it to
     // reference the modified projection list

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/e5188ec8/core/src/main/java/org/eigenbase/rel/rules/PushSemiJoinPastJoinRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/rules/PushSemiJoinPastJoinRule.java b/core/src/main/java/org/eigenbase/rel/rules/PushSemiJoinPastJoinRule.java
index 2457599..26c8e8f 100644
--- a/core/src/main/java/org/eigenbase/rel/rules/PushSemiJoinPastJoinRule.java
+++ b/core/src/main/java/org/eigenbase/rel/rules/PushSemiJoinPastJoinRule.java
@@ -25,8 +25,9 @@ import org.eigenbase.reltype.*;
 import org.eigenbase.rex.*;
 
 /**
- * PushSemiJoinPastJoinRule implements the rule for pushing semijoins down in a
- * tree past a join in order to trigger other rules that will convert semijoins.
+ * PushSemiJoinPastJoinRule implements the rule for pushing semi-joins down in a
+ * tree past a join in order to trigger other rules that will convert
+ * semi-joins.
  *
  * <ul>
  * <li>SemiJoinRel(JoinRel(X, Y), Z) &rarr; JoinRel(SemiJoinRel(X, Z), Y)
@@ -35,7 +36,7 @@ import org.eigenbase.rex.*;
  *
  * <p>Whether this
  * first or second conversion is applied depends on which operands actually
- * participate in the semijoin.</p>
+ * participate in the semi-join.</p>
  */
 public class PushSemiJoinPastJoinRule extends RelOptRule {
   public static final PushSemiJoinPastJoinRule INSTANCE =
@@ -50,7 +51,7 @@ public class PushSemiJoinPastJoinRule extends RelOptRule {
     super(
         operand(
             SemiJoinRel.class,
-            some(operand(JoinRel.class, any()))));
+            some(operand(JoinRelBase.class, any()))));
   }
 
   //~ Methods ----------------------------------------------------------------
@@ -58,22 +59,25 @@ public class PushSemiJoinPastJoinRule extends RelOptRule {
   // implement RelOptRule
   public void onMatch(RelOptRuleCall call) {
     SemiJoinRel semiJoin = call.rel(0);
-    JoinRel joinRel = call.rel(1);
+    final JoinRelBase join = call.rel(1);
+    if (join instanceof SemiJoinRel) {
+      return;
+    }
     List<Integer> leftKeys = semiJoin.getLeftKeys();
     List<Integer> rightKeys = semiJoin.getRightKeys();
 
-    // X is the left child of the join below the semijoin
-    // Y is the right child of the join below the semijoin
-    // Z is the right child of the semijoin
-    int nFieldsX = joinRel.getLeft().getRowType().getFieldList().size();
-    int nFieldsY = joinRel.getRight().getRowType().getFieldList().size();
+    // X is the left child of the join below the semi-join
+    // Y is the right child of the join below the semi-join
+    // Z is the right child of the semi-join
+    int nFieldsX = join.getLeft().getRowType().getFieldList().size();
+    int nFieldsY = join.getRight().getRowType().getFieldList().size();
     int nFieldsZ = semiJoin.getRight().getRowType().getFieldList().size();
     int nTotalFields = nFieldsX + nFieldsY + nFieldsZ;
     List<RelDataTypeField> fields = new ArrayList<RelDataTypeField>();
 
     // create a list of fields for the full join result; note that
-    // we can't simply use the fields from the semijoin because the
-    // rowtype of a semijoin only includes the left hand side fields
+    // we can't simply use the fields from the semi-join because the
+    // row-type of a semi-join only includes the left hand side fields
     List<RelDataTypeField> joinFields =
         semiJoin.getRowType().getFieldList();
     for (int i = 0; i < (nFieldsX + nFieldsY); i++) {
@@ -84,8 +88,8 @@ public class PushSemiJoinPastJoinRule extends RelOptRule {
       fields.add(joinFields.get(i));
     }
 
-    // determine which operands below the semijoin are the actual
-    // Rels that participate in the semijoin
+    // determine which operands below the semi-join are the actual
+    // Rels that participate in the semi-join
     int nKeysFromX = 0;
     for (int leftKey : leftKeys) {
       if (leftKey < nFieldsX) {
@@ -94,10 +98,10 @@ public class PushSemiJoinPastJoinRule extends RelOptRule {
     }
 
     // the keys must all originate from either the left or right;
-    // otherwise, a semijoin wouldn't have been created
+    // otherwise, a semi-join wouldn't have been created
     assert (nKeysFromX == 0) || (nKeysFromX == leftKeys.size());
 
-    // need to convert the semijoin condition and possibly the keys
+    // need to convert the semi-join condition and possibly the keys
     RexNode newSemiJoinFilter;
     List<Integer> newLeftKeys;
     int[] adjustments = new int[nTotalFields];
@@ -105,7 +109,7 @@ public class PushSemiJoinPastJoinRule extends RelOptRule {
       // (X, Y, Z) --> (X, Z, Y)
       // semiJoin(X, Z)
       // pass 0 as Y's adjustment because there shouldn't be any
-      // references to Y in the semijoin filter
+      // references to Y in the semi-join filter
       setJoinAdjustments(
           adjustments,
           nFieldsX,
@@ -142,9 +146,9 @@ public class PushSemiJoinPastJoinRule extends RelOptRule {
     // create the new join
     RelNode leftSemiJoinOp;
     if (nKeysFromX > 0) {
-      leftSemiJoinOp = joinRel.getLeft();
+      leftSemiJoinOp = join.getLeft();
     } else {
-      leftSemiJoinOp = joinRel.getRight();
+      leftSemiJoinOp = join.getRight();
     }
     SemiJoinRel newSemiJoin =
         new SemiJoinRel(
@@ -159,22 +163,20 @@ public class PushSemiJoinPastJoinRule extends RelOptRule {
     RelNode rightJoinRel;
     if (nKeysFromX > 0) {
       leftJoinRel = newSemiJoin;
-      rightJoinRel = joinRel.getRight();
+      rightJoinRel = join.getRight();
     } else {
-      leftJoinRel = joinRel.getLeft();
+      leftJoinRel = join.getLeft();
       rightJoinRel = newSemiJoin;
     }
 
     RelNode newJoinRel =
-        new JoinRel(
-            joinRel.getCluster(),
+        join.copy(
+            join.getTraitSet(),
+            join.getCondition(),
             leftJoinRel,
             rightJoinRel,
-            joinRel.getCondition(),
-            joinRel.getJoinType(),
-            Collections.<String>emptySet(),
-            joinRel.isSemiJoinDone(),
-            joinRel.getSystemFieldList());
+            join.getJoinType(),
+            join.isSemiJoinDone());
 
     call.transformTo(newJoinRel);
   }

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/e5188ec8/core/src/main/java/org/eigenbase/rel/rules/ReduceExpressionsRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/rules/ReduceExpressionsRule.java b/core/src/main/java/org/eigenbase/rel/rules/ReduceExpressionsRule.java
index 4b3a393..73a2223 100644
--- a/core/src/main/java/org/eigenbase/rel/rules/ReduceExpressionsRule.java
+++ b/core/src/main/java/org/eigenbase/rel/rules/ReduceExpressionsRule.java
@@ -174,20 +174,20 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
       };
 
   public static final ReduceExpressionsRule JOIN_INSTANCE =
-      new ReduceExpressionsRule(JoinRel.class,
+      new ReduceExpressionsRule(JoinRelBase.class,
           "ReduceExpressionsRule[Join]") {
         public void onMatch(RelOptRuleCall call) {
-          JoinRel join = call.rel(0);
+          final JoinRelBase join = call.rel(0);
           List<RexNode> expList = new ArrayList<RexNode>(join.getChildExps());
           if (reduceExpressions(join, expList)) {
             call.transformTo(
-                new JoinRel(
-                    join.getCluster(),
+                join.copy(
+                    join.getTraitSet(),
+                    expList.get(0),
                     join.getLeft(),
                     join.getRight(),
-                    expList.get(0),
                     join.getJoinType(),
-                    join.getVariablesStopped()));
+                    join.isSemiJoinDone()));
 
             // New plan is absolutely better than old plan.
             call.getPlanner().setImportance(join, 0.0);

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/e5188ec8/core/src/main/java/org/eigenbase/rel/rules/RemoveDistinctAggregateRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/rules/RemoveDistinctAggregateRule.java b/core/src/main/java/org/eigenbase/rel/rules/RemoveDistinctAggregateRule.java
index 576dc02..673a453 100644
--- a/core/src/main/java/org/eigenbase/rel/rules/RemoveDistinctAggregateRule.java
+++ b/core/src/main/java/org/eigenbase/rel/rules/RemoveDistinctAggregateRule.java
@@ -37,23 +37,25 @@ import com.google.common.collect.ImmutableSet;
 public final class RemoveDistinctAggregateRule extends RelOptRule {
   //~ Static fields/initializers ---------------------------------------------
 
-  /** The singleton. */
+  /** The default instance of the rule; operates only on logical expressions. */
   public static final RemoveDistinctAggregateRule INSTANCE =
-      new RemoveDistinctAggregateRule();
+      new RemoveDistinctAggregateRule(AggregateRel.class,
+          RelFactories.DEFAULT_JOIN_FACTORY);
+
+  private final RelFactories.JoinFactory joinFactory;
 
   //~ Constructors -----------------------------------------------------------
 
-  /**
-   * Private constructor.
-   */
-  private RemoveDistinctAggregateRule() {
-    super(operand(AggregateRel.class, any()));
+  public RemoveDistinctAggregateRule(Class<? extends AggregateRel> clazz,
+      RelFactories.JoinFactory joinFactory) {
+    super(operand(clazz, any()));
+    this.joinFactory = joinFactory;
   }
 
   //~ Methods ----------------------------------------------------------------
 
   public void onMatch(RelOptRuleCall call) {
-    AggregateRel aggregate = call.rel(0);
+    final AggregateRelBase aggregate = call.rel(0);
     if (!aggregate.containsDistinctCall()) {
       return;
     }
@@ -143,12 +145,12 @@ public final class RemoveDistinctAggregateRule extends RelOptRule {
   }
 
   /**
-   * Converts an aggregrate relational expression which contains just one
+   * Converts an aggregate relational expression that contains just one
    * distinct aggregate function (or perhaps several over the same arguments)
    * and no non-distinct aggregate functions.
    */
   private RelNode convertMonopole(
-      AggregateRel aggregate,
+      AggregateRelBase aggregate,
       List<Integer> argList) {
     // For example,
     //    SELECT deptno, COUNT(DISTINCT sal), SUM(DISTINCT sal)
@@ -166,21 +168,18 @@ public final class RemoveDistinctAggregateRule extends RelOptRule {
     // Project the columns of the GROUP BY plus the arguments
     // to the agg function.
     Map<Integer, Integer> sourceOf = new HashMap<Integer, Integer>();
-    final AggregateRel distinct =
+    final AggregateRelBase distinct =
         createSelectDistinct(aggregate, argList, sourceOf);
 
     // Create an aggregate on top, with the new aggregate list.
     final List<AggregateCall> newAggCalls =
         new ArrayList<AggregateCall>(aggregate.getAggCallList());
     rewriteAggCalls(newAggCalls, argList, sourceOf);
-    AggregateRel newAggregate =
-        new AggregateRel(
-            aggregate.getCluster(),
-            distinct,
-            aggregate.getGroupSet(),
-            newAggCalls);
-
-    return newAggregate;
+    return aggregate.copy(
+        aggregate.getTraitSet(),
+        distinct,
+        aggregate.getGroupSet(),
+        newAggCalls);
   }
 
   /**
@@ -203,7 +202,7 @@ public final class RemoveDistinctAggregateRule extends RelOptRule {
    * @return Relational expression
    */
   private RelNode doRewrite(
-      AggregateRel aggregate,
+      AggregateRelBase aggregate,
       RelNode left,
       List<Integer> argList,
       List<RexInputRef> refs) {
@@ -253,13 +252,13 @@ public final class RemoveDistinctAggregateRule extends RelOptRule {
     //
     // Note that if a query contains no non-distinct aggregates, then the
     // very first join/group by is omitted.  In the example above, if
-    // MAX(age) is removed, then the subselect of "e" is not needed, and
+    // MAX(age) is removed, then the sub-select of "e" is not needed, and
     // instead the two other group by's are joined to one another.
 
     // Project the columns of the GROUP BY plus the arguments
     // to the agg function.
     Map<Integer, Integer> sourceOf = new HashMap<Integer, Integer>();
-    final AggregateRel distinct =
+    final AggregateRelBase distinct =
         createSelectDistinct(aggregate, argList, sourceOf);
 
     // Now compute the aggregate functions on top of the distinct dataset.
@@ -318,9 +317,9 @@ public final class RemoveDistinctAggregateRule extends RelOptRule {
       aggCallList.add(newAggCall);
     }
 
-    AggregateRel distinctAgg =
-        new AggregateRel(
-            aggregate.getCluster(),
+    AggregateRelBase distinctAgg =
+        aggregate.copy(
+            aggregate.getTraitSet(),
             distinct,
             aggregate.getGroupSet(),
             aggCallList);
@@ -362,14 +361,13 @@ public final class RemoveDistinctAggregateRule extends RelOptRule {
     }
 
     // Join in the new 'select distinct' relation.
-    return
-        new JoinRel(
-            aggregate.getCluster(),
-            left,
-            distinctAgg,
-            condition,
-            JoinRelType.INNER,
-            ImmutableSet.<String>of());
+    return joinFactory.createJoin(
+        left,
+        distinctAgg,
+        condition,
+        JoinRelType.INNER,
+        ImmutableSet.<String>of(),
+        false);
   }
 
   private static void rewriteAggCalls(
@@ -440,14 +438,14 @@ public final class RemoveDistinctAggregateRule extends RelOptRule {
    * column; in this case sourceOf.get(0) = 0, and sourceOf.get(1) = 2.</p>
    *
    * @param aggregate Aggregate relational expression
-   * @param argList   Ordinals of columns to distinctify
+   * @param argList   Ordinals of columns to make distinct
    * @param sourceOf  Out parameter, is populated with a map of where each
    *                  output field came from
    * @return Aggregate relational expression which projects the required
    * columns
    */
-  private static AggregateRel createSelectDistinct(
-      AggregateRel aggregate,
+  private static AggregateRelBase createSelectDistinct(
+      AggregateRelBase aggregate,
       List<Integer> argList,
       Map<Integer, Integer> sourceOf) {
     final List<Pair<RexNode, String>> projects =
@@ -471,13 +469,11 @@ public final class RemoveDistinctAggregateRule extends RelOptRule {
 
     // Get the distinct values of the GROUP BY fields and the arguments
     // to the agg functions.
-    final AggregateRel distinct =
-        new AggregateRel(
-            aggregate.getCluster(),
-            project,
-            BitSets.range(projects.size()),
-            ImmutableList.<AggregateCall>of());
-    return distinct;
+    return aggregate.copy(
+        aggregate.getTraitSet(),
+        project,
+        BitSets.range(projects.size()),
+        ImmutableList.<AggregateCall>of());
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/e5188ec8/core/src/main/java/org/eigenbase/rel/rules/SemiJoinRel.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/rules/SemiJoinRel.java b/core/src/main/java/org/eigenbase/rel/rules/SemiJoinRel.java
index 1c714b6..8dfa4fa 100644
--- a/core/src/main/java/org/eigenbase/rel/rules/SemiJoinRel.java
+++ b/core/src/main/java/org/eigenbase/rel/rules/SemiJoinRel.java
@@ -72,7 +72,7 @@ public final class SemiJoinRel extends JoinRelBase {
 
   @Override
   public SemiJoinRel copy(RelTraitSet traitSet, RexNode conditionExpr,
-      RelNode left, RelNode right, JoinRelType joinType) {
+      RelNode left, RelNode right, JoinRelType joinType, boolean semiJoinDone) {
     assert joinType == JoinRelType.INNER;
     return new SemiJoinRel(
         getCluster(),

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/e5188ec8/core/src/main/java/org/eigenbase/rel/rules/SwapJoinRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/rules/SwapJoinRule.java b/core/src/main/java/org/eigenbase/rel/rules/SwapJoinRule.java
index 0f1bb42..54e693d 100644
--- a/core/src/main/java/org/eigenbase/rel/rules/SwapJoinRule.java
+++ b/core/src/main/java/org/eigenbase/rel/rules/SwapJoinRule.java
@@ -91,7 +91,7 @@ public class SwapJoinRule extends RelOptRule {
     // that the planner tries the desired order (semijoins after swaps).
     JoinRelBase newJoin =
         join.copy(join.getTraitSet(), condition, join.getRight(),
-            join.getLeft(), joinType.swap());
+            join.getLeft(), joinType.swap(), join.isSemiJoinDone());
     final List<RexNode> exps =
         RelOptUtil.createSwappedJoinExprs(newJoin, join, true);
     return CalcRel.createProject(

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/e5188ec8/core/src/main/java/org/eigenbase/sql2rel/RelFieldTrimmer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/sql2rel/RelFieldTrimmer.java b/core/src/main/java/org/eigenbase/sql2rel/RelFieldTrimmer.java
index 22ef225..131cc97 100644
--- a/core/src/main/java/org/eigenbase/sql2rel/RelFieldTrimmer.java
+++ b/core/src/main/java/org/eigenbase/sql2rel/RelFieldTrimmer.java
@@ -575,7 +575,7 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
 
     final JoinRel newJoin =
         join.copy(join.getTraitSet(), newConditionExpr, newInputs.get(0),
-            newInputs.get(1), join.getJoinType());
+            newInputs.get(1), join.getJoinType(), join.isSemiJoinDone());
 
     return new TrimResult(newJoin, mapping);
   }


[2/2] git commit: [OPTIQ-331] Precision/Scale compatibility checks should always succeed for 'ANY' type

Posted by jh...@apache.org.
[OPTIQ-331] Precision/Scale compatibility checks should always succeed for 'ANY' type


Project: http://git-wip-us.apache.org/repos/asf/incubator-optiq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-optiq/commit/c34c1448
Tree: http://git-wip-us.apache.org/repos/asf/incubator-optiq/tree/c34c1448
Diff: http://git-wip-us.apache.org/repos/asf/incubator-optiq/diff/c34c1448

Branch: refs/heads/master
Commit: c34c144874cb9acbbafa8ff51f35a4f31cadee98
Parents: e5188ec
Author: Mehant Baid <me...@gmail.com>
Authored: Wed Jul 2 20:05:12 2014 -0700
Committer: Julian Hyde <ju...@gmail.com>
Committed: Wed Jul 2 21:38:44 2014 -0700

----------------------------------------------------------------------
 core/src/main/java/org/eigenbase/sql/type/SqlTypeName.java | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/c34c1448/core/src/main/java/org/eigenbase/sql/type/SqlTypeName.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/sql/type/SqlTypeName.java b/core/src/main/java/org/eigenbase/sql/type/SqlTypeName.java
index ae98a59..efff330 100644
--- a/core/src/main/java/org/eigenbase/sql/type/SqlTypeName.java
+++ b/core/src/main/java/org/eigenbase/sql/type/SqlTypeName.java
@@ -72,7 +72,8 @@ public enum SqlTypeName {
   VARBINARY(PrecScale.NO_NO | PrecScale.YES_NO, false, Types.VARBINARY,
       SqlTypeFamily.BINARY),
   NULL(PrecScale.NO_NO, true, Types.NULL, SqlTypeFamily.NULL),
-  ANY(PrecScale.NO_NO, true, Types.JAVA_OBJECT, SqlTypeFamily.ANY),
+  ANY(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES, true,
+      Types.JAVA_OBJECT, SqlTypeFamily.ANY),
   SYMBOL(PrecScale.NO_NO, true, Types.OTHER, null),
   MULTISET(PrecScale.NO_NO, false, Types.ARRAY, SqlTypeFamily.MULTISET),
   ARRAY(PrecScale.NO_NO, false, Types.ARRAY, SqlTypeFamily.ARRAY),