calcite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jh...@apache.org
Subject [1/7] incubator-calcite git commit: [CALCITE-828] Use RelBuilder in rules rather than type-specific RelNode factories
Date Mon, 28 Sep 2015 20:19:32 GMT
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



Mime
View raw message