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:32 UTC

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

Repository: incubator-calcite
Updated Branches:
  refs/heads/master a1e0b0068 -> d697ca164


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
index 2aa0d50..5e11fd1 100644
--- a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
@@ -38,11 +38,16 @@ import org.apache.calcite.tools.Frameworks;
 import org.apache.calcite.tools.Programs;
 import org.apache.calcite.tools.RelBuilder;
 import org.apache.calcite.tools.RelRunners;
+import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.Util;
+import org.apache.calcite.util.mapping.Mappings;
+
+import com.google.common.collect.ImmutableList;
 
 import org.junit.Test;
 
 import java.sql.PreparedStatement;
+import java.util.Arrays;
 import java.util.List;
 
 import static org.hamcrest.CoreMatchers.is;
@@ -256,6 +261,74 @@ public class RelBuilderTest {
                 + "  LogicalTableScan(table=[[scott, EMP]])\n"));
   }
 
+  @Test public void testProjectIdentity() {
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode root =
+        builder.scan("DEPT")
+            .project(builder.fields(Mappings.bijection(Arrays.asList(0, 1, 2))))
+            .build();
+    final String expected = "LogicalTableScan(table=[[scott, DEPT]])\n";
+    assertThat(str(root), is(expected));
+  }
+
+  @Test public void testProjectLeadingEdge() {
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode root =
+        builder.scan("EMP")
+            .project(builder.fields(Mappings.bijection(Arrays.asList(0, 1, 2))))
+            .build();
+    final String expected = "LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2])\n"
+        + "  LogicalTableScan(table=[[scott, EMP]])\n";
+    assertThat(str(root), is(expected));
+  }
+
+  @Test public void testPermute() {
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode root =
+        builder.scan("EMP")
+            .permute(Mappings.bijection(Arrays.asList(1, 2, 0)))
+            .build();
+    final String expected = "LogicalProject(JOB=[$2], EMPNO=[$0], ENAME=[$1])\n"
+        + "  LogicalTableScan(table=[[scott, EMP]])\n";
+    assertThat(str(root), is(expected));
+  }
+
+  @Test public void testConvert() {
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelDataType rowType =
+        builder.getTypeFactory().builder()
+            .add("a", SqlTypeName.BIGINT)
+            .add("b", SqlTypeName.VARCHAR, 10)
+            .add("c", SqlTypeName.VARCHAR, 10)
+            .build();
+    RelNode root =
+        builder.scan("DEPT")
+            .convert(rowType, false)
+            .build();
+    final String expected = ""
+        + "LogicalProject(DEPTNO=[CAST($0):BIGINT NOT NULL], DNAME=[CAST($1):VARCHAR(10) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\" NOT NULL], LOC=[CAST($2):VARCHAR(10) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\" NOT NULL])\n"
+        + "  LogicalTableScan(table=[[scott, DEPT]])\n";
+    assertThat(str(root), is(expected));
+  }
+
+  @Test public void testConvertRename() {
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelDataType rowType =
+        builder.getTypeFactory().builder()
+            .add("a", SqlTypeName.BIGINT)
+            .add("b", SqlTypeName.VARCHAR, 10)
+            .add("c", SqlTypeName.VARCHAR, 10)
+            .build();
+    RelNode root =
+        builder.scan("DEPT")
+            .convert(rowType, true)
+            .build();
+    final String expected = ""
+        + "LogicalProject(a=[CAST($0):BIGINT NOT NULL], b=[CAST($1):VARCHAR(10) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\" NOT NULL], c=[CAST($2):VARCHAR(10) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\" NOT NULL])\n"
+        + "  LogicalTableScan(table=[[scott, DEPT]])\n";
+    assertThat(str(root), is(expected));
+  }
+
   @Test public void testAggregate() {
     // Equivalent SQL:
     //   SELECT COUNT(DISTINCT deptno) AS c
@@ -265,10 +338,8 @@ public class RelBuilderTest {
     RelNode root =
         builder.scan("EMP")
             .aggregate(builder.groupKey(),
-                builder.aggregateCall(SqlStdOperatorTable.COUNT,
-                    true,
-                    "C",
-                    builder.field("DEPTNO")))
+                builder.aggregateCall(SqlStdOperatorTable.COUNT, true, null,
+                    "C", builder.field("DEPTNO")))
             .build();
     assertThat(str(root),
         is("LogicalAggregate(group=[{}], C=[COUNT(DISTINCT $7)])\n"
@@ -289,8 +360,9 @@ public class RelBuilderTest {
                         builder.field(4),
                         builder.field(3)),
                     builder.field(1)),
-                builder.aggregateCall(SqlStdOperatorTable.COUNT, false, "C"),
-                builder.aggregateCall(SqlStdOperatorTable.SUM, false, "S",
+                builder.aggregateCall(SqlStdOperatorTable.COUNT, false, null,
+                    "C"),
+                builder.aggregateCall(SqlStdOperatorTable.SUM, false, null, "S",
                     builder.call(SqlStdOperatorTable.PLUS, builder.field(3),
                         builder.literal(1))))
             .build();
@@ -301,6 +373,75 @@ public class RelBuilderTest {
             + "    LogicalTableScan(table=[[scott, EMP]])\n"));
   }
 
+  @Test public void testAggregateFilter() {
+    // Equivalent SQL:
+    //   SELECT deptno, COUNT(*) FILTER (WHERE empno > 100) AS c
+    //   FROM emp
+    //   GROUP BY ROLLUP(deptno)
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode root =
+        builder.scan("EMP")
+            .aggregate(
+                builder.groupKey(ImmutableBitSet.of(7),
+                    ImmutableList.of(ImmutableBitSet.of(7),
+                        ImmutableBitSet.of())),
+                builder.aggregateCall(SqlStdOperatorTable.COUNT, false,
+                    builder.call(SqlStdOperatorTable.GREATER_THAN,
+                        builder.field("EMPNO"), builder.literal(100)), "C"))
+            .build();
+    final String expected = ""
+        + "LogicalAggregate(group=[{7}], groups=[[{7}, {}]], indicator=[true], C=[COUNT() FILTER $8])\n"
+        + "  LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], $f8=[>($0, 100)])\n"
+        + "    LogicalTableScan(table=[[scott, EMP]])\n";
+    assertThat(str(root), is(expected));
+  }
+
+  @Test public void testAggregateGroupingKeyOutOfRangeFails() {
+    final RelBuilder builder = RelBuilder.create(config().build());
+    try {
+      RelNode root =
+          builder.scan("EMP")
+              .aggregate(builder.groupKey(ImmutableBitSet.of(17), null))
+              .build();
+      fail("expected error, got " + root);
+    } catch (IllegalArgumentException e) {
+      assertThat(e.getMessage(), is("out of bounds: {17}"));
+    }
+  }
+
+  @Test public void testAggregateGroupingSetNotSubsetFails() {
+    final RelBuilder builder = RelBuilder.create(config().build());
+    try {
+      RelNode root =
+          builder.scan("EMP")
+              .aggregate(
+                  builder.groupKey(ImmutableBitSet.of(7),
+                      ImmutableList.of(ImmutableBitSet.of(4),
+                          ImmutableBitSet.of())))
+              .build();
+      fail("expected error, got " + root);
+    } catch (IllegalArgumentException e) {
+      assertThat(e.getMessage(),
+          is("group set element [$4] must be a subset of group key"));
+    }
+  }
+
+  @Test public void testAggregateGroupingSetDuplicateIgnored() {
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode root =
+        builder.scan("EMP")
+            .aggregate(
+                builder.groupKey(ImmutableBitSet.of(7, 6),
+                    ImmutableList.of(ImmutableBitSet.of(7),
+                        ImmutableBitSet.of(6),
+                        ImmutableBitSet.of(7))))
+            .build();
+    final String expected = ""
+        + "LogicalAggregate(group=[{6, 7}], groups=[[{6}, {7}]], indicator=[true])\n"
+        + "  LogicalTableScan(table=[[scott, EMP]])\n";
+    assertThat(str(root), is(expected));
+  }
+
   @Test public void testDistinct() {
     // Equivalent SQL:
     //   SELECT DISTINCT *
@@ -322,14 +463,14 @@ public class RelBuilderTest {
     //   SELECT deptno FROM dept
     final RelBuilder builder = RelBuilder.create(config().build());
     RelNode root =
-        builder.scan("EMP")
+        builder.scan("DEPT")
+            .project(builder.field("DEPTNO"))
+            .scan("EMP")
             .filter(
                 builder.call(SqlStdOperatorTable.EQUALS,
                     builder.field("DEPTNO"),
                     builder.literal(20)))
             .project(builder.field("EMPNO"))
-            .scan("DEPT")
-            .project(builder.field("DEPTNO"))
             .union(true)
             .build();
     assertThat(str(root),
@@ -341,6 +482,55 @@ public class RelBuilderTest {
             + "      LogicalTableScan(table=[[scott, EMP]])\n"));
   }
 
+  @Test public void testUnion3() {
+    // Equivalent SQL:
+    //   SELECT deptno FROM dept
+    //   UNION ALL
+    //   SELECT empno FROM emp
+    //   UNION ALL
+    //   SELECT deptno FROM emp
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode root =
+        builder.scan("DEPT")
+            .project(builder.field("DEPTNO"))
+            .scan("EMP")
+            .project(builder.field("EMPNO"))
+            .scan("EMP")
+            .project(builder.field("DEPTNO"))
+            .union(true, 3)
+            .build();
+    assertThat(str(root),
+        is("LogicalUnion(all=[true])\n"
+            + "  LogicalProject(DEPTNO=[$0])\n"
+            + "    LogicalTableScan(table=[[scott, DEPT]])\n"
+            + "  LogicalProject(EMPNO=[$0])\n"
+            + "    LogicalTableScan(table=[[scott, EMP]])\n"
+            + "  LogicalProject(DEPTNO=[$7])\n"
+            + "    LogicalTableScan(table=[[scott, EMP]])\n"));
+  }
+
+  @Test public void testUnion1() {
+    // Equivalent SQL:
+    //   SELECT deptno FROM dept
+    //   UNION ALL
+    //   SELECT empno FROM emp
+    //   UNION ALL
+    //   SELECT deptno FROM emp
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode root =
+        builder.scan("DEPT")
+            .project(builder.field("DEPTNO"))
+            .scan("EMP")
+            .project(builder.field("EMPNO"))
+            .scan("EMP")
+            .project(builder.field("DEPTNO"))
+            .union(true, 1)
+            .build();
+    assertThat(str(root),
+        is("LogicalProject(DEPTNO=[$7])\n"
+            + "  LogicalTableScan(table=[[scott, EMP]])\n"));
+  }
+
   @Test public void testIntersect() {
     // Equivalent SQL:
     //   SELECT empno FROM emp
@@ -349,14 +539,14 @@ public class RelBuilderTest {
     //   SELECT deptno FROM dept
     final RelBuilder builder = RelBuilder.create(config().build());
     RelNode root =
-        builder.scan("EMP")
+        builder.scan("DEPT")
+            .project(builder.field("DEPTNO"))
+            .scan("EMP")
             .filter(
                 builder.call(SqlStdOperatorTable.EQUALS,
                     builder.field("DEPTNO"),
                     builder.literal(20)))
             .project(builder.field("EMPNO"))
-            .scan("DEPT")
-            .project(builder.field("DEPTNO"))
             .intersect(false)
             .build();
     assertThat(str(root),
@@ -368,6 +558,33 @@ public class RelBuilderTest {
             + "      LogicalTableScan(table=[[scott, EMP]])\n"));
   }
 
+  @Test public void testIntersect3() {
+    // Equivalent SQL:
+    //   SELECT deptno FROM dept
+    //   INTERSECT ALL
+    //   SELECT empno FROM emp
+    //   INTERSECT ALL
+    //   SELECT deptno FROM emp
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode root =
+        builder.scan("DEPT")
+            .project(builder.field("DEPTNO"))
+            .scan("EMP")
+            .project(builder.field("EMPNO"))
+            .scan("EMP")
+            .project(builder.field("DEPTNO"))
+            .intersect(true, 3)
+            .build();
+    assertThat(str(root),
+        is("LogicalIntersect(all=[true])\n"
+            + "  LogicalProject(DEPTNO=[$0])\n"
+            + "    LogicalTableScan(table=[[scott, DEPT]])\n"
+            + "  LogicalProject(EMPNO=[$0])\n"
+            + "    LogicalTableScan(table=[[scott, EMP]])\n"
+            + "  LogicalProject(DEPTNO=[$7])\n"
+            + "    LogicalTableScan(table=[[scott, EMP]])\n"));
+  }
+
   @Test public void testExcept() {
     // Equivalent SQL:
     //   SELECT empno FROM emp
@@ -376,14 +593,14 @@ public class RelBuilderTest {
     //   SELECT deptno FROM dept
     final RelBuilder builder = RelBuilder.create(config().build());
     RelNode root =
-        builder.scan("EMP")
+        builder.scan("DEPT")
+            .project(builder.field("DEPTNO"))
+            .scan("EMP")
             .filter(
                 builder.call(SqlStdOperatorTable.EQUALS,
                     builder.field("DEPTNO"),
                     builder.literal(20)))
             .project(builder.field("EMPNO"))
-            .scan("DEPT")
-            .project(builder.field("DEPTNO"))
             .minus(false)
             .build();
     assertThat(str(root),
@@ -412,14 +629,17 @@ public class RelBuilderTest {
                     builder.field(2, 0, "DEPTNO"),
                     builder.field(2, 1, "DEPTNO")))
             .build();
-    final String expected =
-        "LogicalJoin(condition=[=($7, $0)], joinType=[inner])\n"
-            + "  LogicalFilter(condition=[IS NULL($6)])\n"
-            + "    LogicalTableScan(table=[[scott, EMP]])\n"
-            + "  LogicalTableScan(table=[[scott, DEPT]])\n";
+    final String expected = ""
+        + "LogicalJoin(condition=[=($7, $0)], joinType=[inner])\n"
+        + "  LogicalFilter(condition=[IS NULL($6)])\n"
+        + "    LogicalTableScan(table=[[scott, EMP]])\n"
+        + "  LogicalTableScan(table=[[scott, DEPT]])\n";
     assertThat(str(root), is(expected));
+  }
 
-    // Using USING method
+  /** Same as {@link #testJoin} using USING. */
+  @Test public void testJoinUsing() {
+    final RelBuilder builder = RelBuilder.create(config().build());
     final RelNode root2 =
         builder.scan("EMP")
             .filter(
@@ -428,9 +648,38 @@ public class RelBuilderTest {
             .scan("DEPT")
             .join(JoinRelType.INNER, "DEPTNO")
             .build();
+    final String expected = ""
+        + "LogicalJoin(condition=[=($7, $0)], joinType=[inner])\n"
+        + "  LogicalFilter(condition=[IS NULL($6)])\n"
+        + "    LogicalTableScan(table=[[scott, EMP]])\n"
+        + "  LogicalTableScan(table=[[scott, DEPT]])\n";
     assertThat(str(root2), is(expected));
   }
 
+  @Test public void testJoin2() {
+    // Equivalent SQL:
+    //   SELECT *
+    //   FROM emp
+    //   LEFT JOIN dept ON emp.deptno = dept.deptno AND emp.empno = 123
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode root =
+        builder.scan("EMP")
+            .scan("DEPT")
+            .join(JoinRelType.LEFT,
+                builder.call(SqlStdOperatorTable.EQUALS,
+                    builder.field(2, 0, "DEPTNO"),
+                    builder.field(2, 1, "DEPTNO")),
+                builder.call(SqlStdOperatorTable.EQUALS,
+                    builder.field(2, 0, "EMPNO"),
+                    builder.literal(123)))
+            .build();
+    final String expected = ""
+        + "LogicalJoin(condition=[AND(=($7, $0), =($0, 123))], joinType=[left])\n"
+        + "  LogicalTableScan(table=[[scott, EMP]])\n"
+        + "  LogicalTableScan(table=[[scott, DEPT]])\n";
+    assertThat(str(root), is(expected));
+  }
+
   @Test public void testJoinCartesian() {
     // Equivalent SQL:
     //   SELECT * emp CROSS JOIN dept

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java b/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
index 9ec1eea..d7af516 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
@@ -31,6 +31,7 @@ import org.apache.calcite.rel.RelDistributions;
 import org.apache.calcite.rel.RelFieldCollation;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelRoot;
+import org.apache.calcite.rel.core.RelFactories;
 import org.apache.calcite.rel.logical.LogicalTableScan;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
@@ -51,6 +52,7 @@ import org.apache.calcite.sql.validate.SqlValidatorTable;
 import org.apache.calcite.sql2rel.RelFieldTrimmer;
 import org.apache.calcite.sql2rel.SqlToRelConverter;
 import org.apache.calcite.sql2rel.StandardConvertletTable;
+import org.apache.calcite.tools.RelBuilder;
 import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.Util;
 
@@ -598,7 +600,9 @@ public abstract class SqlToRelTestBase {
       assertValid(rel);
 
       if (trim) {
-        final RelFieldTrimmer trimmer = createFieldTrimmer();
+        final RelBuilder relBuilder =
+            RelFactories.LOGICAL_BUILDER.create(rel.getCluster(), null);
+        final RelFieldTrimmer trimmer = createFieldTrimmer(relBuilder);
         rel = trimmer.trim(rel);
         assertTrue(rel != null);
         assertValid(rel);
@@ -614,10 +618,11 @@ public abstract class SqlToRelTestBase {
     /**
      * Creates a RelFieldTrimmer.
      *
+     * @param relBuilder Builder
      * @return Field trimmer
      */
-    public RelFieldTrimmer createFieldTrimmer() {
-      return new RelFieldTrimmer(getValidator());
+    public RelFieldTrimmer createFieldTrimmer(RelBuilder relBuilder) {
+      return new RelFieldTrimmer(getValidator(), relBuilder);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/tools/PlannerTest.java b/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
index b00b3ee..956576b 100644
--- a/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
+++ b/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
@@ -639,11 +639,10 @@ public class PlannerTest {
             + "  EnumerableProject(empid=[$2], deptno=[$3], name=[$4], salary=[$5], commission=[$6], deptno0=[$7], name0=[$8], employees=[$9], x=[$10], y=[$11], empid0=[$0], name1=[$1])\n"
             + "    EnumerableJoin(condition=[=($0, $2)], joinType=[inner])\n"
             + "      EnumerableTableScan(table=[[hr, dependents]])\n"
-            + "      EnumerableProject(empid=[$0], deptno=[$1], name=[$2], salary=[$3], commission=[$4], deptno0=[$5], name0=[$6], employees=[$7], x=[$8], y=[$9])\n"
-            + "        EnumerableJoin(condition=[=($1, $5)], joinType=[left])\n"
-            + "          EnumerableTableScan(table=[[hr, emps]])\n"
-            + "          EnumerableProject(deptno=[$0], name=[$1], employees=[$2], x=[$3.x], y=[$3.y])\n"
-            + "            EnumerableTableScan(table=[[hr, depts]])");
+            + "      EnumerableJoin(condition=[=($1, $5)], joinType=[left])\n"
+            + "        EnumerableTableScan(table=[[hr, emps]])\n"
+            + "        EnumerableProject(deptno=[$0], name=[$1], employees=[$2], x=[$3.x], y=[$3.y])\n"
+            + "          EnumerableTableScan(table=[[hr, depts]])");
   }
 
   /** It would probably be OK to transform
@@ -679,11 +678,10 @@ public class PlannerTest {
             + "  EnumerableProject(empid=[$2], deptno=[$3], name=[$4], salary=[$5], commission=[$6], deptno0=[$7], name0=[$8], employees=[$9], x=[$10], y=[$11], empid0=[$0], name1=[$1])\n"
             + "    EnumerableJoin(condition=[=($0, $2)], joinType=[left])\n"
             + "      EnumerableTableScan(table=[[hr, dependents]])\n"
-            + "      EnumerableProject(empid=[$0], deptno=[$1], name=[$2], salary=[$3], commission=[$4], deptno0=[$5], name0=[$6], employees=[$7], x=[$8], y=[$9])\n"
-            + "        EnumerableJoin(condition=[=($1, $5)], joinType=[inner])\n"
-            + "          EnumerableTableScan(table=[[hr, emps]])\n"
-            + "          EnumerableProject(deptno=[$0], name=[$1], employees=[$2], x=[$3.x], y=[$3.y])\n"
-            + "            EnumerableTableScan(table=[[hr, depts]])");
+            + "      EnumerableJoin(condition=[=($1, $5)], joinType=[inner])\n"
+            + "        EnumerableTableScan(table=[[hr, emps]])\n"
+            + "        EnumerableProject(deptno=[$0], name=[$1], employees=[$2], x=[$3.x], y=[$3.y])\n"
+            + "          EnumerableTableScan(table=[[hr, depts]])");
   }
 
   private void checkHeuristic(String sql, String expected) throws Exception {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
index 0d01e9a..80d547d 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -428,10 +428,9 @@ LogicalAggregate(group=[{0}], EXPR$1=[MAX($0)], EXPR$2=[AVG($1)], EXPR$3=[MIN($0
         <Resource name="planAfter">
             <![CDATA[
 LogicalProject(NAME=[$0], EXPR$1=[$1], EXPR$2=[CAST(/($2, $3)):INTEGER NOT NULL], EXPR$3=[$4])
-  LogicalProject(NAME=[$0], EXPR$1=[$1], $f2=[$2], $f3=[$3], EXPR$3=[$4])
-    LogicalAggregate(group=[{0}], EXPR$1=[MAX($0)], agg#1=[$SUM0($1)], agg#2=[COUNT()], EXPR$3=[MIN($0)])
-      LogicalProject(NAME=[$1], DEPTNO=[$0])
-        LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+  LogicalAggregate(group=[{0}], EXPR$1=[MAX($0)], agg#1=[$SUM0($1)], agg#2=[COUNT()], EXPR$3=[MIN($0)])
+    LogicalProject(NAME=[$1], DEPTNO=[$0])
+      LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
 ]]>
         </Resource>
     </TestCase>
@@ -753,9 +752,9 @@ LogicalProject(EXPR$0=[CAST($1):VARCHAR(128) CHARACTER SET "ISO-8859-1" COLLATE
   LogicalFilter(condition=[=(CAST(CAST($4):VARCHAR(1) CHARACTER SET "ISO-8859-1" COLLATE "ISO-8859-1$en_US$primary" NOT NULL):VARCHAR(7) CHARACTER SET "ISO-8859-1" COLLATE "ISO-8859-1$en_US$primary" NOT NULL, 'Manager')])
     LogicalProject(DEPTNO=[$0], NAME=[$1], EMPNO=[$3], ENAME=[$4], JOB=[$5], MGR=[$6], HIREDATE=[$7], SAL=[$8], COMM=[$9], DEPTNO0=[$10], SLACKER=[$11])
       LogicalJoin(condition=[=($2, $12)], joinType=[inner])
-        LogicalProject(DEPTNO=[$0], NAME=[$1], $f2=[CAST($0):INTEGER NOT NULL])
+        LogicalProject(DEPTNO=[$0], NAME=[$1], DEPTNO2=[CAST($0):INTEGER NOT NULL])
           LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
-        LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], $f9=[CAST($7):INTEGER NOT NULL])
+        LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], DEPTNO9=[CAST($7):INTEGER NOT NULL])
           LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
         </Resource>
@@ -765,9 +764,9 @@ LogicalProject(EXPR$0=[CAST($1):VARCHAR(128) CHARACTER SET "ISO-8859-1" COLLATE
   LogicalFilter(condition=[=(CAST(CAST($4):VARCHAR(1) CHARACTER SET "ISO-8859-1" COLLATE "ISO-8859-1$en_US$primary" NOT NULL):VARCHAR(7) CHARACTER SET "ISO-8859-1" COLLATE "ISO-8859-1$en_US$primary" NOT NULL, 'Manager')])
     LogicalProject(DEPTNO=[$0], NAME=[$1], EMPNO=[$3], ENAME=[$4], JOB=[$5], MGR=[$6], HIREDATE=[$7], SAL=[$8], COMM=[$9], DEPTNO0=[$10], SLACKER=[$11])
       LogicalJoin(condition=[=($2, $12)], joinType=[inner])
-        LogicalProject(DEPTNO=[$0], NAME=[$1], $f2=[$0])
+        LogicalProject(DEPTNO=[$0], NAME=[$1], DEPTNO2=[$0])
           LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
-        LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], $f9=[$7])
+        LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], DEPTNO9=[$7])
           LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
         </Resource>
@@ -3216,9 +3215,8 @@ LogicalProject(DEPTNO=[$0], JOB=[$1], EXPR$2=[$4])
 LogicalProject(DEPTNO=[CASE($2, null, $0)], JOB=[CASE($3, null, $1)], EXPR$2=[$4])
   LogicalAggregate(group=[{0, 1}], indicator=[true], EXPR$2=[COUNT($2)])
     LogicalAggregate(group=[{0, 1, 2}])
-      LogicalProject(DEPTNO=[$0], JOB=[$1], ENAME=[$2])
-        LogicalProject(DEPTNO=[$7], JOB=[$2], ENAME=[$1])
-          LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+      LogicalProject(DEPTNO=[$7], JOB=[$2], ENAME=[$1])
+        LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
         </Resource>
     </TestCase>
@@ -3617,8 +3615,8 @@ LogicalProject(EMPNO=[$0], EXPR$1=[$2])
         <Resource name="planAfter">
             <![CDATA[
 LogicalProject(EMPNO=[$0], EXPR$1=[$2])
-  LogicalProject($f0=[$0], $f1=[$2], $f2=[$4])
-    LogicalProject($f0=[$0], $f1=[$1], $f2=[$2], $f3=[$3], $f4=[CAST(*($1, $3)):INTEGER NOT NULL])
+  LogicalProject(EMPNO=[$0], DEPTNO=[$2], $f4=[$4])
+    LogicalProject(EMPNO=[$0], EXPR$1=[$1], DEPTNO=[$2], $f1=[$3], $f4=[CAST(*($1, $3)):INTEGER NOT NULL])
       LogicalJoin(condition=[=($0, $2)], joinType=[inner])
         LogicalAggregate(group=[{0}], EXPR$1=[SUM($5)])
           LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
@@ -3976,8 +3974,8 @@ LogicalProject(EMPNO=[$0], MIN_SAL=[$2], MIN_DEPTNO=[$3], SUM_SAL_PLUS=[+($4, 1)
         <Resource name="planAfter">
             <![CDATA[
 LogicalProject(EMPNO=[$0], MIN_SAL=[$2], MIN_DEPTNO=[$3], SUM_SAL_PLUS=[+($4, 1)], MAX_SAL=[$5], SUM_SAL_2=[$4], COUNT_SAL=[$6], COUNT_MGR=[$7])
-  LogicalProject($f0=[$0], $f1=[$7], $f2=[$1], $f3=[$2], $f4=[$9], $f5=[$4], $f6=[$10], $f7=[$11])
-    LogicalProject($f0=[$0], $f1=[$1], $f2=[$2], $f3=[$3], $f4=[$4], $f5=[$5], $f6=[$6], $f7=[$7], $f8=[$8], $f9=[CAST(*($3, $8)):INTEGER NOT NULL], $f10=[*($5, $8)], $f11=[*($6, $8)])
+  LogicalProject(EMPNO=[$0], DEPTNO=[$7], MIN_SAL=[$1], MIN_DEPTNO=[$2], $f9=[$9], MAX_SAL=[$4], $f10=[$10], $f11=[$11])
+    LogicalProject(EMPNO=[$0], MIN_SAL=[$1], MIN_DEPTNO=[$2], SUM_SAL_2=[$3], MAX_SAL=[$4], COUNT_SAL=[$5], COUNT_MGR=[$6], DEPTNO=[$7], $f1=[$8], $f9=[CAST(*($3, $8)):INTEGER NOT NULL], $f10=[*($5, $8)], $f11=[*($6, $8)])
       LogicalJoin(condition=[=($0, $7)], joinType=[inner])
         LogicalAggregate(group=[{0}], MIN_SAL=[MIN($5)], MIN_DEPTNO=[MIN($7)], SUM_SAL_2=[SUM($5)], MAX_SAL=[MAX($5)], COUNT_SAL=[COUNT()], COUNT_MGR=[COUNT($3)])
           LogicalTableScan(table=[[CATALOG, SALES, EMP]])
@@ -4001,7 +3999,7 @@ LogicalAggregate(group=[{}], EXPR$0=[COUNT()])
         <Resource name="planAfter">
             <![CDATA[
 LogicalAggregate(group=[{}], EXPR$0=[$SUM0($4)])
-  LogicalProject($f0=[$0], $f1=[$1], $f2=[$2], $f3=[$3], $f4=[*($1, $3)])
+  LogicalProject(DEPTNO=[$0], EXPR$0=[$1], DEPTNO0=[$2], EXPR$00=[$3], $f4=[*($1, $3)])
     LogicalJoin(condition=[=($0, $2)], joinType=[inner])
       LogicalAggregate(group=[{7}], EXPR$0=[COUNT()])
         LogicalTableScan(table=[[CATALOG, SALES, EMP]])
@@ -4030,7 +4028,7 @@ LogicalAggregate(group=[{9}], SUM_SAL=[SUM($5)], C=[COUNT()])
         </Resource>
         <Resource name="planAfter">
             <![CDATA[
-LogicalProject($f0=[$3], $f1=[$1], $f2=[$2])
+LogicalProject(DEPTNO=[$3], SUM_SAL=[$1], C=[$2])
   LogicalJoin(condition=[=($0, $3)], joinType=[inner])
     LogicalAggregate(group=[{0}], SUM_SAL=[SUM($5)], C=[COUNT()])
       LogicalTableScan(table=[[CATALOG, SALES, EMP]])

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/mongodb/src/test/java/org/apache/calcite/test/MongoAdapterIT.java
----------------------------------------------------------------------
diff --git a/mongodb/src/test/java/org/apache/calcite/test/MongoAdapterIT.java b/mongodb/src/test/java/org/apache/calcite/test/MongoAdapterIT.java
index 1c37369..9b4b325 100644
--- a/mongodb/src/test/java/org/apache/calcite/test/MongoAdapterIT.java
+++ b/mongodb/src/test/java/org/apache/calcite/test/MongoAdapterIT.java
@@ -658,9 +658,9 @@ public class MongoAdapterIT {
             + "STATE=CA; CDC=1072\n")
         .queryContains(
             mongoChecker(
-                "{$project: {STATE: '$state', CITY: '$city'}}",
-                "{$group: {_id: {STATE: '$STATE', CITY: '$CITY'}}}",
-                "{$project: {_id: 0, STATE: '$_id.STATE', CITY: '$_id.CITY'}}",
+                "{$project: {CITY: '$city', STATE: '$state'}}",
+                "{$group: {_id: {CITY: '$CITY', STATE: '$STATE'}}}",
+                "{$project: {_id: 0, CITY: '$_id.CITY', STATE: '$_id.STATE'}}",
                 "{$group: {_id: '$STATE', CDC: {$sum: {$cond: [ {$eq: ['CITY', null]}, 0, 1]}}}}",
                 "{$project: {STATE: '$_id', CDC: '$CDC'}}",
                 "{$sort: {CDC: -1}}",

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/site/_docs/algebra.md
----------------------------------------------------------------------
diff --git a/site/_docs/algebra.md b/site/_docs/algebra.md
index c6a6b7e..e77edb0 100644
--- a/site/_docs/algebra.md
+++ b/site/_docs/algebra.md
@@ -261,15 +261,18 @@ return the `RelBuilder`.
 | `scan(tableName)` | Creates a [TableScan]({{ site.apiRoot }}/org/apache/calcite/rel/core/TableScan.html).
 | `values(fieldNames, value...)`<br/>`values(rowType, tupleList)` | Creates a [Values]({{ site.apiRoot }}/org/apache/calcite/rel/core/Values.html).
 | `filter(expr...)`<br/>`filter(exprList)` | Creates a [Filter]({{ site.apiRoot }}/org/apache/calcite/rel/core/Filter.html) over the AND of the given predicates.
-| `project(expr...)`<br/>`project(exprList)` | Creates a [Project]({{ site.apiRoot }}/org/apache/calcite/rel/core/Project.html). To override the default name, wrap expressions using `alias`.
+| `project(expr...)`<br/>`project(exprList [, fieldNames])` | Creates a [Project]({{ site.apiRoot }}/org/apache/calcite/rel/core/Project.html). To override the default name, wrap expressions using `alias`, or specify the `fieldNames` argument.
+| `permute(mapping)` | Creates a [Project]({{ site.apiRoot }}/org/apache/calcite/rel/core/Project.html) that permutes the fields using `mapping`.
+| `convert(rowType [, rename])` | Creates a [Project]({{ site.apiRoot }}/org/apache/calcite/rel/core/Project.html) that converts the fields to the given types, optionally also renaming them.
 | `aggregate(groupKey, aggCall...)`<br/>`aggregate(groupKey, aggCallList)` | Creates an [Aggregate]({{ site.apiRoot }}/org/apache/calcite/rel/core/Aggregate.html).
 | `distinct()` | Creates an [Aggregate]({{ site.apiRoot }}/org/apache/calcite/rel/core/Aggregate.html) that eliminates duplicate records.
 | `sort(fieldOrdinal...)`<br/>`sort(expr...)`<br/>`sort(exprList)` | Creates a [Sort]({{ site.apiRoot }}/org/apache/calcite/rel/core/Sort.html).<br/><br/>In the first form, field ordinals are 0-based, and a negative ordinal indicates descending; for example, -2 means field 1 descending.<br/><br/>In the other forms, you can wrap expressions in `as`, `nullsFirst` or `nullsLast`.
 | `sortLimit(offset, fetch, expr...)`<br/>`sortLimit(offset, fetch, exprList)` | Creates a [Sort]({{ site.apiRoot }}/org/apache/calcite/rel/core/Sort.html) with offset and limit.
 | `limit(offset, fetch)` | Creates a [Sort]({{ site.apiRoot }}/org/apache/calcite/rel/core/Sort.html) that does not sort, only applies with offset and limit.
-| `join(joinType, expr)`<br/>`join(joinType, fieldName...)` | Creates a [Join]({{ site.apiRoot }}/org/apache/calcite/rel/core/Join.html) of the two most recent relational expressions.<br/><br/>The first form joins on an boolean expression.<br/><br/>The second form joins on named fields; each side must have a field of each name.
-| `union(all)` | Creates a [Union]({{ site.apiRoot }}/org/apache/calcite/rel/core/Union.html) of the two most recent relational expressions.
-| `intersect(all)` | Creates an [Intersect]({{ site.apiRoot }}/org/apache/calcite/rel/core/Intersect.html) of the two most recent relational expressions.
+| `join(joinType, expr...)`<br/>`join(joinType, exprList)`<br/>`join(joinType, fieldName...)` | Creates a [Join]({{ site.apiRoot }}/org/apache/calcite/rel/core/Join.html) of the two most recent relational expressions.<br/><br/>The first form joins on a boolean expression (multiple conditions are combined using AND).<br/><br/>The last form joins on named fields; each side must have a field of each name.
+| `semiJoin(expr)` | Creates a [SemiJoin]({{ site.apiRoot }}/org/apache/calcite/rel/core/SemiJoin.html) of the two most recent relational expressions.
+| `union(all [, n])` | Creates a [Union]({{ site.apiRoot }}/org/apache/calcite/rel/core/Union.html) of the `n` (default two) most recent relational expressions.
+| `intersect(all [, n])` | Creates an [Intersect]({{ site.apiRoot }}/org/apache/calcite/rel/core/Intersect.html) of the `n` (default two) most recent relational expressions.
 | `minus(all)` | Creates a [Minus]({{ site.apiRoot }}/org/apache/calcite/rel/core/Minus.html) of the two most recent relational expressions.
 
 Argument types:
@@ -292,6 +295,12 @@ Argument types:
 * `distinct` boolean
 * `alias` String
 
+The builder methods perform various optimizations, including:
+* `project` returns its input if asked to project all columns in order
+* `filter` flattens the condition (so an `AND` and `OR` may have more than 2 children),
+  simplifies (converting say `x = 1 AND TRUE` to `x = 1`)
+* If you apply `sort` then `limit`, the effect is as if you had called `sortLimit`
+
 ### Stack methods
 
 
@@ -299,6 +308,7 @@ Argument types:
 |:------------------- |:-----------
 | `build()`           | Pops the most recently created relational expression off the stack
 | `push(rel)`         | Pushes a relational expression onto the stack. Relational methods such as `scan`, above, call this method, but user code generally does not
+| `pushAll(collection)` | Pushes a collection of relational expressions onto the stack
 | `peek()`            | Returns the relational expression most recently put onto the stack, but does not remove it
 
 #### Scalar expression methods
@@ -317,6 +327,9 @@ added to the stack.
 | `field(fieldOrdinal)` | Reference, by ordinal, to a field of the top-most relational expression
 | `field(inputCount, inputOrdinal, fieldName)` | Reference, by name, to a field of the (`inputCount` - `inputOrdinal`)th relational expression
 | `field(inputCount, inputOrdinal, fieldOrdinal)` | Reference, by ordinal, to a field of the (`inputCount` - `inputOrdinal`)th relational expression
+| `fields(fieldOrdinalList)` | List of expressions referencing input fields by ordinal
+| `fields(mapping)` | List of expressions referencing input fields by a given mapping
+| `fields(collation)` | List of expressions, `exprList`, such that `sort(exprList)` would replicate collation
 | `call(op, expr...)`<br/>`call(op, exprList)` | Call to a function or operator
 | `and(expr...)`<br/>`and(exprList)` | Logical AND. Flattens nested ANDs, and optimizes cases involving TRUE and FALSE.
 | `or(expr...)`<br/>`or(exprList)` | Logical OR. Flattens nested ORs, and optimizes cases involving TRUE and FALSE.
@@ -338,6 +351,8 @@ The following methods return a
 | Method              | Description
 |:------------------- |:-----------
 | `groupKey(fieldName...)`<br/>`groupKey(fieldOrdinal...)`<br/>`groupKey(expr...)`<br/>`groupKey(exprList)` | Creates a group key of the given expressions
+| `groupKey(exprList, exprListList)` | Creates a group key of the given expressions with grouping sets
+| `groupKey(bitSet, bitSets)` | Creates a group key of the given input columns with grouping sets
 
 ### Aggregate call methods
 
@@ -346,7 +361,7 @@ The following methods return an
 
 | Method              | Description
 |:------------------- |:-----------
-| `aggregateCall(op, distinct, alias, expr...)`<br/>`aggregateCall(op, distinct, alias, exprList)` | Creates a call to a given aggregate function
+| `aggregateCall(op, distinct, filter, alias, expr...)`<br/>`aggregateCall(op, distinct, filter, alias, exprList)` | Creates a call to a given aggregate function, with an optional filter expression
 | `count(distinct, alias, expr...)` | Creates a call to the COUNT aggregate function
 | `countStar(alias)` | Creates a call to the COUNT(*) aggregate function
 | `sum(distinct, alias, expr)` | Creates a call to the SUM aggregate function



[6/7] incubator-calcite git commit: [CALCITE-895] Simplify "(CASE ... END) = constant" inside AND or OR (Hsuan-Yi Chu)

Posted by jh...@apache.org.
[CALCITE-895] Simplify "(CASE ... END) = constant" inside AND or OR (Hsuan-Yi Chu)

Close apache/incubator-calcite#135


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

Branch: refs/heads/master
Commit: 2fa63dda5809d519dc60aa36f464476bed961df3
Parents: 43b88db
Author: Hsuan-Yi Chu <hs...@usc.edu>
Authored: Mon Sep 21 15:39:25 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Sep 28 12:07:15 2015 -0700

----------------------------------------------------------------------
 .../rel/rules/ReduceExpressionsRule.java        | 91 ++++++++++++++------
 .../apache/calcite/test/RelOptRulesTest.java    | 35 +++++++-
 .../org/apache/calcite/test/RelOptRulesTest.xml | 47 +++++++++-
 3 files changed, 146 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2fa63dda/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
index 5ab9192..61c64a8 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
@@ -479,36 +479,77 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
     return ImmutableMap.copyOf(builder);
   }
 
+  /** Return if a given operator can be pushed into Case */
+  private static boolean isPushableIntoCase(RexNode node) {
+    if (!(node instanceof RexCall)) {
+      return false;
+    }
+
+    final RexCall call = (RexCall) node;
+    return call.getType().getSqlTypeName() == SqlTypeName.BOOLEAN
+        && (SqlKind.COMPARISON.contains(call.getKind()) || call.getOperands().size() == 1);
+  }
+
   private static RexCall pushPredicateIntoCase(RexCall call) {
     if (call.getType().getSqlTypeName() != SqlTypeName.BOOLEAN) {
       return call;
     }
-    int caseOrdinal = -1;
-    final List<RexNode> operands = call.getOperands();
-    for (int i = 0; i < operands.size(); i++) {
-      RexNode operand = operands.get(i);
-      switch (operand.getKind()) {
-      case CASE:
-        caseOrdinal = i;
-      }
-    }
-    if (caseOrdinal < 0) {
-      return call;
-    }
-    // Convert
-    //   f(CASE WHEN p1 THEN v1 ... END, arg)
-    // to
-    //   CASE WHEN p1 THEN f(v1, arg) ... END
-    final RexCall case_ = (RexCall) operands.get(caseOrdinal);
-    final List<RexNode> nodes = new ArrayList<>();
-    for (int i = 0; i < case_.getOperands().size(); i++) {
-      RexNode node = case_.getOperands().get(i);
-      if (!RexUtil.isCasePredicate(case_, i)) {
-        node = substitute(call, caseOrdinal, node);
+    final RexShuttle rexShuttle = new RexShuttle() {
+      @Override
+      public RexNode visitCall(RexCall call) {
+        final List<RexNode> newOperands = new ArrayList<>();
+        for (RexNode operand : call.getOperands()) {
+          newOperands.add(operand.accept(this));
+        }
+
+        call = call.clone(call.getType(), newOperands);
+        if (!isPushableIntoCase(call)) {
+          return call;
+        }
+
+        final List<RexNode> operands = call.getOperands();
+        int caseOrdinal = -1;
+        for (int i = 0; i < operands.size(); i++) {
+          RexNode operand = operands.get(i);
+          switch (operand.getKind()) {
+          case CASE:
+            caseOrdinal = i;
+          }
+        }
+        if (caseOrdinal < 0) {
+          return call;
+        }
+
+        // Convert
+        //   f(CASE WHEN p1 THEN v1 ... END, arg)
+        // to
+        //   CASE WHEN p1 THEN f(v1, arg) ... END
+        final RexCall case_ = (RexCall) operands.get(caseOrdinal);
+        final List<RexNode> nodes = new ArrayList<>();
+        for (int i = 0; i < case_.getOperands().size(); i++) {
+          RexNode node = case_.getOperands().get(i);
+          if (!RexUtil.isCasePredicate(case_, i)) {
+            node = substitute(call, caseOrdinal, node);
+
+            // For nested Case-When, the function should be pushed further deeper
+            // For example,
+            // Convert
+            //   f(CASE WHEN p1 THEN (CASE WHEN p2 THEN v2 ... END) ... END, arg)
+            // to
+            //   CASE WHEN p1 THEN f((CASE WHEN p2 THEN v2 ... END), arg) ... END
+            // further to
+            //   CASE WHEN p1 THEN (CASE WHEN p2 THEN f(v2, arg) ... END) ... END
+            if (isPushableIntoCase(node)) {
+              node = node.accept(this);
+            }
+          }
+          nodes.add(node);
+        }
+        return case_.clone(call.getType(), nodes);
       }
-      nodes.add(node);
-    }
-    return case_.clone(call.getType(), nodes);
+    };
+
+    return (RexCall) call.accept(rexShuttle);
   }
 
   /** Converts op(arg0, ..., argOrdinal, ..., argN) to op(arg0,..., node, ..., argN). */

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2fa63dda/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
index 7ba514d..329bf76 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -144,8 +144,41 @@ public class RelOptRulesTest extends RelOptTestBase {
     return DiffRepository.lookup(RelOptRulesTest.class);
   }
 
+  @Test public void testReduceNestedCaseWhen() {
+    HepProgram preProgram = new HepProgramBuilder()
+        .build();
+
+    HepProgramBuilder builder = new HepProgramBuilder();
+    builder.addRuleClass(ReduceExpressionsRule.class);
+    HepPlanner hepPlanner = new HepPlanner(builder.build());
+    hepPlanner.addRule(ReduceExpressionsRule.FILTER_INSTANCE);
+
+    final String sql = "select sal\n"
+            + "from emp\n"
+            + "where case when (sal = 1000) then\n"
+            + "(case when sal = 1000 then null else 1 end is null) else\n"
+            + "(case when sal = 2000 then null else 1 end is null) end is true";
+    checkPlanning(tester, preProgram, hepPlanner, sql);
+  }
+
+  @Test public void testReduceORCaseWhen() {
+    HepProgram preProgram = new HepProgramBuilder()
+        .build();
+
+    HepProgramBuilder builder = new HepProgramBuilder();
+    builder.addRuleClass(ReduceExpressionsRule.class);
+    HepPlanner hepPlanner = new HepPlanner(builder.build());
+    hepPlanner.addRule(ReduceExpressionsRule.FILTER_INSTANCE);
+
+    final String sql = "select sal\n"
+        + "from emp\n"
+        + "where case when sal = 1000 then null else 1 end is null\n"
+        + "OR case when sal = 2000 then null else 1 end is null";
+    checkPlanning(tester, preProgram, hepPlanner, sql);
+  }
+
   @Test public void testProjectToWindowRuleForMultipleWindows() {
-    HepProgram preProgram =  new HepProgramBuilder()
+    HepProgram preProgram = new HepProgramBuilder()
         .build();
 
     HepProgramBuilder builder = new HepProgramBuilder();

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2fa63dda/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
index 80d547d..52948a9 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -16,6 +16,51 @@ See the License for the specific language governing permissions and
 limitations under the License.
 -->
 <Root>
+    <TestCase name="testReduceNestedCaseWhen">
+        <Resource name="sql">
+            <![CDATA[select sal
+from emp
+where case when (sal = 1000) then
+(case when sal = 1000 then null else 1 end is null) else
+(case when sal = 2000 then null else 1 end is null) end is true]]>
+        </Resource>
+        <Resource name="planAfter">
+            <![CDATA[
+LogicalProject(SAL=[$5])
+  LogicalFilter(condition=[CASE(=($5, 1000), =($5, 1000), =($5, 2000))])
+    LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+        <Resource name="planBefore">
+            <![CDATA[
+LogicalProject(SAL=[$5])
+  LogicalFilter(condition=[IS TRUE(CASE(=($5, 1000), IS NULL(CASE(=($5, 1000), null, 1)), IS NULL(CASE(=($5, 2000), null, 1))))])
+    LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+    </TestCase>
+    <TestCase name="testReduceORCaseWhen">
+        <Resource name="sql">
+            <![CDATA[select sal
+from emp
+where case when sal = 1000 then null else 1 end is null
+OR case when sal = 2000 then null else 1 end is null]]>
+        </Resource>
+        <Resource name="planAfter">
+            <![CDATA[
+LogicalProject(SAL=[$5])
+  LogicalFilter(condition=[OR(=($5, 1000), =($5, 2000))])
+    LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+        <Resource name="planBefore">
+            <![CDATA[
+LogicalProject(SAL=[$5])
+  LogicalFilter(condition=[OR(IS NULL(CASE(=($5, 1000), null, 1)), IS NULL(CASE(=($5, 2000), null, 1)))])
+    LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+    </TestCase>
     <TestCase name="testWindowInParenthesis">
         <Resource name="sql">
             <![CDATA[select count(*) over (w), count(*) over w
@@ -583,7 +628,7 @@ LogicalProject(EXPR$0=[+(1, 2)], EXPR$1=[+($0, +(3, 4))], EXPR$2=[+(+(5, 6), $0)
         <Resource name="planAfter">
             <![CDATA[
 LogicalProject(EXPR$0=[3], EXPR$1=[+($0, 7)], EXPR$2=[+(11, $0)], EXPR$3=[null], EXPR$4=[CAST(2):INTEGER], EXPR$5=[ROW(15)])
-  LogicalFilter(condition=[AND(=($0, 15), =($0, CAST(2):INTEGER))])
+  LogicalFilter(condition=[AND(=($0, 15), =($0, 2))])
     LogicalProject(DEPTNO=[$0], NAME=[$1], EMPNO=[$2], ENAME=[$3], JOB=[$4], MGR=[$5], HIREDATE=[$6], SAL=[$7], COMM=[$8], DEPTNO0=[$9], SLACKER=[$10])
       LogicalJoin(condition=[=($0, $11)], joinType=[inner])
         LogicalTableScan(table=[[CATALOG, SALES, DEPT]])


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

Posted by jh...@apache.org.
[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());
   }
 }
 


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

Posted by jh...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/MultiJoinOptimizeBushyRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/MultiJoinOptimizeBushyRule.java b/core/src/main/java/org/apache/calcite/rel/rules/MultiJoinOptimizeBushyRule.java
index 2e6667c..477b74a 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/MultiJoinOptimizeBushyRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/MultiJoinOptimizeBushyRule.java
@@ -18,7 +18,6 @@ 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.prepare.CalcitePrepareImpl;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.JoinRelType;
@@ -30,6 +29,8 @@ import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexPermuteInputsShuttle;
 import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.rex.RexVisitor;
+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.Util;
@@ -37,7 +38,6 @@ import org.apache.calcite.util.mapping.Mappings;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
 
 import java.io.PrintWriter;
@@ -67,25 +67,26 @@ import java.util.List;
  */
 public class MultiJoinOptimizeBushyRule extends RelOptRule {
   public static final MultiJoinOptimizeBushyRule INSTANCE =
-      new MultiJoinOptimizeBushyRule(RelFactories.DEFAULT_JOIN_FACTORY,
-          RelFactories.DEFAULT_PROJECT_FACTORY);
+      new MultiJoinOptimizeBushyRule(RelFactories.LOGICAL_BUILDER);
 
-  private final RelFactories.JoinFactory joinFactory;
-  private final RelFactories.ProjectFactory projectFactory;
   private final PrintWriter pw =
       CalcitePrepareImpl.DEBUG ? new PrintWriter(System.out, true) : null;
 
   /** Creates an MultiJoinOptimizeBushyRule. */
+  public MultiJoinOptimizeBushyRule(RelBuilderFactory relBuilderFactory) {
+    super(operand(MultiJoin.class, any()), relBuilderFactory, null);
+  }
+
+  @Deprecated // to be removed before 2.0
   public MultiJoinOptimizeBushyRule(RelFactories.JoinFactory joinFactory,
       RelFactories.ProjectFactory projectFactory) {
-    super(operand(MultiJoin.class, any()));
-    this.joinFactory = joinFactory;
-    this.projectFactory = projectFactory;
+    this(RelBuilder.proto(joinFactory, projectFactory));
   }
 
   @Override public void onMatch(RelOptRuleCall call) {
     final MultiJoin multiJoinRel = call.rel(0);
     final RexBuilder rexBuilder = multiJoinRel.getCluster().getRexBuilder();
+    final RelBuilder relBuilder = call.builder();
 
     final LoptMultiJoin multiJoin = new LoptMultiJoin(multiJoinRel);
 
@@ -254,11 +255,12 @@ public class MultiJoinOptimizeBushyRule extends RelOptRule {
         final RexNode condition =
             RexUtil.composeConjunction(rexBuilder, joinVertex.conditions,
                 false);
-        relNodes.add(
-            Pair.of(
-                joinFactory.createJoin(left, right, condition.accept(shuttle),
-                    JoinRelType.INNER, ImmutableSet.<String>of(), false),
-                mapping));
+
+        final RelNode join = relBuilder.push(left)
+            .push(right)
+            .join(JoinRelType.INNER, condition.accept(shuttle))
+            .build();
+        relNodes.add(Pair.of(join, mapping));
       }
       if (pw != null) {
         pw.println(Util.last(relNodes));
@@ -266,11 +268,9 @@ public class MultiJoinOptimizeBushyRule extends RelOptRule {
     }
 
     final Pair<RelNode, Mappings.TargetMapping> top = Util.last(relNodes);
-    final RelNode project =
-        RelOptUtil.createProject(projectFactory, top.left,
-            Mappings.asList(top.right));
-
-    call.transformTo(project);
+    relBuilder.push(top.left)
+        .project(relBuilder.fields(top.right));
+    call.transformTo(relBuilder.build());
   }
 
   private void trace(List<Vertex> vertexes,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/ProjectMergeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ProjectMergeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ProjectMergeRule.java
index 89ed15f..4537157 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ProjectMergeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ProjectMergeRule.java
@@ -24,6 +24,8 @@ import org.apache.calcite.rel.core.Project;
 import org.apache.calcite.rel.core.RelFactories;
 import org.apache.calcite.rel.core.RelFactories.ProjectFactory;
 import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
 import org.apache.calcite.util.Permutation;
 
 import java.util.List;
@@ -35,15 +37,13 @@ import java.util.List;
  */
 public class ProjectMergeRule extends RelOptRule {
   public static final ProjectMergeRule INSTANCE =
-      new ProjectMergeRule(true, RelFactories.DEFAULT_PROJECT_FACTORY);
+      new ProjectMergeRule(true, RelFactories.LOGICAL_BUILDER);
 
   //~ Instance fields --------------------------------------------------------
 
   /** Whether to always merge projects. */
   private final boolean force;
 
-  private final ProjectFactory projectFactory;
-
   //~ Constructors -----------------------------------------------------------
 
   /**
@@ -51,13 +51,18 @@ public class ProjectMergeRule extends RelOptRule {
    *
    * @param force Whether to always merge projects
    */
-  public ProjectMergeRule(boolean force, ProjectFactory projectFactory) {
+  public ProjectMergeRule(boolean force, RelBuilderFactory relBuilderFactory) {
     super(
         operand(Project.class,
             operand(Project.class, any())),
+        relBuilderFactory,
         "ProjectMergeRule" + (force ? ":force_mode" : ""));
     this.force = force;
-    this.projectFactory = projectFactory;
+  }
+
+  @Deprecated // to be removed before 2.0
+  public ProjectMergeRule(boolean force, ProjectFactory projectFactory) {
+    this(force, RelBuilder.proto(projectFactory));
   }
 
   //~ Methods ----------------------------------------------------------------
@@ -65,6 +70,7 @@ public class ProjectMergeRule extends RelOptRule {
   public void onMatch(RelOptRuleCall call) {
     final Project topProject = call.rel(0);
     final Project bottomProject = call.rel(1);
+    final RelBuilder relBuilder = call.builder();
 
     // If one or both projects are permutations, short-circuit the complex logic
     // of building a RexProgram.
@@ -81,10 +87,10 @@ public class ProjectMergeRule extends RelOptRule {
           return;
         }
         final Permutation product = topPermutation.product(bottomPermutation);
-        call.transformTo(
-            RelOptUtil.projectMapping(bottomProject.getInput(),
-                product.inverse(), topProject.getRowType().getFieldNames(),
-                projectFactory));
+        relBuilder.push(bottomProject.getInput());
+        relBuilder.project(relBuilder.fields(product),
+            topProject.getRowType().getFieldNames());
+        call.transformTo(relBuilder.build());
         return;
       }
     }
@@ -111,11 +117,9 @@ public class ProjectMergeRule extends RelOptRule {
     }
 
     // replace the two projects with a combined projection
-    RelNode newProjectRel = projectFactory.createProject(
-        bottomProject.getInput(), newProjects,
-        topProject.getRowType().getFieldNames());
-
-    call.transformTo(newProjectRel);
+    relBuilder.push(bottomProject.getInput());
+    relBuilder.project(newProjects, topProject.getRowType().getFieldNames());
+    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/ProjectMultiJoinMergeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ProjectMultiJoinMergeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ProjectMultiJoinMergeRule.java
index 065738e..0cf5d58 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ProjectMultiJoinMergeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ProjectMultiJoinMergeRule.java
@@ -19,7 +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.RelOptUtil;
+import org.apache.calcite.rel.core.RelFactories;
 import org.apache.calcite.rel.logical.LogicalProject;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
 
 /**
  * Planner rule that pushes
@@ -31,18 +34,15 @@ import org.apache.calcite.rel.logical.LogicalProject;
  */
 public class ProjectMultiJoinMergeRule extends RelOptRule {
   public static final ProjectMultiJoinMergeRule INSTANCE =
-      new ProjectMultiJoinMergeRule();
+      new ProjectMultiJoinMergeRule(RelFactories.LOGICAL_BUILDER);
 
   //~ Constructors -----------------------------------------------------------
 
-  /**
-   * Creates a ProjectMultiJoinMergeRule.
-   */
-  private ProjectMultiJoinMergeRule() {
+  /** Creates a ProjectMultiJoinMergeRule. */
+  private ProjectMultiJoinMergeRule(RelBuilderFactory relBuilderFactory) {
     super(
-        operand(
-            LogicalProject.class,
-            operand(MultiJoin.class, any())));
+        operand(LogicalProject.class,
+            operand(MultiJoin.class, any())), relBuilderFactory, null);
   }
 
   //~ Methods ----------------------------------------------------------------
@@ -66,15 +66,13 @@ public class ProjectMultiJoinMergeRule extends RelOptRule {
 
     // create a new MultiJoin that reflects the columns in the projection
     // above the MultiJoin
+    final RelBuilder relBuilder = call.builder();
     MultiJoin newMultiJoin =
         RelOptUtil.projectMultiJoin(multiJoin, project);
-    LogicalProject newProject =
-        (LogicalProject) RelOptUtil.createProject(
-            newMultiJoin,
-            project.getProjects(),
-            project.getRowType().getFieldNames());
+    relBuilder.push(newMultiJoin)
+        .project(project.getProjects(), project.getRowType().getFieldNames());
 
-    call.transformTo(newProject);
+    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/ProjectSortTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ProjectSortTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ProjectSortTransposeRule.java
index fe53113..1287f84 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ProjectSortTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ProjectSortTransposeRule.java
@@ -19,14 +19,14 @@ package org.apache.calcite.rel.rules;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.Project;
 import org.apache.calcite.rel.core.Sort;
-import org.apache.calcite.rel.logical.LogicalProject;
 
 import com.google.common.collect.ImmutableList;
 
 /**
  * Planner rule that pushes
- * a {@link org.apache.calcite.rel.logical.LogicalProject}
+ * a {@link org.apache.calcite.rel.core.Project}
  * past a {@link org.apache.calcite.rel.core.Sort}.
  *
  * @see org.apache.calcite.rel.rules.SortProjectTransposeRule
@@ -42,15 +42,15 @@ public class ProjectSortTransposeRule extends RelOptRule {
    */
   private ProjectSortTransposeRule() {
     super(
-        operand(LogicalProject.class,
+        operand(Project.class,
             operand(Sort.class, any())));
   }
 
   //~ Methods ----------------------------------------------------------------
 
   public void onMatch(RelOptRuleCall call) {
-    LogicalProject project = call.rel(0);
-    Sort sort = call.rel(1);
+    final Project project = call.rel(0);
+    final Sort sort = call.rel(1);
     if (sort.getClass() != Sort.class) {
       return;
     }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/ProjectToWindowRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ProjectToWindowRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ProjectToWindowRule.java
index 92fd282..fe6334e 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ProjectToWindowRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ProjectToWindowRule.java
@@ -21,13 +21,11 @@ import org.apache.calcite.plan.RelOptCluster;
 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.plan.RelTraitSet;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Calc;
 import org.apache.calcite.rel.core.Project;
 import org.apache.calcite.rel.logical.LogicalCalc;
-import org.apache.calcite.rel.logical.LogicalFilter;
 import org.apache.calcite.rel.logical.LogicalWindow;
 import org.apache.calcite.rex.RexCall;
 import org.apache.calcite.rex.RexDynamicParam;
@@ -40,6 +38,7 @@ import org.apache.calcite.rex.RexProgram;
 import org.apache.calcite.rex.RexProgramBuilder;
 import org.apache.calcite.rex.RexVisitorImpl;
 import org.apache.calcite.rex.RexWindow;
+import org.apache.calcite.tools.RelBuilder;
 import org.apache.calcite.util.ImmutableIntList;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Util;
@@ -104,7 +103,8 @@ public abstract class ProjectToWindowRule extends RelOptRule {
         public void onMatch(RelOptRuleCall call) {
           Calc calc = call.rel(0);
           assert RexOver.containsOver(calc.getProgram());
-          CalcRelSplitter transform = new WindowedAggRelSplitter(calc);
+          final CalcRelSplitter transform =
+              new WindowedAggRelSplitter(calc, call.builder());
           RelNode newRel = transform.execute();
           call.transformTo(newRel);
         }
@@ -133,31 +133,30 @@ public abstract class ProjectToWindowRule extends RelOptRule {
                   project.getCluster().getRexBuilder());
           // temporary LogicalCalc, never registered
           final LogicalCalc calc = LogicalCalc.create(input, program);
-          CalcRelSplitter transform = new WindowedAggRelSplitter(calc) {
+          final CalcRelSplitter transform = new WindowedAggRelSplitter(calc,
+              call.builder()) {
             @Override protected RelNode handle(RelNode rel) {
-              if (rel instanceof LogicalCalc) {
-                LogicalCalc calc = (LogicalCalc) rel;
-                final RexProgram program = calc.getProgram();
-                rel = calc.getInput();
-                if (program.getCondition() != null) {
-                  rel = LogicalFilter.create(rel,
-                      program.expandLocalRef(
-                          program.getCondition()));
-                }
-                if (!program.projectsOnlyIdentity()) {
-                  rel = RelOptUtil.createProject(
-                      rel,
-                      Lists.transform(
-                          program.getProjectList(),
-                          new Function<RexLocalRef, RexNode>() {
-                            public RexNode apply(RexLocalRef a0) {
-                              return program.expandLocalRef(a0);
-                            }
-                          }),
-                      calc.getRowType().getFieldNames());
-                }
+              if (!(rel instanceof LogicalCalc)) {
+                return rel;
+              }
+              final LogicalCalc calc = (LogicalCalc) rel;
+              final RexProgram program = calc.getProgram();
+              relBuilder.push(calc.getInput());
+              if (program.getCondition() != null) {
+                relBuilder.filter(
+                    program.expandLocalRef(program.getCondition()));
+              }
+              if (!program.projectsOnlyIdentity()) {
+                relBuilder.project(
+                    Lists.transform(program.getProjectList(),
+                        new Function<RexLocalRef, RexNode>() {
+                          public RexNode apply(RexLocalRef a0) {
+                            return program.expandLocalRef(a0);
+                          }
+                        }),
+                    calc.getRowType().getFieldNames());
               }
-              return rel;
+              return relBuilder.build();
             }
           };
           RelNode newRel = transform.execute();
@@ -175,80 +174,69 @@ public abstract class ProjectToWindowRule extends RelOptRule {
   //~ Inner Classes ----------------------------------------------------------
 
   /**
-   * Splitter which distinguishes between windowed aggregation expressions
+   * Splitter that distinguishes between windowed aggregation expressions
    * (calls to {@link RexOver}) and ordinary expressions.
    */
   static class WindowedAggRelSplitter extends CalcRelSplitter {
-    WindowedAggRelSplitter(Calc calc) {
-      super(
-          calc,
-          new RelType[]{
-            new CalcRelSplitter.RelType("CalcRelType") {
-              protected boolean canImplement(RexFieldAccess field) {
-                return true;
-              }
+    private static final RelType[] REL_TYPES = {
+      new RelType("CalcRelType") {
+        protected boolean canImplement(RexFieldAccess field) {
+          return true;
+        }
 
-              protected boolean canImplement(RexDynamicParam param) {
-                return true;
-              }
+        protected boolean canImplement(RexDynamicParam param) {
+          return true;
+        }
 
-              protected boolean canImplement(RexLiteral literal) {
-                return true;
-              }
+        protected boolean canImplement(RexLiteral literal) {
+          return true;
+        }
 
-              protected boolean canImplement(RexCall call) {
-                return !(call instanceof RexOver);
-              }
+        protected boolean canImplement(RexCall call) {
+          return !(call instanceof RexOver);
+        }
 
-              protected RelNode makeRel(
-                  RelOptCluster cluster,
-                  RelTraitSet traits,
-                  RelNode child,
-                  RexProgram program) {
-                assert !program.containsAggs();
-                program = RexProgramBuilder.normalize(cluster.getRexBuilder(),
-                    program);
-                return super.makeRel(
-                    cluster,
-                    traits,
-                    child,
-                    program);
-              }
-            },
-            new CalcRelSplitter.RelType("WinAggRelType") {
-              protected boolean canImplement(RexFieldAccess field) {
-                return false;
-              }
+        protected RelNode makeRel(RelOptCluster cluster, RelTraitSet traitSet,
+            RelBuilder relBuilder, RelNode input, RexProgram program) {
+          assert !program.containsAggs();
+          program = RexProgramBuilder.normalize(cluster.getRexBuilder(),
+              program);
+          return super.makeRel(cluster, traitSet, relBuilder, input, program);
+        }
+      },
+      new RelType("WinAggRelType") {
+        protected boolean canImplement(RexFieldAccess field) {
+          return false;
+        }
 
-              protected boolean canImplement(RexDynamicParam param) {
-                return false;
-              }
+        protected boolean canImplement(RexDynamicParam param) {
+          return false;
+        }
 
-              protected boolean canImplement(RexLiteral literal) {
-                return false;
-              }
+        protected boolean canImplement(RexLiteral literal) {
+          return false;
+        }
 
-              protected boolean canImplement(RexCall call) {
-                return call instanceof RexOver;
-              }
+        protected boolean canImplement(RexCall call) {
+          return call instanceof RexOver;
+        }
 
-              protected boolean supportsCondition() {
-                return false;
-              }
+        protected boolean supportsCondition() {
+          return false;
+        }
 
-              protected RelNode makeRel(
-                  RelOptCluster cluster,
-                  RelTraitSet traits,
-                  RelNode child,
-                  RexProgram program) {
-                Util.permAssert(
-                    program.getCondition() == null,
-                    "WindowedAggregateRel cannot accept a condition");
-                return LogicalWindow.create(
-                    cluster, traits, child, program);
-              }
-            }
-          });
+        protected RelNode makeRel(RelOptCluster cluster, RelTraitSet traitSet,
+            RelBuilder relBuilder, RelNode input, RexProgram program) {
+          Util.permAssert(program.getCondition() == null,
+              "WindowedAggregateRel cannot accept a condition");
+          return LogicalWindow.create(cluster, traitSet, relBuilder, input,
+              program);
+        }
+      }
+    };
+
+    WindowedAggRelSplitter(Calc calc, RelBuilder relBuilder) {
+      super(calc, relBuilder, REL_TYPES);
     }
 
     @Override protected List<Set<Integer>> getCohorts() {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/SemiJoinProjectTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/SemiJoinProjectTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/SemiJoinProjectTransposeRule.java
index 8cb450e..6e945e5 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/SemiJoinProjectTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/SemiJoinProjectTransposeRule.java
@@ -18,10 +18,10 @@ 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.Join;
 import org.apache.calcite.rel.core.JoinRelType;
+import org.apache.calcite.rel.core.RelFactories;
 import org.apache.calcite.rel.core.SemiJoin;
 import org.apache.calcite.rel.logical.LogicalProject;
 import org.apache.calcite.rel.type.RelDataType;
@@ -32,6 +32,8 @@ import org.apache.calcite.rex.RexInputRef;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexProgram;
 import org.apache.calcite.rex.RexProgramBuilder;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
 import org.apache.calcite.util.ImmutableIntList;
 import org.apache.calcite.util.Pair;
 
@@ -52,17 +54,18 @@ import java.util.List;
  */
 public class SemiJoinProjectTransposeRule extends RelOptRule {
   public static final SemiJoinProjectTransposeRule INSTANCE =
-      new SemiJoinProjectTransposeRule();
+      new SemiJoinProjectTransposeRule(RelFactories.LOGICAL_BUILDER);
 
   //~ Constructors -----------------------------------------------------------
 
   /**
    * Creates a SemiJoinProjectTransposeRule.
    */
-  private SemiJoinProjectTransposeRule() {
+  private SemiJoinProjectTransposeRule(RelBuilderFactory relBuilderFactory) {
     super(
         operand(SemiJoin.class,
-            some(operand(LogicalProject.class, any()))));
+            some(operand(LogicalProject.class, any()))),
+        relBuilderFactory, null);
   }
 
   //~ Methods ----------------------------------------------------------------
@@ -71,9 +74,9 @@ public class SemiJoinProjectTransposeRule extends RelOptRule {
     SemiJoin semiJoin = call.rel(0);
     LogicalProject project = call.rel(1);
 
-    // convert the LHS semijoin keys to reference the child projection
+    // Convert the LHS semi-join keys to reference the child projection
     // expression; all projection expressions must be RexInputRefs,
-    // otherwise, we wouldn't have created this semijoin
+    // otherwise, we wouldn't have created this semi-join.
     final List<Integer> newLeftKeys = new ArrayList<>();
     final List<Integer> leftKeys = semiJoin.getLeftKeys();
     final List<RexNode> projExprs = project.getProjects();
@@ -93,13 +96,11 @@ public class SemiJoinProjectTransposeRule extends RelOptRule {
     // Create the new projection.  Note that the projection expressions
     // are the same as the original because they only reference the LHS
     // of the semijoin and the semijoin only projects out the LHS
-    RelNode newProject =
-        RelOptUtil.createProject(
-            newSemiJoin,
-            projExprs,
-            project.getRowType().getFieldNames());
+    final RelBuilder relBuilder = call.builder();
+    relBuilder.push(newSemiJoin);
+    relBuilder.project(projExprs, project.getRowType().getFieldNames());
 
-    call.transformTo(newProject);
+    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/SortJoinTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/SortJoinTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/SortJoinTransposeRule.java
index b6d87f5..4bc11ec 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/SortJoinTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/SortJoinTransposeRule.java
@@ -36,9 +36,10 @@ import com.google.common.collect.ImmutableList;
 
 /**
  * Planner rule that pushes a {@link org.apache.calcite.rel.core.Sort} past a
- * {@link org.apache.calcite.rel.core.Join}. At the moment, we only consider
- * left/right outer joins.
- * However, an extesion for full outer joins for this rule could be envision.
+ * {@link org.apache.calcite.rel.core.Join}.
+ *
+ * <p>At the moment, we only consider left/right outer joins.
+ * However, an extension for full outer joins for this rule could be envisioned.
  * Special attention should be paid to null values for correctness issues.
  */
 public class SortJoinTransposeRule extends RelOptRule {
@@ -59,8 +60,7 @@ public class SortJoinTransposeRule extends RelOptRule {
 
   //~ Methods ----------------------------------------------------------------
 
-  @Override
-  public boolean matches(RelOptRuleCall call) {
+  @Override public boolean matches(RelOptRuleCall call) {
     final Sort sort = call.rel(0);
     final Join join = call.rel(1);
 
@@ -95,8 +95,7 @@ public class SortJoinTransposeRule extends RelOptRule {
     return true;
   }
 
-  @Override
-  public void onMatch(RelOptRuleCall call) {
+  @Override public void onMatch(RelOptRuleCall call) {
     final Sort sort = call.rel(0);
     final Join join = call.rel(1);
 
@@ -150,8 +149,7 @@ public class SortJoinTransposeRule extends RelOptRule {
     if (rowCount != null && fetch != null) {
       final int offsetVal = offset == null ? 0 : RexLiteral.intValue(offset);
       final int limit = RexLiteral.intValue(fetch);
-      final Double offsetLimit = new Double(offsetVal + limit);
-      if (offsetLimit < rowCount) {
+      if ((double) offsetVal + (double) limit < rowCount) {
         alreadySmaller = false;
       }
     }
@@ -159,3 +157,5 @@ public class SortJoinTransposeRule extends RelOptRule {
   }
 
 }
+
+// End SortJoinTransposeRule.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/SortProjectTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/SortProjectTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/SortProjectTransposeRule.java
index 2240c38..b86bbe3 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/SortProjectTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/SortProjectTransposeRule.java
@@ -24,6 +24,7 @@ import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelCollationTraitDef;
 import org.apache.calcite.rel.RelFieldCollation;
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.Project;
 import org.apache.calcite.rel.core.Sort;
 import org.apache.calcite.rel.logical.LogicalProject;
 import org.apache.calcite.rex.RexUtil;
@@ -37,7 +38,7 @@ import java.util.Map;
 /**
  * Planner rule that pushes
  * a {@link org.apache.calcite.rel.core.Sort}
- * past a {@link org.apache.calcite.rel.logical.LogicalProject}.
+ * past a {@link org.apache.calcite.rel.core.Project}.
  *
  * @see org.apache.calcite.rel.rules.ProjectSortTransposeRule
  */
@@ -52,17 +53,15 @@ public class SortProjectTransposeRule extends RelOptRule {
    */
   private SortProjectTransposeRule() {
     super(
-        operand(
-            Sort.class,
+        operand(Sort.class,
             operand(LogicalProject.class, any())));
   }
 
   //~ Methods ----------------------------------------------------------------
 
-  // implement RelOptRule
   public void onMatch(RelOptRuleCall call) {
     final Sort sort = call.rel(0);
-    final LogicalProject project = call.rel(1);
+    final Project project = call.rel(1);
     final RelOptCluster cluster = project.getCluster();
 
     if (sort.getConvention() != project.getConvention()) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/UnionMergeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/UnionMergeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/UnionMergeRule.java
index 1d4cfcc..fbd3e76 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/UnionMergeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/UnionMergeRule.java
@@ -22,12 +22,10 @@ import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.RelFactories;
 import org.apache.calcite.rel.core.Union;
 import org.apache.calcite.rel.logical.LogicalUnion;
-import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
 import org.apache.calcite.util.Util;
 
-import java.util.ArrayList;
-import java.util.List;
-
 /**
  * UnionMergeRule implements the rule for combining two
  * non-distinct {@link org.apache.calcite.rel.core.Union}s
@@ -35,38 +33,37 @@ import java.util.List;
  */
 public class UnionMergeRule extends RelOptRule {
   public static final UnionMergeRule INSTANCE =
-      new UnionMergeRule(LogicalUnion.class,
-          RelFactories.DEFAULT_SET_OP_FACTORY);
-
-  private final RelFactories.SetOpFactory setOpFactory;
+      new UnionMergeRule(LogicalUnion.class, RelFactories.LOGICAL_BUILDER);
 
   //~ Constructors -----------------------------------------------------------
 
-  /**
-   * Creates a UnionMergeRule.
-   */
-  public UnionMergeRule(Class<? extends Union> clazz,
-      RelFactories.SetOpFactory setOpFactory) {
+  /** Creates a UnionMergeRule. */
+  public UnionMergeRule(Class<? extends Union> unionClazz,
+      RelBuilderFactory relBuilderFactory) {
     super(
-        operand(
-            clazz,
+        operand(unionClazz,
             operand(RelNode.class, any()),
-            operand(RelNode.class, any())));
-    this.setOpFactory = setOpFactory;
+            operand(RelNode.class, any())),
+        relBuilderFactory, null);
+  }
+
+  @Deprecated // to be removed before 2.0
+  public UnionMergeRule(Class<? extends Union> unionClazz,
+      RelFactories.SetOpFactory setOpFactory) {
+    this(unionClazz, RelBuilder.proto(setOpFactory));
   }
 
   //~ Methods ----------------------------------------------------------------
 
-  // implement RelOptRule
   public void onMatch(RelOptRuleCall call) {
-    Union topUnion = call.rel(0);
-    Union bottomUnion;
+    final Union topUnion = call.rel(0);
 
     // We want to combine the Union that's in the second input 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.
+    final Union bottomUnion;
     if (call.rel(2) instanceof Union) {
       bottomUnion = call.rel(2);
     } else if (call.rel(1) instanceof Union) {
@@ -82,22 +79,20 @@ public class UnionMergeRule extends RelOptRule {
 
     // Combine the inputs from the bottom union with the other inputs from
     // the top union
-    List<RelNode> unionInputs = new ArrayList<RelNode>();
+    final RelBuilder relBuilder = call.builder();
     if (call.rel(2) instanceof Union) {
       assert topUnion.getInputs().size() == 2;
-      unionInputs.add(topUnion.getInput(0));
-      unionInputs.addAll(bottomUnion.getInputs());
+      relBuilder.push(topUnion.getInput(0));
+      relBuilder.pushAll(bottomUnion.getInputs());
     } else {
-      unionInputs.addAll(bottomUnion.getInputs());
-      unionInputs.addAll(Util.skip(topUnion.getInputs()));
+      relBuilder.pushAll(bottomUnion.getInputs());
+      relBuilder.pushAll(Util.skip(topUnion.getInputs()));
     }
-    assert unionInputs.size()
-        == bottomUnion.getInputs().size()
+    int n = bottomUnion.getInputs().size()
         + topUnion.getInputs().size()
         - 1;
-    RelNode newUnion = setOpFactory.createSetOp(SqlKind.UNION,
-        unionInputs, true);
-    call.transformTo(newUnion);
+    relBuilder.union(true, n);
+    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/UnionToDistinctRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/UnionToDistinctRule.java b/core/src/main/java/org/apache/calcite/rel/rules/UnionToDistinctRule.java
index 5bb9562..10ae1f4 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/UnionToDistinctRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/UnionToDistinctRule.java
@@ -18,12 +18,11 @@ 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.RelFactories;
 import org.apache.calcite.rel.core.Union;
 import org.apache.calcite.rel.logical.LogicalUnion;
-import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
 
 /**
  * Planner rule that translates a distinct
@@ -35,32 +34,36 @@ import org.apache.calcite.sql.SqlKind;
  */
 public class UnionToDistinctRule extends RelOptRule {
   public static final UnionToDistinctRule INSTANCE =
-      new UnionToDistinctRule(LogicalUnion.class,
-          RelFactories.DEFAULT_SET_OP_FACTORY);
-
-  private final RelFactories.SetOpFactory setOpFactory;
+      new UnionToDistinctRule(LogicalUnion.class, RelFactories.LOGICAL_BUILDER);
 
   //~ Constructors -----------------------------------------------------------
 
   /**
    * Creates a UnionToDistinctRule.
    */
-  public UnionToDistinctRule(Class<? extends Union> clazz,
+  public UnionToDistinctRule(Class<? extends Union> unionClazz,
+      RelBuilderFactory relBuilderFactory) {
+    super(operand(unionClazz, any()), relBuilderFactory, null);
+  }
+
+  @Deprecated // to be removed before 2.0
+  public UnionToDistinctRule(Class<? extends Union> unionClazz,
       RelFactories.SetOpFactory setOpFactory) {
-    super(operand(clazz, any()));
-    this.setOpFactory = setOpFactory;
+    this(unionClazz, RelBuilder.proto(setOpFactory));
   }
 
   //~ Methods ----------------------------------------------------------------
 
   public void onMatch(RelOptRuleCall call) {
-    Union union = call.rel(0);
+    final Union union = call.rel(0);
     if (union.all) {
       return; // nothing to do
     }
-    RelNode unionAll = setOpFactory.createSetOp(SqlKind.UNION,
-        union.getInputs(), true);
-    call.transformTo(RelOptUtil.createDistinctRel(unionAll));
+    final RelBuilder relBuilder = call.builder();
+    relBuilder.pushAll(union.getInputs());
+    relBuilder.union(true, union.getInputs().size());
+    relBuilder.distinct();
+    call.transformTo(relBuilder.build());
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java b/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
index 9e17837..0863332 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
@@ -36,7 +36,6 @@ import org.apache.calcite.rel.logical.LogicalTableFunctionScan;
 import org.apache.calcite.rel.logical.LogicalTableModify;
 import org.apache.calcite.rel.logical.LogicalValues;
 import org.apache.calcite.rel.metadata.RelMetadataQuery;
-import org.apache.calcite.rel.rules.ProjectRemoveRule;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeField;
 import org.apache.calcite.rel.type.RelDataTypeImpl;
@@ -47,6 +46,7 @@ import org.apache.calcite.rex.RexPermuteInputsShuttle;
 import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.rex.RexVisitor;
 import org.apache.calcite.sql.validate.SqlValidator;
+import org.apache.calcite.tools.RelBuilder;
 import org.apache.calcite.util.Bug;
 import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.Pair;
@@ -59,7 +59,6 @@ import org.apache.calcite.util.mapping.MappingType;
 import org.apache.calcite.util.mapping.Mappings;
 
 import com.google.common.base.Function;
-import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 
@@ -99,13 +98,7 @@ 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.SemiJoinFactory semiJoinFactory;
-  private final RelFactories.SortFactory sortFactory;
-  private final RelFactories.AggregateFactory aggregateFactory;
-  private final RelFactories.SetOpFactory setOpFactory;
+  private final RelBuilder relBuilder;
 
   //~ Constructors -----------------------------------------------------------
 
@@ -114,23 +107,22 @@ 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_SEMI_JOIN_FACTORY,
-        RelFactories.DEFAULT_SORT_FACTORY,
-        RelFactories.DEFAULT_AGGREGATE_FACTORY,
-        RelFactories.DEFAULT_SET_OP_FACTORY);
+  public RelFieldTrimmer(SqlValidator validator, RelBuilder relBuilder) {
+    Util.discard(validator); // may be useful one day
+    this.relBuilder = relBuilder;
+    this.trimFieldsDispatcher =
+        ReflectUtil.createMethodDispatcher(
+            TrimResult.class,
+            this,
+            "trimFields",
+            RelNode.class,
+            ImmutableBitSet.class,
+            Set.class);
   }
 
-  /**
-   * Creates a RelFieldTrimmer.
-   *
-   * @param validator Validator
-   */
+  @Deprecated // to be removed before 2.0
   public RelFieldTrimmer(SqlValidator validator,
+      RelOptCluster cluster,
       RelFactories.ProjectFactory projectFactory,
       RelFactories.FilterFactory filterFactory,
       RelFactories.JoinFactory joinFactory,
@@ -138,22 +130,10 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
       RelFactories.SortFactory sortFactory,
       RelFactories.AggregateFactory aggregateFactory,
       RelFactories.SetOpFactory setOpFactory) {
-    Util.discard(validator); // may be useful one day
-    this.trimFieldsDispatcher =
-        ReflectUtil.createMethodDispatcher(
-            TrimResult.class,
-            this,
-            "trimFields",
-            RelNode.class,
-            ImmutableBitSet.class,
-            Set.class);
-    this.projectFactory = Preconditions.checkNotNull(projectFactory);
-    this.filterFactory = Preconditions.checkNotNull(filterFactory);
-    this.joinFactory = Preconditions.checkNotNull(joinFactory);
-    this.semiJoinFactory = Preconditions.checkNotNull(semiJoinFactory);
-    this.sortFactory = Preconditions.checkNotNull(sortFactory);
-    this.aggregateFactory = Preconditions.checkNotNull(aggregateFactory);
-    this.setOpFactory = Preconditions.checkNotNull(setOpFactory);
+    this(validator,
+        RelBuilder.proto(projectFactory, filterFactory, joinFactory,
+            semiJoinFactory, sortFactory, aggregateFactory, setOpFactory)
+        .create(cluster, null));
   }
 
   //~ Methods ----------------------------------------------------------------
@@ -245,11 +225,10 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
               ? rexBuilder.makeZeroLiteral(field.getType())
               : rexBuilder.makeInputRef(field.getType(), source));
     }
-    RelNode project =
-        projectFactory.createProject(
-            trimResult.left, exprList, nameList);
+    relBuilder.push(trimResult.left)
+        .project(exprList, nameList);
     return new TrimResult(
-        project,
+        relBuilder.build(),
         Mappings.createIdentity(fieldList.size()));
   }
 
@@ -383,17 +362,9 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
         RelOptUtil.permute(project.getCluster().getTypeFactory(), rowType,
             mapping);
 
-    final RelNode newProject;
-    if (ProjectRemoveRule.isIdentity(newProjects, newInput.getRowType())) {
-      // The new project would be the identity. It is equivalent to return
-      // its child.
-      newProject = newInput;
-    } else {
-      newProject = projectFactory.createProject(newInput, newProjects,
-          newRowType.getFieldNames());
-      assert newProject.getClass() == project.getClass();
-    }
-    return new TrimResult(newProject, mapping);
+    relBuilder.push(newInput);
+    relBuilder.project(newProjects, newRowType.getFieldNames());
+    return new TrimResult(relBuilder.build(), mapping);
   }
 
   /** Creates a project with a dummy column, to protect the parts of the system
@@ -414,9 +385,9 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
     }
     final RexLiteral expr =
         cluster.getRexBuilder().makeExactLiteral(BigDecimal.ZERO);
-    final RelNode newProject = projectFactory.createProject(input,
-        ImmutableList.<RexNode>of(expr), ImmutableList.of("DUMMY"));
-    return new TrimResult(newProject, mapping);
+    relBuilder.push(input);
+    relBuilder.project(ImmutableList.<RexNode>of(expr), ImmutableList.of("DUMMY"));
+    return new TrimResult(relBuilder.build(), mapping);
   }
 
   /**
@@ -463,13 +434,13 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
     RexNode newConditionExpr =
         conditionExpr.accept(shuttle);
 
-    final RelNode newFilter = filterFactory.createFilter(
-        newInput, newConditionExpr);
+    relBuilder.push(newInput);
+    relBuilder.filter(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
     // needs them for its condition.
-    return new TrimResult(newFilter, inputMapping);
+    return new TrimResult(relBuilder.build(), inputMapping);
   }
 
   /**
@@ -510,15 +481,19 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
           Mappings.createIdentity(fieldCount));
     }
 
-    final RelCollation newCollation =
-        sort.getTraitSet().canonize(RexUtil.apply(inputMapping, collation));
-    final RelNode newSort =
-        sortFactory.createSort(newInput, newCollation, sort.offset, sort.fetch);
+    relBuilder.push(newInput);
+    final int offset =
+        sort.offset == null ? 0 : RexLiteral.intValue(sort.offset);
+    final int fetch =
+        sort.fetch == null ? -1 : RexLiteral.intValue(sort.fetch);
+    final ImmutableList<RexNode> fields =
+        relBuilder.fields(RexUtil.apply(inputMapping, collation));
+    relBuilder.sortLimit(offset, fetch, fields);
 
     // 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
     // needs them for its condition.
-    return new TrimResult(newSort, inputMapping);
+    return new TrimResult(relBuilder.build(), inputMapping);
   }
 
   /**
@@ -636,10 +611,11 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
     RexNode newConditionExpr =
         conditionExpr.accept(shuttle);
 
-    final RelNode newJoin;
+    relBuilder.push(newInputs.get(0));
+    relBuilder.push(newInputs.get(1));
+
     if (join instanceof SemiJoin) {
-      newJoin = semiJoinFactory.createSemiJoin(newInputs.get(0),
-          newInputs.get(1), newConditionExpr);
+      relBuilder.semiJoin(newConditionExpr);
       // For SemiJoins only map fields from the left-side
       Mapping inputMapping = inputMappings.get(0);
       mapping = Mappings.create(MappingType.INVERSE_SURJECTION,
@@ -654,12 +630,10 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
         mapping.set(pair.source + offset, pair.target + newOffset);
       }
     } else {
-      newJoin = joinFactory.createJoin(newInputs.get(0), newInputs.get(1),
-          newConditionExpr, join.getJoinType(), join.getVariablesStopped(),
-          join.isSemiJoinDone());
+      relBuilder.join(join.getJoinType(), newConditionExpr);
     }
 
-    return new TrimResult(newJoin, mapping);
+    return new TrimResult(relBuilder.build(), mapping);
   }
 
   /**
@@ -686,12 +660,9 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
     final Mapping mapping = createMapping(fieldsUsed, fieldCount);
 
     // Create input with trimmed columns.
-    final List<RelNode> newInputs = new ArrayList<>();
     for (RelNode input : setOp.getInputs()) {
       TrimResult trimResult =
           trimChild(setOp, input, fieldsUsed, extraFields);
-      RelNode newInput = trimResult.left;
-      final Mapping inputMapping = trimResult.right;
 
       // We want "mapping", the input gave us "inputMapping", compute
       // "remaining" mapping.
@@ -704,30 +675,44 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
       // the consumer asked for mapping = [b, d],
       // and the transformed input has columns inputMapping = [d, a, b].
       // remaining will permute [b, d] to [d, a, b].
-      Mapping remaining = Mappings.divide(mapping, inputMapping);
+      Mapping remaining = Mappings.divide(mapping, trimResult.right);
 
       // Create a projection; does nothing if remaining is identity.
-      newInput = RelOptUtil.projectMapping(newInput, remaining, null,
-          projectFactory);
+      relBuilder.push(trimResult.left);
+      relBuilder.permute(remaining);
 
-      if (input != newInput) {
+      if (input != relBuilder.peek()) {
         ++changeCount;
       }
-      newInputs.add(newInput);
     }
 
     // If the input is unchanged, and we need to project all columns,
     // there's to do.
     if (changeCount == 0
         && mapping.isIdentity()) {
+      for (RelNode input : setOp.getInputs()) {
+        relBuilder.build();
+      }
       return new TrimResult(
           setOp,
           mapping);
     }
 
-    RelNode newSetOp =
-        setOpFactory.createSetOp(setOp.kind, newInputs, setOp.all);
-    return new TrimResult(newSetOp, mapping);
+    switch (setOp.kind) {
+    case UNION:
+      relBuilder.union(setOp.all, setOp.getInputs().size());
+      break;
+    case INTERSECT:
+      relBuilder.intersect(setOp.all, setOp.getInputs().size());
+      break;
+    case EXCEPT:
+      assert setOp.getInputs().size() == 2;
+      relBuilder.minus(setOp.all);
+      break;
+    default:
+      throw new AssertionError("unknown setOp " + setOp);
+    }
+    return new TrimResult(relBuilder.build(), mapping);
   }
 
   /**
@@ -831,28 +816,29 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
     }
 
     // Now create new agg calls, and populate mapping for them.
-    final List<AggregateCall> newAggCallList = new ArrayList<>();
+    relBuilder.push(newInput);
+    final List<RelBuilder.AggCall> newAggCallList = new ArrayList<>();
     j = groupCount + indicatorCount;
     for (AggregateCall aggCall : aggregate.getAggCallList()) {
       if (fieldsUsed.get(j)) {
-        AggregateCall newAggCall =
-            aggCall.copy(Mappings.apply2(inputMapping, aggCall.getArgList()),
-                Mappings.apply(inputMapping, aggCall.filterArg));
-        if (newAggCall.equals(aggCall)) {
-          newAggCall = aggCall; // immutable -> canonize to save space
-        }
+        final ImmutableList<RexNode> args =
+            relBuilder.fields(
+                Mappings.apply2(inputMapping, aggCall.getArgList()));
+        final RexNode filterArg = aggCall.filterArg < 0 ? null
+            : relBuilder.field(Mappings.apply(inputMapping, aggCall.filterArg));
+        RelBuilder.AggCall newAggCall =
+            relBuilder.aggregateCall(aggCall.getAggregation(),
+                aggCall.isDistinct(), filterArg, aggCall.name, args);
         mapping.set(j, groupCount + indicatorCount + newAggCallList.size());
         newAggCallList.add(newAggCall);
       }
       ++j;
     }
 
-    RelNode newAggregate = aggregateFactory.createAggregate(newInput,
-        aggregate.indicator, newGroupSet, newGroupSets, newAggCallList);
-
-    assert newAggregate.getClass() == aggregate.getClass();
+    final RelBuilder.GroupKey groupKey = relBuilder.groupKey(newGroupSet, newGroupSets);
+    relBuilder.aggregate(groupKey, newAggCallList);
 
-    return new TrimResult(newAggregate, mapping);
+    return new TrimResult(relBuilder.build(), mapping);
   }
 
   /**
@@ -1015,7 +1001,7 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
           (RelNode) tableAccessRel, fieldsUsed, extraFields);
     }
     final RelNode newTableAccessRel =
-        tableAccessRel.project(fieldsUsed, extraFields, this.projectFactory);
+        tableAccessRel.project(fieldsUsed, extraFields, relBuilder);
 
     // Some parts of the system can't handle rows with zero fields, so
     // pretend that one field is used.

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
index b51a0dc..c6c03b2 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -142,6 +142,7 @@ import org.apache.calcite.sql.validate.SqlValidatorImpl;
 import org.apache.calcite.sql.validate.SqlValidatorNamespace;
 import org.apache.calcite.sql.validate.SqlValidatorScope;
 import org.apache.calcite.sql.validate.SqlValidatorUtil;
+import org.apache.calcite.tools.RelBuilder;
 import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.ImmutableIntList;
 import org.apache.calcite.util.NlsString;
@@ -543,7 +544,9 @@ public class SqlToRelConverter {
    * @return Field trimmer
    */
   protected RelFieldTrimmer newFieldTrimmer() {
-    return new RelFieldTrimmer(validator);
+    final RelBuilder relBuilder =
+        RelFactories.LOGICAL_BUILDER.create(cluster, null);
+    return new RelFieldTrimmer(validator, relBuilder);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
index 696e22c..34eb219 100644
--- a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
+++ b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
@@ -20,12 +20,14 @@ import org.apache.calcite.linq4j.Ord;
 import org.apache.calcite.plan.Context;
 import org.apache.calcite.plan.Contexts;
 import org.apache.calcite.plan.RelOptCluster;
-import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptSchema;
 import org.apache.calcite.plan.RelOptTable;
+import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.RelFieldCollation;
 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.JoinRelType;
 import org.apache.calcite.rel.core.Project;
@@ -33,6 +35,7 @@ import org.apache.calcite.rel.core.RelFactories;
 import org.apache.calcite.rel.core.Sort;
 import org.apache.calcite.rel.core.TableScan;
 import org.apache.calcite.rel.core.Values;
+import org.apache.calcite.rel.rules.ProjectRemoveRule;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rel.type.RelDataTypeField;
@@ -50,10 +53,13 @@ import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.calcite.util.ImmutableIntList;
 import org.apache.calcite.util.NlsString;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Stacks;
 import org.apache.calcite.util.Util;
+import org.apache.calcite.util.mapping.Mapping;
+import org.apache.calcite.util.mapping.Mappings;
 
 import com.google.common.base.Function;
 import com.google.common.base.Preconditions;
@@ -64,7 +70,11 @@ import com.google.common.collect.Lists;
 import java.math.BigDecimal;
 import java.util.AbstractList;
 import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
 
 /**
  * Builder for relational expressions.
@@ -98,6 +108,7 @@ public class RelBuilder {
   private final RelFactories.SortFactory sortFactory;
   private final RelFactories.SetOpFactory setOpFactory;
   private final RelFactories.JoinFactory joinFactory;
+  private final RelFactories.SemiJoinFactory semiJoinFactory;
   private final RelFactories.ValuesFactory valuesFactory;
   private final RelFactories.TableScanFactory scanFactory;
   private final List<Frame> stack = new ArrayList<>();
@@ -127,6 +138,9 @@ public class RelBuilder {
     this.joinFactory =
         Util.first(context.unwrap(RelFactories.JoinFactory.class),
             RelFactories.DEFAULT_JOIN_FACTORY);
+    this.semiJoinFactory =
+        Util.first(context.unwrap(RelFactories.SemiJoinFactory.class),
+            RelFactories.DEFAULT_SEMI_JOIN_FACTORY);
     this.valuesFactory =
         Util.first(context.unwrap(RelFactories.ValuesFactory.class),
             RelFactories.DEFAULT_VALUES_FACTORY);
@@ -156,16 +170,21 @@ public class RelBuilder {
     return cluster.getTypeFactory();
   }
 
-  /** Creates a {@link ProtoRelBuilder}, a partially-created RelBuilder.
+  /** Creates a {@link RelBuilderFactory}, a partially-created RelBuilder.
    * Just add a {@link RelOptCluster} and a {@link RelOptSchema} */
-  public static ProtoRelBuilder proto(final Context context) {
-    return new ProtoRelBuilder() {
+  public static RelBuilderFactory proto(final Context context) {
+    return new RelBuilderFactory() {
       public RelBuilder create(RelOptCluster cluster, RelOptSchema schema) {
         return new RelBuilder(context, cluster, schema);
       }
     };
   }
 
+  /** Creates a {@link RelBuilderFactory} that uses a given set of factories. */
+  public static RelBuilderFactory proto(Object... factories) {
+    return proto(Contexts.of(factories));
+  }
+
   // Methods for manipulating the stack
 
   /** Adds a relational expression to be the input to the next relational
@@ -180,6 +199,14 @@ public class RelBuilder {
     return this;
   }
 
+  /** Pushes a collection of relational expressions. */
+  public RelBuilder pushAll(Iterable<? extends RelNode> nodes) {
+    for (RelNode node : nodes) {
+      push(node);
+    }
+    return this;
+  }
+
   /** Returns the final relational expression.
    *
    * <p>Throws if the stack is empty.
@@ -328,6 +355,52 @@ public class RelBuilder {
     return nodes.build();
   }
 
+  /** Returns references to fields for a given collation. */
+  public ImmutableList<RexNode> fields(RelCollation collation) {
+    final ImmutableList.Builder<RexNode> nodes = ImmutableList.builder();
+    for (RelFieldCollation fieldCollation : collation.getFieldCollations()) {
+      RexNode node = field(fieldCollation.getFieldIndex());
+      switch (fieldCollation.direction) {
+      case DESCENDING:
+        node = desc(node);
+      }
+      switch (fieldCollation.nullDirection) {
+      case FIRST:
+        node = nullsFirst(node);
+        break;
+      case LAST:
+        node = nullsLast(node);
+        break;
+      }
+      nodes.add(node);
+    }
+    return nodes.build();
+  }
+
+  /** Returns references to fields for a given list of input ordinals. */
+  public ImmutableList<RexNode> fields(List<? extends Number> ordinals) {
+    final ImmutableList.Builder<RexNode> nodes = ImmutableList.builder();
+    for (Number ordinal : ordinals) {
+      RexNode node = field(ordinal.intValue());
+      nodes.add(node);
+    }
+    return nodes.build();
+  }
+
+  /** Returns references to fields identified by name. */
+  public ImmutableList<RexNode> fields(Iterable<String> fieldNames) {
+    final ImmutableList.Builder<RexNode> builder = ImmutableList.builder();
+    for (String fieldName : fieldNames) {
+      builder.add(field(fieldName));
+    }
+    return builder.build();
+  }
+
+  /** Returns references to fields identified by a mapping. */
+  public ImmutableList<RexNode> fields(Mappings.TargetMapping mapping) {
+    return fields(Mappings.asList(mapping));
+  }
+
   /** Creates a call to a scalar operator. */
   public RexNode call(SqlOperator operator, RexNode... operands) {
     final RexBuilder builder = cluster.getRexBuilder();
@@ -448,69 +521,101 @@ public class RelBuilder {
 
   /** Creates a group key. */
   public GroupKey groupKey(Iterable<? extends RexNode> nodes) {
-    return new GroupKeyImpl(ImmutableList.copyOf(nodes));
+    return new GroupKeyImpl(ImmutableList.copyOf(nodes), null);
+  }
+
+  /** Creates a group key with grouping sets. */
+  public GroupKey groupKey(Iterable<? extends RexNode> nodes,
+      Iterable<? extends Iterable<? extends RexNode>> nodeLists) {
+    final ImmutableList.Builder<ImmutableList<RexNode>> builder =
+        ImmutableList.builder();
+    for (Iterable<? extends RexNode> nodeList : nodeLists) {
+      builder.add(ImmutableList.copyOf(nodeList));
+    }
+    return new GroupKeyImpl(ImmutableList.copyOf(nodes), builder.build());
   }
 
   /** Creates a group key of fields identified by ordinal. */
   public GroupKey groupKey(int... fieldOrdinals) {
-    final ImmutableList.Builder<RexNode> builder = ImmutableList.builder();
-    for (int fieldOrdinal : fieldOrdinals) {
-      builder.add(field(fieldOrdinal));
-    }
-    return groupKey(builder.build());
+    return groupKey(fields(ImmutableIntList.of(fieldOrdinals)));
   }
 
   /** Creates a group key of fields identified by name. */
   public GroupKey groupKey(String... fieldNames) {
-    final ImmutableList.Builder<RexNode> builder = ImmutableList.builder();
-    for (String fieldName : fieldNames) {
-      builder.add(field(fieldName));
+    return groupKey(fields(ImmutableList.copyOf(fieldNames)));
+  }
+
+  /** Creates a group key with grouping sets, both identified by field positions
+   * in the underlying relational expression.
+   *
+   * <p>This method of creating a group key does not allow you to group on new
+   * expressions, only column projections, but is efficient, especially when you
+   * are coming from an existing {@link Aggregate}. */
+  public GroupKey groupKey(ImmutableBitSet groupSet,
+      ImmutableList<ImmutableBitSet> groupSets) {
+    if (groupSet.length() > peek().getRowType().getFieldCount()) {
+      throw new IllegalArgumentException("out of bounds: " + groupSet);
+    }
+    if (groupSets == null) {
+      groupSets = ImmutableList.of(groupSet);
     }
-    return groupKey(builder.build());
+    final ImmutableList<RexNode> nodes =
+        fields(ImmutableIntList.of(groupSet.toArray()));
+    final List<ImmutableList<RexNode>> nodeLists =
+        Lists.transform(groupSets,
+            new Function<ImmutableBitSet, ImmutableList<RexNode>>() {
+              public ImmutableList<RexNode> apply(ImmutableBitSet input) {
+                return fields(ImmutableIntList.of(input.toArray()));
+              }
+            });
+    return groupKey(nodes, nodeLists);
   }
 
   /** Creates a call to an aggregate function. */
-  public AggCall aggregateCall(SqlAggFunction aggFunction,
-      boolean distinct, String alias, RexNode... operands) {
-    return aggregateCall(aggFunction, distinct, alias,
+  public AggCall aggregateCall(SqlAggFunction aggFunction, boolean distinct,
+      RexNode filter, String alias, RexNode... operands) {
+    return aggregateCall(aggFunction, distinct, filter, alias,
         ImmutableList.copyOf(operands));
   }
 
   /** Creates a call to an aggregate function. */
-  public AggCall aggregateCall(SqlAggFunction aggFunction,
-      boolean distinct, String alias, Iterable<? extends RexNode> operands) {
-    return new AggCallImpl(aggFunction, distinct, alias,
+  public AggCall aggregateCall(SqlAggFunction aggFunction, boolean distinct,
+      RexNode filter, String alias, Iterable<? extends RexNode> operands) {
+    return new AggCallImpl(aggFunction, distinct, filter, alias,
         ImmutableList.copyOf(operands));
   }
 
   /** Creates a call to the COUNT aggregate function. */
   public AggCall count(boolean distinct, String alias, RexNode... operands) {
-    return aggregateCall(SqlStdOperatorTable.COUNT, distinct, alias, operands);
+    return aggregateCall(SqlStdOperatorTable.COUNT, distinct, null, alias,
+        operands);
   }
 
   /** Creates a call to the COUNT(*) aggregate function. */
   public AggCall countStar(String alias) {
-    return aggregateCall(SqlStdOperatorTable.COUNT, false, alias);
+    return aggregateCall(SqlStdOperatorTable.COUNT, false, null, alias);
   }
 
   /** Creates a call to the SUM aggregate function. */
   public AggCall sum(boolean distinct, String alias, RexNode operand) {
-    return aggregateCall(SqlStdOperatorTable.SUM, distinct, alias, operand);
+    return aggregateCall(SqlStdOperatorTable.SUM, distinct, null, alias,
+        operand);
   }
 
   /** Creates a call to the AVG aggregate function. */
   public AggCall avg(boolean distinct, String alias, RexNode operand) {
-    return aggregateCall(SqlStdOperatorTable.AVG, distinct, alias, operand);
+    return aggregateCall(
+        SqlStdOperatorTable.AVG, distinct, null, alias, operand);
   }
 
   /** Creates a call to the MIN aggregate function. */
   public AggCall min(String alias, RexNode operand) {
-    return aggregateCall(SqlStdOperatorTable.MIN, false, alias, operand);
+    return aggregateCall(SqlStdOperatorTable.MIN, false, null, alias, operand);
   }
 
   /** Creates a call to the MAX aggregate function. */
   public AggCall max(String alias, RexNode operand) {
-    return aggregateCall(SqlStdOperatorTable.MAX, false, alias, operand);
+    return aggregateCall(SqlStdOperatorTable.MAX, false, null, alias, operand);
   }
 
   // Methods that create relational expressions
@@ -562,21 +667,49 @@ public class RelBuilder {
   /** Creates a {@link org.apache.calcite.rel.core.Project} of the given list
    * of expressions.
    *
-   * <p>Infers all field names.
-   * If an expression projects an input field,
-   * or is a cast an input field,
-   * uses the input field name.
-   * If an expression is a call to
-   * {@link org.apache.calcite.sql.fun.SqlStdOperatorTable#AS}
-   * (see {@link #alias}), removes the
-   * call but uses the intended alias.
-   * After the field names have been inferred, makes the
-   * field names unique by appending numeric suffixes. */
+   * <p>Infers names as would {@link #project(Iterable, Iterable)} if all
+   * suggested names were null.
+   *
+   * @param nodes Expressions
+   */
   public RelBuilder project(Iterable<? extends RexNode> nodes) {
+    return project(nodes, ImmutableList.<String>of());
+  }
+
+  /** Creates a {@link org.apache.calcite.rel.core.Project} of the given list
+   * of expressions, using the given names.
+   *
+   * <p>Names are deduced as follows:
+   * <ul>
+   *   <li>If the length of {@code fieldNames} is greater than the index of
+   *     the current entry in {@code nodes}, and the entry in
+   *     {@code fieldNames} is not null, uses it; otherwise
+   *   <li>If an expression projects an input field,
+   *     or is a cast an input field,
+   *     uses the input field name; otherwise
+   *   <li>If an expression is a call to
+   *     {@link org.apache.calcite.sql.fun.SqlStdOperatorTable#AS}
+   *     (see {@link #alias}), removes the call but uses the intended alias.
+   * </ul>
+   *
+   * <p>After the field names have been inferred, makes the
+   * field names unique by appending numeric suffixes.
+   *
+   * @param nodes Expressions
+   * @param fieldNames Suggested field names
+   */
+  public RelBuilder project(Iterable<? extends RexNode> nodes,
+      Iterable<String> fieldNames) {
     final List<String> names = new ArrayList<>();
     final List<RexNode> exprList = Lists.newArrayList(nodes);
+    final Iterator<String> nameIterator = fieldNames.iterator();
     for (RexNode node : nodes) {
-      names.add(inferAlias(exprList, node));
+      final String name = nameIterator.hasNext() ? nameIterator.next() : null;
+      final String name2 = inferAlias(exprList, node);
+      names.add(Util.first(name, name2));
+    }
+    if (ProjectRemoveRule.isIdentity(exprList, peek().getRowType())) {
+      return this;
     }
     final RelNode project =
         projectFactory.createProject(build(), ImmutableList.copyOf(exprList),
@@ -634,17 +767,41 @@ public class RelBuilder {
   /** Creates an {@link org.apache.calcite.rel.core.Aggregate} with a list of
    * calls. */
   public RelBuilder aggregate(GroupKey groupKey, Iterable<AggCall> aggCalls) {
-    final ImmutableBitSet.Builder builder = ImmutableBitSet.builder();
     final RelDataType inputRowType = peek().getRowType();
     final List<RexNode> extraNodes = projects(inputRowType);
-    for (RexNode node : ((GroupKeyImpl) groupKey).nodes) {
-      builder.set(registerExpression(extraNodes, node));
+    final GroupKeyImpl groupKey_ = (GroupKeyImpl) groupKey;
+    final ImmutableBitSet groupSet =
+        ImmutableBitSet.of(registerExpressions(extraNodes, groupKey_.nodes));
+    final ImmutableList<ImmutableBitSet> groupSets;
+    if (groupKey_.nodeLists != null) {
+      final int sizeBefore = extraNodes.size();
+      final SortedSet<ImmutableBitSet> groupSetSet =
+          new TreeSet<>(ImmutableBitSet.ORDERING);
+      for (ImmutableList<RexNode> nodeList : groupKey_.nodeLists) {
+        final ImmutableBitSet groupSet2 =
+            ImmutableBitSet.of(registerExpressions(extraNodes, nodeList));
+        if (!groupSet.contains(groupSet2)) {
+          throw new IllegalArgumentException("group set element " + nodeList
+              + " must be a subset of group key");
+        }
+        groupSetSet.add(groupSet2);
+      }
+      groupSets = ImmutableList.copyOf(groupSetSet);
+      if (extraNodes.size() > sizeBefore) {
+        throw new IllegalArgumentException(
+            "group sets contained expressions not in group key: "
+                + extraNodes.subList(sizeBefore, extraNodes.size()));
+      }
+    } else {
+      groupSets = ImmutableList.of(groupSet);
     }
-    final ImmutableBitSet groupSet = builder.build();
     for (AggCall aggCall : aggCalls) {
-      final AggCallImpl aggCall1 = (AggCallImpl) aggCall;
-      for (RexNode operand : aggCall1.operands) {
-        registerExpression(extraNodes, operand);
+      if (aggCall instanceof AggCallImpl) {
+        final AggCallImpl aggCall1 = (AggCallImpl) aggCall;
+        registerExpressions(extraNodes, aggCall1.operands);
+        if (aggCall1.filter != null) {
+          registerExpression(extraNodes, aggCall1.filter);
+        }
       }
     }
     if (extraNodes.size() > inputRowType.getFieldCount()) {
@@ -653,18 +810,27 @@ public class RelBuilder {
     final RelNode r = build();
     final List<AggregateCall> aggregateCalls = new ArrayList<>();
     for (AggCall aggCall : aggCalls) {
-      final List<Integer> args = new ArrayList<>();
-      final AggCallImpl aggCall1 = (AggCallImpl) aggCall;
-      for (RexNode operand : aggCall1.operands) {
-        args.add(registerExpression(extraNodes, operand));
+      final AggregateCall aggregateCall;
+      if (aggCall instanceof AggCallImpl) {
+        final AggCallImpl aggCall1 = (AggCallImpl) aggCall;
+        final List<Integer> args = registerExpressions(extraNodes, aggCall1.operands);
+        final int filterArg = aggCall1.filter == null ? -1
+            : registerExpression(extraNodes, aggCall1.filter);
+        aggregateCall =
+            AggregateCall.create(aggCall1.aggFunction, aggCall1.distinct, args,
+                filterArg, groupSet.cardinality(), r, null, aggCall1.alias);
+      } else {
+        aggregateCall = ((AggCallImpl2) aggCall).aggregateCall;
       }
-      aggregateCalls.add(
-          AggregateCall.create(aggCall1.aggFunction, aggCall1.distinct,
-              args, -1, groupSet.cardinality(), r, null, aggCall1.alias));
+      aggregateCalls.add(aggregateCall);
     }
 
-    RelNode aggregate = aggregateFactory.createAggregate(r, false, groupSet,
-        ImmutableList.of(groupSet), aggregateCalls);
+    assert ImmutableBitSet.ORDERING.isStrictlyOrdered(groupSets) : groupSets;
+    for (ImmutableBitSet set : groupSets) {
+      assert groupSet.contains(set);
+    }
+    RelNode aggregate = aggregateFactory.createAggregate(r,
+        groupSets.size() > 1, groupSet, groupSets, aggregateCalls);
     push(aggregate);
     return this;
   }
@@ -687,18 +853,60 @@ public class RelBuilder {
     return i;
   }
 
+  private static List<Integer> registerExpressions(List<RexNode> extraNodes,
+      Iterable<? extends RexNode> nodes) {
+    final List<Integer> builder = new ArrayList<>();
+    for (RexNode node : nodes) {
+      builder.add(registerExpression(extraNodes, node));
+    }
+    return builder;
+  }
+
+  private RelBuilder setOp(boolean all, SqlKind kind, int n) {
+    List<RelNode> inputs = new LinkedList<>();
+    for (int i = 0; i < n; i++) {
+      inputs.add(0, build());
+    }
+    switch (kind) {
+    case UNION:
+    case INTERSECT:
+      if (n < 1) {
+        throw new IllegalArgumentException("bad INTERSECT/UNION input count");
+      }
+      break;
+    case EXCEPT:
+      if (n != 2) {
+        throw new AssertionError("bad EXCEPT input count");
+      }
+      break;
+    default:
+      throw new AssertionError("bad setOp " + kind);
+    }
+    switch (n) {
+    case 1:
+      return push(inputs.get(0));
+    default:
+      return push(setOpFactory.createSetOp(kind, inputs, all));
+    }
+  }
+
   /** Creates a {@link org.apache.calcite.rel.core.Union} of the two most recent
    * relational expressions on the stack.
    *
    * @param all Whether to create UNION ALL
    */
   public RelBuilder union(boolean all) {
-    final RelNode left = build();
-    final RelNode right = build();
-    final RelNode union = setOpFactory.createSetOp(SqlKind.UNION,
-        ImmutableList.of(left, right), all);
-    push(union);
-    return this;
+    return union(all, 2);
+  }
+
+  /** Creates a {@link org.apache.calcite.rel.core.Union} of the {@code n}
+   * most recent relational expressions on the stack.
+   *
+   * @param all Whether to create UNION ALL
+   * @param n Number of inputs to the UNION operator
+   */
+  public RelBuilder union(boolean all, int n) {
+    return setOp(all, SqlKind.UNION, n);
   }
 
   /** Creates an {@link org.apache.calcite.rel.core.Intersect} of the two most
@@ -707,12 +915,17 @@ public class RelBuilder {
    * @param all Whether to create INTERSECT ALL
    */
   public RelBuilder intersect(boolean all) {
-    final RelNode left = build();
-    final RelNode right = build();
-    final RelNode intersect = setOpFactory.createSetOp(SqlKind.INTERSECT,
-        ImmutableList.of(left, right), all);
-    push(intersect);
-    return this;
+    return intersect(all, 2);
+  }
+
+  /** Creates an {@link org.apache.calcite.rel.core.Intersect} of the {@code n}
+   * most recent relational expressions on the stack.
+   *
+   * @param all Whether to create INTERSECT ALL
+   * @param n Number of inputs to the INTERSECT operator
+   */
+  public RelBuilder intersect(boolean all, int n) {
+    return setOp(all, SqlKind.INTERSECT, n);
   }
 
   /** Creates a {@link org.apache.calcite.rel.core.Minus} of the two most recent
@@ -721,19 +934,23 @@ public class RelBuilder {
    * @param all Whether to create EXCEPT ALL
    */
   public RelBuilder minus(boolean all) {
-    final RelNode left = build();
-    final RelNode right = build();
-    final RelNode except = setOpFactory.createSetOp(SqlKind.EXCEPT,
-        ImmutableList.of(left, right), all);
-    push(except);
-    return this;
+    return setOp(all, SqlKind.EXCEPT, 2);
   }
 
   /** Creates a {@link org.apache.calcite.rel.core.Join}. */
-  public RelBuilder join(JoinRelType joinType, RexNode condition) {
+  public RelBuilder join(JoinRelType joinType, RexNode condition0,
+      RexNode... conditions) {
+    return join(joinType, Lists.asList(condition0, conditions));
+  }
+
+  /** Creates a {@link org.apache.calcite.rel.core.Join} with multiple
+   * conditions. */
+  public RelBuilder join(JoinRelType joinType,
+      Iterable<? extends RexNode> conditions) {
     final Frame right = Stacks.pop(stack);
     final Frame left = Stacks.pop(stack);
-    final RelNode join = joinFactory.createJoin(left.rel, right.rel, condition,
+    final RelNode join = joinFactory.createJoin(left.rel, right.rel,
+        RexUtil.composeConjunction(cluster.getRexBuilder(), conditions, false),
         joinType, ImmutableSet.<String>of(), false);
     final List<Pair<String, RelDataType>> pairs = new ArrayList<>();
     pairs.addAll(left.right);
@@ -759,9 +976,24 @@ public class RelBuilder {
               field(2, 0, fieldName),
               field(2, 1, fieldName)));
     }
-    final RexNode condition =
-        RexUtil.composeConjunction(cluster.getRexBuilder(), conditions, false);
-    return join(joinType, condition);
+    return join(joinType, conditions);
+  }
+
+  /** Creates a {@link org.apache.calcite.rel.core.SemiJoin}. */
+  public RelBuilder semiJoin(Iterable<? extends RexNode> conditions) {
+    final Frame right = Stacks.pop(stack);
+    final Frame left = Stacks.pop(stack);
+    final RelNode semiJoin =
+        semiJoinFactory.createSemiJoin(left.rel, right.rel,
+            RexUtil.composeConjunction(cluster.getRexBuilder(), conditions,
+                false));
+    Stacks.push(stack, new Frame(semiJoin, left.right));
+    return this;
+  }
+
+  /** Creates a {@link org.apache.calcite.rel.core.SemiJoin}. */
+  public RelBuilder semiJoin(RexNode... conditions) {
+    return semiJoin(ImmutableList.copyOf(conditions));
   }
 
   /** Assigns a table alias to the top entry on the stack. */
@@ -1007,6 +1239,46 @@ public class RelBuilder {
     }
   }
 
+  /**
+   * Creates a projection that converts the current relational expression's
+   * output to a desired row type.
+   *
+   * @param castRowType row type after cast
+   * @param rename      if true, use field names from castRowType; if false,
+   *                    preserve field names from rel
+   */
+  public RelBuilder convert(RelDataType castRowType, boolean rename) {
+    final RelNode r = build();
+    final RelNode r2 =
+        RelOptUtil.createCastRel(r, castRowType, rename, projectFactory);
+    push(r2);
+    return this;
+  }
+
+  public RelBuilder permute(Mapping mapping) {
+    assert mapping.getMappingType().isSingleSource();
+    assert mapping.getMappingType().isMandatorySource();
+    if (mapping.isIdentity()) {
+      return this;
+    }
+    final List<RexNode> exprList = Lists.newArrayList();
+    for (int i = 0; i < mapping.getTargetCount(); i++) {
+      exprList.add(field(mapping.getSource(i)));
+    }
+    return project(exprList);
+  }
+
+  public RelBuilder aggregate(GroupKey groupKey,
+      List<AggregateCall> aggregateCalls) {
+    return aggregate(groupKey,
+        Lists.transform(
+            aggregateCalls, new Function<AggregateCall, AggCall>() {
+              public AggCall apply(AggregateCall input) {
+                return new AggCallImpl2(input);
+              }
+            }));
+  }
+
   /** Information necessary to create a call to an aggregate function.
    *
    * @see RelBuilder#aggregateCall */
@@ -1021,10 +1293,13 @@ public class RelBuilder {
 
   /** Implementation of {@link RelBuilder.GroupKey}. */
   private static class GroupKeyImpl implements GroupKey {
-    private final ImmutableList<RexNode> nodes;
+    final ImmutableList<RexNode> nodes;
+    final ImmutableList<ImmutableList<RexNode>> nodeLists;
 
-    GroupKeyImpl(ImmutableList<RexNode> nodes) {
-      this.nodes = nodes;
+    GroupKeyImpl(ImmutableList<RexNode> nodes,
+        ImmutableList<ImmutableList<RexNode>> nodeLists) {
+      this.nodes = Preconditions.checkNotNull(nodes);
+      this.nodeLists = nodeLists;
     }
   }
 
@@ -1032,32 +1307,28 @@ public class RelBuilder {
   private static class AggCallImpl implements AggCall {
     private final SqlAggFunction aggFunction;
     private final boolean distinct;
+    private final RexNode filter;
     private final String alias;
     private final ImmutableList<RexNode> operands;
 
-    AggCallImpl(SqlAggFunction aggFunction, boolean distinct,
+    AggCallImpl(SqlAggFunction aggFunction, boolean distinct, RexNode filter,
         String alias, ImmutableList<RexNode> operands) {
       this.aggFunction = aggFunction;
       this.distinct = distinct;
+      this.filter = filter;
       this.alias = alias;
       this.operands = operands;
     }
   }
 
-  /** A partially-created RelBuilder.
-   *
-   * <p>Add a cluster, and optionally a schema,
-   * when you want to create a builder.
-   *
-   * <p>A {@code ProtoRelBuilder} can be shared among queries, and thus can
-   * be inside a {@link RelOptRule}. It is a nice way to encapsulate the policy
-   * that this particular rule instance should create {@code DrillFilter}
-   * and {@code DrillProject} versus {@code HiveFilter} and {@code HiveProject}.
-   *
-   * @see RelFactories#DEFAULT_PROTO
-   */
-  public interface ProtoRelBuilder {
-    RelBuilder create(RelOptCluster cluster, RelOptSchema schema);
+  /** Implementation of {@link RelBuilder.AggCall} that wraps an
+   * {@link AggregateCall}. */
+  private static class AggCallImpl2 implements AggCall {
+    private final AggregateCall aggregateCall;
+
+    AggCallImpl2(AggregateCall aggregateCall) {
+      this.aggregateCall = Preconditions.checkNotNull(aggregateCall);
+    }
   }
 
   /** Builder stack frame.
@@ -1079,8 +1350,10 @@ public class RelBuilder {
 
     private static String deriveAlias(RelNode rel) {
       if (rel instanceof TableScan) {
-        TableScan scan = (TableScan) rel;
-        return Util.last(scan.getTable().getQualifiedName());
+        final List<String> names = rel.getTable().getQualifiedName();
+        if (!names.isEmpty()) {
+          return Util.last(names);
+        }
       }
       return null;
     }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/tools/RelBuilderFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/tools/RelBuilderFactory.java b/core/src/main/java/org/apache/calcite/tools/RelBuilderFactory.java
new file mode 100644
index 0000000..2aefca6
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/tools/RelBuilderFactory.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.tools;
+
+import org.apache.calcite.plan.RelOptCluster;
+import org.apache.calcite.plan.RelOptRule;
+import org.apache.calcite.plan.RelOptSchema;
+import org.apache.calcite.rel.core.RelFactories;
+
+/** A partially-created RelBuilder.
+ *
+ * <p>Add a cluster, and optionally a schema,
+ * when you want to create a builder.
+ *
+ * <p>A {@code ProtoRelBuilder} can be shared among queries, and thus can
+ * be inside a {@link RelOptRule}. It is a nice way to encapsulate the policy
+ * that this particular rule instance should create {@code DrillFilter}
+ * and {@code DrillProject} versus {@code HiveFilter} and {@code HiveProject}.
+ *
+ * @see RelFactories#LOGICAL_BUILDER
+ */
+public interface RelBuilderFactory {
+  /** Creates a RelBuilder. */
+  RelBuilder create(RelOptCluster cluster, RelOptSchema schema);
+}
+
+// End RelBuilderFactory.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java b/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
index cc7ec8c..265990e 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
@@ -206,7 +206,7 @@ public class JdbcAdapterTest {
             + "FROM \"SCOTT\".\"EMP\") AS \"t0\" ON \"t\".\"MGR\" = \"t0\".\"EMPNO\" AND (\"t\".\"SAL\" > \"t0\".\"SAL\" OR \"t\".\"HIREDATE\" < \"t0\".\"HIREDATE\")");
   }
 
-  @Test public void tesJoin3TablesPlan() {
+  @Test public void testJoin3TablesPlan() {
     CalciteAssert.model(JdbcTest.SCOTT_MODEL)
         .query("select  empno, ename, dname, grade \n"
             + "from scott.emp e inner join scott.dept d \n"


[7/7] incubator-calcite git commit: Improve [CALCITE-895] fix, visiting the whole expression via a shuttle

Posted by jh...@apache.org.
Improve [CALCITE-895] fix, visiting the whole expression via a shuttle


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

Branch: refs/heads/master
Commit: d697ca16456424f04ad81e550ee19f677c7520b2
Parents: 2fa63dd
Author: Julian Hyde <jh...@apache.org>
Authored: Tue Sep 22 13:05:00 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Sep 28 12:10:22 2015 -0700

----------------------------------------------------------------------
 .../rel/rules/ReduceExpressionsRule.java        | 125 ++++++++-----------
 1 file changed, 50 insertions(+), 75 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/d697ca16/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
index 61c64a8..8a56928 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
@@ -335,15 +335,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
     RexBuilder rexBuilder = rel.getCluster().getRexBuilder();
 
     // Replace predicates on CASE to CASE on predicates.
-    for (int i = 0; i < expList.size(); i++) {
-      RexNode exp = expList.get(i);
-      if (exp instanceof RexCall) {
-        RexNode exp2 = pushPredicateIntoCase((RexCall) exp);
-        if (exp2 != exp) {
-          expList.set(i, exp2);
-        }
-      }
-    }
+    new CaseShuttle().mutate(expList);
 
     // Find reducible expressions.
     final List<RexNode> constExps = Lists.newArrayList();
@@ -479,77 +471,47 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
     return ImmutableMap.copyOf(builder);
   }
 
-  /** Return if a given operator can be pushed into Case */
-  private static boolean isPushableIntoCase(RexNode node) {
-    if (!(node instanceof RexCall)) {
-      return false;
-    }
-
-    final RexCall call = (RexCall) node;
-    return call.getType().getSqlTypeName() == SqlTypeName.BOOLEAN
-        && (SqlKind.COMPARISON.contains(call.getKind()) || call.getOperands().size() == 1);
-  }
-
+  /** Pushes predicates into a CASE.
+   *
+   * <p>We have a loose definition of 'predicate': any boolean expression will
+   * do, except CASE. For example '(CASE ...) = 5' or '(CASE ...) IS NULL'.
+   */
   private static RexCall pushPredicateIntoCase(RexCall call) {
     if (call.getType().getSqlTypeName() != SqlTypeName.BOOLEAN) {
       return call;
     }
-    final RexShuttle rexShuttle = new RexShuttle() {
-      @Override
-      public RexNode visitCall(RexCall call) {
-        final List<RexNode> newOperands = new ArrayList<>();
-        for (RexNode operand : call.getOperands()) {
-          newOperands.add(operand.accept(this));
-        }
-
-        call = call.clone(call.getType(), newOperands);
-        if (!isPushableIntoCase(call)) {
-          return call;
-        }
-
-        final List<RexNode> operands = call.getOperands();
-        int caseOrdinal = -1;
-        for (int i = 0; i < operands.size(); i++) {
-          RexNode operand = operands.get(i);
-          switch (operand.getKind()) {
-          case CASE:
-            caseOrdinal = i;
-          }
-        }
-        if (caseOrdinal < 0) {
-          return call;
-        }
-
-        // Convert
-        //   f(CASE WHEN p1 THEN v1 ... END, arg)
-        // to
-        //   CASE WHEN p1 THEN f(v1, arg) ... END
-        final RexCall case_ = (RexCall) operands.get(caseOrdinal);
-        final List<RexNode> nodes = new ArrayList<>();
-        for (int i = 0; i < case_.getOperands().size(); i++) {
-          RexNode node = case_.getOperands().get(i);
-          if (!RexUtil.isCasePredicate(case_, i)) {
-            node = substitute(call, caseOrdinal, node);
-
-            // For nested Case-When, the function should be pushed further deeper
-            // For example,
-            // Convert
-            //   f(CASE WHEN p1 THEN (CASE WHEN p2 THEN v2 ... END) ... END, arg)
-            // to
-            //   CASE WHEN p1 THEN f((CASE WHEN p2 THEN v2 ... END), arg) ... END
-            // further to
-            //   CASE WHEN p1 THEN (CASE WHEN p2 THEN f(v2, arg) ... END) ... END
-            if (isPushableIntoCase(node)) {
-              node = node.accept(this);
-            }
-          }
-          nodes.add(node);
-        }
-        return case_.clone(call.getType(), nodes);
+    switch (call.getKind()) {
+    case CASE:
+    case AND:
+    case OR:
+      return call; // don't push CASE into CASE!
+    }
+    int caseOrdinal = -1;
+    final List<RexNode> operands = call.getOperands();
+    for (int i = 0; i < operands.size(); i++) {
+      RexNode operand = operands.get(i);
+      switch (operand.getKind()) {
+      case CASE:
+        caseOrdinal = i;
       }
-    };
-
-    return (RexCall) call.accept(rexShuttle);
+    }
+    if (caseOrdinal < 0) {
+      return call;
+    }
+    // Convert
+    //   f(CASE WHEN p1 THEN v1 ... END, arg)
+    // to
+    //   CASE WHEN p1 THEN f(v1, arg) ... END
+    final RexCall case_ = (RexCall) operands.get(caseOrdinal);
+    final List<RexNode> nodes = new ArrayList<>();
+    for (int i = 0; i < case_.getOperands().size(); i++) {
+      RexNode node = case_.getOperands().get(i);
+      if (!RexUtil.isCasePredicate(case_, i)) {
+        node = substitute(call, caseOrdinal, node);
+      }
+      nodes.add(node);
+    }
+    return case_.clone(call.getType(), nodes);
   }
 
   /** Converts op(arg0, ..., argOrdinal, ..., argN) to op(arg0,..., node, ..., argN). */
@@ -860,6 +822,19 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
     }
   }
 
+  /** Shuttle that pushes predicates into a CASE. */
+  private static class CaseShuttle extends RexShuttle {
+    @Override public RexNode visitCall(RexCall call) {
+      for (;;) {
+        call = (RexCall) super.visitCall(call);
+        final RexCall old = call;
+        call = pushPredicateIntoCase(call);
+        if (call == old) {
+          return call;
+        }
+      }
+    }
+  }
 }
 
 // End ReduceExpressionsRule.java


[5/7] incubator-calcite git commit: Extending [CALCITE-865], add table types used by Oracle and DB2

Posted by jh...@apache.org.
Extending [CALCITE-865], add table types used by Oracle and DB2


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

Branch: refs/heads/master
Commit: 43b88dbfc57fa433ac7f4fdd1f849441f353351d
Parents: 815fa26
Author: Julian Hyde <jh...@apache.org>
Authored: Mon Sep 28 12:02:30 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Sep 28 12:02:30 2015 -0700

----------------------------------------------------------------------
 .../java/org/apache/calcite/schema/Schema.java  | 80 ++++++++++++++++++--
 1 file changed, 75 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/43b88dbf/core/src/main/java/org/apache/calcite/schema/Schema.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/schema/Schema.java b/core/src/main/java/org/apache/calcite/schema/Schema.java
index 6745e21..5f59e8c 100644
--- a/core/src/main/java/org/apache/calcite/schema/Schema.java
+++ b/core/src/main/java/org/apache/calcite/schema/Schema.java
@@ -146,13 +146,13 @@ public interface Schema {
   enum TableType {
     /** A regular table.
      *
-     * <p>Used by PostgreSQL, MySQL and others. */
+     * <p>Used by DB2, MySQL, PostgreSQL and others. */
     TABLE,
 
     /** A relation whose contents are calculated by evaluating a SQL
      * expression.
      *
-     * <p>Used by PostgreSQL and others. */
+     * <p>Used by DB2, PostgreSQL and others. */
     VIEW,
 
     /** Foreign table.
@@ -177,7 +177,7 @@ public interface Schema {
 
     /** Sequence table.
      *
-     * <p>Used by Apache Phoenix, PostgreSQL and others.
+     * <p>Used by Apache Phoenix, Oracle, PostgreSQL and others.
      * In Phoenix, must have a single BIGINT column called "$seq". */
     SEQUENCE,
 
@@ -200,7 +200,8 @@ public interface Schema {
      * "TABLES" and "COLUMNS" table in the "metamodel" schema, examples of
      * system tables.
      *
-     * <p>Used by PostgreSQL, MySQL and others. */
+     * <p>Specified by the JDBC standard and used by DB2, MySQL, Oracle,
+     * PostgreSQL and others. */
     SYSTEM_TABLE,
 
     /** System view.
@@ -245,9 +246,78 @@ public interface Schema {
 
     /** A table that is only visible to one connection.
      *
-     * <p>Used by PostgreSQL, MySQL. */
+     * <p>Specified by the JDBC standard and used by PostgreSQL, MySQL. */
     LOCAL_TEMPORARY,
 
+    /** A synonym.
+     *
+     * <p>Used by DB2, Oracle. */
+    SYNONYM,
+
+    /** An alias.
+     *
+     * <p>Specified by the JDBC standard. */
+    ALIAS,
+
+    /** A global temporary table.
+     *
+     * <p>Specified by the JDBC standard. */
+    GLOBAL_TEMPORARY,
+
+    /** An accel-only table.
+     *
+     * <p>Used by DB2.
+     */
+    ACCEL_ONLY_TABLE,
+
+    /** An auxiliary table.
+     *
+     * <p>Used by DB2.
+     */
+    AUXILIARY_TABLE,
+
+    /** A global temporary table.
+     *
+     * <p>Used by DB2.
+     */
+    GLOBAL_TEMPORARY_TABLE,
+
+    /** A hierarchy table.
+     *
+     * <p>Used by DB2.
+     */
+    HIERARCHY_TABLE,
+
+    /** An inoperative view.
+     *
+     * <p>Used by DB2.
+     */
+    INOPERATIVE_VIEW,
+
+    /** A materialized query table.
+     *
+     * <p>Used by DB2.
+     */
+    MATERIALIZED_QUERY_TABLE,
+
+    /** A nickname.
+     *
+     * <p>Used by DB2.
+     */
+    NICKNAME,
+
+    /** A typed table.
+     *
+     * <p>Used by DB2.
+     */
+    TYPED_TABLE,
+
+    /** A typed view.
+     *
+     * <p>Used by DB2.
+     */
+    TYPED_VIEW,
+
     /** Table type not known to Calcite.
      *
      * <p>If you get one of these, please fix the problem by adding an enum


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

Posted by jh...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java
index bcf80a9..e1f1396 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java
@@ -29,17 +29,17 @@ import org.apache.calcite.rel.logical.LogicalUnion;
 import org.apache.calcite.rel.metadata.RelMdUtil;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.sql.SqlAggFunction;
-import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.sql.fun.SqlCountAggFunction;
 import org.apache.calcite.sql.fun.SqlMinMaxAggFunction;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.fun.SqlSumAggFunction;
 import org.apache.calcite.sql.fun.SqlSumEmptyIsZeroAggFunction;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 
-import java.util.ArrayList;
 import java.util.IdentityHashMap;
 import java.util.List;
 import java.util.Map;
@@ -52,13 +52,7 @@ import java.util.Map;
 public class AggregateUnionTransposeRule extends RelOptRule {
   public static final AggregateUnionTransposeRule INSTANCE =
       new AggregateUnionTransposeRule(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);
 
   private static final Map<Class<? extends SqlAggFunction>, Boolean>
   SUPPORTED_AGGREGATES = new IdentityHashMap<>();
@@ -70,18 +64,22 @@ public class AggregateUnionTransposeRule extends RelOptRule {
     SUPPORTED_AGGREGATES.put(SqlSumEmptyIsZeroAggFunction.class, true);
   }
 
-  /**
-   * Constructor.
-   */
+  /** Creates an AggregateUnionTransposeRule. */
+  public AggregateUnionTransposeRule(Class<? extends Aggregate> aggregateClass,
+      Class<? extends Union> unionClass, RelBuilderFactory relBuilderFactory) {
+    super(
+        operand(aggregateClass,
+            operand(unionClass, any())),
+        relBuilderFactory, null);
+  }
+
+  @Deprecated // to be removed before 2.0
   public AggregateUnionTransposeRule(Class<? extends Aggregate> aggregateClass,
       RelFactories.AggregateFactory aggregateFactory,
       Class<? extends Union> unionClass,
       RelFactories.SetOpFactory setOpFactory) {
-    super(
-        operand(aggregateClass,
-            operand(unionClass, any())));
-    this.aggregateFactory = aggregateFactory;
-    this.setOpFactory = setOpFactory;
+    this(aggregateClass, unionClass,
+        RelBuilder.proto(aggregateFactory, setOpFactory));
   }
 
   public void onMatch(RelOptRuleCall call) {
@@ -114,27 +112,24 @@ public class AggregateUnionTransposeRule extends RelOptRule {
       return;
     }
 
-    boolean anyTransformed = false;
-
     // create corresponding aggregates on top of each union child
-    final List<RelNode> newUnionInputs = new ArrayList<>();
+    final RelBuilder relBuilder = call.builder();
+    int transformCount = 0;
     for (RelNode input : union.getInputs()) {
       boolean alreadyUnique =
           RelMdUtil.areColumnsDefinitelyUnique(
               input,
               aggRel.getGroupSet());
 
-      if (alreadyUnique) {
-        newUnionInputs.add(input);
-      } else {
-        anyTransformed = true;
-        newUnionInputs.add(
-            aggregateFactory.createAggregate(input, false,
-                aggRel.getGroupSet(), null, aggRel.getAggCallList()));
+      relBuilder.push(input);
+      if (!alreadyUnique) {
+        ++transformCount;
+        relBuilder.aggregate(relBuilder.groupKey(aggRel.getGroupSet(), null),
+            aggRel.getAggCallList());
       }
     }
 
-    if (!anyTransformed) {
+    if (transformCount == 0) {
       // none of the children could benefit from the push-down,
       // so bail out (preventing the infinite loop to which most
       // planners would succumb)
@@ -142,14 +137,11 @@ public class AggregateUnionTransposeRule extends RelOptRule {
     }
 
     // create a new union whose children are the aggregates created above
-    RelNode newUnion = setOpFactory.createSetOp(SqlKind.UNION,
-        newUnionInputs, true);
-
-    RelNode newTopAggRel =
-        aggregateFactory.createAggregate(newUnion, aggRel.indicator,
-            aggRel.getGroupSet(), aggRel.getGroupSets(), transformedAggCalls);
-
-    call.transformTo(newTopAggRel);
+    relBuilder.union(true, union.getInputs().size());
+    relBuilder.aggregate(
+        relBuilder.groupKey(aggRel.getGroupSet(), aggRel.getGroupSets()),
+        transformedAggCalls);
+    call.transformTo(relBuilder.build());
   }
 
   private List<AggregateCall> transformAggCalls(RelNode input, int groupCount,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/CalcRelSplitter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/CalcRelSplitter.java b/core/src/main/java/org/apache/calcite/rel/rules/CalcRelSplitter.java
index a8810d8..047e950 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/CalcRelSplitter.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/CalcRelSplitter.java
@@ -35,6 +35,7 @@ import org.apache.calcite.rex.RexProgram;
 import org.apache.calcite.rex.RexShuttle;
 import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.rex.RexVisitorImpl;
+import org.apache.calcite.tools.RelBuilder;
 import org.apache.calcite.util.IntList;
 import org.apache.calcite.util.Util;
 import org.apache.calcite.util.graph.DefaultDirectedGraph;
@@ -85,6 +86,7 @@ public abstract class CalcRelSplitter {
   private final RelOptCluster cluster;
   private final RelTraitSet traits;
   private final RelNode child;
+  protected final RelBuilder relBuilder;
 
   //~ Constructors -----------------------------------------------------------
 
@@ -95,7 +97,8 @@ public abstract class CalcRelSplitter {
    * @param relTypes Array of rel types, e.g. {Java, Fennel}. Must be
    *                 distinct.
    */
-  CalcRelSplitter(Calc calc, RelType[] relTypes) {
+  CalcRelSplitter(Calc calc, RelBuilder relBuilder, RelType[] relTypes) {
+    this.relBuilder = relBuilder;
     for (int i = 0; i < relTypes.length; i++) {
       assert relTypes[i] != null;
       for (int j = 0; j < i; j++) {
@@ -220,11 +223,7 @@ public abstract class CalcRelSplitter {
               conditionExprOrdinal,
               outputRowType);
       rel =
-          relType.makeRel(
-              cluster,
-              traits,
-              rel,
-              program1);
+          relType.makeRel(cluster, traits, relBuilder, rel, program1);
 
       // Sometimes a level's program merely projects its inputs. We don't
       // want these. They cause an explosion in the search space.
@@ -452,8 +451,8 @@ public abstract class CalcRelSplitter {
           });
     }
     TopologicalOrderIterator<Integer, DefaultEdge> iter =
-        new TopologicalOrderIterator<Integer, DefaultEdge>(graph);
-    final List<Integer> permutation = new ArrayList<Integer>();
+        new TopologicalOrderIterator<>(graph);
+    final List<Integer> permutation = new ArrayList<>();
     while (iter.hasNext()) {
       permutation.add(iter.next());
     }
@@ -522,7 +521,7 @@ public abstract class CalcRelSplitter {
       int conditionExprOrdinal,
       RelDataType outputRowType) {
     // Build a list of expressions to form the calc.
-    List<RexNode> exprs = new ArrayList<RexNode>();
+    List<RexNode> exprs = new ArrayList<>();
 
     // exprInverseOrdinals describes where an expression in allExprs comes
     // from -- from an input, from a calculated expression, or -1 if not
@@ -569,9 +568,9 @@ public abstract class CalcRelSplitter {
     // ordinals are offsets into allExprs, so we need to map them into
     // exprs.
     final List<RexLocalRef> projectRefs =
-        new ArrayList<RexLocalRef>(projectExprOrdinals.length);
+        new ArrayList<>(projectExprOrdinals.length);
     final List<String> fieldNames =
-        new ArrayList<String>(projectExprOrdinals.length);
+        new ArrayList<>(projectExprOrdinals.length);
     for (int i = 0; i < projectExprOrdinals.length; i++) {
       final int projectExprOrdinal = projectExprOrdinals[i];
       final int index = exprInverseOrdinals[projectExprOrdinal];
@@ -768,12 +767,10 @@ public abstract class CalcRelSplitter {
       return true;
     }
 
-    protected RelNode makeRel(
-        RelOptCluster cluster,
-        RelTraitSet traits,
-        RelNode child,
+    protected RelNode makeRel(RelOptCluster cluster,
+        RelTraitSet traitSet, RelBuilder relBuilder, RelNode input,
         RexProgram program) {
-      return LogicalCalc.create(child, program);
+      return LogicalCalc.create(input, program);
     }
 
     /**
@@ -865,6 +862,7 @@ public abstract class CalcRelSplitter {
    * Control exception for {@link ImplementTester}.
    */
   private static class CannotImplement extends RuntimeException {
+    @SuppressWarnings("ThrowableInstanceNeverThrown")
     static final CannotImplement INSTANCE = new CannotImplement();
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/CalcSplitRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/CalcSplitRule.java b/core/src/main/java/org/apache/calcite/rel/rules/CalcSplitRule.java
index 276b1c4..359ade9 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/CalcSplitRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/CalcSplitRule.java
@@ -18,11 +18,12 @@ 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.Calc;
 import org.apache.calcite.rel.core.Filter;
+import org.apache.calcite.rel.core.RelFactories;
 import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
 import org.apache.calcite.util.Pair;
 
 import com.google.common.collect.ImmutableList;
@@ -38,21 +39,22 @@ import com.google.common.collect.ImmutableList;
  * {@link org.apache.calcite.interpreter.Interpreter}.
  */
 public class CalcSplitRule extends RelOptRule {
-  public static final CalcSplitRule INSTANCE = new CalcSplitRule();
+  public static final CalcSplitRule INSTANCE =
+      new CalcSplitRule(RelFactories.LOGICAL_BUILDER);
 
-  private CalcSplitRule() {
-    super(operand(Calc.class, any()));
+  private CalcSplitRule(RelBuilderFactory relBuilderFactory) {
+    super(operand(Calc.class, any()), relBuilderFactory, null);
   }
 
   @Override public void onMatch(RelOptRuleCall call) {
     final Calc calc = call.rel(0);
     final Pair<ImmutableList<RexNode>, ImmutableList<RexNode>> projectFilter =
         calc.getProgram().split();
-    final RelNode rel = calc.getInput();
-    final RelNode rel2 = RelOptUtil.createFilter(rel, projectFilter.right);
-    final RelNode rel3 = RelOptUtil.createProject(rel2, projectFilter.left,
-        calc.getRowType().getFieldNames());
-    call.transformTo(rel3);
+    final RelBuilder relBuilder = call.builder();
+    relBuilder.push(calc.getInput());
+    relBuilder.filter(projectFilter.right);
+    relBuilder.project(projectFilter.left, calc.getRowType().getFieldNames());
+    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/FilterAggregateTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/FilterAggregateTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/FilterAggregateTransposeRule.java
index b364ef3..efdb06e 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/FilterAggregateTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/FilterAggregateTransposeRule.java
@@ -28,6 +28,7 @@ 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.tools.RelBuilderFactory;
 import org.apache.calcite.util.ImmutableBitSet;
 
 import com.google.common.collect.ImmutableList;
@@ -48,10 +49,8 @@ public class FilterAggregateTransposeRule extends RelOptRule {
    *
    * <p>It matches any kind of agg. or filter */
   public static final FilterAggregateTransposeRule INSTANCE =
-      new FilterAggregateTransposeRule(Filter.class, RelFactories.DEFAULT_PROTO,
-          Aggregate.class);
-
-  private final RelBuilder.ProtoRelBuilder protoBuilder;
+      new FilterAggregateTransposeRule(Filter.class,
+          RelFactories.LOGICAL_BUILDER, Aggregate.class);
 
   //~ Constructors -----------------------------------------------------------
 
@@ -63,12 +62,12 @@ public class FilterAggregateTransposeRule extends RelOptRule {
    */
   public FilterAggregateTransposeRule(
       Class<? extends Filter> filterClass,
-      RelBuilder.ProtoRelBuilder protoBuilder,
+      RelBuilderFactory builderFactory,
       Class<? extends Aggregate> aggregateClass) {
     super(
         operand(filterClass,
-            operand(aggregateClass, any())));
-    this.protoBuilder = protoBuilder;
+            operand(aggregateClass, any())),
+        builderFactory, null);
   }
 
   @Deprecated // to be removed before 2.0
@@ -108,7 +107,7 @@ public class FilterAggregateTransposeRule extends RelOptRule {
       }
     }
 
-    final RelBuilder builder = call.builder(protoBuilder);
+    final RelBuilder builder = call.builder();
     RelNode rel =
         builder.push(aggRel.getInput()).filter(pushedConditions).build();
     if (rel == aggRel.getInput(0)) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/FilterCorrelateRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/FilterCorrelateRule.java b/core/src/main/java/org/apache/calcite/rel/rules/FilterCorrelateRule.java
index 2b38074..982f6d8 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/FilterCorrelateRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/FilterCorrelateRule.java
@@ -27,7 +27,8 @@ import org.apache.calcite.rel.core.RelFactories;
 import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexUtil;
-import org.apache.calcite.util.Util;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
 
 import com.google.common.collect.ImmutableList;
 
@@ -41,25 +42,28 @@ import java.util.List;
 public class FilterCorrelateRule extends RelOptRule {
 
   public static final FilterCorrelateRule INSTANCE =
-      new FilterCorrelateRule(RelFactories.DEFAULT_FILTER_FACTORY,
-          RelFactories.DEFAULT_PROJECT_FACTORY);
-
-  private final RelFactories.FilterFactory filterFactory;
+      new FilterCorrelateRule(RelFactories.LOGICAL_BUILDER);
 
   //~ Constructors -----------------------------------------------------------
 
   /**
+   * Creates a FilterCorrelateRule.
+   */
+  public FilterCorrelateRule(RelBuilderFactory builderFactory) {
+    super(
+        operand(Filter.class,
+            operand(Correlate.class, RelOptRule.any())),
+        builderFactory, "FilterCorrelateRule");
+  }
+
+  /**
    * Creates a FilterCorrelateRule with an explicit root operand and
    * factories.
    */
+  @Deprecated // to be removed before 2.0
   public FilterCorrelateRule(RelFactories.FilterFactory filterFactory,
       RelFactories.ProjectFactory projectFactory) {
-    super(
-        operand(Filter.class,
-            operand(Correlate.class, RelOptRule.any())),
-        "FilterCorrelateRule");
-    this.filterFactory = filterFactory;
-    Util.discard(projectFactory); // for future use
+    this(RelBuilder.proto(filterFactory, projectFactory));
   }
 
   //~ Methods ----------------------------------------------------------------
@@ -97,10 +101,11 @@ public class FilterCorrelateRule extends RelOptRule {
     // Create Filters on top of the children if any filters were
     // pushed to them.
     final RexBuilder rexBuilder = corr.getCluster().getRexBuilder();
-    RelNode leftRel =
-        RelOptUtil.createFilter(corr.getLeft(), leftFilters, filterFactory);
-    RelNode rightRel =
-        RelOptUtil.createFilter(corr.getRight(), rightFilters, filterFactory);
+    final RelBuilder relBuilder = call.builder();
+    final RelNode leftRel =
+        relBuilder.push(corr.getLeft()).filter(leftFilters).build();
+    final RelNode rightRel =
+        relBuilder.push(corr.getRight()).filter(rightFilters).build();
 
     // Create the new Correlate
     RelNode newCorrRel =
@@ -117,9 +122,10 @@ public class FilterCorrelateRule extends RelOptRule {
 
     // Create a Filter on top of the join if needed
     RelNode newRel =
-        RelOptUtil.createFilter(newCorrRel,
-            RexUtil.fixUp(rexBuilder, aboveFilters, newCorrRel.getRowType()),
-            filterFactory);
+        relBuilder.push(newCorrRel)
+        .filter(
+            RexUtil.fixUp(rexBuilder, aboveFilters, newCorrRel.getRowType()))
+        .build();
 
     call.transformTo(newRel);
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java b/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java
index f393ffd..e2ec169 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java
@@ -29,7 +29,10 @@ import org.apache.calcite.rel.core.RelFactories;
 import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexUtil;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
 
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
@@ -54,28 +57,23 @@ public abstract class FilterJoinRule extends RelOptRule {
 
   /** Rule that pushes predicates from a Filter into the Join below them. */
   public static final FilterJoinRule FILTER_ON_JOIN =
-      new FilterIntoJoinRule(true, RelFactories.DEFAULT_FILTER_FACTORY,
-          RelFactories.DEFAULT_PROJECT_FACTORY, TRUE_PREDICATE);
+      new FilterIntoJoinRule(true, RelFactories.LOGICAL_BUILDER,
+          TRUE_PREDICATE);
 
   /** Dumber version of {@link #FILTER_ON_JOIN}. Not intended for production
    * use, but keeps some tests working for which {@code FILTER_ON_JOIN} is too
    * smart. */
   public static final FilterJoinRule DUMB_FILTER_ON_JOIN =
-      new FilterIntoJoinRule(false, RelFactories.DEFAULT_FILTER_FACTORY,
-          RelFactories.DEFAULT_PROJECT_FACTORY, TRUE_PREDICATE);
+      new FilterIntoJoinRule(false, RelFactories.LOGICAL_BUILDER,
+          TRUE_PREDICATE);
 
   /** Rule that pushes predicates in a Join into the inputs to the join. */
   public static final FilterJoinRule JOIN =
-      new JoinConditionPushRule(RelFactories.DEFAULT_FILTER_FACTORY,
-          RelFactories.DEFAULT_PROJECT_FACTORY, TRUE_PREDICATE);
+      new JoinConditionPushRule(RelFactories.LOGICAL_BUILDER, TRUE_PREDICATE);
 
   /** Whether to try to strengthen join-type. */
   private final boolean smart;
 
-  private final RelFactories.FilterFactory filterFactory;
-
-  private final RelFactories.ProjectFactory projectFactory;
-
   /** Predicate that returns whether a filter is valid in the ON clause of a
    * join for this particular kind of join. If not, Calcite will push it back to
    * above the join. */
@@ -84,28 +82,39 @@ public abstract class FilterJoinRule extends RelOptRule {
   //~ Constructors -----------------------------------------------------------
 
   /**
+   * Creates a FilterProjectTransposeRule with an explicit root operand and
+   * factories.
+   */
+  protected FilterJoinRule(RelOptRuleOperand operand, String id,
+      boolean smart, RelBuilderFactory relBuilderFactory, Predicate predicate) {
+    super(operand, relBuilderFactory, "FilterJoinRule:" + id);
+    this.smart = smart;
+    this.predicate = Preconditions.checkNotNull(predicate);
+  }
+
+  /**
    * Creates a FilterJoinRule with an explicit root operand and
    * factories.
    */
+  @Deprecated // to be removed before 2.0
   protected FilterJoinRule(RelOptRuleOperand operand, String id,
       boolean smart, RelFactories.FilterFactory filterFactory,
       RelFactories.ProjectFactory projectFactory) {
-    this(operand, id, smart, filterFactory, projectFactory, TRUE_PREDICATE);
+    this(operand, id, smart, RelBuilder.proto(filterFactory, projectFactory),
+        TRUE_PREDICATE);
   }
 
   /**
    * Creates a FilterProjectTransposeRule with an explicit root operand and
    * factories.
    */
+  @Deprecated // to be removed before 2.0
   protected FilterJoinRule(RelOptRuleOperand operand, String id,
       boolean smart, RelFactories.FilterFactory filterFactory,
       RelFactories.ProjectFactory projectFactory,
       Predicate predicate) {
-    super(operand, "FilterJoinRule:" + id);
-    this.smart = smart;
-    this.filterFactory = filterFactory;
-    this.projectFactory = projectFactory;
-    this.predicate = predicate;
+    this(operand, id, smart, RelBuilder.proto(filterFactory, projectFactory),
+        predicate);
   }
 
   //~ Methods ----------------------------------------------------------------
@@ -139,8 +148,8 @@ public abstract class FilterJoinRule extends RelOptRule {
       joinType = RelOptUtil.simplifyJoin(join, origAboveFilters, joinType);
     }
 
-    List<RexNode> leftFilters = new ArrayList<RexNode>();
-    List<RexNode> rightFilters = new ArrayList<RexNode>();
+    final List<RexNode> leftFilters = new ArrayList<>();
+    final List<RexNode> rightFilters = new ArrayList<>();
 
     // TODO - add logic to derive additional filters.  E.g., from
     // (t1.a = 1 AND t2.a = 2) OR (t1.b = 3 AND t2.b = 4), you can
@@ -204,13 +213,14 @@ public abstract class FilterJoinRule extends RelOptRule {
       return;
     }
 
-    // create FilterRels on top of the children if any filters were
+    // create Filters on top of the children if any filters were
     // pushed to them
     final RexBuilder rexBuilder = join.getCluster().getRexBuilder();
-    RelNode leftRel =
-        RelOptUtil.createFilter(join.getLeft(), leftFilters, filterFactory);
-    RelNode rightRel =
-        RelOptUtil.createFilter(join.getRight(), rightFilters, filterFactory);
+    final RelBuilder relBuilder = call.builder();
+    final RelNode leftRel =
+        relBuilder.push(join.getLeft()).filter(leftFilters).build();
+    final RelNode rightRel =
+        relBuilder.push(join.getRight()).filter(rightFilters).build();
 
     // create the new join node referencing the new children and
     // containing its new join filters (if there are any)
@@ -242,18 +252,17 @@ public abstract class FilterJoinRule extends RelOptRule {
       call.getPlanner().onCopy(filter, rightRel);
     }
 
+    relBuilder.push(newJoinRel);
+
     // Create a project on top of the join if some of the columns have become
     // NOT NULL due to the join-type getting stricter.
-    newJoinRel = RelOptUtil.createCastRel(newJoinRel, join.getRowType(),
-        false, projectFactory);
+    relBuilder.convert(join.getRowType(), false);
 
     // create a FilterRel on top of the join if needed
-    RelNode newRel =
-        RelOptUtil.createFilter(newJoinRel,
-            RexUtil.fixUp(rexBuilder, aboveFilters, newJoinRel.getRowType()),
-            filterFactory);
+    relBuilder.filter(
+        RexUtil.fixUp(rexBuilder, aboveFilters, newJoinRel.getRowType()));
 
-    call.transformTo(newRel);
+    call.transformTo(relBuilder.build());
   }
 
   /**
@@ -286,13 +295,19 @@ public abstract class FilterJoinRule extends RelOptRule {
 
   /** Rule that pushes parts of the join condition to its inputs. */
   public static class JoinConditionPushRule extends FilterJoinRule {
-    public JoinConditionPushRule(RelFactories.FilterFactory filterFactory,
-        RelFactories.ProjectFactory projectFactory, Predicate predicate) {
+    public JoinConditionPushRule(RelBuilderFactory relBuilderFactory,
+        Predicate predicate) {
       super(RelOptRule.operand(Join.class, RelOptRule.any()),
-          "FilterJoinRule:no-filter", true, filterFactory, projectFactory,
+          "FilterJoinRule:no-filter", true, relBuilderFactory,
           predicate);
     }
 
+    @Deprecated // to be removed before 2.0
+    public JoinConditionPushRule(RelFactories.FilterFactory filterFactory,
+        RelFactories.ProjectFactory projectFactory, Predicate predicate) {
+      this(RelBuilder.proto(filterFactory, projectFactory), predicate);
+    }
+
     @Override public void onMatch(RelOptRuleCall call) {
       Join join = call.rel(0);
       perform(call, null, join);
@@ -303,16 +318,22 @@ public abstract class FilterJoinRule extends RelOptRule {
    * condition and into the inputs of the join. */
   public static class FilterIntoJoinRule extends FilterJoinRule {
     public FilterIntoJoinRule(boolean smart,
-        RelFactories.FilterFactory filterFactory,
-        RelFactories.ProjectFactory projectFactory,
-        Predicate predicate) {
+        RelBuilderFactory relBuilderFactory, Predicate predicate) {
       super(
           operand(Filter.class,
               operand(Join.class, RelOptRule.any())),
-          "FilterJoinRule:filter", smart, filterFactory, projectFactory,
+          "FilterJoinRule:filter", smart, relBuilderFactory,
           predicate);
     }
 
+    @Deprecated // to be removed before 2.0
+    public FilterIntoJoinRule(boolean smart,
+        RelFactories.FilterFactory filterFactory,
+        RelFactories.ProjectFactory projectFactory,
+        Predicate predicate) {
+      this(smart, RelBuilder.proto(filterFactory, projectFactory), predicate);
+    }
+
     @Override public void onMatch(RelOptRuleCall call) {
       Filter filter = call.rel(0);
       Join join = call.rel(1);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/FilterMergeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/FilterMergeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/FilterMergeRule.java
index 418e5c8..1f414f8 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/FilterMergeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/FilterMergeRule.java
@@ -16,6 +16,7 @@
  */
 package org.apache.calcite.rel.rules;
 
+import org.apache.calcite.plan.Contexts;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
 import org.apache.calcite.rel.core.Filter;
@@ -24,7 +25,8 @@ import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexProgram;
 import org.apache.calcite.rex.RexProgramBuilder;
-import org.apache.calcite.rex.RexUtil;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
 
 /**
  * Planner rule that combines two
@@ -32,25 +34,27 @@ import org.apache.calcite.rex.RexUtil;
  */
 public class FilterMergeRule extends RelOptRule {
   public static final FilterMergeRule INSTANCE =
-      new FilterMergeRule(RelFactories.DEFAULT_FILTER_FACTORY);
-
-  private final RelFactories.FilterFactory filterFactory;
+      new FilterMergeRule(RelFactories.LOGICAL_BUILDER);
 
   //~ Constructors -----------------------------------------------------------
 
   /**
    * Creates a FilterMergeRule.
    */
-  public FilterMergeRule(RelFactories.FilterFactory filterFactory) {
+  public FilterMergeRule(RelBuilderFactory relBuilderFactory) {
     super(
         operand(Filter.class,
-            operand(Filter.class, any())));
-    this.filterFactory = filterFactory;
+            operand(Filter.class, any())),
+        relBuilderFactory, null);
+  }
+
+  @Deprecated // to be removed before 2.0
+  public FilterMergeRule(RelFactories.FilterFactory filterFactory) {
+    this(RelBuilder.proto(Contexts.of(filterFactory)));
   }
 
   //~ Methods ----------------------------------------------------------------
 
-  // implement RelOptRule
   public void onMatch(RelOptRuleCall call) {
     final Filter topFilter = call.rel(0);
     final Filter bottomFilter = call.rel(1);
@@ -72,12 +76,11 @@ public class FilterMergeRule extends RelOptRule {
         mergedProgram.expandLocalRef(
             mergedProgram.getCondition());
 
-    Filter newFilterRel =
-        (Filter) filterFactory.createFilter(
-            bottomFilter.getInput(),
-            RexUtil.flatten(rexBuilder, newCondition));
+    final RelBuilder relBuilder = call.builder();
+    relBuilder.push(bottomFilter.getInput())
+        .filter(newCondition);
 
-    call.transformTo(newFilterRel);
+    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/FilterProjectTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java
index a81d595..f37ca7b 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java
@@ -28,6 +28,8 @@ import org.apache.calcite.rex.RexCall;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexOver;
 import org.apache.calcite.rex.RexUtil;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
 
 /**
  * Planner rule that pushes
@@ -39,15 +41,13 @@ public class FilterProjectTransposeRule extends RelOptRule {
    * {@link org.apache.calcite.rel.rules.FilterProjectTransposeRule}.
    *
    * <p>It matches any kind of join or filter, and generates the same kind of
-   * join and filter. It uses null values for {@code filterFactory} and
-   * {@code projectFactory} to achieve this. */
+   * join and filter. */
   public static final FilterProjectTransposeRule INSTANCE =
-      new FilterProjectTransposeRule(
-          Filter.class, null,
-          Project.class, null);
+      new FilterProjectTransposeRule(Filter.class, Project.class, true, true,
+          RelFactories.LOGICAL_BUILDER);
 
-  private final RelFactories.FilterFactory filterFactory;
-  private final RelFactories.ProjectFactory projectFactory;
+  private final boolean copyFilter;
+  private final boolean copyProject;
 
   //~ Constructors -----------------------------------------------------------
 
@@ -59,19 +59,30 @@ public class FilterProjectTransposeRule extends RelOptRule {
    */
   public FilterProjectTransposeRule(
       Class<? extends Filter> filterClass,
-      RelFactories.FilterFactory filterFactory,
       Class<? extends Project> projectClass,
-      RelFactories.ProjectFactory projectFactory) {
+      boolean copyFilter, boolean copyProject,
+      RelBuilderFactory relBuilderFactory) {
     super(
         operand(filterClass,
-            operand(projectClass, any())));
-    this.filterFactory = filterFactory;
-    this.projectFactory = projectFactory;
+            operand(projectClass, any())),
+        relBuilderFactory, null);
+    this.copyFilter = copyFilter;
+    this.copyProject = copyProject;
+  }
+
+  @Deprecated // to be removed before 2.0
+  public FilterProjectTransposeRule(
+      Class<? extends Filter> filterClass,
+      RelFactories.FilterFactory filterFactory,
+      Class<? extends Project> projectClass,
+      RelFactories.ProjectFactory projectFactory) {
+    this(filterClass, projectClass, filterFactory == null,
+        projectFactory == null,
+        RelBuilder.proto(filterFactory, projectFactory));
   }
 
   //~ Methods ----------------------------------------------------------------
 
-  // implement RelOptRule
   public void onMatch(RelOptRuleCall call) {
     final Filter filter = call.rel(0);
     final Project project = call.rel(1);
@@ -105,18 +116,20 @@ public class FilterProjectTransposeRule extends RelOptRule {
       newCondition = ((RexCall) newCondition).getOperands().get(0);
     }
 
+    final RelBuilder relBuilder = call.builder();
     RelNode newFilterRel =
-        filterFactory == null
+        copyFilter
             ? filter.copy(filter.getTraitSet(), project.getInput(),
                 newCondition)
-            : filterFactory.createFilter(project.getInput(), newCondition);
+            : relBuilder.push(project.getInput()).filter(newCondition).build();
 
     RelNode newProjRel =
-        projectFactory == null
+        copyProject
             ? project.copy(project.getTraitSet(), newFilterRel,
                 project.getProjects(), project.getRowType())
-            : projectFactory.createProject(newFilterRel, project.getProjects(),
-                project.getRowType().getFieldNames());
+            : relBuilder.push(newFilterRel)
+                .project(project.getProjects(), project.getRowType().getFieldNames())
+                .build();
 
     call.transformTo(newProjRel);
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/FilterSetOpTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/FilterSetOpTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/FilterSetOpTransposeRule.java
index 4e04d0b..db327ba 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/FilterSetOpTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/FilterSetOpTransposeRule.java
@@ -16,6 +16,7 @@
  */
 package org.apache.calcite.rel.rules;
 
+import org.apache.calcite.plan.Contexts;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
 import org.apache.calcite.plan.RelOptUtil;
@@ -26,6 +27,8 @@ import org.apache.calcite.rel.core.SetOp;
 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.tools.RelBuilderFactory;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -36,20 +39,23 @@ import java.util.List;
  */
 public class FilterSetOpTransposeRule extends RelOptRule {
   public static final FilterSetOpTransposeRule INSTANCE =
-      new FilterSetOpTransposeRule(RelFactories.DEFAULT_FILTER_FACTORY);
-
-  private final RelFactories.FilterFactory filterFactory;
+      new FilterSetOpTransposeRule(RelFactories.LOGICAL_BUILDER);
 
   //~ Constructors -----------------------------------------------------------
 
   /**
    * Creates a FilterSetOpTransposeRule.
    */
-  public FilterSetOpTransposeRule(RelFactories.FilterFactory filterFactory) {
+  public FilterSetOpTransposeRule(RelBuilderFactory relBuilderFactory) {
     super(
         operand(Filter.class,
-            operand(SetOp.class, any())));
-    this.filterFactory = filterFactory;
+            operand(SetOp.class, any())),
+        relBuilderFactory, null);
+  }
+
+  @Deprecated // to  be removed before 2.0
+  public FilterSetOpTransposeRule(RelFactories.FilterFactory filterFactory) {
+    this(RelBuilder.proto(Contexts.of(filterFactory)));
   }
 
   //~ Methods ----------------------------------------------------------------
@@ -64,10 +70,11 @@ public class FilterSetOpTransposeRule extends RelOptRule {
     // create filters on top of each setop child, modifying the filter
     // condition to reference each setop child
     RexBuilder rexBuilder = filterRel.getCluster().getRexBuilder();
+    final RelBuilder relBuilder = call.builder();
     List<RelDataTypeField> origFields =
         setOp.getRowType().getFieldList();
     int[] adjustments = new int[origFields.size()];
-    List<RelNode> newSetOpInputs = new ArrayList<RelNode>();
+    final List<RelNode> newSetOpInputs = new ArrayList<>();
     for (RelNode input : setOp.getInputs()) {
       RexNode newCondition =
           condition.accept(
@@ -76,7 +83,7 @@ public class FilterSetOpTransposeRule extends RelOptRule {
                   origFields,
                   input.getRowType().getFieldList(),
                   adjustments));
-      newSetOpInputs.add(filterFactory.createFilter(input, newCondition));
+      newSetOpInputs.add(relBuilder.push(input).filter(newCondition).build());
     }
 
     // create a new setop whose children are the filters created above

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/JoinCommuteRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/JoinCommuteRule.java b/core/src/main/java/org/apache/calcite/rel/rules/JoinCommuteRule.java
index 36673f1..863bf25 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/JoinCommuteRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/JoinCommuteRule.java
@@ -16,6 +16,7 @@
  */
 package org.apache.calcite.rel.rules;
 
+import org.apache.calcite.plan.Contexts;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
 import org.apache.calcite.plan.RelOptUtil;
@@ -31,6 +32,8 @@ import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexCall;
 import org.apache.calcite.rex.RexInputRef;
 import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
 import org.apache.calcite.util.Util;
 
 import com.google.common.collect.ImmutableList;
@@ -56,7 +59,6 @@ public class JoinCommuteRule extends RelOptRule {
   /** Instance of the rule that swaps outer joins as well as inner joins. */
   public static final JoinCommuteRule SWAP_OUTER = new JoinCommuteRule(true);
 
-  private final ProjectFactory projectFactory;
   private final boolean swapOuter;
 
   //~ Constructors -----------------------------------------------------------
@@ -64,21 +66,26 @@ public class JoinCommuteRule extends RelOptRule {
   /**
    * Creates a JoinCommuteRule.
    */
+  public JoinCommuteRule(Class<? extends Join> clazz,
+      RelBuilderFactory relBuilderFactory, boolean swapOuter) {
+    super(operand(clazz, any()), relBuilderFactory, null);
+    this.swapOuter = swapOuter;
+  }
+
   private JoinCommuteRule(boolean swapOuter) {
-    this(LogicalJoin.class, RelFactories.DEFAULT_PROJECT_FACTORY, swapOuter);
+    this(LogicalJoin.class, RelFactories.LOGICAL_BUILDER, swapOuter);
   }
 
   @Deprecated // to be removed before 2.0
   public JoinCommuteRule(Class<? extends Join> clazz,
       ProjectFactory projectFactory) {
-    this(clazz, projectFactory, false);
+    this(clazz, RelBuilder.proto(Contexts.of(projectFactory)), false);
   }
 
+  @Deprecated // to be removed before 2.0
   public JoinCommuteRule(Class<? extends Join> clazz,
       ProjectFactory projectFactory, boolean swapOuter) {
-    super(operand(clazz, any()));
-    this.projectFactory = projectFactory;
-    this.swapOuter = swapOuter;
+    this(clazz, RelBuilder.proto(Contexts.of(projectFactory)), swapOuter);
   }
 
   //~ Methods ----------------------------------------------------------------
@@ -154,14 +161,13 @@ public class JoinCommuteRule extends RelOptRule {
     // b0,b1,a0,a1,a2 from (select a0,a1,a2,b0,b1 from b join a)' is the
     // same as 'b join a'. If we didn't do this, the swap join rule
     // would fire on the new join, ad infinitum.
+    final RelBuilder relBuilder = call.builder();
     final List<RexNode> exps =
         RelOptUtil.createSwappedJoinExprs(newJoin, join, false);
-    RelNode project =
-        projectFactory.createProject(swapped, exps,
-            newJoin.getRowType().getFieldNames());
+    relBuilder.push(swapped)
+        .project(exps, newJoin.getRowType().getFieldNames());
 
-    RelNode rel = call.getPlanner().ensureRegistered(project, newJoin);
-    Util.discard(rel);
+    call.getPlanner().ensureRegistered(relBuilder.build(), newJoin);
   }
 
   //~ Inner Classes ----------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/JoinProjectTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/JoinProjectTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/JoinProjectTransposeRule.java
index afcea6b..c40c56a 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/JoinProjectTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/JoinProjectTransposeRule.java
@@ -16,6 +16,7 @@
  */
 package org.apache.calcite.rel.rules;
 
+import org.apache.calcite.plan.Contexts;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
 import org.apache.calcite.plan.RelOptRuleOperand;
@@ -35,6 +36,8 @@ import org.apache.calcite.rex.RexLocalRef;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexProgram;
 import org.apache.calcite.rex.RexProgramBuilder;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
 import org.apache.calcite.util.Pair;
 
 import java.util.ArrayList;
@@ -81,14 +84,14 @@ public class JoinProjectTransposeRule extends RelOptRule {
               operand(LogicalProject.class, any()),
               operand(LogicalProject.class, any())),
           "Join(IncludingOuter)ProjectTransposeRule(Project-Project)",
-          true, RelFactories.DEFAULT_PROJECT_FACTORY);
+          true, RelFactories.LOGICAL_BUILDER);
 
   public static final JoinProjectTransposeRule LEFT_PROJECT_INCLUDE_OUTER =
       new JoinProjectTransposeRule(
           operand(LogicalJoin.class,
               some(operand(LogicalProject.class, any()))),
           "Join(IncludingOuter)ProjectTransposeRule(Project-Other)",
-          true, RelFactories.DEFAULT_PROJECT_FACTORY);
+          true, RelFactories.LOGICAL_BUILDER);
 
   public static final JoinProjectTransposeRule RIGHT_PROJECT_INCLUDE_OUTER =
       new JoinProjectTransposeRule(
@@ -97,30 +100,40 @@ public class JoinProjectTransposeRule extends RelOptRule {
               operand(RelNode.class, any()),
               operand(LogicalProject.class, any())),
           "Join(IncludingOuter)ProjectTransposeRule(Other-Project)",
-          true, RelFactories.DEFAULT_PROJECT_FACTORY);
+          true, RelFactories.LOGICAL_BUILDER);
 
   private final boolean includeOuter;
-  private final ProjectFactory projectFactory;
 
   //~ Constructors -----------------------------------------------------------
+
+  /** Creates a JoinProjectTransposeRule. */
+  public JoinProjectTransposeRule(RelOptRuleOperand operand,
+      String description, boolean includeOuter,
+      RelBuilderFactory relBuilderFactory) {
+    super(operand, relBuilderFactory, description);
+    this.includeOuter = includeOuter;
+  }
+
+  /** Creates a JoinProjectTransposeRule with default factory. */
   public JoinProjectTransposeRule(
       RelOptRuleOperand operand,
       String description) {
-    this(operand, description, false, RelFactories.DEFAULT_PROJECT_FACTORY);
+    this(operand, description, false, RelFactories.LOGICAL_BUILDER);
   }
 
-  @Deprecated
+  @Deprecated // to be removed before 2.0
   public JoinProjectTransposeRule(RelOptRuleOperand operand,
       String description, ProjectFactory projectFactory) {
-    this(operand, description, false, projectFactory);
+    this(operand, description, false,
+        RelBuilder.proto(Contexts.of(projectFactory)));
   }
 
+  @Deprecated // to be removed before 2.0
   public JoinProjectTransposeRule(RelOptRuleOperand operand,
       String description, boolean includeOuter,
       ProjectFactory projectFactory) {
-    super(operand, description);
-    this.includeOuter = includeOuter;
-    this.projectFactory = projectFactory;
+    this(operand, description, includeOuter,
+        RelBuilder.proto(Contexts.of(projectFactory)));
   }
 
   //~ Methods ----------------------------------------------------------------
@@ -181,9 +194,8 @@ public class JoinProjectTransposeRule extends RelOptRule {
     // the LHS.  If the join input was not a projection, simply create
     // references to the inputs.
     int nProjExprs = joinRel.getRowType().getFieldCount();
-    List<Pair<RexNode, String>> projects =
-        new ArrayList<Pair<RexNode, String>>();
-    RexBuilder rexBuilder = joinRel.getCluster().getRexBuilder();
+    final List<Pair<RexNode, String>> projects = new ArrayList<>();
+    final RexBuilder rexBuilder = joinRel.getCluster().getRexBuilder();
 
     createProjectExprs(
         leftProj,
@@ -204,7 +216,7 @@ public class JoinProjectTransposeRule extends RelOptRule {
         joinChildrenRowType.getFieldList(),
         projects);
 
-    List<RelDataType> projTypes = new ArrayList<RelDataType>();
+    final List<RelDataType> projTypes = new ArrayList<>();
     for (int i = 0; i < nProjExprs; i++) {
       projTypes.add(projects.get(i).left.getType());
     }
@@ -247,7 +259,7 @@ public class JoinProjectTransposeRule extends RelOptRule {
 
     // expand out the new projection expressions; if the join is an
     // outer join, modify the expressions to reference the join output
-    List<RexNode> newProjExprs = new ArrayList<RexNode>();
+    final List<RexNode> newProjExprs = new ArrayList<>();
     List<RexLocalRef> projList = mergedProgram.getProjectList();
     List<RelDataTypeField> newJoinFields =
         newJoinRel.getRowType().getFieldList();
@@ -268,18 +280,16 @@ public class JoinProjectTransposeRule extends RelOptRule {
     }
 
     // finally, create the projection on top of the join
-    RelNode newProjRel = projectFactory.createProject(newJoinRel, newProjExprs,
-        joinRel.getRowType().getFieldNames());
+    final RelBuilder relBuilder = call.builder();
+    relBuilder.push(newJoinRel);
+    relBuilder.project(newProjExprs, joinRel.getRowType().getFieldNames());
     // if the join was outer, we might need a cast after the
     // projection to fix differences wrt nullability of fields
     if (joinType != JoinRelType.INNER) {
-      RelNode newTopProjRel = RelOptUtil.createCastRel(newProjRel, joinRel.getRowType(),
-          false, projectFactory);
-      call.transformTo(newTopProjRel);
-      return;
+      relBuilder.convert(joinRel.getRowType(), false);
     }
 
-    call.transformTo(newProjRel);
+    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/JoinPushExpressionsRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/JoinPushExpressionsRule.java b/core/src/main/java/org/apache/calcite/rel/rules/JoinPushExpressionsRule.java
index e3bbe4d..4fb33e5 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/JoinPushExpressionsRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/JoinPushExpressionsRule.java
@@ -23,6 +23,8 @@ import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Join;
 import org.apache.calcite.rel.core.RelFactories;
 import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
 
 /**
  * Planner rule that pushes down expressions in "equal" join condition.
@@ -36,23 +38,25 @@ import org.apache.calcite.rex.RexNode;
 public class JoinPushExpressionsRule extends RelOptRule {
 
   public static final JoinPushExpressionsRule INSTANCE =
-      new JoinPushExpressionsRule(Join.class,
-          RelFactories.DEFAULT_PROJECT_FACTORY);
-
-  private final RelFactories.ProjectFactory projectFactory;
+      new JoinPushExpressionsRule(Join.class, RelFactories.LOGICAL_BUILDER);
 
   /** Creates a JoinPushExpressionsRule. */
   public JoinPushExpressionsRule(Class<? extends Join> clazz,
+      RelBuilderFactory relBuilderFactory) {
+    super(operand(clazz, any()), relBuilderFactory, null);
+  }
+
+  @Deprecated // to be removed before 2.0
+  public JoinPushExpressionsRule(Class<? extends Join> clazz,
       RelFactories.ProjectFactory projectFactory) {
-    super(operand(clazz, any()));
-    this.projectFactory = projectFactory;
+    this(clazz, RelBuilder.proto(projectFactory));
   }
 
   @Override public void onMatch(RelOptRuleCall call) {
     Join join = call.rel(0);
 
     // Push expression in join condition into Project below Join.
-    RelNode newJoin = RelOptUtil.pushDownJoinConditions(join, projectFactory);
+    RelNode newJoin = RelOptUtil.pushDownJoinConditions(join, call.builder());
 
     // If the join is the same, we bail out
     if (newJoin instanceof Join) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/JoinPushThroughJoinRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/JoinPushThroughJoinRule.java b/core/src/main/java/org/apache/calcite/rel/rules/JoinPushThroughJoinRule.java
index 6a292f6..402557d 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/JoinPushThroughJoinRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/JoinPushThroughJoinRule.java
@@ -30,6 +30,8 @@ import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexPermuteInputsShuttle;
 import org.apache.calcite.rex.RexUtil;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
 import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.mapping.Mappings;
 
@@ -65,31 +67,34 @@ public class JoinPushThroughJoinRule extends RelOptRule {
   public static final RelOptRule RIGHT =
       new JoinPushThroughJoinRule(
           "JoinPushThroughJoinRule:right", true, LogicalJoin.class,
-          RelFactories.DEFAULT_PROJECT_FACTORY);
+          RelFactories.LOGICAL_BUILDER);
 
   /** Instance of the rule that works on logical joins only, and pushes to the
    * left. */
   public static final RelOptRule LEFT =
       new JoinPushThroughJoinRule(
           "JoinPushThroughJoinRule:left", false, LogicalJoin.class,
-          RelFactories.DEFAULT_PROJECT_FACTORY);
+          RelFactories.LOGICAL_BUILDER);
 
   private final boolean right;
 
-  private final ProjectFactory projectFactory;
-
   /**
    * Creates a JoinPushThroughJoinRule.
    */
   public JoinPushThroughJoinRule(String description, boolean right,
-      Class<? extends Join> clazz, ProjectFactory projectFactory) {
+      Class<? extends Join> clazz, RelBuilderFactory relBuilderFactory) {
     super(
         operand(clazz,
             operand(clazz, any()),
             operand(RelNode.class, any())),
-        description);
+        relBuilderFactory, description);
     this.right = right;
-    this.projectFactory = projectFactory;
+  }
+
+  @Deprecated // to be removed before 2.0
+  public JoinPushThroughJoinRule(String description, boolean right,
+      Class<? extends Join> clazz, ProjectFactory projectFactory) {
+    this(description, right, clazz, RelBuilder.proto(projectFactory));
   }
 
   @Override public void onMatch(RelOptRuleCall call) {
@@ -137,8 +142,8 @@ public class JoinPushThroughJoinRule extends RelOptRule {
 
     // Split the condition of topJoin into a conjunction. Each of the
     // parts that does not use columns from B can be pushed down.
-    final List<RexNode> intersecting = new ArrayList<RexNode>();
-    final List<RexNode> nonIntersecting = new ArrayList<RexNode>();
+    final List<RexNode> intersecting = new ArrayList<>();
+    final List<RexNode> nonIntersecting = new ArrayList<>();
     split(topJoin.getCondition(), bBitSet, intersecting, nonIntersecting);
 
     // If there's nothing to push down, it's not worth proceeding.
@@ -148,8 +153,8 @@ public class JoinPushThroughJoinRule extends RelOptRule {
 
     // Split the condition of bottomJoin into a conjunction. Each of the
     // parts that use columns from B will need to be pulled up.
-    final List<RexNode> bottomIntersecting = new ArrayList<RexNode>();
-    final List<RexNode> bottomNonIntersecting = new ArrayList<RexNode>();
+    final List<RexNode> bottomIntersecting = new ArrayList<>();
+    final List<RexNode> bottomNonIntersecting = new ArrayList<>();
     split(
         bottomJoin.getCondition(), bBitSet, bottomIntersecting,
         bottomNonIntersecting);
@@ -161,7 +166,7 @@ public class JoinPushThroughJoinRule extends RelOptRule {
             aCount + bCount + cCount,
             0, 0, aCount,
             aCount, aCount + bCount, cCount);
-    List<RexNode> newBottomList = new ArrayList<RexNode>();
+    final List<RexNode> newBottomList = new ArrayList<>();
     new RexPermuteInputsShuttle(bottomMapping, relA, relC)
         .visitList(nonIntersecting, newBottomList);
     final Mappings.TargetMapping bottomBottomMapping =
@@ -185,7 +190,7 @@ public class JoinPushThroughJoinRule extends RelOptRule {
             0, 0, aCount,
             aCount + cCount, aCount, bCount,
             aCount, aCount + bCount, cCount);
-    List<RexNode> newTopList = new ArrayList<RexNode>();
+    final List<RexNode> newTopList = new ArrayList<>();
     new RexPermuteInputsShuttle(topMapping, newBottomJoin, relB)
         .visitList(intersecting, newTopList);
     new RexPermuteInputsShuttle(topMapping, newBottomJoin, relB)
@@ -198,10 +203,10 @@ public class JoinPushThroughJoinRule extends RelOptRule {
             relB, topJoin.getJoinType(), topJoin.isSemiJoinDone());
 
     assert !Mappings.isIdentity(topMapping);
-    final RelNode newProject = RelOptUtil.createProject(projectFactory,
-        newTopJoin, Mappings.asList(topMapping));
-
-    call.transformTo(newProject);
+    final RelBuilder relBuilder = call.builder();
+    relBuilder.push(newTopJoin);
+    relBuilder.project(relBuilder.fields(topMapping));
+    call.transformTo(relBuilder.build());
   }
 
   /**
@@ -244,8 +249,8 @@ public class JoinPushThroughJoinRule extends RelOptRule {
 
     // Split the condition of topJoin into a conjunction. Each of the
     // parts that does not use columns from A can be pushed down.
-    final List<RexNode> intersecting = new ArrayList<RexNode>();
-    final List<RexNode> nonIntersecting = new ArrayList<RexNode>();
+    final List<RexNode> intersecting = new ArrayList<>();
+    final List<RexNode> nonIntersecting = new ArrayList<>();
     split(topJoin.getCondition(), aBitSet, intersecting, nonIntersecting);
 
     // If there's nothing to push down, it's not worth proceeding.
@@ -255,8 +260,8 @@ public class JoinPushThroughJoinRule extends RelOptRule {
 
     // Split the condition of bottomJoin into a conjunction. Each of the
     // parts that use columns from B will need to be pulled up.
-    final List<RexNode> bottomIntersecting = new ArrayList<RexNode>();
-    final List<RexNode> bottomNonIntersecting = new ArrayList<RexNode>();
+    final List<RexNode> bottomIntersecting = new ArrayList<>();
+    final List<RexNode> bottomNonIntersecting = new ArrayList<>();
     split(
         bottomJoin.getCondition(), aBitSet, bottomIntersecting,
         bottomNonIntersecting);
@@ -268,7 +273,7 @@ public class JoinPushThroughJoinRule extends RelOptRule {
             aCount + bCount + cCount,
             cCount, aCount, bCount,
             0, aCount + bCount, cCount);
-    List<RexNode> newBottomList = new ArrayList<RexNode>();
+    final List<RexNode> newBottomList = new ArrayList<>();
     new RexPermuteInputsShuttle(bottomMapping, relC, relB)
         .visitList(nonIntersecting, newBottomList);
     final Mappings.TargetMapping bottomBottomMapping =
@@ -293,7 +298,7 @@ public class JoinPushThroughJoinRule extends RelOptRule {
             cCount + bCount, 0, aCount,
             cCount, aCount, bCount,
             0, aCount + bCount, cCount);
-    List<RexNode> newTopList = new ArrayList<RexNode>();
+    final List<RexNode> newTopList = new ArrayList<>();
     new RexPermuteInputsShuttle(topMapping, newBottomJoin, relA)
         .visitList(intersecting, newTopList);
     new RexPermuteInputsShuttle(topMapping, newBottomJoin, relA)
@@ -305,10 +310,10 @@ public class JoinPushThroughJoinRule extends RelOptRule {
         topJoin.copy(topJoin.getTraitSet(), newTopCondition, newBottomJoin,
             relA, topJoin.getJoinType(), topJoin.isSemiJoinDone());
 
-    final RelNode newProject = RelOptUtil.createProject(projectFactory,
-        newTopJoin, Mappings.asList(topMapping));
-
-    call.transformTo(newProject);
+    final RelBuilder relBuilder = call.builder();
+    relBuilder.push(newTopJoin);
+    relBuilder.project(relBuilder.fields(topMapping));
+    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/JoinPushTransitivePredicatesRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/JoinPushTransitivePredicatesRule.java b/core/src/main/java/org/apache/calcite/rel/rules/JoinPushTransitivePredicatesRule.java
index 3b7056d..1d375c6 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/JoinPushTransitivePredicatesRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/JoinPushTransitivePredicatesRule.java
@@ -16,6 +16,7 @@
  */
 package org.apache.calcite.rel.rules;
 
+import org.apache.calcite.plan.Contexts;
 import org.apache.calcite.plan.RelOptPredicateList;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
@@ -24,7 +25,8 @@ import org.apache.calcite.rel.core.Join;
 import org.apache.calcite.rel.core.RelFactories;
 import org.apache.calcite.rel.metadata.RelMetadataQuery;
 import org.apache.calcite.rex.RexBuilder;
-import org.apache.calcite.rex.RexUtil;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
 
 /**
  * Planner rule that infers predicates from on a
@@ -38,17 +40,21 @@ import org.apache.calcite.rex.RexUtil;
  * and applies them appropriately.
  */
 public class JoinPushTransitivePredicatesRule extends RelOptRule {
-  private final RelFactories.FilterFactory filterFactory;
-
   /** The singleton. */
   public static final JoinPushTransitivePredicatesRule INSTANCE =
       new JoinPushTransitivePredicatesRule(Join.class,
-          RelFactories.DEFAULT_FILTER_FACTORY);
+          RelFactories.LOGICAL_BUILDER);
+
+  /** Creates a JoinPushTransitivePredicatesRule. */
+  public JoinPushTransitivePredicatesRule(Class<? extends Join> clazz,
+      RelBuilderFactory relBuilderFactory) {
+    super(operand(clazz, any()), relBuilderFactory, null);
+  }
 
+  @Deprecated // to be removed before 2.0
   public JoinPushTransitivePredicatesRule(Class<? extends Join> clazz,
       RelFactories.FilterFactory filterFactory) {
-    super(operand(clazz, any()));
-    this.filterFactory = filterFactory;
+    this(clazz, RelBuilder.proto(Contexts.of(filterFactory)));
   }
 
   @Override public void onMatch(RelOptRuleCall call) {
@@ -60,21 +66,22 @@ public class JoinPushTransitivePredicatesRule extends RelOptRule {
       return;
     }
 
-    RexBuilder rB = join.getCluster().getRexBuilder();
-    RelNode lChild = join.getLeft();
-    RelNode rChild = join.getRight();
+    final RexBuilder rexBuilder = join.getCluster().getRexBuilder();
+    final RelBuilder relBuilder = call.builder();
 
+    RelNode lChild = join.getLeft();
     if (preds.leftInferredPredicates.size() > 0) {
       RelNode curr = lChild;
-      lChild = filterFactory.createFilter(lChild,
-          RexUtil.composeConjunction(rB, preds.leftInferredPredicates, false));
+      lChild = relBuilder.push(lChild)
+          .filter(preds.leftInferredPredicates).build();
       call.getPlanner().onCopy(curr, lChild);
     }
 
+    RelNode rChild = join.getRight();
     if (preds.rightInferredPredicates.size() > 0) {
       RelNode curr = rChild;
-      rChild = filterFactory.createFilter(rChild,
-          RexUtil.composeConjunction(rB, preds.rightInferredPredicates, false));
+      rChild = relBuilder.push(rChild)
+          .filter(preds.rightInferredPredicates).build();
       call.getPlanner().onCopy(curr, rChild);
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/JoinToCorrelateRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/JoinToCorrelateRule.java b/core/src/main/java/org/apache/calcite/rel/rules/JoinToCorrelateRule.java
index 9ed7631..5280524 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/JoinToCorrelateRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/JoinToCorrelateRule.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.CorrelationId;
 import org.apache.calcite.rel.core.RelFactories;
@@ -29,8 +29,9 @@ import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexInputRef;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexShuttle;
-import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.sql.SemiJoinType;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
 import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.Util;
 
@@ -60,19 +61,20 @@ public class JoinToCorrelateRule extends RelOptRule {
   //~ Static fields/initializers ---------------------------------------------
 
   public static final JoinToCorrelateRule INSTANCE =
-      new JoinToCorrelateRule(RelFactories.DEFAULT_FILTER_FACTORY);
-
-  protected final RelFactories.FilterFactory filterFactory;
+      new JoinToCorrelateRule(RelFactories.LOGICAL_BUILDER);
 
   //~ Constructors -----------------------------------------------------------
 
   /**
    * Private constructor; use singleton {@link #INSTANCE}.
    */
+  protected JoinToCorrelateRule(RelBuilderFactory relBuilderFactory) {
+    super(operand(LogicalJoin.class, any()), relBuilderFactory, null);
+  }
+
+  @Deprecated // to be removed before 2.0
   protected JoinToCorrelateRule(RelFactories.FilterFactory filterFactory) {
-    super(operand(LogicalJoin.class, any()));
-    this.filterFactory = filterFactory;
-    assert filterFactory != null : "Filter factory should not be null";
+    this(RelBuilder.proto(Contexts.of(filterFactory)));
   }
 
   //~ Methods ----------------------------------------------------------------
@@ -99,15 +101,15 @@ public class JoinToCorrelateRule extends RelOptRule {
     final int leftFieldCount = left.getRowType().getFieldCount();
     final RelOptCluster cluster = join.getCluster();
     final RexBuilder rexBuilder = cluster.getRexBuilder();
+    final RelBuilder relBuilder = call.builder();
     final int dynInId = cluster.createCorrel();
     final CorrelationId correlationId = new CorrelationId(dynInId);
     final RexNode corrVar =
         rexBuilder.makeCorrel(left.getRowType(), correlationId.getName());
     final ImmutableBitSet.Builder requiredColumns = ImmutableBitSet.builder();
-    RexNode joinCondition = join.getCondition();
 
     // Replace all references of left input with FieldAccess(corrVar, field)
-    joinCondition = joinCondition.accept(new RexShuttle() {
+    final RexNode joinCondition = join.getCondition().accept(new RexShuttle() {
       @Override public RexNode visitInputRef(RexInputRef input) {
         int field = input.getIndex();
         if (field >= leftFieldCount) {
@@ -119,12 +121,11 @@ public class JoinToCorrelateRule extends RelOptRule {
       }
     });
 
-    joinCondition = RexUtil.flatten(rexBuilder, joinCondition);
-    final RelNode filteredRight =
-        RelOptUtil.createFilter(right, joinCondition, filterFactory);
+    relBuilder.push(right).filter(joinCondition);
+
     RelNode newRel =
         LogicalCorrelate.create(left,
-            filteredRight,
+            relBuilder.build(),
             correlationId,
             requiredColumns.build(),
             SemiJoinType.of(join.getJoinType()));

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/815fa262/core/src/main/java/org/apache/calcite/rel/rules/LoptOptimizeJoinRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/LoptOptimizeJoinRule.java b/core/src/main/java/org/apache/calcite/rel/rules/LoptOptimizeJoinRule.java
index 7a365f3..f521a71 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/LoptOptimizeJoinRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/LoptOptimizeJoinRule.java
@@ -25,7 +25,6 @@ import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Join;
 import org.apache.calcite.rel.core.JoinInfo;
 import org.apache.calcite.rel.core.JoinRelType;
-import org.apache.calcite.rel.core.Project;
 import org.apache.calcite.rel.core.RelFactories;
 import org.apache.calcite.rel.core.SemiJoin;
 import org.apache.calcite.rel.metadata.RelColumnOrigin;
@@ -40,13 +39,14 @@ import org.apache.calcite.rex.RexInputRef;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
 import org.apache.calcite.util.BitSets;
 import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.ImmutableIntList;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.mapping.IntPair;
 
-import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
 
 import java.util.ArrayList;
@@ -69,29 +69,22 @@ import java.util.TreeSet;
  */
 public class LoptOptimizeJoinRule extends RelOptRule {
   public static final LoptOptimizeJoinRule INSTANCE =
-      new LoptOptimizeJoinRule(
-          RelFactories.DEFAULT_JOIN_FACTORY,
-          RelFactories.DEFAULT_PROJECT_FACTORY,
-          RelFactories.DEFAULT_FILTER_FACTORY);
-
-  private final RelFactories.JoinFactory joinFactory;
-  private final RelFactories.ProjectFactory projectFactory;
-  private final RelFactories.FilterFactory filterFactory;
+      new LoptOptimizeJoinRule(RelFactories.LOGICAL_BUILDER);
 
   /** Creates a LoptOptimizeJoinRule. */
-  public LoptOptimizeJoinRule(
-      RelFactories.JoinFactory joinFactory,
+  public LoptOptimizeJoinRule(RelBuilderFactory relBuilderFactory) {
+    super(operand(MultiJoin.class, any()), relBuilderFactory, null);
+  }
+
+  @Deprecated // to be removed before 2.0
+  public LoptOptimizeJoinRule(RelFactories.JoinFactory joinFactory,
       RelFactories.ProjectFactory projectFactory,
       RelFactories.FilterFactory filterFactory) {
-    super(operand(MultiJoin.class, any()));
-    this.joinFactory = joinFactory;
-    this.projectFactory = projectFactory;
-    this.filterFactory = filterFactory;
+    this(RelBuilder.proto(joinFactory, projectFactory, filterFactory));
   }
 
   //~ Methods ----------------------------------------------------------------
 
-  // implement RelOptRule
   public void onMatch(RelOptRuleCall call) {
     final MultiJoin multiJoinRel = call.rel(0);
     final LoptMultiJoin multiJoin = new LoptMultiJoin(multiJoinRel);
@@ -125,7 +118,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
 
     findRemovableSelfJoins(multiJoin);
 
-    findBestOrderings(multiJoin, semiJoinOpt, call);
+    findBestOrderings(call.builder(), multiJoin, semiJoinOpt, call);
   }
 
   /**
@@ -136,7 +129,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
    * @param multiJoin join factors being optimized
    */
   private void findRemovableOuterJoins(LoptMultiJoin multiJoin) {
-    List<Integer> removalCandidates = new ArrayList<Integer>();
+    final List<Integer> removalCandidates = new ArrayList<>();
     for (int factIdx = 0;
         factIdx < multiJoin.getNumJoinFactors();
         factIdx++) {
@@ -146,7 +139,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
     }
 
     while (!removalCandidates.isEmpty()) {
-      Set<Integer> retryCandidates = new HashSet<Integer>();
+      final Set<Integer> retryCandidates = new HashSet<>();
 
     outerForLoop:
       for (int factIdx : removalCandidates) {
@@ -161,7 +154,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
         // be RexInputRefs and only one side corresponds to the null
         // generating factor
         RexNode outerJoinCond = multiJoin.getOuterJoinCond(factIdx);
-        List<RexNode> ojFilters = new ArrayList<RexNode>();
+        final List<RexNode> ojFilters = new ArrayList<>();
         RelOptUtil.decomposeConjunction(outerJoinCond, ojFilters);
         int numFields = multiJoin.getNumFieldsInJoinFactor(factIdx);
         final ImmutableBitSet.Builder joinKeyBuilder =
@@ -300,10 +293,10 @@ public class LoptOptimizeJoinRule extends RelOptRule {
     // See if a simple factor is repeated and therefore potentially is
     // part of a self-join.  Restrict each factor to at most one
     // self-join.
-    List<RelOptTable> repeatedTables = new ArrayList<RelOptTable>();
-    TreeSet<Integer> sortedFactors = new TreeSet<Integer>();
+    final List<RelOptTable> repeatedTables = new ArrayList<>();
+    final TreeSet<Integer> sortedFactors = new TreeSet<>();
     sortedFactors.addAll(simpleFactors.keySet());
-    Map<Integer, Integer> selfJoinPairs = new HashMap<Integer, Integer>();
+    final Map<Integer, Integer> selfJoinPairs = new HashMap<>();
     Integer [] factors =
         sortedFactors.toArray(new Integer[sortedFactors.size()]);
     for (int i = 0; i < factors.length; i++) {
@@ -327,7 +320,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
     // allow the join to be removed.
     for (Integer factor1 : selfJoinPairs.keySet()) {
       int factor2 = selfJoinPairs.get(factor1);
-      List<RexNode> selfJoinFilters = new ArrayList<RexNode>();
+      final List<RexNode> selfJoinFilters = new ArrayList<>();
       for (RexNode filter : multiJoin.getJoinFilters()) {
         ImmutableBitSet joinFactors =
             multiJoin.getFactorsRefByJoinFilter(filter);
@@ -359,8 +352,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
    * correspond
    */
   private Map<Integer, RelOptTable> getSimpleFactors(LoptMultiJoin multiJoin) {
-    Map<Integer, RelOptTable> returnList =
-        new HashMap<Integer, RelOptTable>();
+    final Map<Integer, RelOptTable> returnList = new HashMap<>();
 
     // Loop through all join factors and locate the ones where each
     // column referenced from the factor is not derived and originates
@@ -441,10 +433,11 @@ public class LoptOptimizeJoinRule extends RelOptRule {
    * @param call RelOptRuleCall associated with this rule
    */
   private void findBestOrderings(
+      RelBuilder relBuilder,
       LoptMultiJoin multiJoin,
       LoptSemiJoinOptimizer semiJoinOpt,
       RelOptRuleCall call) {
-    List<RelNode> plans = new ArrayList<RelNode>();
+    final List<RelNode> plans = new ArrayList<>();
 
     List<String> fieldNames =
         multiJoin.getMultiJoinRel().getRowType().getFieldNames();
@@ -457,6 +450,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
       }
       LoptJoinTree joinTree =
           createOrdering(
+              relBuilder,
               multiJoin,
               semiJoinOpt,
               i);
@@ -465,7 +459,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
       }
 
       RelNode newProject =
-          createTopProject(multiJoin, joinTree, fieldNames);
+          createTopProject(call.builder(), multiJoin, joinTree, fieldNames);
       plans.add(newProject);
     }
 
@@ -491,6 +485,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
    * @return created projection
    */
   private RelNode createTopProject(
+      RelBuilder relBuilder,
       LoptMultiJoin multiJoin,
       LoptJoinTree joinTree,
       List<String> fieldNames) {
@@ -506,8 +501,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
 
     // create a mapping from each factor to its field offset in the join
     // ordering
-    Map<Integer, Integer> factorToOffsetMap =
-        new HashMap<Integer, Integer>();
+    final Map<Integer, Integer> factorToOffsetMap = new HashMap<>();
     for (int pos = 0, fieldStart = 0; pos < nJoinFactors; pos++) {
       factorToOffsetMap.put(newJoinOrder.get(pos), fieldStart);
       fieldStart +=
@@ -540,21 +534,18 @@ public class LoptOptimizeJoinRule extends RelOptRule {
                 newOffset));
       }
     }
-    Project newProject =
-        (Project) projectFactory.createProject(
-            joinTree.getJoinTree(),
-            newProjExprs,
-            fieldNames);
+
+    relBuilder.push(joinTree.getJoinTree());
+    relBuilder.project(newProjExprs, fieldNames);
 
     // Place the post-join filter (if it exists) on top of the final
     // projection.
     RexNode postJoinFilter =
         multiJoin.getMultiJoinRel().getPostJoinFilter();
     if (postJoinFilter != null) {
-      return filterFactory.createFilter(newProject, postJoinFilter);
-    } else {
-      return newProject;
+      relBuilder.filter(postJoinFilter);
     }
+    return relBuilder.build();
   }
 
   /**
@@ -675,6 +666,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
    * firstFactor to appear as the first factor in the join
    */
   private LoptJoinTree createOrdering(
+      RelBuilder relBuilder,
       LoptMultiJoin multiJoin,
       LoptSemiJoinOptimizer semiJoinOpt,
       int firstFactor) {
@@ -682,8 +674,8 @@ public class LoptOptimizeJoinRule extends RelOptRule {
     int nJoinFactors = multiJoin.getNumJoinFactors();
     BitSet factorsToAdd = BitSets.range(0, nJoinFactors);
     BitSet factorsAdded = new BitSet(nJoinFactors);
-    List<RexNode> filtersToAdd =
-        new ArrayList<RexNode>(multiJoin.getJoinFilters());
+    final List<RexNode> filtersToAdd =
+        new ArrayList<>(multiJoin.getJoinFilters());
 
     int prevFactor = -1;
     while (factorsToAdd.cardinality() > 0) {
@@ -725,6 +717,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
       factorsNeeded.and(factorsAdded);
       joinTree =
           addFactorToTree(
+              relBuilder,
               multiJoin,
               semiJoinOpt,
               joinTree,
@@ -866,6 +859,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
    * add the factor; otherwise, null is returned
    */
   private LoptJoinTree addFactorToTree(
+      RelBuilder relBuilder,
       LoptMultiJoin multiJoin,
       LoptSemiJoinOptimizer semiJoinOpt,
       LoptJoinTree joinTree,
@@ -877,6 +871,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
     // join that can be removed, then create a replacement join
     if (multiJoin.isRemovableOuterJoinFactor(factorToAdd)) {
       return createReplacementJoin(
+          relBuilder,
           multiJoin,
           semiJoinOpt,
           joinTree,
@@ -892,6 +887,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
     // table is in the current join tree
     if (multiJoin.getJoinRemovalFactor(factorToAdd) != null) {
       return createReplacementSemiJoin(
+          relBuilder,
           multiJoin,
           semiJoinOpt,
           joinTree,
@@ -912,9 +908,10 @@ public class LoptOptimizeJoinRule extends RelOptRule {
     // created by addToTop() because the factor being added is part of
     // a self-join, then pass the original filter list so the added
     // filters will still be removed from the list.
-    List<RexNode> tmpFilters = new ArrayList<RexNode>(filtersToAdd);
+    final List<RexNode> tmpFilters = new ArrayList<>(filtersToAdd);
     LoptJoinTree topTree =
         addToTop(
+            relBuilder,
             multiJoin,
             semiJoinOpt,
             joinTree,
@@ -923,6 +920,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
             selfJoin);
     LoptJoinTree pushDownTree =
         pushDownFactor(
+            relBuilder,
             multiJoin,
             semiJoinOpt,
             joinTree,
@@ -1013,6 +1011,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
    * returned
    */
   private LoptJoinTree pushDownFactor(
+      RelBuilder relBuilder,
       LoptMultiJoin multiJoin,
       LoptSemiJoinOptimizer semiJoinOpt,
       LoptJoinTree joinTree,
@@ -1081,6 +1080,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
     LoptJoinTree subTree = (childNo == 0) ? left : right;
     subTree =
         addFactorToTree(
+            relBuilder,
             multiJoin,
             semiJoinOpt,
             subTree,
@@ -1134,6 +1134,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
 
     // create the new join tree with the factor pushed down
     return createJoinSubtree(
+        relBuilder,
         multiJoin,
         left,
         right,
@@ -1159,6 +1160,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
    * @return new join tree
    */
   private LoptJoinTree addToTop(
+      RelBuilder relBuilder,
       LoptMultiJoin multiJoin,
       LoptSemiJoinOptimizer semiJoinOpt,
       LoptJoinTree joinTree,
@@ -1210,6 +1212,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
     }
 
     return createJoinSubtree(
+        relBuilder,
         multiJoin,
         joinTree,
         rightTree,
@@ -1334,7 +1337,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
       int factorAdded,
       List<Integer> origJoinOrder,
       List<RelDataTypeField> origFields) {
-    List<Integer> newJoinOrder = new ArrayList<Integer>();
+    List<Integer> newJoinOrder = new ArrayList<>();
     left.getTreeOrder(newJoinOrder);
     right.getTreeOrder(newJoinOrder);
 
@@ -1517,6 +1520,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
    * been joined in yet
    */
   private LoptJoinTree createReplacementSemiJoin(
+      RelBuilder relBuilder,
       LoptMultiJoin multiJoin,
       LoptSemiJoinOptimizer semiJoinOpt,
       LoptJoinTree factTree,
@@ -1555,6 +1559,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
     }
 
     return createReplacementJoin(
+        relBuilder,
         multiJoin,
         semiJoinOpt,
         factTree,
@@ -1586,6 +1591,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
    * that can be removed
    */
   private LoptJoinTree createReplacementJoin(
+      RelBuilder relBuilder,
       LoptMultiJoin multiJoin,
       LoptSemiJoinOptimizer semiJoinOpt,
       LoptJoinTree currJoinTree,
@@ -1651,11 +1657,9 @@ public class LoptOptimizeJoinRule extends RelOptRule {
       }
       projects.add(Pair.of(projExpr, newFields.get(i).getName()));
     }
-    Project projRel =
-        (Project) projectFactory.createProject(
-            currJoinRel,
-            Pair.left(projects),
-            Pair.right(projects));
+
+    relBuilder.push(currJoinRel);
+    relBuilder.project(Pair.left(projects), Pair.right(projects));
 
     // remove the join conditions corresponding to the join we're removing;
     // we don't actually need to use them, but we need to remove them
@@ -1675,15 +1679,13 @@ public class LoptOptimizeJoinRule extends RelOptRule {
     // Filters referencing factors other than leftIdx and factorToAdd
     // still do need to be applied.  So, add them into a separate
     // LogicalFilter placed on top off the projection created above.
-    RelNode topRelNode = projRel;
     if (leftIdx >= 0) {
-      topRelNode =
-          addAdditionalFilters(
-              topRelNode,
-              multiJoin,
-              currJoinTree,
-              newTree,
-              filtersToAdd);
+      addAdditionalFilters(
+          relBuilder,
+          multiJoin,
+          currJoinTree,
+          newTree,
+          filtersToAdd);
     }
 
     // finally, create a join tree consisting of the current join's join
@@ -1692,7 +1694,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
     // though we really aren't; this is needed so we can map the columns
     // from the new factor as we go up in the join tree
     return new LoptJoinTree(
-        topRelNode,
+        relBuilder.build(),
         currJoinTree.getFactorTree(),
         newTree.getFactorTree());
   }
@@ -1718,6 +1720,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
    * @return created LogicalJoin
    */
   private LoptJoinTree createJoinSubtree(
+      RelBuilder relBuilder,
       LoptMultiJoin multiJoin,
       LoptJoinTree left,
       LoptJoinTree right,
@@ -1770,61 +1773,50 @@ public class LoptOptimizeJoinRule extends RelOptRule {
       }
     }
 
-    RelNode joinTree =
-        joinFactory.createJoin(
-            left.getJoinTree(),
-            right.getJoinTree(),
-            condition,
-            joinType,
-            ImmutableSet.<String>of(),
-            true);
+    relBuilder.push(left.getJoinTree())
+        .push(right.getJoinTree())
+        .join(joinType, condition);
 
     // if this is a left or right outer join, and additional filters can
     // be applied to the resulting join, then they need to be applied
     // as a filter on top of the outer join result
     if ((joinType == JoinRelType.LEFT) || (joinType == JoinRelType.RIGHT)) {
       assert !selfJoin;
-      joinTree =
-          addAdditionalFilters(
-              joinTree,
-              multiJoin,
-              left,
-              right,
-              filtersToAdd);
+      addAdditionalFilters(
+          relBuilder,
+          multiJoin,
+          left,
+          right,
+          filtersToAdd);
     }
 
     return new LoptJoinTree(
-        joinTree,
+        relBuilder.build(),
         left.getFactorTree(),
         right.getFactorTree(),
         selfJoin);
   }
 
   /**
-   * Determines whether any additional filters are applicable to a jointree.
+   * Determines whether any additional filters are applicable to a join tree.
    * If there are any, creates a filter node on top of the join tree with the
    * additional filters.
    *
-   * @param joinTree current join tree
+   * @param relBuilder Builder holding current join tree
    * @param multiJoin join factors being optimized
    * @param left left side of join tree
    * @param right right side of join tree
    * @param filtersToAdd remaining filters
-   *
-   * @return a filter node if additional filters are found; otherwise, returns
-   * original joinTree
    */
-  private RelNode addAdditionalFilters(
-      RelNode joinTree,
+  private void addAdditionalFilters(
+      RelBuilder relBuilder,
       LoptMultiJoin multiJoin,
       LoptJoinTree left,
       LoptJoinTree right,
       List<RexNode> filtersToAdd) {
     RexNode filterCond =
         addFilters(multiJoin, left, -1, right, filtersToAdd, false);
-    if (filterCond.isAlwaysTrue()) {
-      return joinTree;
-    } else {
+    if (!filterCond.isAlwaysTrue()) {
       // adjust the filter to reflect the outer join output
       int [] adjustments = new int[multiJoin.getNumTotalFields()];
       if (needsAdjustment(multiJoin, adjustments, left, right, false)) {
@@ -1835,10 +1827,10 @@ public class LoptOptimizeJoinRule extends RelOptRule {
                 new RelOptUtil.RexInputConverter(
                     rexBuilder,
                     multiJoin.getMultiJoinFields(),
-                    joinTree.getRowType().getFieldList(),
+                    relBuilder.peek().getRowType().getFieldList(),
                     adjustments));
+        relBuilder.filter(filterCond);
       }
-      return filterFactory.createFilter(joinTree, filterCond);
     }
   }
 
@@ -1946,7 +1938,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
       boolean selfJoin) {
     boolean needAdjustment = false;
 
-    List<Integer> joinOrder = new ArrayList<Integer>();
+    final List<Integer> joinOrder = new ArrayList<>();
     joinTree.getTreeOrder(joinOrder);
     if (otherTree != null) {
       otherTree.getTreeOrder(joinOrder);