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 2015/09/28 22:19:35 UTC

[4/7] incubator-calcite git commit: [CALCITE-828] Use RelBuilder in rules rather than type-specific RelNode factories

[CALCITE-828] Use RelBuilder in rules rather than type-specific RelNode factories

All rules now have a RelBuilderFactory, from which RelOptCall can
create a RelBuilder. All built-in rules that took a relational
expression factory (for example ProjectFactory) now use the RelBuilder.
We have converted some, but not all, other implicit uses of a factory.

We now recommend that any rules that are generic have a
RelBuilderFactory constructor parameter, but we have not changed
existing rules to implement this policy. People will need to adapt
rules and write tests to ensure the rules are generic.

Add various methods to RelBuilder.

Mostly we add new rule constructors and deprecate the old constructor.
But a few breaking changes:
* Rename ProtoRelBuilder to RelBuilderFactory;
* Rename DEFAULT_PROTO to LOGICAL_BUILDER;
* Change signature of TableScan.project method;
* Change signature of RelFieldTrimmer constructor;
* Add filter argument to RelBuilder.aggregateCall method.

Also, not an API change, but a change in behavior: RelBuilder methods
to create set operations (union, except, intersect) get their
left-to-right arguments by reading the oldest-to-newest stack elements.


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

Branch: refs/heads/master
Commit: 815fa262b83d5a864b1eacdc3661df3b04704c20
Parents: a1e0b00
Author: Julian Hyde <jh...@apache.org>
Authored: Tue Sep 22 01:20:38 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Sun Sep 27 20:22:49 2015 -0700

----------------------------------------------------------------------
 .../java/org/apache/calcite/plan/Contexts.java  |   6 +-
 .../org/apache/calcite/plan/RelOptRule.java     |  31 +-
 .../org/apache/calcite/plan/RelOptRuleCall.java |   6 +-
 .../org/apache/calcite/plan/RelOptUtil.java     |  86 ++--
 .../apache/calcite/rel/core/RelFactories.java   |   8 +-
 .../org/apache/calcite/rel/core/TableScan.java  |  18 +-
 .../calcite/rel/logical/LogicalWindow.java      |  14 +-
 .../AggregateExpandDistinctAggregatesRule.java  | 178 +++----
 .../rel/rules/AggregateJoinTransposeRule.java   |  97 ++--
 .../rel/rules/AggregateProjectMergeRule.java    |  15 +-
 .../AggregateProjectPullUpConstantsRule.java    |  76 ++-
 .../rel/rules/AggregateReduceFunctionsRule.java |  82 ++--
 .../calcite/rel/rules/AggregateRemoveRule.java  |  12 +-
 .../rel/rules/AggregateStarTableRule.java       |  81 ++--
 .../rel/rules/AggregateUnionAggregateRule.java  |  65 ++-
 .../rel/rules/AggregateUnionTransposeRule.java  |  64 ++-
 .../calcite/rel/rules/CalcRelSplitter.java      |  30 +-
 .../apache/calcite/rel/rules/CalcSplitRule.java |  22 +-
 .../rel/rules/FilterAggregateTransposeRule.java |  15 +-
 .../calcite/rel/rules/FilterCorrelateRule.java  |  42 +-
 .../calcite/rel/rules/FilterJoinRule.java       |  95 ++--
 .../calcite/rel/rules/FilterMergeRule.java      |  29 +-
 .../rel/rules/FilterProjectTransposeRule.java   |  49 +-
 .../rel/rules/FilterSetOpTransposeRule.java     |  23 +-
 .../calcite/rel/rules/JoinCommuteRule.java      |  28 +-
 .../rel/rules/JoinProjectTransposeRule.java     |  54 ++-
 .../rel/rules/JoinPushExpressionsRule.java      |  18 +-
 .../rel/rules/JoinPushThroughJoinRule.java      |  59 +--
 .../rules/JoinPushTransitivePredicatesRule.java |  33 +-
 .../calcite/rel/rules/JoinToCorrelateRule.java  |  29 +-
 .../calcite/rel/rules/LoptOptimizeJoinRule.java | 164 ++++---
 .../rel/rules/MultiJoinOptimizeBushyRule.java   |  38 +-
 .../calcite/rel/rules/ProjectMergeRule.java     |  32 +-
 .../rel/rules/ProjectMultiJoinMergeRule.java    |  26 +-
 .../rel/rules/ProjectSortTransposeRule.java     |  10 +-
 .../calcite/rel/rules/ProjectToWindowRule.java  | 164 +++----
 .../rel/rules/SemiJoinProjectTransposeRule.java |  25 +-
 .../rel/rules/SortJoinTransposeRule.java        |  18 +-
 .../rel/rules/SortProjectTransposeRule.java     |   9 +-
 .../calcite/rel/rules/UnionMergeRule.java       |  55 +--
 .../calcite/rel/rules/UnionToDistinctRule.java  |  31 +-
 .../apache/calcite/sql2rel/RelFieldTrimmer.java | 178 ++++---
 .../calcite/sql2rel/SqlToRelConverter.java      |   5 +-
 .../org/apache/calcite/tools/RelBuilder.java    | 465 +++++++++++++++----
 .../apache/calcite/tools/RelBuilderFactory.java |  41 ++
 .../apache/calcite/test/JdbcAdapterTest.java    |   2 +-
 .../org/apache/calcite/test/RelBuilderTest.java | 291 +++++++++++-
 .../apache/calcite/test/SqlToRelTestBase.java   |  11 +-
 .../org/apache/calcite/tools/PlannerTest.java   |  18 +-
 .../org/apache/calcite/test/RelOptRulesTest.xml |  32 +-
 .../org/apache/calcite/test/MongoAdapterIT.java |   6 +-
 site/_docs/algebra.md                           |  25 +-
 52 files changed, 1820 insertions(+), 1191 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/plan/Contexts.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/Contexts.java b/core/src/main/java/org/apache/calcite/plan/Contexts.java
index 7612999..2aad6b1 100644
--- a/core/src/main/java/org/apache/calcite/plan/Contexts.java
+++ b/core/src/main/java/org/apache/calcite/plan/Contexts.java
@@ -57,11 +57,13 @@ public class Contexts {
     return new WrapContext(o);
   }
 
-  /** Returns a context that wraps an array of objects. */
+  /** Returns a context that wraps an array of objects, ignoring any nulls. */
   public static Context of(Object... os) {
     final List<Context> contexts = new ArrayList<>();
     for (Object o : os) {
-      contexts.add(of(o));
+      if (o != null) {
+        contexts.add(of(o));
+      }
     }
     return chain(contexts);
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/plan/RelOptRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptRule.java b/core/src/main/java/org/apache/calcite/plan/RelOptRule.java
index 464568a..2d5c5d6 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptRule.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptRule.java
@@ -17,8 +17,11 @@
 package org.apache.calcite.plan;
 
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.RelFactories;
+import org.apache.calcite.tools.RelBuilderFactory;
 
 import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;
@@ -52,10 +55,15 @@ public abstract class RelOptRule {
    */
   private final RelOptRuleOperand operand;
 
+  /** Factory for a builder for relational expressions.
+   *
+   * <p>The actual builder is available via {@link RelOptRuleCall#builder()}. */
+  public final RelBuilderFactory relBuilderFactory;
+
   /**
    * Flattened list of operands.
    */
-  public List<RelOptRuleOperand> operands;
+  public final List<RelOptRuleOperand> operands;
 
   //~ Constructors -----------------------------------------------------------
 
@@ -65,7 +73,7 @@ public abstract class RelOptRule {
    * @param operand root operand, must not be null
    */
   public RelOptRule(RelOptRuleOperand operand) {
-    this(operand, null);
+    this(operand, RelFactories.LOGICAL_BUILDER, null);
   }
 
   /**
@@ -75,8 +83,20 @@ public abstract class RelOptRule {
    * @param description Description, or null to guess description
    */
   public RelOptRule(RelOptRuleOperand operand, String description) {
-    assert operand != null;
-    this.operand = operand;
+    this(operand, RelFactories.LOGICAL_BUILDER, description);
+  }
+
+  /**
+   * Creates a rule with an explicit description.
+   *
+   * @param operand     root operand, must not be null
+   * @param description Description, or null to guess description
+   * @param relBuilderFactory Builder for relational expressions
+   */
+  public RelOptRule(RelOptRuleOperand operand,
+      RelBuilderFactory relBuilderFactory, String description) {
+    this.operand = Preconditions.checkNotNull(operand);
+    this.relBuilderFactory = Preconditions.checkNotNull(relBuilderFactory);
     if (description == null) {
       description = guessDescription(getClass().getName());
     }
@@ -282,8 +302,7 @@ public abstract class RelOptRule {
    */
   private List<RelOptRuleOperand> flattenOperands(
       RelOptRuleOperand rootOperand) {
-    List<RelOptRuleOperand> operandList =
-        new ArrayList<RelOptRuleOperand>();
+    final List<RelOptRuleOperand> operandList = new ArrayList<>();
 
     // Flatten the operands into a list.
     rootOperand.setRule(this);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/plan/RelOptRuleCall.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptRuleCall.java b/core/src/main/java/org/apache/calcite/plan/RelOptRuleCall.java
index 9a1fb0d..788549b 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptRuleCall.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptRuleCall.java
@@ -214,10 +214,10 @@ public abstract class RelOptRuleCall {
   }
 
   /** Creates a {@link org.apache.calcite.tools.RelBuilder} to be used by
-   * code within the call. The {@code protoBuilder} argument contains policies
+   * code within the call. The {@link RelOptRule#relBuilderFactory} argument contains policies
    * such as what implementation of {@link Filter} to create. */
-  public RelBuilder builder(RelBuilder.ProtoRelBuilder protoBuilder) {
-    return protoBuilder.create(rel(0).getCluster(), null);
+  public RelBuilder builder() {
+    return rule.relBuilderFactory.create(rel(0).getCluster(), null);
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
index 7762bf7..7be75b7 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
@@ -71,6 +71,8 @@ import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.type.MultisetSqlType;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.sql.validate.SqlValidatorUtil;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
 import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Permutation;
@@ -2990,44 +2992,28 @@ public abstract class RelOptUtil {
    * of AND, equals, and input fields, plus the remaining non-equal conditions.
    *
    * @param originalJoin Join whose condition is to be pushed down
-   */
-  public static RelNode pushDownJoinConditions(Join originalJoin) {
-    return pushDownJoinConditions(originalJoin, RelFactories.DEFAULT_PROJECT_FACTORY);
-  }
-
-  /**
-   * Pushes down expressions in "equal" join condition.
-   *
-   * <p>For example, given
-   * "emp JOIN dept ON emp.deptno + 1 = dept.deptno", adds a project above
-   * "emp" that computes the expression
-   * "emp.deptno + 1". The resulting join condition is a simple combination
-   * of AND, equals, and input fields, plus the remaining non-equal conditions.
-   *
-   * @param originalJoin Join whose condition is to be pushed down
-   * @param projectFactory Factory to create project operator
+   * @param relBuilder Factory to create project operator
    */
   public static RelNode pushDownJoinConditions(Join originalJoin,
-          RelFactories.ProjectFactory projectFactory) {
+      RelBuilder relBuilder) {
     RexNode joinCond = originalJoin.getCondition();
     final JoinRelType joinType = originalJoin.getJoinType();
-    RelNode leftRel = originalJoin.getLeft();
-    RelNode rightRel = originalJoin.getRight();
 
     final List<RexNode> extraLeftExprs = new ArrayList<>();
     final List<RexNode> extraRightExprs = new ArrayList<>();
-    final int leftCount = leftRel.getRowType().getFieldCount();
-    final int rightCount = rightRel.getRowType().getFieldCount();
+    final int leftCount = originalJoin.getLeft().getRowType().getFieldCount();
+    final int rightCount = originalJoin.getRight().getRowType().getFieldCount();
 
     if (!containsGet(joinCond)) {
       joinCond = pushDownEqualJoinConditions(
           joinCond, leftCount, rightCount, extraLeftExprs, extraRightExprs);
     }
+
+    relBuilder.push(originalJoin.getLeft());
     if (!extraLeftExprs.isEmpty()) {
       final List<RelDataTypeField> fields =
-          leftRel.getRowType().getFieldList();
-      leftRel = RelOptUtil.createProject(
-          leftRel,
+          relBuilder.peek().getRowType().getFieldList();
+      final List<Pair<RexNode, String>> pairs =
           new AbstractList<Pair<RexNode, String>>() {
             public int size() {
               return leftCount + extraLeftExprs.size();
@@ -3037,21 +3023,21 @@ public abstract class RelOptUtil {
               if (index < leftCount) {
                 RelDataTypeField field = fields.get(index);
                 return Pair.<RexNode, String>of(
-                    new RexInputRef(index, field.getType()),
-                    field.getName());
+                    new RexInputRef(index, field.getType()), field.getName());
               } else {
                 return Pair.of(extraLeftExprs.get(index - leftCount), null);
               }
             }
-          },
-          true, projectFactory);
+          };
+      relBuilder.project(Pair.left(pairs), Pair.right(pairs));
     }
+
+    relBuilder.push(originalJoin.getRight());
     if (!extraRightExprs.isEmpty()) {
       final List<RelDataTypeField> fields =
-          rightRel.getRowType().getFieldList();
+          relBuilder.peek().getRowType().getFieldList();
       final int newLeftCount = leftCount + extraLeftExprs.size();
-      rightRel = RelOptUtil.createProject(
-          rightRel,
+      final List<Pair<RexNode, String>> pairs =
           new AbstractList<Pair<RexNode, String>>() {
             public int size() {
               return rightCount + extraRightExprs.size();
@@ -3071,12 +3057,15 @@ public abstract class RelOptUtil {
                     null);
               }
             }
-          },
-          true, projectFactory);
+          };
+      relBuilder.project(Pair.left(pairs), Pair.right(pairs));
     }
 
-    RelNode join = originalJoin.copy(originalJoin.getTraitSet(),
-        joinCond, leftRel, rightRel, joinType, originalJoin.isSemiJoinDone());
+    final RelNode right = relBuilder.build();
+    final RelNode left = relBuilder.build();
+    relBuilder.push(
+        originalJoin.copy(originalJoin.getTraitSet(),
+            joinCond, left, right, joinType, originalJoin.isSemiJoinDone()));
 
     if (!extraLeftExprs.isEmpty() || !extraRightExprs.isEmpty()) {
       Mappings.TargetMapping mapping =
@@ -3085,9 +3074,32 @@ public abstract class RelOptUtil {
                   + rightCount + extraRightExprs.size(),
               0, 0, leftCount,
               leftCount, leftCount + extraLeftExprs.size(), rightCount);
-      return RelOptUtil.createProject(join, mapping, projectFactory);
+      relBuilder.project(relBuilder.fields(mapping.inverse()));
     }
-    return join;
+    return relBuilder.build();
+  }
+
+  /**
+   * Pushes down expressions in "equal" join condition, using the default
+   * builder.
+   *
+   * @see #pushDownJoinConditions(Join, RelBuilder)
+   */
+  public static RelNode pushDownJoinConditions(Join originalJoin) {
+    return pushDownJoinConditions(originalJoin, RelFactories.LOGICAL_BUILDER);
+  }
+
+  @Deprecated // to be removed before 2.0
+  public static RelNode pushDownJoinConditions(Join originalJoin,
+      RelFactories.ProjectFactory projectFactory) {
+    return pushDownJoinConditions(
+        originalJoin, RelBuilder.proto(projectFactory));
+  }
+
+  private static RelNode pushDownJoinConditions(Join originalJoin,
+      RelBuilderFactory relBuilderFactory) {
+    return pushDownJoinConditions(originalJoin,
+        relBuilderFactory.create(originalJoin.getCluster(), null));
   }
 
   private static boolean containsGet(RexNode node) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java b/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java
index e8cbd3c..d58150b 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java
@@ -39,6 +39,7 @@ import org.apache.calcite.rex.RexLiteral;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
 import org.apache.calcite.util.ImmutableBitSet;
 
 import com.google.common.collect.ImmutableList;
@@ -77,10 +78,9 @@ public class RelFactories {
   public static final TableScanFactory DEFAULT_TABLE_SCAN_FACTORY =
       new TableScanFactoryImpl();
 
-  /** Creates a {@link RelBuilder} that will create logical relational
-   * expressions for everything.
-   */
-  public static final RelBuilder.ProtoRelBuilder DEFAULT_PROTO =
+  /** A {@link RelBuilderFactory} that creates a {@link RelBuilder} that will
+   * create logical relational expressions for everything. */
+  public static final RelBuilderFactory LOGICAL_BUILDER =
       RelBuilder.proto(
           Contexts.of(DEFAULT_PROJECT_FACTORY,
               DEFAULT_FILTER_FACTORY,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/core/TableScan.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/TableScan.java b/core/src/main/java/org/apache/calcite/rel/core/TableScan.java
index 40bf0cf..4371802 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/TableScan.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/TableScan.java
@@ -31,6 +31,7 @@ import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeField;
 import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.tools.RelBuilder;
 import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.ImmutableIntList;
 
@@ -116,9 +117,9 @@ public abstract class TableScan extends AbstractRelNode {
    * fields that were not included in the table's official type.
    *
    * <p>The default implementation assumes that tables cannot do either of
-   * these operations, therefore it adds a
-   * {@link org.apache.calcite.rel.logical.LogicalProject}, projecting
-   * {@code NULL} values for the extra fields.</p>
+   * these operations, therefore it adds a {@link Project} that projects
+   * {@code NULL} values for the extra fields, using the
+   * {@link RelBuilder#project(Iterable)} method.
    *
    * <p>Sub-classes, representing table types that have these capabilities,
    * should override.</p>
@@ -126,19 +127,20 @@ public abstract class TableScan extends AbstractRelNode {
    * @param fieldsUsed  Bitmap of the fields desired by the consumer
    * @param extraFields Extra fields, not advertised in the table's row-type,
    *                    wanted by the consumer
+   * @param relBuilder Builder used to create a Project
    * @return Relational expression that projects the desired fields
    */
   public RelNode project(ImmutableBitSet fieldsUsed,
       Set<RelDataTypeField> extraFields,
-      RelFactories.ProjectFactory projectFactory) {
+      RelBuilder relBuilder) {
     final int fieldCount = getRowType().getFieldCount();
     if (fieldsUsed.equals(ImmutableBitSet.range(fieldCount))
         && extraFields.isEmpty()) {
       return this;
     }
-    List<RexNode> exprList = new ArrayList<RexNode>();
-    List<String> nameList = new ArrayList<String>();
-    RexBuilder rexBuilder = getCluster().getRexBuilder();
+    final List<RexNode> exprList = new ArrayList<>();
+    final List<String> nameList = new ArrayList<>();
+    final RexBuilder rexBuilder = getCluster().getRexBuilder();
     final List<RelDataTypeField> fields = getRowType().getFieldList();
 
     // Project the subset of fields.
@@ -159,7 +161,7 @@ public abstract class TableScan extends AbstractRelNode {
       nameList.add(extraField.getName());
     }
 
-    return projectFactory.createProject(this, exprList, nameList);
+    return relBuilder.push(this).project(exprList, nameList).build();
   }
 
   @Override public RelNode accept(RelShuttle shuttle) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/logical/LogicalWindow.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalWindow.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalWindow.java
index ea9e3c1..559dc0e 100644
--- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalWindow.java
+++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalWindow.java
@@ -34,6 +34,7 @@ import org.apache.calcite.rex.RexProgram;
 import org.apache.calcite.rex.RexShuttle;
 import org.apache.calcite.rex.RexWindow;
 import org.apache.calcite.rex.RexWindowBound;
+import org.apache.calcite.tools.RelBuilder;
 import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.Pair;
 
@@ -99,10 +100,8 @@ public final class LogicalWindow extends Window {
   /**
    * Creates a LogicalWindow by parsing a {@link RexProgram}.
    */
-  public static RelNode create(
-      RelOptCluster cluster,
-      RelTraitSet traitSet,
-      RelNode child,
+  public static RelNode create(RelOptCluster cluster,
+      RelTraitSet traitSet, RelBuilder relBuilder, RelNode child,
       final RexProgram program) {
     final RelDataType outRowType = program.getOutputRowType();
     // Build a list of distinct groups, partitions and aggregate
@@ -277,10 +276,9 @@ public final class LogicalWindow extends Window {
       projectList.add(ref);
     }
 
-    return RelOptUtil.createProject(
-        window,
-        projectList,
-        outRowType.getFieldNames());
+    return relBuilder.push(window)
+        .project(projectList, outRowType.getFieldNames())
+        .build();
   }
 
   private static List<RexNode> toInputRefs(

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/AggregateExpandDistinctAggregatesRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateExpandDistinctAggregatesRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateExpandDistinctAggregatesRule.java
index 81733f0..96449e9 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateExpandDistinctAggregatesRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateExpandDistinctAggregatesRule.java
@@ -16,10 +16,10 @@
  */
 package org.apache.calcite.rel.rules;
 
+import org.apache.calcite.plan.Contexts;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Aggregate;
 import org.apache.calcite.rel.core.AggregateCall;
@@ -32,17 +32,18 @@ import org.apache.calcite.rel.type.RelDataTypeField;
 import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexInputRef;
 import org.apache.calcite.rex.RexNode;
-import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.sql.SqlAggFunction;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
 import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.ImmutableIntList;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Util;
 
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 
@@ -77,38 +78,40 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
   /** The default instance of the rule; operates only on logical expressions. */
   public static final AggregateExpandDistinctAggregatesRule INSTANCE =
       new AggregateExpandDistinctAggregatesRule(LogicalAggregate.class, true,
-          RelFactories.DEFAULT_JOIN_FACTORY);
+          RelFactories.LOGICAL_BUILDER);
 
   /** Instance of the rule that operates only on logical expressions and
    * generates a join. */
   public static final AggregateExpandDistinctAggregatesRule JOIN =
       new AggregateExpandDistinctAggregatesRule(LogicalAggregate.class, false,
-          RelFactories.DEFAULT_JOIN_FACTORY);
+          RelFactories.LOGICAL_BUILDER);
   public static final BigDecimal TWO = BigDecimal.valueOf(2L);
 
   public final boolean useGroupingSets;
-  public final RelFactories.JoinFactory joinFactory;
-  public final RelFactories.AggregateFactory aggregateFactory =
-      RelFactories.DEFAULT_AGGREGATE_FACTORY;
-  public final RelFactories.ProjectFactory projectFactory =
-      RelFactories.DEFAULT_PROJECT_FACTORY;
 
   //~ Constructors -----------------------------------------------------------
 
   public AggregateExpandDistinctAggregatesRule(
       Class<? extends LogicalAggregate> clazz,
       boolean useGroupingSets,
-      RelFactories.JoinFactory joinFactory) {
-    super(operand(clazz, any()));
+      RelBuilderFactory relBuilderFactory) {
+    super(operand(clazz, any()), relBuilderFactory, null);
     this.useGroupingSets = useGroupingSets;
-    this.joinFactory = joinFactory;
+  }
+
+  @Deprecated // to be removed before 2.0
+  public AggregateExpandDistinctAggregatesRule(
+      Class<? extends LogicalAggregate> clazz,
+      boolean useGroupingSets,
+      RelFactories.JoinFactory joinFactory) {
+    this(clazz, useGroupingSets, RelBuilder.proto(Contexts.of(joinFactory)));
   }
 
   @Deprecated // to be removed before 2.0
   public AggregateExpandDistinctAggregatesRule(
       Class<? extends LogicalAggregate> clazz,
       RelFactories.JoinFactory joinFactory) {
-    this(clazz, false, joinFactory);
+    this(clazz, false, RelBuilder.proto(Contexts.of(joinFactory)));
   }
 
   //~ Methods ----------------------------------------------------------------
@@ -130,15 +133,16 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
       }
       argLists.add(Pair.of(aggCall.getArgList(), aggCall.filterArg));
     }
-    Util.permAssert(argLists.size() > 0, "containsDistinctCall lied");
+    Preconditions.checkState(argLists.size() > 0, "containsDistinctCall lied");
 
     // If all of the agg expressions are distinct and have the same
     // arguments then we can use a more efficient form.
     if (nonDistinctCount == 0 && argLists.size() == 1) {
       final Pair<List<Integer>, Integer> pair =
           Iterables.getOnlyElement(argLists);
-      RelNode converted = convertMonopole(aggregate, pair.left, pair.right);
-      call.transformTo(converted);
+      final RelBuilder relBuilder = call.builder();
+      convertMonopole(relBuilder, aggregate, pair.left, pair.right);
+      call.transformTo(relBuilder.build());
       return;
     }
 
@@ -179,27 +183,27 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
     // In the case where there are no non-distinct aggregates (regardless of
     // whether there are group bys), there's no need to generate the
     // extra aggregate and join.
-    RelNode rel;
-    if (newAggCallList.isEmpty()) {
-      rel = null;
-    } else {
-      rel = aggregateFactory.createAggregate(aggregate.getInput(),
-          aggregate.indicator,
-          groupSet, aggregate.getGroupSets(), newAggCallList);
+    final RelBuilder relBuilder = call.builder();
+    relBuilder.push(aggregate.getInput());
+    int n = 0;
+    if (!newAggCallList.isEmpty()) {
+      final RelBuilder.GroupKey groupKey =
+          relBuilder.groupKey(groupSet, aggregate.getGroupSets());
+      relBuilder.aggregate(groupKey, newAggCallList);
+      ++n;
     }
 
     // For each set of operands, find and rewrite all calls which have that
     // set of operands.
     for (Pair<List<Integer>, Integer> argList : argLists) {
-      rel = doRewrite(aggregate, rel, argList.left, argList.right, refs);
+      doRewrite(relBuilder, aggregate, n++, argList.left, argList.right, refs);
     }
 
-    rel = RelOptUtil.createProject(rel, refs, fieldNames);
-
-    call.transformTo(rel);
+    relBuilder.project(refs, fieldNames);
+    call.transformTo(relBuilder.build());
   }
 
-  private void rewriteUsingGroupingSets(RelOptRuleCall ruleCall,
+  private void rewriteUsingGroupingSets(RelOptRuleCall call,
       Aggregate aggregate, Set<Pair<List<Integer>, Integer>> argLists) {
     final Set<ImmutableBitSet> groupSetTreeSet =
         new TreeSet<>(ImmutableBitSet.ORDERING);
@@ -216,15 +220,17 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
     final ImmutableBitSet fullGroupSet = ImmutableBitSet.union(groupSets);
 
     final List<AggregateCall> distinctAggCalls = new ArrayList<>();
-    for (Pair<AggregateCall, String> call : aggregate.getNamedAggCalls()) {
-      if (!call.left.isDistinct()) {
-        distinctAggCalls.add(call.left.rename(call.right));
+    for (Pair<AggregateCall, String> aggCall : aggregate.getNamedAggCalls()) {
+      if (!aggCall.left.isDistinct()) {
+        distinctAggCalls.add(aggCall.left.rename(aggCall.right));
       }
     }
 
-    final RelNode distinct =
-        aggregateFactory.createAggregate(aggregate.getInput(),
-            groupSets.size() > 1, fullGroupSet, groupSets, distinctAggCalls);
+    final RelBuilder relBuilder = call.builder();
+    relBuilder.push(aggregate.getInput());
+    relBuilder.aggregate(relBuilder.groupKey(fullGroupSet, groupSets),
+        distinctAggCalls);
+    final RelNode distinct = relBuilder.peek();
     final int groupCount = fullGroupSet.cardinality();
     final int indicatorCount = groupSets.size() > 1 ? groupCount : 0;
 
@@ -288,49 +294,48 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
       filters.put(groupSet, registrar.register(groupSet));
     }
 
-    RelNode r = distinct;
     if (!predicates.isEmpty()) {
       List<Pair<RexNode, String>> nodes = new ArrayList<>();
-      for (RelDataTypeField f : r.getRowType().getFieldList()) {
+      for (RelDataTypeField f : relBuilder.peek().getRowType().getFieldList()) {
         final RexNode node = rexBuilder.makeInputRef(f.getType(), f.getIndex());
         nodes.add(Pair.of(node, f.getName()));
       }
       nodes.addAll(predicates);
-      r = RelOptUtil.createProject(r, nodes, false);
+      relBuilder.project(Pair.left(nodes), Pair.right(nodes));
     }
 
     int x = groupCount + indicatorCount;
     final List<AggregateCall> newCalls = new ArrayList<>();
-    for (AggregateCall call : aggregate.getAggCallList()) {
+    for (AggregateCall aggCall : aggregate.getAggCallList()) {
       final int newFilterArg;
       final List<Integer> newArgList;
       final SqlAggFunction aggregation;
-      if (!call.isDistinct()) {
+      if (!aggCall.isDistinct()) {
         aggregation = SqlStdOperatorTable.MIN;
         newArgList = ImmutableIntList.of(x++);
         newFilterArg = filters.get(aggregate.getGroupSet());
       } else {
-        aggregation = call.getAggregation();
-        newArgList = remap(fullGroupSet, call.getArgList());
+        aggregation = aggCall.getAggregation();
+        newArgList = remap(fullGroupSet, aggCall.getArgList());
         newFilterArg =
             filters.get(
-                ImmutableBitSet.of(call.getArgList())
-                    .setIf(call.filterArg, call.filterArg >= 0)
+                ImmutableBitSet.of(aggCall.getArgList())
+                    .setIf(aggCall.filterArg, aggCall.filterArg >= 0)
                     .union(aggregate.getGroupSet()));
       }
       final AggregateCall newCall =
           AggregateCall.create(aggregation, false, newArgList, newFilterArg,
-              aggregate.getGroupCount(), distinct, null, call.name);
+              aggregate.getGroupCount(), distinct, null, aggCall.name);
       newCalls.add(newCall);
     }
 
-    final RelNode newAggregate =
-        aggregateFactory.createAggregate(r, aggregate.indicator,
+    relBuilder.aggregate(
+        relBuilder.groupKey(
             remap(fullGroupSet, aggregate.getGroupSet()),
-            remap(fullGroupSet, aggregate.getGroupSets()), newCalls);
-    ruleCall.transformTo(
-        RelOptUtil.createCastRel(newAggregate, aggregate.getRowType(), true,
-            projectFactory));
+            remap(fullGroupSet, aggregate.getGroupSets())),
+        newCalls);
+    relBuilder.convert(aggregate.getRowType(), true);
+    call.transformTo(relBuilder.build());
   }
 
   private static ImmutableBitSet remap(ImmutableBitSet groupSet,
@@ -370,8 +375,8 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
    * distinct aggregate function (or perhaps several over the same arguments)
    * and no non-distinct aggregate functions.
    */
-  private RelNode convertMonopole(Aggregate aggregate, List<Integer> argList,
-      int filterArg) {
+  private RelBuilder convertMonopole(RelBuilder relBuilder, Aggregate aggregate,
+      List<Integer> argList, int filterArg) {
     // For example,
     //    SELECT deptno, COUNT(DISTINCT sal), SUM(DISTINCT sal)
     //    FROM emp
@@ -388,17 +393,18 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
     // Project the columns of the GROUP BY plus the arguments
     // to the agg function.
     final Map<Integer, Integer> sourceOf = new HashMap<>();
-    final Aggregate distinct =
-        createSelectDistinct(aggregate, argList, filterArg, sourceOf);
+    createSelectDistinct(relBuilder, aggregate, argList, filterArg, sourceOf);
 
     // Create an aggregate on top, with the new aggregate list.
     final List<AggregateCall> newAggCalls =
         Lists.newArrayList(aggregate.getAggCallList());
     rewriteAggCalls(newAggCalls, argList, sourceOf);
     final int cardinality = aggregate.getGroupSet().cardinality();
-    return aggregate.copy(aggregate.getTraitSet(), distinct,
-        aggregate.indicator, ImmutableBitSet.range(cardinality), null,
-        newAggCalls);
+    relBuilder.push(
+        aggregate.copy(aggregate.getTraitSet(), relBuilder.build(),
+            aggregate.indicator, ImmutableBitSet.range(cardinality), null,
+            newAggCalls));
+    return relBuilder;
   }
 
   /**
@@ -409,9 +415,10 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
    * relational expression, and modifies the set of top-level calls.
    *
    * @param aggregate Original aggregate
-   * @param left      Child relational expression (either the original
+   * @param n         Ordinal of this in a join. {@code relBuilder} contains the
+   *                  input relational expression (either the original
    *                  aggregate, the output from the previous call to this
-   *                  method, or null in the case where we're converting the
+   *                  method. {@code n} is 0 if we're converting the
    *                  first distinct aggregate in a query with no non-distinct
    *                  aggregates)
    * @param argList   Arguments to the distinct aggregate function
@@ -420,14 +427,14 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
    *                  result of this rule. Those relating to this arg list will
    *                  be modified  @return Relational expression
    */
-  private RelNode doRewrite(Aggregate aggregate, RelNode left,
+  private void doRewrite(RelBuilder relBuilder, Aggregate aggregate, int n,
       List<Integer> argList, int filterArg, List<RexInputRef> refs) {
     final RexBuilder rexBuilder = aggregate.getCluster().getRexBuilder();
     final List<RelDataTypeField> leftFields;
-    if (left == null) {
+    if (n == 0) {
       leftFields = null;
     } else {
-      leftFields = left.getRowType().getFieldList();
+      leftFields = relBuilder.peek().getRowType().getFieldList();
     }
 
     // LogicalAggregate(
@@ -474,8 +481,7 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
     // Project the columns of the GROUP BY plus the arguments
     // to the agg function.
     final Map<Integer, Integer> sourceOf = new HashMap<>();
-    final Aggregate distinct =
-        createSelectDistinct(aggregate, argList, filterArg, sourceOf);
+    createSelectDistinct(relBuilder, aggregate, argList, filterArg, sourceOf);
 
     // Now compute the aggregate functions on top of the distinct dataset.
     // Each distinct agg becomes a non-distinct call to the corresponding
@@ -516,7 +522,7 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
           AggregateCall.create(aggCall.getAggregation(), false, newArgs,
               newFilterArg, aggCall.getType(), aggCall.getName());
       assert refs.get(i) == null;
-      if (left == null) {
+      if (n == 0) {
         refs.set(i,
             new RexInputRef(groupAndIndicatorCount + aggCallList.size(),
                 newAggCall.getType()));
@@ -542,20 +548,20 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
               ImmutableBitSet.permute(aggregate.getGroupSets(), map));
     }
 
-    Aggregate distinctAgg =
-        aggregate.copy(aggregate.getTraitSet(), distinct, aggregate.indicator,
-            newGroupSet, newGroupingSets, aggCallList);
+    relBuilder.push(
+        aggregate.copy(aggregate.getTraitSet(), relBuilder.build(),
+            aggregate.indicator, newGroupSet, newGroupingSets, aggCallList));
 
     // If there's no left child yet, no need to create the join
-    if (left == null) {
-      return distinctAgg;
+    if (n == 0) {
+      return;
     }
 
     // Create the join condition. It is of the form
     //  'left.f0 = right.f0 and left.f1 = right.f1 and ...'
     // where {f0, f1, ...} are the GROUP BY fields.
     final List<RelDataTypeField> distinctFields =
-        distinctAgg.getRowType().getFieldList();
+        relBuilder.peek().getRowType().getFieldList();
     final List<RexNode> conditions = Lists.newArrayList();
     for (i = 0; i < groupAndIndicatorCount; ++i) {
       // null values form its own group
@@ -569,12 +575,7 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
     }
 
     // Join in the new 'select distinct' relation.
-    return joinFactory.createJoin(left,
-        distinctAgg,
-        RexUtil.composeConjunction(rexBuilder, conditions, false),
-        JoinRelType.INNER,
-        ImmutableSet.<String>of(),
-        false);
+    relBuilder.join(JoinRelType.INNER, conditions);
   }
 
   private static void rewriteAggCalls(
@@ -641,6 +642,7 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
    * <p>The <code>sourceOf</code> map is populated with the source of each
    * column; in this case sourceOf.get(0) = 0, and sourceOf.get(1) = 2.</p>
    *
+   * @param relBuilder Relational expression builder
    * @param aggregate Aggregate relational expression
    * @param argList   Ordinals of columns to make distinct
    * @param filterArg Ordinal of column to filter on, or -1
@@ -649,12 +651,13 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
    * @return Aggregate relational expression which projects the required
    * columns
    */
-  private static Aggregate createSelectDistinct(Aggregate aggregate,
-      List<Integer> argList, int filterArg, Map<Integer, Integer> sourceOf) {
+  private RelBuilder createSelectDistinct(RelBuilder relBuilder,
+      Aggregate aggregate, List<Integer> argList, int filterArg,
+      Map<Integer, Integer> sourceOf) {
+    relBuilder.push(aggregate.getInput());
     final List<Pair<RexNode, String>> projects = new ArrayList<>();
-    final RelNode child = aggregate.getInput();
     final List<RelDataTypeField> childFields =
-        child.getRowType().getFieldList();
+        relBuilder.peek().getRowType().getFieldList();
     for (int i : aggregate.getGroupSet()) {
       sourceOf.put(i, projects.size());
       projects.add(RexInputRef.of2(i, childFields));
@@ -689,14 +692,15 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
       sourceOf.put(arg, projects.size());
       projects.add(RexInputRef.of2(arg, childFields));
     }
-    final RelNode project =
-        RelOptUtil.createProject(child, projects, false);
+    relBuilder.project(Pair.left(projects), Pair.right(projects));
 
     // Get the distinct values of the GROUP BY fields and the arguments
     // to the agg functions.
-    return aggregate.copy(aggregate.getTraitSet(), project, false,
-        ImmutableBitSet.range(projects.size()),
-        null, ImmutableList.<AggregateCall>of());
+    relBuilder.push(
+        aggregate.copy(aggregate.getTraitSet(), relBuilder.build(), false,
+            ImmutableBitSet.range(projects.size()),
+            null, ImmutableList.<AggregateCall>of()));
+    return relBuilder;
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/AggregateJoinTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateJoinTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateJoinTransposeRule.java
index 8dfe4aa..0f4d733 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateJoinTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateJoinTransposeRule.java
@@ -36,6 +36,8 @@ import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.sql.SqlAggFunction;
 import org.apache.calcite.sql.SqlSplittableAggFunction;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
 import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.mapping.Mapping;
 import org.apache.calcite.util.mapping.Mappings;
@@ -60,76 +62,72 @@ import java.util.TreeMap;
  */
 public class AggregateJoinTransposeRule extends RelOptRule {
   public static final AggregateJoinTransposeRule INSTANCE =
-      new AggregateJoinTransposeRule(LogicalAggregate.class,
-          RelFactories.DEFAULT_AGGREGATE_FACTORY,
-          LogicalJoin.class,
-          RelFactories.DEFAULT_JOIN_FACTORY,
-          RelFactories.DEFAULT_PROJECT_FACTORY);
+      new AggregateJoinTransposeRule(LogicalAggregate.class, LogicalJoin.class,
+          RelFactories.LOGICAL_BUILDER, false);
 
   /** Extended instance of the rule that can push down aggregate functions. */
   public static final AggregateJoinTransposeRule EXTENDED =
-      new AggregateJoinTransposeRule(LogicalAggregate.class,
-          RelFactories.DEFAULT_AGGREGATE_FACTORY,
-          LogicalJoin.class,
-          RelFactories.DEFAULT_JOIN_FACTORY,
-          RelFactories.DEFAULT_PROJECT_FACTORY, true);
-
-  private final RelFactories.AggregateFactory aggregateFactory;
-
-  private final RelFactories.JoinFactory joinFactory;
-
-  private final RelFactories.ProjectFactory projectFactory;
+      new AggregateJoinTransposeRule(LogicalAggregate.class, LogicalJoin.class,
+          RelFactories.LOGICAL_BUILDER, true);
 
   private final boolean allowFunctions;
 
-  @Deprecated
+  /** Creates an AggregateJoinTransposeRule. */
+  public AggregateJoinTransposeRule(Class<? extends Aggregate> aggregateClass,
+      Class<? extends Join> joinClass, RelBuilderFactory relBuilderFactory,
+      boolean allowFunctions) {
+    super(
+        operand(aggregateClass, null, Aggregate.IS_SIMPLE,
+            operand(joinClass, any())), relBuilderFactory, null);
+    this.allowFunctions = allowFunctions;
+  }
+
+  @Deprecated // to be removed before 2.0
   public AggregateJoinTransposeRule(Class<? extends Aggregate> aggregateClass,
       RelFactories.AggregateFactory aggregateFactory,
       Class<? extends Join> joinClass,
       RelFactories.JoinFactory joinFactory) {
-    this(aggregateClass, aggregateFactory, joinClass, joinFactory,
-            RelFactories.DEFAULT_PROJECT_FACTORY, false);
+    this(aggregateClass, joinClass,
+        RelBuilder.proto(aggregateFactory, joinFactory), false);
   }
 
-  @Deprecated
+  @Deprecated // to be removed before 2.0
   public AggregateJoinTransposeRule(Class<? extends Aggregate> aggregateClass,
       RelFactories.AggregateFactory aggregateFactory,
       Class<? extends Join> joinClass,
       RelFactories.JoinFactory joinFactory,
       boolean allowFunctions) {
-    this(aggregateClass, aggregateFactory, joinClass, joinFactory,
-            RelFactories.DEFAULT_PROJECT_FACTORY, allowFunctions);
+    this(aggregateClass, joinClass,
+        RelBuilder.proto(aggregateFactory, joinFactory), allowFunctions);
   }
 
-  /** Creates an AggregateJoinTransposeRule. */
+  @Deprecated // to be removed before 2.0
   public AggregateJoinTransposeRule(Class<? extends Aggregate> aggregateClass,
       RelFactories.AggregateFactory aggregateFactory,
       Class<? extends Join> joinClass,
       RelFactories.JoinFactory joinFactory,
       RelFactories.ProjectFactory projectFactory) {
-    this(aggregateClass, aggregateFactory, joinClass, joinFactory, projectFactory, false);
+    this(aggregateClass, joinClass,
+        RelBuilder.proto(aggregateFactory, joinFactory, projectFactory), false);
   }
 
-  /** Creates an AggregateJoinTransposeRule that may push down functions. */
+  @Deprecated // to be removed before 2.0
   public AggregateJoinTransposeRule(Class<? extends Aggregate> aggregateClass,
       RelFactories.AggregateFactory aggregateFactory,
       Class<? extends Join> joinClass,
       RelFactories.JoinFactory joinFactory,
       RelFactories.ProjectFactory projectFactory,
       boolean allowFunctions) {
-    super(
-        operand(aggregateClass, null, Aggregate.IS_SIMPLE,
-            operand(joinClass, any())));
-    this.aggregateFactory = aggregateFactory;
-    this.joinFactory = joinFactory;
-    this.projectFactory = projectFactory;
-    this.allowFunctions = allowFunctions;
+    this(aggregateClass, joinClass,
+        RelBuilder.proto(aggregateFactory, joinFactory, projectFactory),
+        allowFunctions);
   }
 
   public void onMatch(RelOptRuleCall call) {
     final Aggregate aggregate = call.rel(0);
     final Join join = call.rel(1);
     final RexBuilder rexBuilder = aggregate.getCluster().getRexBuilder();
+    final RelBuilder relBuilder = call.builder();
 
     // If any aggregate functions do not support splitting, bail out
     // If any aggregate call has a filter, bail out
@@ -248,8 +246,10 @@ public class AggregateJoinTransposeRule extends RelOptRule {
                     + belowAggCallRegistry.register(call1));
           }
         }
-        side.newInput = aggregateFactory.createAggregate(joinInput, false,
-            belowAggregateKey, null, belowAggCalls);
+        side.newInput = relBuilder.push(joinInput)
+            .aggregate(relBuilder.groupKey(belowAggregateKey, null),
+                belowAggCalls)
+            .build();
       }
       offset += fieldCount;
       belowOffset += side.newInput.getRowType().getFieldCount();
@@ -276,9 +276,9 @@ public class AggregateJoinTransposeRule extends RelOptRule {
         RexUtil.apply(mapping, join.getCondition());
 
     // Create new join
-    RelNode newJoin = joinFactory.createJoin(sides.get(0).newInput,
-        sides.get(1).newInput, newCondition, join.getJoinType(),
-        join.getVariablesStopped(), join.isSemiJoinDone());
+    relBuilder.push(sides.get(0).newInput)
+        .push(sides.get(1).newInput)
+        .join(join.getJoinType(), newCondition);
 
     // Aggregate above to sum up the sub-totals
     final List<AggregateCall> newAggCalls = new ArrayList<>();
@@ -286,7 +286,8 @@ public class AggregateJoinTransposeRule extends RelOptRule {
         aggregate.getGroupCount() + aggregate.getIndicatorCount();
     final int newLeftWidth = sides.get(0).newInput.getRowType().getFieldCount();
     final List<RexNode> projects =
-        new ArrayList<>(rexBuilder.identityProjects(newJoin.getRowType()));
+        new ArrayList<>(
+            rexBuilder.identityProjects(relBuilder.peek().getRowType()));
     for (Ord<AggregateCall> aggCall : Ord.zip(aggregate.getAggCallList())) {
       final SqlAggFunction aggregation = aggCall.e.getAggregation();
       final SqlSplittableAggFunction splitter =
@@ -296,21 +297,20 @@ public class AggregateJoinTransposeRule extends RelOptRule {
       final Integer rightSubTotal = sides.get(1).split.get(aggCall.i);
       newAggCalls.add(
           splitter.topSplit(rexBuilder, registry(projects),
-              groupIndicatorCount, newJoin.getRowType(), aggCall.e,
+              groupIndicatorCount, relBuilder.peek().getRowType(), aggCall.e,
               leftSubTotal == null ? -1 : leftSubTotal,
               rightSubTotal == null ? -1 : rightSubTotal + newLeftWidth));
     }
-    RelNode r = newJoin;
   b:
     if (allColumnsInAggregate && newAggCalls.isEmpty()) {
       // no need to aggregate
     } else {
-      r = RelOptUtil.createProject(r, projects, null, true, projectFactory);
+      relBuilder.project(projects);
       if (allColumnsInAggregate) {
         // let's see if we can convert
         List<RexNode> projects2 = new ArrayList<>();
         for (int key : Mappings.apply(mapping, aggregate.getGroupSet())) {
-          projects2.add(rexBuilder.makeInputRef(r, key));
+          projects2.add(relBuilder.field(key));
         }
         for (AggregateCall newAggCall : newAggCalls) {
           final SqlSplittableAggFunction splitter =
@@ -318,21 +318,22 @@ public class AggregateJoinTransposeRule extends RelOptRule {
                   .unwrap(SqlSplittableAggFunction.class);
           if (splitter != null) {
             projects2.add(
-                splitter.singleton(rexBuilder, r.getRowType(), newAggCall));
+                splitter.singleton(rexBuilder, relBuilder.peek().getRowType(),
+                    newAggCall));
           }
         }
         if (projects2.size()
             == aggregate.getGroupSet().cardinality() + newAggCalls.size()) {
           // We successfully converted agg calls into projects.
-          r = RelOptUtil.createProject(r, projects2, null, true, projectFactory);
+          relBuilder.project(projects2);
           break b;
         }
       }
-      r = aggregateFactory.createAggregate(r, aggregate.indicator,
-          Mappings.apply(mapping, aggregate.getGroupSet()),
-          Mappings.apply2(mapping, aggregate.getGroupSets()), newAggCalls);
+      relBuilder.aggregate(
+          relBuilder.groupKey(Mappings.apply(mapping, aggregate.getGroupSet()),
+              Mappings.apply2(mapping, aggregate.getGroupSets())), newAggCalls);
     }
-    call.transformTo(r);
+    call.transformTo(relBuilder.build());
   }
 
   /** Computes the closure of a set of columns according to a given list of

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectMergeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectMergeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectMergeRule.java
index e581e1a..5fd7d53 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectMergeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectMergeRule.java
@@ -18,14 +18,13 @@ package org.apache.calcite.rel.rules;
 
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Aggregate;
 import org.apache.calcite.rel.core.AggregateCall;
 import org.apache.calcite.rel.core.Project;
-import org.apache.calcite.rel.core.RelFactories;
 import org.apache.calcite.rex.RexInputRef;
 import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.tools.RelBuilder;
 import org.apache.calcite.util.ImmutableBitSet;
 
 import com.google.common.collect.ImmutableList;
@@ -60,13 +59,13 @@ public class AggregateProjectMergeRule extends RelOptRule {
   public void onMatch(RelOptRuleCall call) {
     final Aggregate aggregate = call.rel(0);
     final Project project = call.rel(1);
-    RelNode x = apply(aggregate, project);
+    RelNode x = apply(call, aggregate, project);
     if (x != null) {
       call.transformTo(x);
     }
   }
 
-  public static RelNode apply(Aggregate aggregate,
+  public static RelNode apply(RelOptRuleCall call, Aggregate aggregate,
       Project project) {
     final List<Integer> newKeys = Lists.newArrayList();
     final Map<Integer, Integer> map = new HashMap<>();
@@ -123,7 +122,8 @@ public class AggregateProjectMergeRule extends RelOptRule {
 
     // Add a project if the group set is not in the same order or
     // contains duplicates.
-    RelNode rel = newAggregate;
+    final RelBuilder relBuilder = call.builder();
+    relBuilder.push(newAggregate);
     if (!newKeys.equals(newGroupSet.asList())) {
       final List<Integer> posList = Lists.newArrayList();
       for (int newKey : newKeys) {
@@ -139,11 +139,10 @@ public class AggregateProjectMergeRule extends RelOptRule {
            i < newAggregate.getRowType().getFieldCount(); i++) {
         posList.add(i);
       }
-      rel = RelOptUtil.createProject(RelFactories.DEFAULT_PROJECT_FACTORY,
-          rel, posList);
+      relBuilder.project(relBuilder.fields(posList));
     }
 
-    return rel;
+    return relBuilder.build();
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectPullUpConstantsRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectPullUpConstantsRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectPullUpConstantsRule.java
index 75bb99e..94a28eb 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectPullUpConstantsRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectPullUpConstantsRule.java
@@ -18,20 +18,17 @@ package org.apache.calcite.rel.rules;
 
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.calcite.plan.RelOptUtil;
-import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Aggregate;
 import org.apache.calcite.rel.core.AggregateCall;
 import org.apache.calcite.rel.logical.LogicalAggregate;
 import org.apache.calcite.rel.logical.LogicalProject;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeField;
-import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexLocalRef;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexProgram;
+import org.apache.calcite.tools.RelBuilder;
 import org.apache.calcite.util.ImmutableBitSet;
-import org.apache.calcite.util.IntList;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Permutation;
 import org.apache.calcite.util.mapping.Mapping;
@@ -79,10 +76,9 @@ public class AggregateProjectPullUpConstantsRule extends RelOptRule {
 
   //~ Methods ----------------------------------------------------------------
 
-  // implement RelOptRule
   public void onMatch(RelOptRuleCall call) {
-    LogicalAggregate aggregate = call.rel(0);
-    LogicalProject input = call.rel(1);
+    final LogicalAggregate aggregate = call.rel(0);
+    final LogicalProject input = call.rel(1);
 
     final int groupCount = aggregate.getGroupCount();
     if (groupCount == 1) {
@@ -99,8 +95,8 @@ public class AggregateProjectPullUpConstantsRule extends RelOptRule {
           input.getCluster().getRexBuilder());
 
     final RelDataType childRowType = input.getRowType();
-    IntList constantList = new IntList();
-    Map<Integer, RexNode> constants = new HashMap<Integer, RexNode>();
+    final List<Integer> constantList = new ArrayList<>();
+    final Map<Integer, RexNode> constants = new HashMap<>();
     for (int i : aggregate.getGroupSet()) {
       final RexLocalRef ref = program.getProjectList().get(i);
       if (program.isConstant(ref)) {
@@ -126,22 +122,22 @@ public class AggregateProjectPullUpConstantsRule extends RelOptRule {
     }
 
     final int newGroupCount = groupCount - constantList.size();
-    final RelNode newAggregate;
 
     // If the constants are on the trailing edge of the group list, we just
     // reduce the group count.
+    final RelBuilder relBuilder = call.builder();
+    relBuilder.push(input);
     if (constantList.get(0) == newGroupCount) {
       // Clone aggregate calls.
-      final List<AggregateCall> newAggCalls =
-          new ArrayList<AggregateCall>();
+      final List<AggregateCall> newAggCalls = new ArrayList<>();
       for (AggregateCall aggCall : aggregate.getAggCallList()) {
         newAggCalls.add(
             aggCall.adaptTo(input, aggCall.getArgList(), aggCall.filterArg,
                 groupCount, newGroupCount));
       }
-      newAggregate =
-          LogicalAggregate.create(input, false,
-              ImmutableBitSet.range(newGroupCount), null, newAggCalls);
+      relBuilder.aggregate(
+          relBuilder.groupKey(ImmutableBitSet.range(newGroupCount), null),
+          newAggCalls);
     } else {
       // Create the mapping from old field positions to new field
       // positions.
@@ -164,14 +160,13 @@ public class AggregateProjectPullUpConstantsRule extends RelOptRule {
       }
 
       // Create a projection to permute fields into these positions.
-      final RelNode project = createProjection(mapping, input);
+      createProjection(relBuilder, mapping);
 
       // Adjust aggregate calls for new field positions.
-      final List<AggregateCall> newAggCalls =
-          new ArrayList<AggregateCall>();
+      final List<AggregateCall> newAggCalls = new ArrayList<>();
       for (AggregateCall aggCall : aggregate.getAggCallList()) {
         final int argCount = aggCall.getArgList().size();
-        final List<Integer> args = new ArrayList<Integer>(argCount);
+        final List<Integer> args = new ArrayList<>(argCount);
         for (int j = 0; j < argCount; j++) {
           final Integer arg = aggCall.getArgList().get(j);
           args.add(mapping.getTarget(arg));
@@ -179,43 +174,38 @@ public class AggregateProjectPullUpConstantsRule extends RelOptRule {
         final int filterArg = aggCall.filterArg < 0 ? aggCall.filterArg
             : mapping.getTarget(aggCall.filterArg);
         newAggCalls.add(
-            aggCall.adaptTo(project, args, filterArg, groupCount,
+            aggCall.adaptTo(relBuilder.peek(), args, filterArg, groupCount,
                 newGroupCount));
       }
 
       // Aggregate on projection.
-      newAggregate =
-          LogicalAggregate.create(project, false,
-              ImmutableBitSet.range(newGroupCount), null, newAggCalls);
+      relBuilder.aggregate(
+          relBuilder.groupKey(ImmutableBitSet.range(newGroupCount), null),
+              newAggCalls);
     }
 
-    final RexBuilder rexBuilder = aggregate.getCluster().getRexBuilder();
-
     // Create a projection back again.
-    List<Pair<RexNode, String>> projects =
-        new ArrayList<Pair<RexNode, String>>();
+    List<Pair<RexNode, String>> projects = new ArrayList<>();
     int source = 0;
     for (RelDataTypeField field : aggregate.getRowType().getFieldList()) {
       RexNode expr;
       final int i = field.getIndex();
       if (i >= groupCount) {
         // Aggregate expressions' names and positions are unchanged.
-        expr = rexBuilder.makeInputRef(newAggregate, i - constantList.size());
+        expr = relBuilder.field(i - constantList.size());
       } else if (constantList.contains(i)) {
         // Re-generate the constant expression in the project.
         expr = constants.get(i);
       } else {
         // Project the aggregation expression, in its original
         // position.
-        expr = rexBuilder.makeInputRef(newAggregate, source);
+        expr = relBuilder.field(source);
         ++source;
       }
       projects.add(Pair.of(expr, field.getName()));
     }
-    final RelNode inverseProject =
-        RelOptUtil.createProject(newAggregate, projects, false);
-
-    call.transformTo(inverseProject);
+    relBuilder.project(Pair.left(projects), Pair.right(projects)); // inverse
+    call.transformTo(relBuilder.build());
   }
 
   /**
@@ -225,29 +215,25 @@ public class AggregateProjectPullUpConstantsRule extends RelOptRule {
    * <p>For example, given a relational expression [A, B, C, D] and a mapping
    * [2:1, 3:0], returns a projection [$3 AS C, $2 AS B].
    *
+   * @param relBuilder Relational expression builder
    * @param mapping Mapping to apply to source columns
-   * @param child   Relational expression
-   * @return Relational expressions with permutation applied
    */
-  private static RelNode createProjection(
-      final Mapping mapping,
-      RelNode child) {
+  private static RelBuilder createProjection(RelBuilder relBuilder,
+      Mapping mapping) {
     // Every target has precisely one source; every source has at most
     // one target.
     assert mapping.getMappingType().isA(MappingType.INVERSE_SURJECTION);
-    final RelDataType childRowType = child.getRowType();
+    final RelDataType childRowType = relBuilder.peek().getRowType();
     assert mapping.getSourceCount() == childRowType.getFieldCount();
-    List<Pair<RexNode, String>> projects =
-        new ArrayList<Pair<RexNode, String>>();
+    final List<Pair<RexNode, String>> projects = new ArrayList<>();
     for (int target = 0; target < mapping.getTargetCount(); ++target) {
       int source = mapping.getSource(target);
-      final RexBuilder rexBuilder = child.getCluster().getRexBuilder();
       projects.add(
-          Pair.of(
-              (RexNode) rexBuilder.makeInputRef(child, source),
+          Pair.<RexNode, String>of(
+              relBuilder.field(source),
               childRowType.getFieldList().get(source).getName()));
     }
-    return RelOptUtil.createProject(child, projects, false);
+    return relBuilder.project(Pair.left(projects), Pair.right(projects));
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
index 752c212..f01d738 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
@@ -19,10 +19,10 @@ package org.apache.calcite.rel.rules;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
 import org.apache.calcite.plan.RelOptRuleOperand;
-import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Aggregate;
 import org.apache.calcite.rel.core.AggregateCall;
+import org.apache.calcite.rel.core.RelFactories;
 import org.apache.calcite.rel.logical.LogicalAggregate;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
@@ -35,6 +35,8 @@ import org.apache.calcite.sql.fun.SqlAvgAggFunction;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.fun.SqlSumAggFunction;
 import org.apache.calcite.sql.type.SqlTypeUtil;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
 import org.apache.calcite.util.CompositeList;
 import org.apache.calcite.util.ImmutableIntList;
 import org.apache.calcite.util.Util;
@@ -82,12 +84,14 @@ public class AggregateReduceFunctionsRule extends RelOptRule {
 
   /** The singleton. */
   public static final AggregateReduceFunctionsRule INSTANCE =
-      new AggregateReduceFunctionsRule(operand(LogicalAggregate.class, any()));
+      new AggregateReduceFunctionsRule(operand(LogicalAggregate.class, any()),
+          RelFactories.LOGICAL_BUILDER);
 
   //~ Constructors -----------------------------------------------------------
 
-  protected AggregateReduceFunctionsRule(RelOptRuleOperand operand) {
-    super(operand);
+  protected AggregateReduceFunctionsRule(RelOptRuleOperand operand,
+      RelBuilderFactory relBuilderFactory) {
+    super(operand, relBuilderFactory, null);
   }
 
   //~ Methods ----------------------------------------------------------------
@@ -152,9 +156,9 @@ public class AggregateReduceFunctionsRule extends RelOptRule {
     // List of input expressions. If a particular aggregate needs more, it
     // will add an expression to the end, and we will create an extra
     // project.
-    RelNode input = oldAggRel.getInput();
-    final List<RexNode> inputExprs =
-        new ArrayList<>(rexBuilder.identityProjects(input.getRowType()));
+    final RelBuilder relBuilder = ruleCall.builder();
+    relBuilder.push(oldAggRel.getInput());
+    final List<RexNode> inputExprs = new ArrayList<>(relBuilder.fields());
 
     // create new agg function calls and rest of project list together
     for (AggregateCall oldCall : oldCalls) {
@@ -164,29 +168,16 @@ public class AggregateReduceFunctionsRule extends RelOptRule {
     }
 
     final int extraArgCount =
-        inputExprs.size() - input.getRowType().getFieldCount();
+        inputExprs.size() - relBuilder.peek().getRowType().getFieldCount();
     if (extraArgCount > 0) {
-      input =
-          RelOptUtil.createProject(
-              input,
-              inputExprs,
-              CompositeList.of(
-                  input.getRowType().getFieldNames(),
-                  Collections.<String>nCopies(
-                      extraArgCount,
-                      null)));
+      relBuilder.project(inputExprs,
+          CompositeList.of(
+              relBuilder.peek().getRowType().getFieldNames(),
+              Collections.<String>nCopies(extraArgCount, null)));
     }
-    Aggregate newAggRel =
-        newAggregateRel(
-            oldAggRel, input, newCalls);
-
-    RelNode projectRel =
-        RelOptUtil.createProject(
-            newAggRel,
-            projList,
-            oldAggRel.getRowType().getFieldNames());
-
-    ruleCall.transformTo(projectRel);
+    newAggregateRel(relBuilder, oldAggRel, newCalls);
+    relBuilder.project(projList, oldAggRel.getRowType().getFieldNames());
+    ruleCall.transformTo(relBuilder.build());
   }
 
   private RexNode reduceAgg(
@@ -206,38 +197,33 @@ public class AggregateReduceFunctionsRule extends RelOptRule {
       switch (subtype) {
       case AVG:
         // replace original AVG(x) with SUM(x) / COUNT(x)
-        return reduceAvg(
-            oldAggRel, oldCall, newCalls, aggCallMapping);
+        return reduceAvg(oldAggRel, oldCall, newCalls, aggCallMapping);
       case STDDEV_POP:
         // replace original STDDEV_POP(x) with
         //   SQRT(
         //     (SUM(x * x) - SUM(x) * SUM(x) / COUNT(x))
         //     / COUNT(x))
-        return reduceStddev(
-            oldAggRel, oldCall, true, true, newCalls, aggCallMapping,
-            inputExprs);
+        return reduceStddev(oldAggRel, oldCall, true, true, newCalls,
+            aggCallMapping, inputExprs);
       case STDDEV_SAMP:
         // replace original STDDEV_POP(x) with
         //   SQRT(
         //     (SUM(x * x) - SUM(x) * SUM(x) / COUNT(x))
         //     / CASE COUNT(x) WHEN 1 THEN NULL ELSE COUNT(x) - 1 END)
-        return reduceStddev(
-            oldAggRel, oldCall, false, true, newCalls, aggCallMapping,
-            inputExprs);
+        return reduceStddev(oldAggRel, oldCall, false, true, newCalls,
+            aggCallMapping, inputExprs);
       case VAR_POP:
         // replace original VAR_POP(x) with
         //     (SUM(x * x) - SUM(x) * SUM(x) / COUNT(x))
         //     / COUNT(x)
-        return reduceStddev(
-            oldAggRel, oldCall, true, false, newCalls, aggCallMapping,
-            inputExprs);
+        return reduceStddev(oldAggRel, oldCall, true, false, newCalls,
+            aggCallMapping, inputExprs);
       case VAR_SAMP:
         // replace original VAR_POP(x) with
         //     (SUM(x * x) - SUM(x) * SUM(x) / COUNT(x))
         //     / CASE COUNT(x) WHEN 1 THEN NULL ELSE COUNT(x) - 1 END
-        return reduceStddev(
-            oldAggRel, oldCall, false, false, newCalls, aggCallMapping,
-            inputExprs);
+        return reduceStddev(oldAggRel, oldCall, false, false, newCalls,
+            aggCallMapping, inputExprs);
       default:
         throw Util.unexpected(subtype);
       }
@@ -541,17 +527,17 @@ public class AggregateReduceFunctionsRule extends RelOptRule {
    * into Aggregate and subclasses - but it's only needed for some
    * subclasses.
    *
+   * @param relBuilder Builder of relational expressions; at the top of its
+   *                   stack is its input
    * @param oldAggregate LogicalAggregate to clone.
-   * @param input  Input relational expression
    * @param newCalls  New list of AggregateCalls
-   * @return shallow clone with new list of AggregateCalls.
    */
-  protected Aggregate newAggregateRel(
+  protected void newAggregateRel(RelBuilder relBuilder,
       Aggregate oldAggregate,
-      RelNode input,
       List<AggregateCall> newCalls) {
-    return LogicalAggregate.create(input, oldAggregate.indicator,
-        oldAggregate.getGroupSet(), oldAggregate.getGroupSets(),
+    relBuilder.aggregate(
+        relBuilder.groupKey(oldAggregate.getGroupSet(),
+            oldAggregate.getGroupSets()),
         newCalls);
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/AggregateRemoveRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateRemoveRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateRemoveRule.java
index 12f735c..bbb19f3 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateRemoveRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateRemoveRule.java
@@ -18,9 +18,9 @@ package org.apache.calcite.rel.rules;
 
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.logical.LogicalAggregate;
+import org.apache.calcite.tools.RelBuilder;
 
 /**
  * Planner rule that removes
@@ -67,15 +67,13 @@ public class AggregateRemoveRule extends RelOptRule {
 
     // If aggregate was projecting a subset of columns, add a project for the
     // same effect.
-    RelNode rel;
+    final RelBuilder relBuilder = call.builder();
+    relBuilder.push(newInput);
     if (newInput.getRowType().getFieldCount()
         > aggregate.getRowType().getFieldCount()) {
-      rel = RelOptUtil.createProject(newInput,
-          aggregate.getGroupSet().toList());
-    } else {
-      rel = newInput;
+      relBuilder.project(relBuilder.fields(aggregate.getGroupSet().toList()));
     }
-    call.transformTo(rel);
+    call.transformTo(relBuilder.build());
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/AggregateStarTableRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateStarTableRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateStarTableRule.java
index e9c7c9c..7464a0f 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateStarTableRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateStarTableRule.java
@@ -37,6 +37,7 @@ import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.schema.Table;
 import org.apache.calcite.schema.impl.StarTable;
 import org.apache.calcite.sql.SqlAggFunction;
+import org.apache.calcite.tools.RelBuilder;
 import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.mapping.AbstractSourceMapping;
@@ -71,7 +72,7 @@ public class AggregateStarTableRule extends RelOptRule {
           final Project project = call.rel(1);
           final StarTable.StarTableScan scan = call.rel(2);
           final RelNode rel =
-              AggregateProjectMergeRule.apply(aggregate, project);
+              AggregateProjectMergeRule.apply(call, aggregate, project);
           final Aggregate aggregate2;
           final Project project2;
           if (rel instanceof Aggregate) {
@@ -106,11 +107,12 @@ public class AggregateStarTableRule extends RelOptRule {
     final List<Lattice.Measure> measures =
         lattice.lattice.toMeasures(aggregate.getAggCallList());
     final Pair<CalciteSchema.TableEntry, TileKey> pair =
-        lattice.getAggregate(call.getPlanner(), aggregate.getGroupSet(),
-            measures);
+        lattice.getAggregate(
+            call.getPlanner(), aggregate.getGroupSet(), measures);
     if (pair == null) {
       return;
     }
+    final RelBuilder relBuilder = call.builder();
     final CalciteSchema.TableEntry tableEntry = pair.left;
     final TileKey tileKey = pair.right;
     final double rowCount = aggregate.getRows();
@@ -118,9 +120,12 @@ public class AggregateStarTableRule extends RelOptRule {
     final RelDataType aggregateTableRowType =
         aggregateTable.getRowType(cluster.getTypeFactory());
     final RelOptTable aggregateRelOptTable =
-        RelOptTableImpl.create(table.getRelOptSchema(), aggregateTableRowType,
-            tableEntry, rowCount);
-    RelNode rel = aggregateRelOptTable.toRel(RelOptUtil.getContext(cluster));
+        RelOptTableImpl.create(
+            table.getRelOptSchema(),
+            aggregateTableRowType,
+            tableEntry,
+            rowCount);
+    relBuilder.push(aggregateRelOptTable.toRel(RelOptUtil.getContext(cluster)));
     if (tileKey == null) {
       if (CalcitePrepareImpl.DEBUG) {
         System.out.println("Using materialization "
@@ -143,44 +148,50 @@ public class AggregateStarTableRule extends RelOptRule {
       }
       for (AggregateCall aggCall : aggregate.getAggCallList()) {
         final AggregateCall copy =
-            rollUp(groupSet.cardinality(), rel, aggCall, tileKey);
+            rollUp(groupSet.cardinality(), relBuilder, aggCall, tileKey);
         if (copy == null) {
           return;
         }
         aggCalls.add(copy);
       }
-      rel = aggregate.copy(aggregate.getTraitSet(), rel, false,
-          groupSet.build(), null, aggCalls);
+      relBuilder.push(
+          aggregate.copy(aggregate.getTraitSet(), relBuilder.build(), false,
+              groupSet.build(), null, aggCalls));
     } else if (!tileKey.measures.equals(measures)) {
-      System.out.println("Using materialization "
-          + aggregateRelOptTable.getQualifiedName()
-          + ", right granularity, but different measures "
-          + aggregate.getAggCallList());
-      rel = RelOptUtil.createProject(rel,
-          new AbstractSourceMapping(
-              tileKey.dimensions.cardinality() + tileKey.measures.size(),
-              aggregate.getRowType().getFieldCount()) {
-            public int getSourceOpt(int source) {
-              assert aggregate.getIndicatorCount() == 0;
-              if (source < aggregate.getGroupCount()) {
-                int in = tileKey.dimensions.nth(source);
-                return aggregate.getGroupSet().indexOf(in);
-              }
-              Lattice.Measure measure =
-                  measures.get(source - aggregate.getGroupCount());
-              int i = tileKey.measures.indexOf(measure);
-              assert i >= 0;
-              return tileKey.dimensions.cardinality() + i;
-            }
-          });
+      if (CalcitePrepareImpl.DEBUG) {
+        System.out.println("Using materialization "
+            + aggregateRelOptTable.getQualifiedName()
+            + ", right granularity, but different measures "
+            + aggregate.getAggCallList());
+      }
+      relBuilder.project(
+          relBuilder.fields(
+              new AbstractSourceMapping(
+                  tileKey.dimensions.cardinality() + tileKey.measures.size(),
+                  aggregate.getRowType().getFieldCount()) {
+                public int getSourceOpt(int source) {
+                  assert aggregate.getIndicatorCount() == 0;
+                  if (source < aggregate.getGroupCount()) {
+                    int in = tileKey.dimensions.nth(source);
+                    return aggregate.getGroupSet().indexOf(in);
+                  }
+                  Lattice.Measure measure =
+                      measures.get(source - aggregate.getGroupCount());
+                  int i = tileKey.measures.indexOf(measure);
+                  assert i >= 0;
+                  return tileKey.dimensions.cardinality() + i;
+                }
+              } .inverse()));
     }
     if (postProject != null) {
-      rel = postProject.copy(postProject.getTraitSet(), ImmutableList.of(rel));
+      relBuilder.push(
+          postProject.copy(postProject.getTraitSet(),
+              ImmutableList.of(relBuilder.peek())));
     }
-    call.transformTo(rel);
+    call.transformTo(relBuilder.build());
   }
 
-  private static AggregateCall rollUp(int groupCount, RelNode input,
+  private static AggregateCall rollUp(int groupCount, RelBuilder relBuilder,
       AggregateCall aggregateCall, TileKey tileKey) {
     if (aggregateCall.isDistinct()) {
       return null;
@@ -201,7 +212,7 @@ public class AggregateStarTableRule extends RelOptRule {
         break tryRoll;
       }
       return AggregateCall.create(roll, false, ImmutableList.of(offset + i), -1,
-          groupCount, input, null, aggregateCall.name);
+          groupCount, relBuilder.peek(), null, aggregateCall.name);
     }
 
     // Second, try to satisfy the aggregation based on group set columns.
@@ -216,7 +227,7 @@ public class AggregateStarTableRule extends RelOptRule {
         newArgs.add(z);
       }
       return AggregateCall.create(aggregation, false, newArgs, -1,
-          groupCount, input, null, aggregateCall.name);
+          groupCount, relBuilder.peek(), null, aggregateCall.name);
     }
 
     // No roll up possible.

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionAggregateRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionAggregateRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionAggregateRule.java
index 9f64f0f..8eeaaa7 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionAggregateRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionAggregateRule.java
@@ -24,11 +24,8 @@ import org.apache.calcite.rel.core.RelFactories;
 import org.apache.calcite.rel.core.Union;
 import org.apache.calcite.rel.logical.LogicalAggregate;
 import org.apache.calcite.rel.logical.LogicalUnion;
-import org.apache.calcite.sql.SqlKind;
-
-import com.google.common.collect.ImmutableList;
-
-import java.util.List;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
 
 /**
  * Planner rule that matches
@@ -44,13 +41,7 @@ import java.util.List;
 public class AggregateUnionAggregateRule extends RelOptRule {
   public static final AggregateUnionAggregateRule INSTANCE =
       new AggregateUnionAggregateRule(LogicalAggregate.class,
-          RelFactories.DEFAULT_AGGREGATE_FACTORY,
-          LogicalUnion.class,
-          RelFactories.DEFAULT_SET_OP_FACTORY);
-
-  private final RelFactories.AggregateFactory aggregateFactory;
-
-  private final RelFactories.SetOpFactory setOpFactory;
+          LogicalUnion.class, RelFactories.LOGICAL_BUILDER);
 
   //~ Constructors -----------------------------------------------------------
 
@@ -58,48 +49,50 @@ public class AggregateUnionAggregateRule extends RelOptRule {
    * Creates a AggregateUnionAggregateRule.
    */
   public AggregateUnionAggregateRule(Class<? extends Aggregate> aggregateClass,
-      RelFactories.AggregateFactory aggregateFactory,
-      Class<? extends Union> unionClass,
-      RelFactories.SetOpFactory setOpFactory) {
+      Class<? extends Union> unionClass, RelBuilderFactory relBuilderFactory) {
     super(
         operand(aggregateClass, null, Aggregate.IS_SIMPLE,
             operand(unionClass,
                 operand(RelNode.class, any()),
-                operand(RelNode.class, any()))));
-    this.aggregateFactory = aggregateFactory;
-    this.setOpFactory = setOpFactory;
+                operand(RelNode.class, any()))),
+        relBuilderFactory, null);
+  }
+
+  @Deprecated // to be removed before 2.0
+  public AggregateUnionAggregateRule(Class<? extends Aggregate> aggregateClass,
+      RelFactories.AggregateFactory aggregateFactory,
+      Class<? extends Union> unionClass,
+      RelFactories.SetOpFactory setOpFactory) {
+    this(aggregateClass, unionClass,
+        RelBuilder.proto(aggregateFactory, setOpFactory));
   }
 
   //~ Methods ----------------------------------------------------------------
 
-  // implement RelOptRule
   public void onMatch(RelOptRuleCall call) {
-    Union union = call.rel(1);
+    final Aggregate topAggRel = call.rel(0);
+    final Union union = call.rel(1);
 
     // If distincts haven't been removed yet, defer invoking this rule
     if (!union.all) {
       return;
     }
 
-    Aggregate topAggRel = call.rel(0);
-    Aggregate bottomAggRel;
-
     // We want to apply this rule on the pattern where the LogicalAggregate
     // is the second input into the Union first.  Hence, that's why the
     // rule pattern matches on generic RelNodes rather than explicit
     // UnionRels.  By doing so, and firing this rule in a bottom-up order,
     // it allows us to only specify a single pattern for this rule.
-    List<RelNode> unionInputs;
+    final RelBuilder relBuilder = call.builder();
+    final Aggregate bottomAggRel;
     if (call.rel(3) instanceof Aggregate) {
       bottomAggRel = call.rel(3);
-      unionInputs = ImmutableList.of(
-          call.rel(2),
-          call.rel(3).getInput(0));
+      relBuilder.push(call.rel(2))
+          .push(call.rel(3).getInput(0));
     } else if (call.rel(2) instanceof Aggregate) {
       bottomAggRel = call.rel(2);
-      unionInputs = ImmutableList.of(
-          call.rel(2).getInput(0),
-          call.rel(3));
+      relBuilder.push(call.rel(2).getInput(0))
+          .push(call.rel(3));
     } else {
       return;
     }
@@ -110,14 +103,10 @@ public class AggregateUnionAggregateRule extends RelOptRule {
       return;
     }
 
-    RelNode newUnion = setOpFactory.createSetOp(SqlKind.UNION,
-        unionInputs, true);
-
-    RelNode newAggRel =
-        aggregateFactory.createAggregate(newUnion, false,
-            topAggRel.getGroupSet(), null, topAggRel.getAggCallList());
-
-    call.transformTo(newAggRel);
+    relBuilder.union(true);
+    relBuilder.aggregate(relBuilder.groupKey(topAggRel.getGroupSet(), null),
+        topAggRel.getAggCallList());
+    call.transformTo(relBuilder.build());
   }
 }