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/30 00:47:12 UTC

git commit: [OPTIQ-392] RelFieldTrimmer should use factory to create new rel nodes

Repository: incubator-optiq
Updated Branches:
  refs/heads/master e60fa76e2 -> d30a76bb1


[OPTIQ-392] RelFieldTrimmer should use factory to create new rel nodes

Add SetOpRel.kind, to distinguish between UNION, INTERSECT, MINUS (aka EXCEPT).

Close apache/incubator-optiq#9


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

Branch: refs/heads/master
Commit: d30a76bb185169556923fbf6ba621252f56f6ba4
Parents: e60fa76
Author: Ashutosh Chauhan <ha...@apache.org>
Authored: Fri Aug 29 15:16:57 2014 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Fri Aug 29 15:46:46 2014 -0700

----------------------------------------------------------------------
 .../org/eigenbase/rel/IntersectRelBase.java     |   3 +-
 .../java/org/eigenbase/rel/MinusRelBase.java    |   3 +-
 .../java/org/eigenbase/rel/RelFactories.java    |  98 +++++++++++++++++
 .../main/java/org/eigenbase/rel/SetOpRel.java   |  19 +++-
 .../org/eigenbase/rel/TableAccessRelBase.java   |  27 ++---
 .../java/org/eigenbase/rel/UnionRelBase.java    |   3 +-
 .../org/eigenbase/sql2rel/RelFieldTrimmer.java  | 108 ++++++++++---------
 7 files changed, 189 insertions(+), 72 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/d30a76bb/core/src/main/java/org/eigenbase/rel/IntersectRelBase.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/IntersectRelBase.java b/core/src/main/java/org/eigenbase/rel/IntersectRelBase.java
index 4357f4e..6f43441 100644
--- a/core/src/main/java/org/eigenbase/rel/IntersectRelBase.java
+++ b/core/src/main/java/org/eigenbase/rel/IntersectRelBase.java
@@ -22,6 +22,7 @@ import java.util.List;
 import org.eigenbase.rel.metadata.RelMetadataQuery;
 import org.eigenbase.relopt.RelOptCluster;
 import org.eigenbase.relopt.RelTraitSet;
+import org.eigenbase.sql.SqlKind;
 
 /**
  * Abstract base class for implementations of
@@ -36,7 +37,7 @@ public abstract class IntersectRelBase extends SetOpRel {
       RelTraitSet traits,
       List<RelNode> inputs,
       boolean all) {
-    super(cluster, traits, inputs, all);
+    super(cluster, traits, inputs, SqlKind.INTERSECT, all);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/d30a76bb/core/src/main/java/org/eigenbase/rel/MinusRelBase.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/MinusRelBase.java b/core/src/main/java/org/eigenbase/rel/MinusRelBase.java
index 98cde09..06039f8 100644
--- a/core/src/main/java/org/eigenbase/rel/MinusRelBase.java
+++ b/core/src/main/java/org/eigenbase/rel/MinusRelBase.java
@@ -22,6 +22,7 @@ import java.util.List;
 import org.eigenbase.rel.metadata.RelMetadataQuery;
 import org.eigenbase.relopt.RelOptCluster;
 import org.eigenbase.relopt.RelTraitSet;
+import org.eigenbase.sql.SqlKind;
 
 /**
  * Abstract base class for implementations of
@@ -33,7 +34,7 @@ public abstract class MinusRelBase extends SetOpRel {
       RelTraitSet traits,
       List<RelNode> inputs,
       boolean all) {
-    super(cluster, traits, inputs, all);
+    super(cluster, traits, inputs, SqlKind.EXCEPT, all);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/d30a76bb/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 062e405..0bb7788 100644
--- a/core/src/main/java/org/eigenbase/rel/RelFactories.java
+++ b/core/src/main/java/org/eigenbase/rel/RelFactories.java
@@ -18,13 +18,17 @@
 package org.eigenbase.rel;
 
 import java.util.AbstractList;
+import java.util.BitSet;
 import java.util.List;
 import java.util.Set;
 
+import org.eigenbase.rel.rules.SemiJoinRel;
 import org.eigenbase.relopt.RelOptCluster;
+import org.eigenbase.relopt.RelTraitSet;
 import org.eigenbase.reltype.RelDataTypeField;
 import org.eigenbase.rex.RexBuilder;
 import org.eigenbase.rex.RexNode;
+import org.eigenbase.sql.SqlKind;
 import org.eigenbase.util.mapping.Mappings;
 
 import com.google.common.collect.ImmutableList;
@@ -42,6 +46,15 @@ public class RelFactories {
 
   public static final JoinFactory DEFAULT_JOIN_FACTORY = new JoinFactoryImpl();
 
+  public static final SortFactory DEFAULT_SORT_FACTORY =
+    new SortFactoryImpl();
+
+  public static final AggregateFactory DEFAULT_AGGREGATE_FACTORY =
+    new AggregateFactoryImpl();
+
+  public static final SetOpFactory DEFAULT_SET_OP_FACTORY =
+      new SetOpFactoryImpl();
+
   private RelFactories() {
   }
 
@@ -70,6 +83,79 @@ public class RelFactories {
   }
 
   /**
+   * Can create a {@link org.eigenbase.rel.SortRel} of the appropriate type
+   * for this rule's calling convention.
+   */
+  public interface SortFactory {
+    RelNode createSort(RelTraitSet traits, RelNode child,
+        RelCollation collation, RexNode offset, RexNode fetch);
+  }
+
+  /**
+   * Implementation of {@link org.eigenbase.rel.RelFactories.SortFactory} that
+   * returns vanilla {@link SortRel}.
+   */
+  private static class SortFactoryImpl implements SortFactory {
+    public RelNode createSort(RelTraitSet traits, RelNode child,
+        RelCollation collation, RexNode offset, RexNode fetch) {
+      return new SortRel(child.getCluster(), traits, child, collation,
+          offset, fetch);
+    }
+  }
+
+  /**
+   * Can create a {@link org.eigenbase.rel.SetOpRel} for a particular kind of
+   * set operation (UNION, EXCEPT, INTERSECT) and of the appropriate type
+   * for this rule's calling convention.
+   */
+  public interface SetOpFactory {
+    RelNode createSetOp(SqlKind kind, List<RelNode> inputs, boolean all);
+  }
+
+  /**
+   * Implementation of {@link org.eigenbase.rel.RelFactories.SetOpFactory} that
+   * returns a vanilla {@link SetOpRel} for the particular kind of set
+   * operation (UNION, EXCEPT, INTERSECT).
+   */
+  private static class SetOpFactoryImpl implements SetOpFactory {
+    public RelNode createSetOp(SqlKind kind, List<RelNode> inputs,
+        boolean all) {
+      final RelOptCluster cluster = inputs.get(0).getCluster();
+      switch (kind) {
+      case UNION:
+        return new UnionRel(cluster, inputs, all);
+      case EXCEPT:
+        return new MinusRel(cluster, inputs, all);
+      case INTERSECT:
+        return new IntersectRel(cluster, inputs, all);
+      default:
+        throw new AssertionError("not a set op: " + kind);
+      }
+    }
+  }
+
+  /**
+   * Can create a {@link org.eigenbase.rel.AggregateRel} of the appropriate type
+   * for this rule's calling convention.
+   */
+  public interface AggregateFactory {
+    RelNode createAggrRelNode(RelNode child, BitSet groupSet,
+      List<AggregateCall> aggCalls);
+  }
+
+  /**
+   * Implementation of {@link org.eigenbase.rel.RelFactories.AggregateFactory} that
+   * returns vanilla {@link AggregateRel}.
+   */
+  private static class AggregateFactoryImpl implements AggregateFactory {
+
+    public RelNode createAggrRelNode(RelNode child, BitSet groupSet,
+        List<AggregateCall> aggCalls) {
+      return new AggregateRel(child.getCluster(), child, groupSet, aggCalls);
+    }
+  }
+
+  /**
    * Can create a {@link org.eigenbase.rel.FilterRel} of the appropriate type
    * for this rule's calling convention.
    */
@@ -112,6 +198,9 @@ public class RelFactories {
     RelNode createJoin(RelNode left, RelNode right, RexNode condition,
         JoinRelType joinType, Set<String> variablesStopped,
         boolean semiJoinDone);
+
+    SemiJoinRel createSemiJoinRel(RelTraitSet traitSet, RelNode left,
+      RelNode right, RexNode condition);
   }
 
   /**
@@ -126,6 +215,13 @@ public class RelFactories {
       return new JoinRel(cluster, left, right, condition, joinType,
           variablesStopped, semiJoinDone, ImmutableList.<RelDataTypeField>of());
     }
+
+    public SemiJoinRel createSemiJoinRel(RelTraitSet traitSet, RelNode left,
+        RelNode right, RexNode condition) {
+      final JoinInfo joinInfo = JoinInfo.of(left, right, condition);
+      return new SemiJoinRel(left.getCluster(), traitSet, left, right,
+        condition, joinInfo.leftKeys, joinInfo.rightKeys);
+    }
   }
 
   /**
@@ -150,10 +246,12 @@ public class RelFactories {
     final RexBuilder rexBuilder = child.getCluster().getRexBuilder();
     return factory.createProject(child,
         new AbstractList<RexNode>() {
+          @Override
           public int size() {
             return posList.size();
           }
 
+          @Override
           public RexNode get(int index) {
             final int pos = posList.get(index);
             return rexBuilder.makeInputRef(child, pos);

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/d30a76bb/core/src/main/java/org/eigenbase/rel/SetOpRel.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/SetOpRel.java b/core/src/main/java/org/eigenbase/rel/SetOpRel.java
index 5a39aea..6a650e4 100644
--- a/core/src/main/java/org/eigenbase/rel/SetOpRel.java
+++ b/core/src/main/java/org/eigenbase/rel/SetOpRel.java
@@ -20,9 +20,11 @@ import java.util.*;
 
 import org.eigenbase.relopt.*;
 import org.eigenbase.reltype.*;
+import org.eigenbase.sql.SqlKind;
 
 import net.hydromatic.linq4j.Ord;
 
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 
 /**
@@ -33,6 +35,7 @@ public abstract class SetOpRel extends AbstractRelNode {
   //~ Instance fields --------------------------------------------------------
 
   protected ImmutableList<RelNode> inputs;
+  public final SqlKind kind;
   public final boolean all;
 
   //~ Constructors -----------------------------------------------------------
@@ -44,8 +47,13 @@ public abstract class SetOpRel extends AbstractRelNode {
       RelOptCluster cluster,
       RelTraitSet traits,
       List<RelNode> inputs,
+      SqlKind kind,
       boolean all) {
     super(cluster, traits);
+    Preconditions.checkArgument(kind == SqlKind.UNION
+        || kind == SqlKind.INTERSECT
+        || kind == SqlKind.EXCEPT);
+    this.kind = kind;
     this.inputs = ImmutableList.copyOf(inputs);
     this.all = all;
   }
@@ -54,9 +62,8 @@ public abstract class SetOpRel extends AbstractRelNode {
    * Creates a SetOpRel by parsing serialized output.
    */
   protected SetOpRel(RelInput input) {
-    this(
-        input.getCluster(), input.getTraitSet(), input.getInputs(),
-        input.getBoolean("all"));
+    this(input.getCluster(), input.getTraitSet(), input.getInputs(),
+        SqlKind.UNION, input.getBoolean("all"));
   }
 
   //~ Methods ----------------------------------------------------------------
@@ -66,6 +73,7 @@ public abstract class SetOpRel extends AbstractRelNode {
       List<RelNode> inputs,
       boolean all);
 
+  @Override
   public SetOpRel copy(
       RelTraitSet traitSet,
       List<RelNode> inputs) {
@@ -87,10 +95,12 @@ public abstract class SetOpRel extends AbstractRelNode {
     return !all && columns.nextClearBit(0) >= getRowType().getFieldCount();
   }
 
+  @Override
   public List<RelNode> getInputs() {
     return inputs;
   }
 
+  @Override
   public RelWriter explainTerms(RelWriter pw) {
     super.explainTerms(pw);
     for (Ord<RelNode> ord : Ord.zip(inputs)) {
@@ -99,13 +109,16 @@ public abstract class SetOpRel extends AbstractRelNode {
     return pw.item("all", all);
   }
 
+  @Override
   protected RelDataType deriveRowType() {
     return getCluster().getTypeFactory().leastRestrictive(
         new AbstractList<RelDataType>() {
+          @Override
           public RelDataType get(int index) {
             return inputs.get(index).getRowType();
           }
 
+          @Override
           public int size() {
             return inputs.size();
           }

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/d30a76bb/core/src/main/java/org/eigenbase/rel/TableAccessRelBase.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/TableAccessRelBase.java b/core/src/main/java/org/eigenbase/rel/TableAccessRelBase.java
index 8f7901f..7532080 100644
--- a/core/src/main/java/org/eigenbase/rel/TableAccessRelBase.java
+++ b/core/src/main/java/org/eigenbase/rel/TableAccessRelBase.java
@@ -59,35 +59,34 @@ public abstract class TableAccessRelBase extends AbstractRelNode {
 
   //~ Methods ----------------------------------------------------------------
 
-  public double getRows() {
+  @Override public double getRows() {
     return table.getRowCount();
   }
 
-  public RelOptTable getTable() {
+  @Override public RelOptTable getTable() {
     return table;
   }
 
-  public List<RelCollation> getCollationList() {
+  @Override public List<RelCollation> getCollationList() {
     return table.getCollationList();
   }
 
-  @Override
-  public boolean isKey(BitSet columns) {
+  @Override public boolean isKey(BitSet columns) {
     return table.isKey(columns);
   }
 
-  public RelOptCost computeSelfCost(RelOptPlanner planner) {
+  @Override public RelOptCost computeSelfCost(RelOptPlanner planner) {
     double dRows = table.getRowCount();
     double dCpu = dRows + 1; // ensure non-zero cost
     double dIo = 0;
     return planner.getCostFactory().makeCost(dRows, dCpu, dIo);
   }
 
-  public RelDataType deriveRowType() {
+  @Override public RelDataType deriveRowType() {
     return table.getRowType();
   }
 
-  public RelWriter explainTerms(RelWriter pw) {
+  @Override public RelWriter explainTerms(RelWriter pw) {
     return super.explainTerms(pw)
         .item("table", table.getQualifiedName());
   }
@@ -108,9 +107,8 @@ public abstract class TableAccessRelBase extends AbstractRelNode {
    *                    wanted by the consumer
    * @return Relational expression that projects the desired fields
    */
-  public RelNode project(
-      BitSet fieldsUsed,
-      Set<RelDataTypeField> extraFields) {
+  public RelNode project(BitSet fieldsUsed, Set<RelDataTypeField> extraFields,
+    RelFactories.ProjectFactory projectFactory) {
     final int fieldCount = getRowType().getFieldCount();
     if (fieldsUsed.equals(BitSets.range(fieldCount))
         && extraFields.isEmpty()) {
@@ -139,12 +137,7 @@ public abstract class TableAccessRelBase extends AbstractRelNode {
       nameList.add(extraField.getName());
     }
 
-    return new ProjectRel(
-        getCluster(),
-        this,
-        exprList,
-        nameList,
-        ProjectRel.Flags.BOXED);
+    return projectFactory.createProject(this, exprList, nameList);
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/d30a76bb/core/src/main/java/org/eigenbase/rel/UnionRelBase.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/UnionRelBase.java b/core/src/main/java/org/eigenbase/rel/UnionRelBase.java
index 3635b10..4d31b71 100644
--- a/core/src/main/java/org/eigenbase/rel/UnionRelBase.java
+++ b/core/src/main/java/org/eigenbase/rel/UnionRelBase.java
@@ -20,6 +20,7 @@ import java.util.List;
 
 import org.eigenbase.rel.metadata.*;
 import org.eigenbase.relopt.*;
+import org.eigenbase.sql.SqlKind;
 
 /**
  * <code>UnionRelBase</code> is an abstract base class for implementations of
@@ -33,7 +34,7 @@ public abstract class UnionRelBase extends SetOpRel {
       RelTraitSet traits,
       List<RelNode> inputs,
       boolean all) {
-    super(cluster, traits, inputs, all);
+    super(cluster, traits, inputs, SqlKind.UNION, all);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/d30a76bb/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 14ae9be..093be8e 100644
--- a/core/src/main/java/org/eigenbase/sql2rel/RelFieldTrimmer.java
+++ b/core/src/main/java/org/eigenbase/sql2rel/RelFieldTrimmer.java
@@ -33,6 +33,7 @@ import net.hydromatic.linq4j.Ord;
 
 import net.hydromatic.optiq.util.BitSets;
 
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 
 /**
@@ -64,6 +65,12 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
   //~ Instance fields --------------------------------------------------------
 
   private final ReflectUtil.MethodDispatcher<TrimResult> trimFieldsDispatcher;
+  private final RelFactories.ProjectFactory projectFactory;
+  private final RelFactories.FilterFactory filterFactory;
+  private final RelFactories.JoinFactory joinFactory;
+  private final RelFactories.SortFactory sortFactory;
+  private final RelFactories.AggregateFactory aggregateFactory;
+  private final RelFactories.SetOpFactory setOpFactory;
 
   //~ Constructors -----------------------------------------------------------
 
@@ -73,6 +80,27 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
    * @param validator Validator
    */
   public RelFieldTrimmer(SqlValidator validator) {
+    this(validator,
+        RelFactories.DEFAULT_PROJECT_FACTORY,
+        RelFactories.DEFAULT_FILTER_FACTORY,
+        RelFactories.DEFAULT_JOIN_FACTORY,
+        RelFactories.DEFAULT_SORT_FACTORY,
+        RelFactories.DEFAULT_AGGREGATE_FACTORY,
+        RelFactories.DEFAULT_SET_OP_FACTORY);
+  }
+
+  /**
+   * Creates a RelFieldTrimmer.
+   *
+   * @param validator Validator
+   */
+  public RelFieldTrimmer(SqlValidator validator,
+    RelFactories.ProjectFactory projectFactory,
+    RelFactories.FilterFactory filterFactory,
+    RelFactories.JoinFactory joinFactory,
+    RelFactories.SortFactory sortFactory,
+    RelFactories.AggregateFactory aggregateFactory,
+    RelFactories.SetOpFactory setOpFactory) {
     Util.discard(validator); // may be useful one day
     this.trimFieldsDispatcher =
         ReflectUtil.createMethodDispatcher(
@@ -82,6 +110,12 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
             RelNode.class,
             BitSet.class,
             Set.class);
+    this.projectFactory = Preconditions.checkNotNull(projectFactory);
+    this.filterFactory = Preconditions.checkNotNull(filterFactory);
+    this.joinFactory = Preconditions.checkNotNull(joinFactory);
+    this.sortFactory = Preconditions.checkNotNull(sortFactory);
+    this.aggregateFactory = Preconditions.checkNotNull(aggregateFactory);
+    this.setOpFactory = Preconditions.checkNotNull(setOpFactory);
   }
 
   //~ Methods ----------------------------------------------------------------
@@ -167,7 +201,7 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
               : rexBuilder.makeInputRef(field.getType(), source));
     }
     RelNode project =
-        CalcRel.createProject(
+        projectFactory.createProject(
             trimResult.left, exprList, nameList);
     return new TrimResult(
         project,
@@ -305,9 +339,6 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
         RelOptUtil.permute(project.getCluster().getTypeFactory(), rowType,
             mapping);
 
-    final List<RelCollation> newCollations =
-        RexUtil.apply(inputMapping, project.getCollationList());
-
     final RelNode newProject;
     if (RemoveTrivialProjectRule.isIdentity(
         newProjectExprList,
@@ -317,16 +348,8 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
       // its child.
       newProject = newInput;
     } else {
-      newProject = new ProjectRel(
-          project.getCluster(),
-          project.getCluster().traitSetOf(
-              newCollations.isEmpty()
-                  ? RelCollationImpl.EMPTY
-                  : newCollations.get(0)),
-          newInput,
-          newProjectExprList,
-          newRowType,
-          project.getFlags());
+      newProject = projectFactory.createProject(newInput, newProjectExprList,
+          newRowType.getFieldNames());
       assert newProject.getClass() == project.getClass();
     }
     return new TrimResult(newProject, mapping);
@@ -349,14 +372,9 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
       return new TrimResult(input, mapping);
     }
     final RexLiteral expr =
-        cluster.getRexBuilder().makeExactLiteral(
-            BigDecimal.ZERO);
-    RelDataType newRowType =
-        cluster.getTypeFactory().builder().add("DUMMY", expr.getType()).build();
-    ProjectRel newProject = new ProjectRel(cluster,
-        cluster.traitSetOf(RelCollationImpl.EMPTY), input,
-        ImmutableList.<RexNode>of(expr), newRowType,
-        ProjectRelBase.Flags.BOXED);
+        cluster.getRexBuilder().makeExactLiteral(BigDecimal.ZERO);
+    final RelNode newProject = projectFactory.createProject(input,
+        ImmutableList.<RexNode>of(expr), ImmutableList.of("DUMMY"));
     return new TrimResult(newProject, mapping);
   }
 
@@ -403,12 +421,8 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
     RexNode newConditionExpr =
         conditionExpr.accept(shuttle);
 
-    final FilterRel newFilter =
-        new FilterRel(
-            filter.getCluster(),
-            newInput,
-            newConditionExpr);
-    assert newFilter.getClass() == filter.getClass();
+    final RelNode newFilter = filterFactory.createFilter(newInput,
+        newConditionExpr);
 
     // The result has the same mapping as the input gave us. Sometimes we
     // return fields that the consumer didn't ask for, because the filter
@@ -453,12 +467,9 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
           Mappings.createIdentity(fieldCount));
     }
 
-    final SortRel newSort =
-        sort.copy(
-            sort.getTraitSet(),
-            newInput,
-            RexUtil.apply(inputMapping, collation));
-    assert newSort.getClass() == sort.getClass();
+    final RelNode newSort = sortFactory.createSort(sort.getTraitSet(),
+        newInput, RexUtil.apply(inputMapping, collation),
+        sort.offset, sort.fetch);
 
     // The result has the same mapping as the input gave us. Sometimes we
     // return fields that the consumer didn't ask for, because the filter
@@ -474,7 +485,6 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
       JoinRelBase join,
       BitSet fieldsUsed,
       Set<RelDataTypeField> extraFields) {
-    final RelDataType rowType = join.getRowType();
     final int fieldCount = join.getSystemFieldList().size()
         + join.getLeft().getRowType().getFieldCount()
         + join.getRight().getRowType().getFieldCount();
@@ -586,12 +596,11 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
     RexNode newConditionExpr =
         conditionExpr.accept(shuttle);
 
-    final JoinRelBase newJoin =
-        join.copy(join.getTraitSet(), newConditionExpr, newInputs.get(0),
-            newInputs.get(1), join.getJoinType(), join.isSemiJoinDone());
-
-    // For SemiJoins only map fields from the left-side
-    if (newJoin instanceof SemiJoinRel) {
+    final JoinRelBase newJoin;
+    if (join instanceof SemiJoinRel) {
+      newJoin = joinFactory.createSemiJoinRel(join.getTraitSet(),
+          newInputs.get(0), newInputs.get(1), newConditionExpr);
+      // For SemiJoins only map fields from the left-side
       Mapping inputMapping = inputMappings.get(0);
       mapping = Mappings.create(MappingType.INVERSE_SURJECTION,
           join.getRowType().getFieldCount(),
@@ -604,6 +613,10 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
       for (IntPair pair : inputMapping) {
         mapping.set(pair.source + offset, pair.target + newOffset);
       }
+    } else {
+      newJoin = (JoinRelBase) joinFactory.createJoin(
+        newInputs.get(0), newInputs.get(1), newConditionExpr,
+        join.getJoinType(), join.getVariablesStopped(), join.isSemiJoinDone());
     }
 
     return new TrimResult(newJoin, mapping);
@@ -671,7 +684,8 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
           mapping);
     }
 
-    RelNode newSetOp = setOp.copy(setOp.getTraitSet(), newInputs);
+    RelNode newSetOp =
+        setOpFactory.createSetOp(setOp.kind, newInputs, setOp.all);
     return new TrimResult(newSetOp, mapping);
   }
 
@@ -782,12 +796,8 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
       ++j;
     }
 
-    RelNode newAggregate =
-        new AggregateRel(
-            aggregate.getCluster(),
-            newInput,
-            newGroupSet,
-            newAggCallList);
+    RelNode newAggregate = aggregateFactory.createAggrRelNode(newInput,
+      newGroupSet, newAggCallList);
 
     assert newAggregate.getClass() == aggregate.getClass();
 
@@ -948,7 +958,7 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
           (RelNode) tableAccessRel, fieldsUsed, extraFields);
     }
     final RelNode newTableAccessRel =
-        tableAccessRel.project(fieldsUsed, extraFields);
+        tableAccessRel.project(fieldsUsed, extraFields, this.projectFactory);
 
     // Some parts of the system can't handle rows with zero fields, so
     // pretend that one field is used.