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/02 02:09:37 UTC

[01/18] incubator-calcite git commit: Formatting

Repository: incubator-calcite
Updated Branches:
  refs/heads/master 7a06c4fc4 -> 3e4d2b5c7


Formatting


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

Branch: refs/heads/master
Commit: 831a364c14b65299b37804b67aa03223c6831744
Parents: 7a06c4f
Author: Julian Hyde <jh...@apache.org>
Authored: Tue Sep 1 14:16:25 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Sep 1 14:16:25 2015 -0700

----------------------------------------------------------------------
 .../apache/calcite/rel/rules/JoinPushExpressionsRule.java | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/831a364c/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 3e9ec97..e3bbe4d 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
@@ -35,12 +35,13 @@ import org.apache.calcite.rex.RexNode;
  */
 public class JoinPushExpressionsRule extends RelOptRule {
 
-  public static final JoinPushExpressionsRule INSTANCE = new JoinPushExpressionsRule(
-          Join.class, RelFactories.DEFAULT_PROJECT_FACTORY);
+  public static final JoinPushExpressionsRule INSTANCE =
+      new JoinPushExpressionsRule(Join.class,
+          RelFactories.DEFAULT_PROJECT_FACTORY);
 
   private final RelFactories.ProjectFactory projectFactory;
 
-
+  /** Creates a JoinPushExpressionsRule. */
   public JoinPushExpressionsRule(Class<? extends Join> clazz,
       RelFactories.ProjectFactory projectFactory) {
     super(operand(clazz, any()));
@@ -63,5 +64,6 @@ public class JoinPushExpressionsRule extends RelOptRule {
 
     call.transformTo(newJoin);
   }
-
 }
+
+// End JoinPushExpressionsRule.java


[17/18] incubator-calcite git commit: [CALCITE-846] Push aggregate with FILTER through UNION ALL

Posted by jh...@apache.org.
[CALCITE-846] Push aggregate with FILTER through UNION ALL


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

Branch: refs/heads/master
Commit: 0c1a135833cccdd7f75e18544ed2a627fdad1119
Parents: b967073
Author: Julian Hyde <jh...@apache.org>
Authored: Fri Aug 14 11:49:23 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Sep 1 16:17:16 2015 -0700

----------------------------------------------------------------------
 .../rel/rules/AggregateUnionTransposeRule.java  |  7 ++-
 .../apache/calcite/test/RelOptRulesTest.java    | 19 ++++----
 .../org/apache/calcite/test/RelOptRulesTest.xml | 50 +++++++++++++++++---
 core/src/test/resources/sql/agg.oq              | 25 ++++++++++
 4 files changed, 82 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/0c1a1358/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 df55f0d..bcf80a9 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
@@ -61,8 +61,7 @@ public class AggregateUnionTransposeRule extends RelOptRule {
   private final RelFactories.SetOpFactory setOpFactory;
 
   private static final Map<Class<? extends SqlAggFunction>, Boolean>
-  SUPPORTED_AGGREGATES =
-      new IdentityHashMap<Class<? extends SqlAggFunction>, Boolean>();
+  SUPPORTED_AGGREGATES = new IdentityHashMap<>();
 
   static {
     SUPPORTED_AGGREGATES.put(SqlMinMaxAggFunction.class, true);
@@ -118,7 +117,7 @@ public class AggregateUnionTransposeRule extends RelOptRule {
     boolean anyTransformed = false;
 
     // create corresponding aggregates on top of each union child
-    List<RelNode> newUnionInputs = new ArrayList<RelNode>();
+    final List<RelNode> newUnionInputs = new ArrayList<>();
     for (RelNode input : union.getInputs()) {
       boolean alreadyUnique =
           RelMdUtil.areColumnsDefinitelyUnique(
@@ -178,7 +177,7 @@ public class AggregateUnionTransposeRule extends RelOptRule {
       }
       AggregateCall newCall =
           AggregateCall.create(aggFun, origCall.isDistinct(),
-              ImmutableList.of(groupCount + ord.i), groupCount, input,
+              ImmutableList.of(groupCount + ord.i), -1, groupCount, input,
               aggType, origCall.getName());
       newCalls.add(newCall);
     }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/0c1a1358/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 8c1f678..b98bf73 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -149,14 +149,13 @@ public class RelOptRulesTest extends RelOptTestBase {
     HepPlanner hepPlanner = new HepPlanner(builder.build());
     hepPlanner.addRule(ProjectToWindowRule.PROJECT);
 
-    checkPlanning(tester,
-        preProgram,
-        hepPlanner,
-        "select count(*) over(partition by empno order by sal) as count1,\n"
-            + "count(*) over(partition by deptno order by sal) as count2, \n"
-            + "sum(deptno) over(partition by empno order by sal) as sum1, \n"
-            + "sum(deptno) over(partition by deptno order by sal) as sum2 \n"
-            + "from emp");
+    final String sql = "select\n"
+        + " count(*) over(partition by empno order by sal) as count1,\n"
+        + " count(*) over(partition by deptno order by sal) as count2,\n"
+        + " sum(deptno) over(partition by empno order by sal) as sum1,\n"
+        + " sum(deptno) over(partition by deptno order by sal) as sum2\n"
+        + "from emp";
+    checkPlanning(tester, preProgram, hepPlanner, sql);
   }
 
   @Test public void testUnionToDistinctRule() {
@@ -1338,6 +1337,10 @@ public class RelOptRulesTest extends RelOptTestBase {
     basePushAggThroughUnion();
   }
 
+  @Test public void testPushCountFilterThroughUnion() throws Exception {
+    basePushAggThroughUnion();
+  }
+
   @Test public void testPullFilterThroughAggregate() throws Exception {
     HepProgram preProgram = HepProgram.builder()
         .addRuleInstance(ProjectMergeRule.INSTANCE)

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/0c1a1358/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 542f153..199fb6b 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -18,13 +18,12 @@ limitations under the License.
 <Root>
     <TestCase name="testProjectToWindowRuleForMultipleWindows">
         <Resource name="sql">
-            <![CDATA[
-select count(*) over(partition by empno order by sal) as count1,
-    count(*) over(partition by deptno order by sal) as count2,
-    sum(deptno)  over(partition by empno order by sal) as sum1,
-    sum(deptno)  over(partition by deptno order by sal) as sum2
-    from emp
-]]>
+            <![CDATA[select
+ count(*) over(partition by empno order by sal) as count1,
+ count(*) over(partition by deptno order by sal) as count2,
+ sum(deptno) over(partition by empno order by sal) as sum1,
+ sum(deptno) over(partition by deptno order by sal) as sum2
+from emp]]>
         </Resource>
         <Resource name="planAfter">
             <![CDATA[
@@ -1598,6 +1597,43 @@ LogicalProject(DEPTNO=[CASE($2, null, $0)], JOB=[CASE($3, null, $1)], EXPR$2=[$4
 ]]>
         </Resource>
     </TestCase>
+    <TestCase name="testPushCountFilterThroughUnion">
+        <Resource name="sql">
+            <![CDATA[select deptno, count(*) filter (where job = 'CLERK')
+from (
+  select * from emp where deptno = 10
+  union all
+  select * from emp where deptno > 20)
+group by deptno]]>
+        </Resource>
+        <Resource name="planBefore">
+            <![CDATA[
+LogicalAggregate(group=[{0}], EXPR$1=[COUNT() FILTER $1])
+  LogicalProject(DEPTNO=[$7], $f1=[=($2, 'CLERK')])
+    LogicalUnion(all=[true])
+      LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
+        LogicalFilter(condition=[=($7, 10)])
+          LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+      LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
+        LogicalFilter(condition=[>($7, 20)])
+          LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+        <Resource name="planAfter">
+            <![CDATA[
+LogicalAggregate(group=[{0}], EXPR$1=[$SUM0($1)])
+  LogicalUnion(all=[true])
+    LogicalAggregate(group=[{0}], EXPR$1=[COUNT() FILTER $1])
+      LogicalProject(DEPTNO=[$7], $f1=[=($2, 'CLERK')])
+        LogicalFilter(condition=[=($7, 10)])
+          LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+    LogicalAggregate(group=[{0}], EXPR$1=[COUNT() FILTER $1])
+      LogicalProject(DEPTNO=[$7], $f1=[=($2, 'CLERK')])
+        LogicalFilter(condition=[>($7, 20)])
+          LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+    </TestCase>
     <TestCase name="testPullFilterThroughAggregate">
         <Resource name="sql">
             <![CDATA[select empno, sal, deptno from (  select empno, sal, deptno  from emp  where sal > 5000)group by empno, sal, deptno]]>

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/0c1a1358/core/src/test/resources/sql/agg.oq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/agg.oq b/core/src/test/resources/sql/agg.oq
index 2fe0cc2..0ef4909 100644
--- a/core/src/test/resources/sql/agg.oq
+++ b/core/src/test/resources/sql/agg.oq
@@ -771,6 +771,31 @@ select avg(comm) as a, count(comm) as c from "scott".emp where empno < 7844;
 
 !ok
 
+# [CALCITE-846] Push aggregate with FILTER through UNION ALL
+select deptno, count(*) filter (where job = 'CLERK') as cf, count(*) as c
+from (
+  select * from "scott".emp where deptno < 20
+  union all
+  select * from "scott".emp where deptno > 20)
+group by deptno;
++--------+----+---+
+| DEPTNO | CF | C |
++--------+----+---+
+|     10 |  1 | 3 |
+|     30 |  1 | 6 |
++--------+----+---+
+(2 rows)
+
+!ok
+EnumerableAggregate(group=[{0}], CF=[COUNT() FILTER $1], C=[COUNT()])
+  EnumerableCalc(expr#0..1=[{inputs}], expr#2=['CLERK'], expr#3=[=($t0, $t2)], DEPTNO=[$t1], $f1=[$t3])
+    EnumerableUnion(all=[true])
+      EnumerableCalc(expr#0..7=[{inputs}], expr#8=[20], expr#9=[<($t7, $t8)], JOB=[$t2], DEPTNO=[$t7], $condition=[$t9])
+        EnumerableTableScan(table=[[scott, EMP]])
+      EnumerableCalc(expr#0..7=[{inputs}], expr#8=[20], expr#9=[>($t7, $t8)], JOB=[$t2], DEPTNO=[$t7], $condition=[$t9])
+        EnumerableTableScan(table=[[scott, EMP]])
+!plan
+
 # [CALCITE-751] Aggregate join transpose
 select count(*)
 from "scott".emp join "scott".dept using (deptno);


[12/18] incubator-calcite git commit: [CALCITE-819] Add RelRoot, a contract for the result of a relational expression

Posted by jh...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/main/java/org/apache/calcite/tools/Programs.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/tools/Programs.java b/core/src/main/java/org/apache/calcite/tools/Programs.java
index 3f6c05f..fd249a4 100644
--- a/core/src/main/java/org/apache/calcite/tools/Programs.java
+++ b/core/src/main/java/org/apache/calcite/tools/Programs.java
@@ -29,6 +29,7 @@ import org.apache.calcite.plan.hep.HepProgram;
 import org.apache.calcite.plan.hep.HepProgramBuilder;
 import org.apache.calcite.prepare.CalcitePrepareImpl;
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.Calc;
 import org.apache.calcite.rel.metadata.ChainedRelMetadataProvider;
 import org.apache.calcite.rel.metadata.DefaultRelMetadataProvider;
 import org.apache.calcite.rel.metadata.RelMetadataProvider;
@@ -61,7 +62,6 @@ import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
 
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.List;
 
 /**
@@ -94,7 +94,7 @@ public class Programs {
           FilterCalcMergeRule.INSTANCE,
           ProjectCalcMergeRule.INSTANCE);
 
-  /** Program that converts filters and projects to calcs. */
+  /** Program that converts filters and projects to {@link Calc}s. */
   public static final Program CALC_PROGRAM =
       hep(CALC_RULES, true, new DefaultRelMetadataProvider());
 
@@ -157,7 +157,7 @@ public class Programs {
   }
 
   /** Creates a program from a list of rules. */
-  public static Program ofRules(Collection<RelOptRule> rules) {
+  public static Program ofRules(Iterable<? extends RelOptRule> rules) {
     return of(RuleSets.ofList(rules));
   }
 
@@ -167,8 +167,8 @@ public class Programs {
   }
 
   /** Creates a program that executes a list of rules in a HEP planner. */
-  public static Program hep(ImmutableList<RelOptRule> rules, boolean noDag,
-      RelMetadataProvider metadataProvider) {
+  public static Program hep(Iterable<? extends RelOptRule> rules,
+      boolean noDag, RelMetadataProvider metadataProvider) {
     final HepProgramBuilder builder = HepProgram.builder();
     for (RelOptRule rule : rules) {
       builder.addRuleInstance(rule);
@@ -205,7 +205,8 @@ public class Programs {
    * {@link org.apache.calcite.rel.rules.MultiJoin} and
    * {@link org.apache.calcite.rel.rules.LoptOptimizeJoinRule})
    * if there are 6 or more joins (7 or more relations). */
-  public static Program heuristicJoinOrder(final Collection<RelOptRule> rules,
+  public static Program heuristicJoinOrder(
+      final Iterable<? extends RelOptRule> rules,
       final boolean bushy, final int minJoinCount) {
     return new Program() {
       public RelNode run(RelOptPlanner planner, RelNode rel,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/main/java/org/apache/calcite/tools/RuleSets.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/tools/RuleSets.java b/core/src/main/java/org/apache/calcite/tools/RuleSets.java
index 8a1cdc0..62bb5a1 100644
--- a/core/src/main/java/org/apache/calcite/tools/RuleSets.java
+++ b/core/src/main/java/org/apache/calcite/tools/RuleSets.java
@@ -20,7 +20,6 @@ import org.apache.calcite.plan.RelOptRule;
 
 import com.google.common.collect.ImmutableList;
 
-import java.util.Collection;
 import java.util.Iterator;
 
 /**
@@ -38,7 +37,7 @@ public class RuleSets {
   }
 
   /** Creates a rule set with a given collection of rules. */
-  public static RuleSet ofList(Collection<RelOptRule> rules) {
+  public static RuleSet ofList(Iterable<? extends RelOptRule> rules) {
     return new ListRuleSet(ImmutableList.copyOf(rules));
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/main/java/org/apache/calcite/util/ImmutableIntList.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/ImmutableIntList.java b/core/src/main/java/org/apache/calcite/util/ImmutableIntList.java
index 3dcfae6..8610dea 100644
--- a/core/src/main/java/org/apache/calcite/util/ImmutableIntList.java
+++ b/core/src/main/java/org/apache/calcite/util/ImmutableIntList.java
@@ -17,6 +17,7 @@
 package org.apache.calcite.util;
 
 import org.apache.calcite.runtime.FlatLists;
+import org.apache.calcite.util.mapping.Mappings;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
@@ -246,7 +247,10 @@ public class ImmutableIntList extends FlatLists.AbstractFlatList<Integer> {
     };
   }
 
-  /** Returns the identity list [0, ..., count - 1]. */
+  /** Returns the identity list [0, ..., count - 1].
+   *
+   * @see Mappings#isIdentity(List, int)
+   */
   public static ImmutableIntList identity(int count) {
     final int[] integers = new int[count];
     for (int i = 0; i < integers.length; i++) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/test/java/org/apache/calcite/test/InterpreterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/InterpreterTest.java b/core/src/test/java/org/apache/calcite/test/InterpreterTest.java
index 9f5200c..eea164b 100644
--- a/core/src/test/java/org/apache/calcite/test/InterpreterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/InterpreterTest.java
@@ -106,6 +106,19 @@ public class InterpreterTest {
     assertRows(interpreter, "[b, 2]", "[c, 3]");
   }
 
+  /** Tests a plan where the sort field is projected away. */
+  @Test public void testInterpretOrder() throws Exception {
+    final String sql = "select y\n"
+        + "from (values (1, 'a'), (2, 'b'), (3, 'c')) as t(x, y)\n"
+        + "order by -x";
+    SqlNode parse = planner.parse(sql);
+    SqlNode validate = planner.validate(parse);
+    RelNode convert = planner.rel(validate).project();
+
+    final Interpreter interpreter = new Interpreter(dataContext, convert);
+    assertRows(interpreter, "[c]", "[b]", "[a]");
+  }
+
   private static void assertRows(Interpreter interpreter, String... rows) {
     assertRows(interpreter, false, rows);
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/test/java/org/apache/calcite/test/JdbcFrontLinqBackTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcFrontLinqBackTest.java b/core/src/test/java/org/apache/calcite/test/JdbcFrontLinqBackTest.java
index e4131c3..5f41784 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcFrontLinqBackTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcFrontLinqBackTest.java
@@ -93,8 +93,8 @@ public class JdbcFrontLinqBackTest {
         .query("select upper(\"name\") as un, \"deptno\"\n"
             + "from \"hr\".\"emps\" as e\n"
             + "order by \"deptno\", \"name\" desc")
-        .explainContains(
-            "EnumerableCalc(expr#0..1=[{inputs}], expr#2=[UPPER($t1)], UN=[$t2], deptno=[$t0])\n"
+        .explainContains(""
+            + "EnumerableCalc(expr#0..1=[{inputs}], expr#2=[UPPER($t1)], UN=[$t2], deptno=[$t0], name=[$t1])\n"
             + "  EnumerableSort(sort0=[$0], sort1=[$1], dir0=[ASC], dir1=[DESC])\n"
             + "    EnumerableCalc(expr#0..4=[{inputs}], deptno=[$t1], name=[$t2])\n"
             + "      EnumerableTableScan(table=[[hr, emps]])")
@@ -209,8 +209,7 @@ public class JdbcFrontLinqBackTest {
   }
 
   @Test public void testInsert() {
-    final List<JdbcTest.Employee> employees =
-        new ArrayList<JdbcTest.Employee>();
+    final List<JdbcTest.Employee> employees = new ArrayList<>();
     CalciteAssert.AssertThat with = mutable(employees);
     with.query("select * from \"foo\".\"bar\"")
         .returns(
@@ -293,8 +292,7 @@ public class JdbcFrontLinqBackTest {
   }
 
   @Test public void testInsert2() {
-    final List<JdbcTest.Employee> employees =
-        new ArrayList<JdbcTest.Employee>();
+    final List<JdbcTest.Employee> employees = new ArrayList<>();
     CalciteAssert.AssertThat with = mutable(employees);
     with.query("insert into \"foo\".\"bar\" values (1, 1, 'second', 2, 2)")
         .returns("ROWCOUNT=1\n");
@@ -311,8 +309,7 @@ public class JdbcFrontLinqBackTest {
 
   /** Some of the rows have the wrong number of columns. */
   @Test public void testInsertMultipleRowMismatch() {
-    final List<JdbcTest.Employee> employees =
-        new ArrayList<JdbcTest.Employee>();
+    final List<JdbcTest.Employee> employees = new ArrayList<>();
     CalciteAssert.AssertThat with = mutable(employees);
     with.query("insert into \"foo\".\"bar\" values\n"
         + " (1, 3, 'third'),\n"

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/test/java/org/apache/calcite/test/JdbcTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcTest.java b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
index 2ff7e99..e1ee242 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -2940,11 +2940,9 @@ public class JdbcTest {
     CalciteAssert.hr()
         .query("select * from \"hr\".\"emps\"\n"
             + "order by - \"empid\"")
-        .explainContains(""
-            + "EnumerableCalc(expr#0..5=[{inputs}], proj#0..4=[{exprs}])\n"
-            + "  EnumerableSort(sort0=[$5], dir0=[ASC])\n"
-            + "    EnumerableCalc(expr#0..4=[{inputs}], expr#5=[-($t0)], proj#0..5=[{exprs}])\n"
-            + "      EnumerableTableScan(table=[[hr, emps]])")
+        .explainContains("EnumerableSort(sort0=[$5], dir0=[ASC])\n"
+            + "  EnumerableCalc(expr#0..4=[{inputs}], expr#5=[-($t0)], proj#0..5=[{exprs}])\n"
+            + "    EnumerableTableScan(table=[[hr, emps]])")
         .returns(""
             + "empid=200; deptno=20; name=Eric; salary=8000.0; commission=500\n"
             + "empid=150; deptno=10; name=Sebastian; salary=7000.0; commission=null\n"

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java b/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
index 5ade0c8..c53cc7a 100644
--- a/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
@@ -28,6 +28,7 @@ import org.apache.calcite.rel.RelCollationTraitDef;
 import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.RelFieldCollation;
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.RelRoot;
 import org.apache.calcite.rel.core.Aggregate;
 import org.apache.calcite.rel.core.AggregateCall;
 import org.apache.calcite.rel.core.Join;
@@ -127,10 +128,10 @@ public class RelMetadataTest extends SqlToRelTestBase {
   // ----------------------------------------------------------------------
 
   private RelNode convertSql(String sql) {
-    RelNode rel = tester.convertSqlToRel(sql);
+    final RelRoot root = tester.convertSqlToRel(sql);
     DefaultRelMetadataProvider provider = new DefaultRelMetadataProvider();
-    rel.getCluster().setMetadataProvider(provider);
-    return rel;
+    root.rel.getCluster().setMetadataProvider(provider);
+    return root.rel;
   }
 
   private void checkPercentageOriginalRows(String sql, double expected) {
@@ -996,7 +997,7 @@ public class RelMetadataTest extends SqlToRelTestBase {
             ImmutableList.<ImmutableBitSet>of(),
             ImmutableList.of(
                 AggregateCall.create(
-                    SqlStdOperatorTable.COUNT, false, ImmutableIntList.of(),
+                    SqlStdOperatorTable.COUNT, false, ImmutableIntList.of(), -1,
                     2, join, null, null)));
     rowSize = RelMetadataQuery.getAverageRowSize(aggregate);
     columnSizes = RelMetadataQuery.getAverageColumnSizes(aggregate);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/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 b98bf73..fc6d5bb 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -24,6 +24,7 @@ import org.apache.calcite.plan.hep.HepProgram;
 import org.apache.calcite.plan.hep.HepProgramBuilder;
 import org.apache.calcite.prepare.Prepare;
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.RelRoot;
 import org.apache.calcite.rel.core.Join;
 import org.apache.calcite.rel.core.JoinRelType;
 import org.apache.calcite.rel.core.RelFactories;
@@ -424,9 +425,9 @@ public class RelOptRulesTest extends RelOptTestBase {
     }
 
     final SqlNode validatedQuery = validator.validate(sqlQuery);
-    RelNode rel =
+    RelRoot root =
         converter.convertQuery(validatedQuery, false, true);
-    rel = converter.decorrelate(sqlQuery, rel);
+    root = root.withRel(converter.decorrelate(sqlQuery, root.rel));
 
     final HepProgram program =
         HepProgram.builder()
@@ -437,14 +438,14 @@ public class RelOptRulesTest extends RelOptTestBase {
             .build();
 
     HepPlanner planner = new HepPlanner(program);
-    planner.setRoot(rel);
-    rel = planner.findBestExp();
+    planner.setRoot(root.rel);
+    root = root.withRel(planner.findBestExp());
 
-    String planBefore = NL + RelOptUtil.toString(rel);
+    String planBefore = NL + RelOptUtil.toString(root.rel);
     diffRepos.assertEquals("planBefore", "${planBefore}", planBefore);
     converter.setTrimUnusedFields(true);
-    rel = converter.trimUnusedFields(false, rel);
-    String planAfter = NL + RelOptUtil.toString(rel);
+    root = root.withRel(converter.trimUnusedFields(false, root.rel));
+    String planAfter = NL + RelOptUtil.toString(root.rel);
     diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
   }
 
@@ -858,7 +859,7 @@ public class RelOptRulesTest extends RelOptTestBase {
         .build();
 
     // Remove the executor
-    tester.convertSqlToRel("values 1").getCluster().getPlanner()
+    tester.convertSqlToRel("values 1").rel.getCluster().getPlanner()
         .setExecutor(null);
 
     // Rule should not fire, but there should be no NPE
@@ -1474,7 +1475,8 @@ public class RelOptRulesTest extends RelOptTestBase {
         .build();
     HepPlanner planner = new HepPlanner(program);
 
-    RelNode relInitial = tester.convertSqlToRel(sql);
+    final RelRoot root = tester.convertSqlToRel(sql);
+    final RelNode relInitial = root.rel;
 
     assertTrue(relInitial != null);
 
@@ -1488,9 +1490,9 @@ public class RelOptRulesTest extends RelOptTestBase {
         new CachingRelMetadataProvider(plannerChain, planner));
 
     planner.setRoot(relInitial);
-    RelNode relAfter = planner.findBestExp();
+    RelNode relBefore = planner.findBestExp();
 
-    String planBefore = NL + RelOptUtil.toString(relAfter);
+    String planBefore = NL + RelOptUtil.toString(relBefore);
     diffRepos.assertEquals("planBefore", "${planBefore}", planBefore);
 
     HepProgram program2 = new HepProgramBuilder()
@@ -1504,8 +1506,8 @@ public class RelOptRulesTest extends RelOptTestBase {
         .build();
     HepPlanner planner2 = new HepPlanner(program2);
     planner.registerMetadataProviders(list);
-    planner2.setRoot(relAfter);
-    relAfter = planner2.findBestExp();
+    planner2.setRoot(relBefore);
+    RelNode relAfter = planner2.findBestExp();
 
     String planAfter = NL + RelOptUtil.toString(relAfter);
     diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java b/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java
index 790aa25..777991a 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java
@@ -23,6 +23,7 @@ import org.apache.calcite.plan.hep.HepPlanner;
 import org.apache.calcite.plan.hep.HepProgram;
 import org.apache.calcite.plan.hep.HepProgramBuilder;
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.RelRoot;
 import org.apache.calcite.rel.metadata.ChainedRelMetadataProvider;
 import org.apache.calcite.rel.metadata.DefaultRelMetadataProvider;
 import org.apache.calcite.rel.metadata.RelMetadataProvider;
@@ -99,7 +100,8 @@ abstract class RelOptTestBase extends SqlToRelTestBase {
       String sql) {
     final DiffRepository diffRepos = getDiffRepos();
     String sql2 = diffRepos.expand("sql", sql);
-    RelNode relInitial = tester.convertSqlToRel(sql2);
+    final RelRoot root = tester.convertSqlToRel(sql2);
+    final RelNode relInitial = root.rel;
 
     assertTrue(relInitial != null);
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/test/java/org/apache/calcite/test/RexTransformerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RexTransformerTest.java b/core/src/test/java/org/apache/calcite/test/RexTransformerTest.java
index b7ea814..22bb852 100644
--- a/core/src/test/java/org/apache/calcite/test/RexTransformerTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RexTransformerTest.java
@@ -20,6 +20,7 @@ import org.apache.calcite.jdbc.JavaTypeFactoryImpl;
 import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.logical.LogicalJoin;
+import org.apache.calcite.rel.logical.LogicalProject;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rel.type.RelDataTypeField;
@@ -67,7 +68,7 @@ public class RexTransformerTest {
   private static RelNode toRel(String sql) {
     final SqlToRelTestBase test = new SqlToRelTestBase() {
     };
-    return test.createTester().convertSqlToRel(sql);
+    return test.createTester().convertSqlToRel(sql).rel;
   }
 
   @Before public void setUp() {
@@ -377,7 +378,8 @@ public class RexTransformerTest {
         + "ON CAST(a.empno AS int) <> b.deptno";
 
     final RelNode relNode = toRel(sql);
-    final LogicalJoin join = (LogicalJoin) relNode.getInput(0);
+    final LogicalProject project = (LogicalProject) relNode;
+    final LogicalJoin join = (LogicalJoin) project.getInput(0);
     final List<RexNode> leftJoinKeys = new ArrayList<>();
     final List<RexNode> rightJoinKeys = new ArrayList<>();
     final ArrayList<RelDataTypeField> sysFieldList = new ArrayList<>();

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
index cb0310c..28f31f5 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
@@ -1076,7 +1076,7 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
 
   @Test public void testExplainAsXml() {
     String sql = "select 1 + 2, 3 from (values (true))";
-    final RelNode rel = tester.convertSqlToRel(sql);
+    final RelNode rel = tester.convertSqlToRel(sql).rel;
     StringWriter sw = new StringWriter();
     PrintWriter pw = new PrintWriter(sw);
     RelXmlWriter planWriter =

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/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 f9752e5..9ec1eea 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
@@ -30,6 +30,7 @@ import org.apache.calcite.rel.RelDistribution;
 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.logical.LogicalTableScan;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
@@ -124,7 +125,7 @@ public abstract class SqlToRelTestBase {
      * @param sql SQL statement
      * @return Relational expression, never null
      */
-    RelNode convertSqlToRel(String sql);
+    RelRoot convertSqlToRel(String sql);
 
     SqlNode parseQuery(String sql) throws Exception;
 
@@ -463,7 +464,7 @@ public abstract class SqlToRelTestBase {
       this.catalogReaderFactory = catalogReaderFactory;
     }
 
-    public RelNode convertSqlToRel(String sql) {
+    public RelRoot convertSqlToRel(String sql) {
       Util.pre(sql != null, "sql != null");
       final SqlNode sqlQuery;
       try {
@@ -484,20 +485,20 @@ public abstract class SqlToRelTestBase {
               typeFactory);
       converter.setTrimUnusedFields(true);
       final SqlNode validatedQuery = validator.validate(sqlQuery);
-      RelNode rel =
+      RelRoot root =
           converter.convertQuery(validatedQuery, false, true);
-      assert rel != null;
+      assert root != null;
       if (enableDecorrelate || enableTrim) {
-        rel = converter.flattenTypes(rel, true);
+        root = root.withRel(converter.flattenTypes(root.rel, true));
       }
       if (enableDecorrelate) {
-        rel = converter.decorrelate(sqlQuery, rel);
+        root = root.withRel(converter.decorrelate(sqlQuery, root.rel));
       }
       if (enableTrim) {
         converter.setTrimUnusedFields(true);
-        rel = converter.trimUnusedFields(false, rel);
+        root = root.withRel(converter.trimUnusedFields(false, root.rel));
       }
-      return rel;
+      return root;
     }
 
     protected SqlToRelConverter createSqlToRelConverter(
@@ -591,7 +592,7 @@ public abstract class SqlToRelTestBase {
         String plan,
         boolean trim) {
       String sql2 = getDiffRepos().expand("sql", sql);
-      RelNode rel = convertSqlToRel(sql2);
+      RelNode rel = convertSqlToRel(sql2).project();
 
       assertTrue(rel != null);
       assertValid(rel);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/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 551a612..b00b3ee 100644
--- a/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
+++ b/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
@@ -364,11 +364,10 @@ public class PlannerTest {
         + "from emps "
         + "order by emps.deptno) "
         + "order by deptno",
-        "EnumerableProject(empid=[$0])\n"
-        + "  EnumerableProject(empid=[$0], deptno=[$1])\n"
-        + "    EnumerableSort(sort0=[$1], dir0=[ASC])\n"
-        + "      EnumerableProject(empid=[$0], deptno=[$1], name=[$2], salary=[$3], commission=[$4])\n"
-        + "        EnumerableTableScan(table=[[hr, emps]])\n");
+        "EnumerableProject(empid=[$0], deptno=[$1])\n"
+        + "  EnumerableSort(sort0=[$1], dir0=[ASC])\n"
+        + "    EnumerableProject(empid=[$0], deptno=[$1], name=[$2], salary=[$3], commission=[$4])\n"
+        + "      EnumerableTableScan(table=[[hr, emps]])\n");
   }
 
   /** Unit test that parses, validates, converts and
@@ -380,11 +379,10 @@ public class PlannerTest {
         + "from emps "
         + "order by emps.deptno) "
         + "order by deptno",
-        "EnumerableProject(EXPR$0=[$0])\n"
-        + "  EnumerableProject(EXPR$0=[+($0, $1)], deptno=[$1])\n"
-        + "    EnumerableSort(sort0=[$1], dir0=[ASC])\n"
-        + "      EnumerableProject(empid=[$0], deptno=[$1])\n"
-        + "        EnumerableTableScan(table=[[hr, emps]])\n");
+        "EnumerableProject(EXPR$0=[+($0, $1)], deptno=[$1])\n"
+        + "  EnumerableSort(sort0=[$1], dir0=[ASC])\n"
+        + "    EnumerableProject(empid=[$0], deptno=[$1])\n"
+        + "      EnumerableTableScan(table=[[hr, emps]])\n");
   }
 
   /** Tests that outer order by is not removed since window function
@@ -459,12 +457,11 @@ public class PlannerTest {
         .replace(EnumerableConvention.INSTANCE);
     RelNode transform = planner.transform(0, traitSet, convert);
     assertThat(toString(transform),
-        equalTo("EnumerableProject(empid=[$0])\n"
-            + "  EnumerableSort(sort0=[$1], dir0=[ASC])\n"
-            + "    EnumerableProject(empid=[$0], deptno=[$1])\n"
-            + "      EnumerableSort(sort0=[$1], dir0=[ASC])\n"
-            + "        EnumerableProject(empid=[$0], deptno=[$1], name=[$2], salary=[$3], commission=[$4])\n"
-            + "          EnumerableTableScan(table=[[hr, emps]])\n"));
+        equalTo("EnumerableSort(sort0=[$1], dir0=[ASC])\n"
+            + "  EnumerableProject(empid=[$0], deptno=[$1])\n"
+            + "    EnumerableSort(sort0=[$1], dir0=[ASC])\n"
+            + "      EnumerableProject(empid=[$0], deptno=[$1], name=[$2], salary=[$3], commission=[$4])\n"
+            + "        EnumerableTableScan(table=[[hr, emps]])\n"));
   }
 
   /** Unit test that parses, validates, converts and plans. Planner is

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
index a9f7727..0ff7c29 100644
--- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
@@ -2409,12 +2409,11 @@ LogicalAggregate(group=[{0}], EMPID=[MIN($1)])
 ]]>
         </Resource>
     </TestCase>
-
     <TestCase name="testCorrelationScalarAggAndFilter">
         <Resource name="sql">
             <![CDATA[SELECT e1.empno FROM emp e1, dept d1 where e1.deptno = d1.deptno
-     and e1.deptno < 10 and d1.deptno < 15
-     and e1.sal > (select avg(sal) from emp e2 where e1.empno = e2.empno)]]>
+and e1.deptno < 10 and d1.deptno < 15
+and e1.sal > (select avg(sal) from emp e2 where e1.empno = e2.empno)]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -2442,12 +2441,11 @@ LogicalProject(EMPNO=[$0])
 ]]>
         </Resource>
     </TestCase>
-
     <TestCase name="testCorrelationExistsAndFilter">
         <Resource name="sql">
             <![CDATA[SELECT e1.empno FROM emp e1, dept d1 where e1.deptno = d1.deptno
-     and e1.deptno < 10 and d1.deptno < 15
-     and exists (select * from emp e2 where e1.empno = e2.empno)]]>
+and e1.deptno < 10 and d1.deptno < 15
+and exists (select * from emp e2 where e1.empno = e2.empno)]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -2476,12 +2474,11 @@ LogicalProject(EMPNO=[$0])
 ]]>
         </Resource>
     </TestCase>
-
     <TestCase name="testCorrelationNotExistsAndFilter">
         <Resource name="sql">
             <![CDATA[SELECT e1.empno FROM emp e1, dept d1 where e1.deptno = d1.deptno
-     and e1.deptno < 10 and d1.deptno < 15
-     and not exists (select * from emp e2 where e1.empno = e2.empno)]]>
+and e1.deptno < 10 and d1.deptno < 15
+and not exists (select * from emp e2 where e1.empno = e2.empno)]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/test/resources/sql/sort.oq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/sort.oq b/core/src/test/resources/sql/sort.oq
index 931d58f..5a25b6b 100644
--- a/core/src/test/resources/sql/sort.oq
+++ b/core/src/test/resources/sql/sort.oq
@@ -85,6 +85,19 @@ select * from e as e1, e as e2 order by e1.empid + e2.empid, e1.empid;
 
 !ok
 
+# WITH ... LIMIT
+with e as (select "empid" as empid from "hr"."emps" where "empid" < 200)
+select * from e where empid > 100 limit 5;
++-------+
+| EMPID |
++-------+
+|   150 |
+|   110 |
++-------+
+(2 rows)
+
+!ok
+
 # [CALCITE-634] Allow ORDER BY aggregate function in SELECT DISTINCT, provided
 # that it occurs in SELECT clause
 select distinct "deptno", count(*) as c


[02/18] incubator-calcite git commit: Add 1.4 release announcement

Posted by jh...@apache.org.
Add 1.4 release announcement


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

Branch: refs/heads/master
Commit: 27b359bf4c8a3aacc658daacf8442fd7cab11b05
Parents: 831a364
Author: Julian Hyde <jh...@apache.org>
Authored: Tue Sep 1 15:00:07 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Sep 1 15:42:09 2015 -0700

----------------------------------------------------------------------
 site/_docs/history.md                           | 86 +++++++++-----------
 site/_docs/howto.md                             |  4 +-
 .../2015-09-02-release-1.4.0-incubating.md      | 39 +++++++++
 3 files changed, 81 insertions(+), 48 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/27b359bf/site/_docs/history.md
----------------------------------------------------------------------
diff --git a/site/_docs/history.md b/site/_docs/history.md
index a0bc735..8b51e84 100644
--- a/site/_docs/history.md
+++ b/site/_docs/history.md
@@ -26,10 +26,13 @@ limitations under the License.
 For a full list of releases, see
 <a href="https://github.com/apache/incubator-calcite/releases">github</a>.
 
-## <a href="https://github.com/apache/incubator-calcite/releases/tag/calcite-1.4.0-incubating">1.4.0-incubating</a> / 2015-08-23
+## <a href="https://github.com/apache/incubator-calcite/releases/tag/calcite-1.4.0-incubating">1.4.0-incubating</a> / 2015-09-02
 {: #v1-4-0}
 
-In addition to a large number of bug fixes and minor enhancements, this release includes improvements in Lattice Functionality, Materialized Views and the ability to generate relational albegra using a builder.
+In addition to a large number of bug fixes and minor enhancements,
+this release includes improvements to lattices and matierlized views,
+and adds a builder API so that you can easily create relational
+algebra expressions.
 
 New features
 
@@ -43,10 +46,10 @@ New features
       Detect if materialized view can be used to rewrite a query in
   non-trivial cases (Amogh Margoor)
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-732">CALCITE-732</a>]
-      Implement multiple distinct-COUNT using GROUPING SETS
+      Implement multiple distinct-`COUNT` using `GROUPING SETS`
 * Add various `BitSet` and `ImmutableBitSet` utilities
 
-Website Updates
+Website updates
 
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-810">CALCITE-810</a>]
       Add committers' organizations to the web site
@@ -63,62 +66,57 @@ Website Updates
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-355">CALCITE-355</a>]
       Web site
 
-Bug fixes, API Changes and Minor Enhancements
+Bug fixes, API changes and minor enhancements
 
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-741">CALCITE-741</a>]
-      Ensure that the source release's DEPENDENCIES file includes all module
-  dependencies.
+      Ensure that the source release's `DEPENDENCIES` file includes all module
+  dependencies
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-743">CALCITE-743</a>]
-      Ensure only a single source assembly is executed.
+      Ensure only a single source assembly is executed
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-850">CALCITE-850</a>]
       Remove push down expressions from `FilterJoinRule` and create a new rule
   for it
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-834">CALCITE-834</a>]
       `StackOverflowError` getting predicates from the metadata provider
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-833">CALCITE-833</a>]
-      RelOptUtil.splitJoinCondition incorrectly splits a join condition
+      `RelOptUtil.splitJoinCondition` incorrectly splits a join condition
   (Hsuan-Yi Chu)
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-822">CALCITE-822</a>]
       Add a unit test case to test collation of `LogicalAggregate`
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-822">CALCITE-822</a>]
       Revert incorrect `LogicalAggregate` collation inferring logic made in
-  CALCITE-783 (Milinda Pathirage)
+  [<a href="https://issues.apache.org/jira/browse/CALCITE-783">CALCITE-783</a>]
+  (Milinda Pathirage)
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-826">CALCITE-826</a>]
       Use `ProjectFactory` in `AggregateJoinTranposeRule` and `FilterJoinRule`
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-821">CALCITE-821</a>]
-      Frameworks gives NPE when `FrameworkConfig` has no default schema
+      `Frameworks` gives NPE when `FrameworkConfig` has no default schema
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-811">CALCITE-811</a>]
       Extend `JoinProjectTransposeRule` with option to support outer joins
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-805">CALCITE-805</a>]
       Add support for using an alternative grammar specification for left and
   right curly braces. Additionally, add support for including addition token
-  manager declarations.
+  manager declarations
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-803">CALCITE-803</a>]
-      Add `MYSQL_ANSI` Lexing policy.
+      Add `MYSQL_ANSI` Lexing policy
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-717">CALCITE-717</a>]
       Compare BINARY and VARBINARY on unsigned byte values (Low Chin Wei)
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-814">CALCITE-814</a>]
       `RexBuilder` reverses precision and scale of `DECIMAL` literal
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-813">CALCITE-813</a>]
       Upgrade `updateCount`, `maxRows` from int to long
-* Fix up [<a
-  href="https://issues.apache.org/jira/browse/CALCITE-714">CALCITE-714</a>]
-  
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-714">CALCITE-714</a>]
       When de-correlating, push join condition into subquery
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-751">CALCITE-751</a>]
       Push aggregate with aggregate functions through join
 * Add `RelBuilder.avg`
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-806">CALCITE-806</a>]
-      ROW_NUMBER should emit distinct values
+      `ROW_NUMBER` should emit distinct values
 * Document JSON model, making javadoc consistent with the model reference
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-808">CALCITE-808</a>]
       Optimize `ProjectMergeRule`
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-791">CALCITE-791</a>]
       Optimize `RelOptUtil.pushFilterPastProject`
-* Complete [<a
-  href="https://issues.apache.org/jira/browse/CALCITE-783">CALCITE-783</a>]
-      by fixing some planner rules
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-783">CALCITE-783</a>]
       Infer collation of `Project` using monotonicity (Milinda Pathirage)
 * Change the argument types of `SqlOperator.getMonotonicity` to allow it to be
@@ -128,53 +126,52 @@ Bug fixes, API Changes and Minor Enhancements
   (Hsuan-Yi Chu)
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-787">CALCITE-787</a>]
       Star table wrongly assigned to materialized view (Amogh Margoor)
-* Fix up previous commit; add some tests for constant reduction
 * Remove duplicate resources from XML test reference files
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-795">CALCITE-795</a>]
       Loss of precision when sending a decimal number via the remote JSON
   service (Lukáš Lalinský)
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-774">CALCITE-774</a>]
-      When GROUP BY is present, ensure that window function operands only
-  refer to GROUP BY keys (Hsuan-Yi Chu)
+      When `GROUP BY` is present, ensure that window function operands only
+  refer to grouping keys (Hsuan-Yi Chu)
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-799">CALCITE-799</a>]
-      Incorrect result for "HAVING count(*) > 1"
+      Incorrect result for `HAVING count(*) > 1`
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-801">CALCITE-801</a>]
-      NullPointerException using USING on table alias with column aliases
+      `NullPointerException` using `USING` on table alias with column aliases
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-390">CALCITE-390</a>]
       Infer predicates for semi-join
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-789">CALCITE-789</a>]
-      `MetaImpl.MetaCatalog` should expose TABLE_CAT instead of TABLE_CATALOG
+      `MetaImpl.MetaCatalog` should expose `TABLE_CAT` instead of
+      `TABLE_CATALOG`
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-752">CALCITE-752</a>]
       Add back sqlline as a dependency to csv example
-* Re-enable a test; fix some code formatting; fix Windows line endings
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-780">CALCITE-780</a>]
       HTTP error 413 when sending a long string to the Avatica server
-* In RelBuilder, calling sort then limit has same effect as calling sortLimit
-* Add Ord.reverse
+* In `RelBuilder`, calling `sort` then `limit` has same effect as calling
+  `sortLimit`
+* Add `Ord.reverse`
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-788">CALCITE-788</a>]
       Allow `EnumerableJoin` to be sub-classed (Li Yang)
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-280">CALCITE-280</a>]
-      BigDecimal underflow (Li Yang)
+      `BigDecimal` underflow (Li Yang)
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-763">CALCITE-763</a>]
       Missing translation from `Sort` to `MutableSort` (Maryann Xue)
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-770">CALCITE-770</a>]
       Ignore window aggregates and ranking functions when finding aggregate
   functions
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-765">CALCITE-765</a>]
-      Set Content-Type from the RPC server to application/json (Lukáš Lalinský)
+      Set `Content-Type` from the RPC server to `application/json` (Lukáš Lalinský)
 * Fix Windows line-endings in `RelBuilderTest`
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-727">CALCITE-727</a>]
-      Constant folding involving CASE and NULL
-* Related to [<a
-  href="https://issues.apache.org/jira/browse/CALCITE-758">CALCITE-758</a>]
-     , speed up matching by not considering tiles separately from other
+      Constant folding involving `CASE` and `NULL`
+* Related to
+  [<a href="https://issues.apache.org/jira/browse/CALCITE-758">CALCITE-758</a>],
+  speed up matching by not considering tiles separately from other
   materialized views
-* Test case and workaround for [<a
-  href="https://issues.apache.org/jira/browse/CALCITE-760">CALCITE-760</a>]
+* Test case and workaround for
+  [<a href="https://issues.apache.org/jira/browse/CALCITE-760">CALCITE-760</a>]
       `Aggregate` recommender blows up if row count estimate is too high
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-753">CALCITE-753</a>]
       `Aggregate` operators may derive row types with duplicate column names
-  Close apache/incubator-calcite#91
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-457">CALCITE-457</a>]
       Push condition of non-ansi join into join operator
 * Change jsonRequest encoding to UTF-8 (Guitao Ding)
@@ -183,16 +180,13 @@ Bug fixes, API Changes and Minor Enhancements
 * Fix coverity warnings
 * Remove deprecated `SqlTypeName` methods
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-754">CALCITE-754</a>]
-      Validator error when resolving OVER clause of JOIN query
-* Test case for [<a
-  href="https://issues.apache.org/jira/browse/CALCITE-754">CALCITE-754</a>]
-      Validator error when resolving OVER clause of JOIN query (Hsuan-Yi Chu)
+      Validator error when resolving `OVER` clause of `JOIN` query
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-429">CALCITE-429</a>]
       Cardinality provider for use by lattice algorithm
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-740">CALCITE-740</a>]
-      Redundant WHERE clause causes wrong result in MongoDB adapter
+      Redundant `WHERE` clause causes wrong result in MongoDB adapter
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-665">CALCITE-665</a>]
-      ClassCastException in MongoDB adapter
+      `ClassCastException` in MongoDB adapter
 * Separate `TableFactory` from suggested table name, so one `TableFactory` can be
   used for several tables
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-749">CALCITE-749</a>]
@@ -209,8 +203,8 @@ Bug fixes, API Changes and Minor Enhancements
   "NNN-description"
 * Clean up
 * Upgrade tpcds
-* Make `JdbcTest.testVersion` more permissive, so that version.major and
-  version.minor can be set just before a release, rather than just after as at
+* Make `JdbcTest.testVersion` more permissive, so that `version.major` and
+  `version.minor` can be set just before a release, rather than just after as at
   present
 
 ## <a href="https://github.com/apache/incubator-calcite/releases/tag/calcite-1.3.0-incubating">1.3.0-incubating</a> / 2015-05-30

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/27b359bf/site/_docs/howto.md
----------------------------------------------------------------------
diff --git a/site/_docs/howto.md b/site/_docs/howto.md
index cd5011a..e061e12 100644
--- a/site/_docs/howto.md
+++ b/site/_docs/howto.md
@@ -37,8 +37,8 @@ Unpack the source distribution `.tar.gz` or `.zip` file,
 then build using maven:
 
 {% highlight bash %}
-$ tar xvfz calcite-1.3.0-incubating-source.tar.gz
-$ cd calcite-1.3.0-incubating
+$ tar xvfz calcite-1.4.0-incubating-source.tar.gz
+$ cd calcite-1.4.0-incubating
 $ mvn install
 {% endhighlight %}
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/27b359bf/site/_posts/2015-09-02-release-1.4.0-incubating.md
----------------------------------------------------------------------
diff --git a/site/_posts/2015-09-02-release-1.4.0-incubating.md b/site/_posts/2015-09-02-release-1.4.0-incubating.md
new file mode 100644
index 0000000..b44b62b
--- /dev/null
+++ b/site/_posts/2015-09-02-release-1.4.0-incubating.md
@@ -0,0 +1,39 @@
+---
+layout: news_item
+date: "2015-09-02 12:00:00 +0000"
+author: jhyde
+version: 1.4.0-incubating
+categories: [release]
+tag: v1-4-0
+sha: 0c0c203d
+---
+<!--
+{% comment %}
+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.
+{% endcomment %}
+-->
+
+In addition to a large number of bug fixes and minor enhancements,
+this release includes improvements to
+<a href="https://issues.apache.org/jira/browse/CALCITE-758">lattices</a> and
+<a href="https://issues.apache.org/jira/browse/CALCITE-761">materialized views</a>,
+and adds a
+<a href="https://issues.apache.org/jira/browse/CALCITE-748">builder API</a>
+so that you can easily create relational algebra expressions.
+
+Read more about the [builder](/news/2015/06/05/algebra-builder/),
+[relational algebra](/docs/algebra.html), and
+[lattices](/docs/lattice.html).


[08/18] incubator-calcite git commit: [CALCITE-825] Allow user to specify sort order of an ArrayTable

Posted by jh...@apache.org.
[CALCITE-825] Allow user to specify sort order of an ArrayTable


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

Branch: refs/heads/master
Commit: 87e7454cf5ba1c1d1a492371e493bfae5445e62e
Parents: a5688ff
Author: Julian Hyde <jh...@apache.org>
Authored: Fri Aug 7 16:16:05 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Sep 1 16:17:15 2015 -0700

----------------------------------------------------------------------
 .../calcite/adapter/clone/ArrayTable.java       | 47 +++++++++++---------
 .../calcite/adapter/clone/CloneSchema.java      | 26 ++++++++---
 .../apache/calcite/jdbc/CalciteMetaImpl.java    |  4 +-
 .../org/apache/calcite/jdbc/CalcitePrepare.java | 18 +++++---
 .../materialize/MaterializationService.java     |  1 +
 .../calcite/prepare/CalcitePrepareImpl.java     |  6 +++
 .../org/apache/calcite/prepare/Prepare.java     | 12 +++++
 .../org/apache/calcite/rel/RelCollations.java   | 16 ++++---
 8 files changed, 90 insertions(+), 40 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/87e7454c/core/src/main/java/org/apache/calcite/adapter/clone/ArrayTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/clone/ArrayTable.java b/core/src/main/java/org/apache/calcite/adapter/clone/ArrayTable.java
index b9bdba8..d87165c 100644
--- a/core/src/main/java/org/apache/calcite/adapter/clone/ArrayTable.java
+++ b/core/src/main/java/org/apache/calcite/adapter/clone/ArrayTable.java
@@ -27,7 +27,6 @@ import org.apache.calcite.linq4j.Queryable;
 import org.apache.calcite.linq4j.tree.Primitive;
 import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelCollations;
-import org.apache.calcite.rel.RelFieldCollation;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rel.type.RelProtoDataType;
@@ -80,14 +79,7 @@ class ArrayTable extends AbstractQueryableTable implements ScannableTable {
         keys.add(ImmutableBitSet.of(ord.i));
       }
     }
-    final List<RelCollation> collations;
-    if (content.sortField >= 0) {
-      collations = ImmutableList.of(
-          RelCollations.of(new RelFieldCollation(content.sortField)));
-    } else {
-      collations = ImmutableList.of();
-    }
-    return Statistics.of(content.size, keys, collations);
+    return Statistics.of(content.size, keys, content.collations);
   }
 
   public Enumerable<Object[]> scan(DataContext root) {
@@ -111,6 +103,11 @@ class ArrayTable extends AbstractQueryableTable implements ScannableTable {
     };
   }
 
+  @SuppressWarnings("unchecked")
+  private static <T> Pair<Object, T> toPair(Object dataSet) {
+    return (Pair<Object, T>) dataSet;
+  }
+
   /** How a column's values are represented. */
   enum RepresentationType {
     /** Constant. Contains only one value.
@@ -450,16 +447,14 @@ class ArrayTable extends AbstractQueryableTable implements ScannableTable {
     }
 
     public Object permute(Object dataSet, int[] sources) {
-      final Pair<Object, Comparable[]> pair =
-          (Pair<Object, Comparable[]>) dataSet;
+      final Pair<Object, Comparable[]> pair = toPair(dataSet);
       Object codes = pair.left;
       Comparable[] codeValues = pair.right;
       return Pair.of(representation.permute(codes, sources), codeValues);
     }
 
     public Object getObject(Object dataSet, int ordinal) {
-      final Pair<Object, Comparable[]> pair =
-          (Pair<Object, Comparable[]>) dataSet;
+      final Pair<Object, Comparable[]> pair = toPair(dataSet);
       int code = representation.getInt(pair.left, ordinal);
       return pair.right[code];
     }
@@ -469,8 +464,7 @@ class ArrayTable extends AbstractQueryableTable implements ScannableTable {
     }
 
     public int size(Object dataSet) {
-      final Pair<Object, Comparable[]> pair =
-          (Pair<Object, Comparable[]>) dataSet;
+      final Pair<Object, Comparable[]> pair = toPair(dataSet);
       return representation.size(pair.left);
     }
 
@@ -581,22 +575,22 @@ class ArrayTable extends AbstractQueryableTable implements ScannableTable {
     }
 
     public Object getObject(Object dataSet, int ordinal) {
-      Pair<Object, Integer> pair = (Pair<Object, Integer>) dataSet;
+      Pair<Object, Integer> pair = toPair(dataSet);
       return pair.left;
     }
 
     public int getInt(Object dataSet, int ordinal) {
-      Pair<Object, Integer> pair = (Pair<Object, Integer>) dataSet;
+      Pair<Object, Integer> pair = toPair(dataSet);
       return ((Number) pair.left).intValue();
     }
 
     public int size(Object dataSet) {
-      Pair<Object, Integer> pair = (Pair<Object, Integer>) dataSet;
+      Pair<Object, Integer> pair = toPair(dataSet);
       return pair.right;
     }
 
     public String toString(Object dataSet) {
-      Pair<Object, Integer> pair = (Pair<Object, Integer>) dataSet;
+      Pair<Object, Integer> pair = toPair(dataSet);
       return Collections.nCopies(pair.right, pair.left).toString();
     }
   }
@@ -808,12 +802,21 @@ class ArrayTable extends AbstractQueryableTable implements ScannableTable {
   public static class Content {
     private final List<Column> columns;
     private final int size;
-    private final int sortField;
+    private final ImmutableList<RelCollation> collations;
 
-    public Content(List<? extends Column> columns, int size, int sortField) {
+    public Content(List<? extends Column> columns, int size,
+        Iterable<? extends RelCollation> collations) {
       this.columns = ImmutableList.copyOf(columns);
       this.size = size;
-      this.sortField = sortField;
+      this.collations = ImmutableList.copyOf(collations);
+    }
+
+    @Deprecated // to be removed before 2.0
+    public Content(List<? extends Column> columns, int size, int sortField) {
+      this(columns, size,
+          sortField >= 0
+              ? RelCollations.createSingleton(sortField)
+              : ImmutableList.<RelCollation>of());
     }
 
     @SuppressWarnings("unchecked")

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/87e7454c/core/src/main/java/org/apache/calcite/adapter/clone/CloneSchema.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/clone/CloneSchema.java b/core/src/main/java/org/apache/calcite/adapter/clone/CloneSchema.java
index 2f996b9..afd3798 100644
--- a/core/src/main/java/org/apache/calcite/adapter/clone/CloneSchema.java
+++ b/core/src/main/java/org/apache/calcite/adapter/clone/CloneSchema.java
@@ -23,6 +23,8 @@ import org.apache.calcite.jdbc.CalciteConnection;
 import org.apache.calcite.linq4j.Enumerable;
 import org.apache.calcite.linq4j.QueryProvider;
 import org.apache.calcite.linq4j.Queryable;
+import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.type.RelProtoDataType;
 import org.apache.calcite.schema.QueryableTable;
 import org.apache.calcite.schema.Schema;
@@ -34,6 +36,7 @@ import org.apache.calcite.schema.impl.AbstractSchema;
 
 import com.google.common.base.Supplier;
 import com.google.common.base.Suppliers;
+import com.google.common.collect.ImmutableList;
 
 import java.lang.reflect.Type;
 import java.util.LinkedHashMap;
@@ -63,7 +66,7 @@ public class CloneSchema extends AbstractSchema {
   }
 
   @Override protected Map<String, Table> getTableMap() {
-    final Map<String, Table> map = new LinkedHashMap<String, Table>();
+    final Map<String, Table> map = new LinkedHashMap<>();
     for (String name : sourceSchema.getTableNames()) {
       final Table table = sourceSchema.getTable(name);
       if (table instanceof QueryableTable) {
@@ -81,14 +84,22 @@ public class CloneSchema extends AbstractSchema {
         sourceTable.asQueryable(queryProvider, sourceSchema, name);
     final JavaTypeFactory typeFactory =
         ((CalciteConnection) queryProvider).getTypeFactory();
-    return createCloneTable(typeFactory, Schemas.proto(sourceTable), null,
-        queryable);
+    return createCloneTable(typeFactory, Schemas.proto(sourceTable),
+        ImmutableList.<RelCollation>of(), null, queryable);
   }
 
+  @Deprecated // to be removed before 2.0
   public static <T> Table createCloneTable(final JavaTypeFactory typeFactory,
       final RelProtoDataType protoRowType,
       final List<ColumnMetaData.Rep> repList,
       final Enumerable<T> source) {
+    return createCloneTable(typeFactory, protoRowType,
+        ImmutableList.<RelCollation>of(), repList, source);
+  }
+
+  public static <T> Table createCloneTable(final JavaTypeFactory typeFactory,
+      final RelProtoDataType protoRowType, final List<RelCollation> collations,
+      final List<ColumnMetaData.Rep> repList, final Enumerable<T> source) {
     final Type elementType;
     if (source instanceof QueryableTable) {
       elementType = ((QueryableTable) source).getElementType();
@@ -108,10 +119,15 @@ public class CloneSchema extends AbstractSchema {
             new Supplier<ArrayTable.Content>() {
               public ArrayTable.Content get() {
                 final ColumnLoader loader =
-                    new ColumnLoader<T>(typeFactory, source, protoRowType,
+                    new ColumnLoader<>(typeFactory, source, protoRowType,
                         repList);
+                final List<RelCollation> collation2 =
+                    collations.isEmpty()
+                        && loader.sortField >= 0
+                        ? RelCollations.createSingleton(loader.sortField)
+                        : collations;
                 return new ArrayTable.Content(loader.representationValues,
-                    loader.size(), loader.sortField);
+                    loader.size(), collation2);
               }
             }));
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/87e7454c/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java
index 9f8ade3..fabaf26 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java
@@ -34,6 +34,7 @@ import org.apache.calcite.linq4j.Queryable;
 import org.apache.calcite.linq4j.function.Function1;
 import org.apache.calcite.linq4j.function.Functions;
 import org.apache.calcite.linq4j.function.Predicate1;
+import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rel.type.RelDataTypeFactoryImpl;
@@ -195,7 +196,8 @@ public class CalciteMetaImpl extends MetaImpl {
       final CalcitePrepare.CalciteSignature<Object> signature =
           new CalcitePrepare.CalciteSignature<Object>("",
               ImmutableList.<AvaticaParameter>of(), internalParameters, null,
-              columns, cursorFactory, -1, null) {
+              columns, cursorFactory, ImmutableList.<RelCollation>of(), -1,
+              null) {
             @Override public Enumerable<Object> enumerable(
                 DataContext dataContext) {
               return Linq4j.asEnumerable(firstFrame.rows);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/87e7454c/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java b/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
index 2453f98..fe2f898 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
@@ -30,6 +30,7 @@ import org.apache.calcite.linq4j.tree.ClassDeclaration;
 import org.apache.calcite.plan.RelOptPlanner;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.prepare.CalcitePrepareImpl;
+import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
@@ -260,19 +261,18 @@ public interface CalcitePrepare {
    * statement directly, without an explicit prepare step. */
   class CalciteSignature<T> extends Meta.Signature {
     @JsonIgnore public final RelDataType rowType;
+    @JsonIgnore private final List<RelCollation> collationList;
     private final long maxRowCount;
     private final Bindable<T> bindable;
 
-    public CalciteSignature(String sql,
-        List<AvaticaParameter> parameterList,
-        Map<String, Object> internalParameters,
-        RelDataType rowType,
-        List<ColumnMetaData> columns,
-        Meta.CursorFactory cursorFactory,
-        long maxRowCount,
+    public CalciteSignature(String sql, List<AvaticaParameter> parameterList,
+        Map<String, Object> internalParameters, RelDataType rowType,
+        List<ColumnMetaData> columns, Meta.CursorFactory cursorFactory,
+        List<RelCollation> collationList, long maxRowCount,
         Bindable<T> bindable) {
       super(columns, sql, parameterList, internalParameters, cursorFactory);
       this.rowType = rowType;
+      this.collationList = collationList;
       this.maxRowCount = maxRowCount;
       this.bindable = bindable;
     }
@@ -286,6 +286,10 @@ public interface CalcitePrepare {
       }
       return enumerable;
     }
+
+    public List<RelCollation> getCollationList() {
+      return collationList;
+    }
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/87e7454c/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java b/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java
index 615d185..fc9ac2b 100644
--- a/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java
+++ b/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java
@@ -369,6 +369,7 @@ public class MaterializationService {
           Schemas.prepare(connection, schema, viewSchemaPath, viewSql, map);
       return CloneSchema.createCloneTable(connection.getTypeFactory(),
           RelDataTypeImpl.proto(calciteSignature.rowType),
+          calciteSignature.getCollationList(),
           Lists.transform(calciteSignature.columns,
               new Function<ColumnMetaData, ColumnMetaData.Rep>() {
                 public ColumnMetaData.Rep apply(ColumnMetaData column) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/87e7454c/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
index b7f444f..524e34f 100644
--- a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
@@ -62,6 +62,7 @@ import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.plan.hep.HepPlanner;
 import org.apache.calcite.plan.hep.HepProgramBuilder;
 import org.apache.calcite.plan.volcano.VolcanoPlanner;
+import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelCollationTraitDef;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Filter;
@@ -600,6 +601,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
         x,
         columns,
         cursorFactory,
+        ImmutableList.<RelCollation>of(),
         -1,
         new Bindable<T>() {
           public Enumerable<T> bind(DataContext dataContext) {
@@ -720,6 +722,9 @@ public class CalcitePrepareImpl implements CalcitePrepare {
         preparingStmt.resultConvention == BindableConvention.INSTANCE
             ? Meta.CursorFactory.ARRAY
             : Meta.CursorFactory.deduce(columns, resultClazz),
+        preparedResult instanceof Prepare.PreparedResultImpl
+            ? ((Prepare.PreparedResultImpl) preparedResult).collations
+            : ImmutableList.<RelCollation>of(),
         maxRowCount,
         bindable);
   }
@@ -1063,6 +1068,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
           resultType,
           parameterRowType,
           fieldOrigins,
+          ImmutableList.copyOf(collations),
           rootRel,
           mapTableModOp(isDml, sqlKind),
           isDml) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/87e7454c/core/src/main/java/org/apache/calcite/prepare/Prepare.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/Prepare.java b/core/src/main/java/org/apache/calcite/prepare/Prepare.java
index 5892fa9..8ff5c0d 100644
--- a/core/src/main/java/org/apache/calcite/prepare/Prepare.java
+++ b/core/src/main/java/org/apache/calcite/prepare/Prepare.java
@@ -28,7 +28,9 @@ import org.apache.calcite.plan.RelOptSchema;
 import org.apache.calcite.plan.RelOptTable;
 import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.Sort;
 import org.apache.calcite.rel.logical.LogicalTableModify;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rex.RexExecutorImpl;
@@ -55,6 +57,7 @@ import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 
 import java.lang.reflect.Type;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.logging.Level;
@@ -76,6 +79,7 @@ public abstract class Prepare {
   protected final Convention resultConvention;
   protected CalciteTimingTracer timingTracer;
   protected List<List<String>> fieldOrigins;
+  protected final List<RelCollation> collations = new ArrayList<>();
   protected RelDataType parameterRowType;
 
   // temporary. for testing.
@@ -226,6 +230,11 @@ public abstract class Prepare {
       timingTracer.traceTime("end sql2rel");
     }
 
+    assert collations.isEmpty();
+    if (rootRel instanceof Sort) {
+      collations.add(((Sort) rootRel).getCollation());
+    }
+
     final RelDataType resultType = validator.getValidatedNodeType(sqlQuery);
     fieldOrigins = validator.getFieldOrigins(sqlQuery);
     assert fieldOrigins.size() == resultType.getFieldCount();
@@ -500,17 +509,20 @@ public abstract class Prepare {
     protected final boolean isDml;
     protected final LogicalTableModify.Operation tableModOp;
     protected final List<List<String>> fieldOrigins;
+    protected final List<RelCollation> collations;
 
     public PreparedResultImpl(
         RelDataType rowType,
         RelDataType parameterRowType,
         List<List<String>> fieldOrigins,
+        List<RelCollation> collations,
         RelNode rootRel,
         LogicalTableModify.Operation tableModOp,
         boolean isDml) {
       this.rowType = Preconditions.checkNotNull(rowType);
       this.parameterRowType = Preconditions.checkNotNull(parameterRowType);
       this.fieldOrigins = Preconditions.checkNotNull(fieldOrigins);
+      this.collations = ImmutableList.copyOf(collations);
       this.rootRel = Preconditions.checkNotNull(rootRel);
       this.tableModOp = tableModOp;
       this.isDml = isDml;

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/87e7454c/core/src/main/java/org/apache/calcite/rel/RelCollations.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/RelCollations.java b/core/src/main/java/org/apache/calcite/rel/RelCollations.java
index 2ee3b59..36f1327 100644
--- a/core/src/main/java/org/apache/calcite/rel/RelCollations.java
+++ b/core/src/main/java/org/apache/calcite/rel/RelCollations.java
@@ -63,14 +63,20 @@ public class RelCollations {
   }
 
   /**
+   * Creates a collation containing one field.
+   */
+  public static RelCollation of(int fieldIndex) {
+    return of(
+        new RelFieldCollation(fieldIndex,
+            RelFieldCollation.Direction.ASCENDING,
+            RelFieldCollation.NullDirection.UNSPECIFIED));
+  }
+
+  /**
    * Creates a list containing one collation containing one field.
    */
   public static List<RelCollation> createSingleton(int fieldIndex) {
-    return ImmutableList.of(
-        of(
-            new RelFieldCollation(fieldIndex,
-                RelFieldCollation.Direction.ASCENDING,
-                RelFieldCollation.NullDirection.UNSPECIFIED)));
+    return ImmutableList.of(of(fieldIndex));
   }
 
   /**


[13/18] incubator-calcite git commit: [CALCITE-819] Add RelRoot, a contract for the result of a relational expression

Posted by jh...@apache.org.
[CALCITE-819] Add RelRoot, a contract for the result of a relational expression

Remove PRESERVE collation


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

Branch: refs/heads/master
Commit: 5a3970635030ddde27e4237da5d8c5c3419c34b5
Parents: 0c1a135
Author: Julian Hyde <jh...@apache.org>
Authored: Thu Aug 13 01:00:09 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Sep 1 16:17:16 2015 -0700

----------------------------------------------------------------------
 .../adapter/enumerable/EnumerableProject.java   |   3 +-
 .../enumerable/EnumerableProjectRule.java       |  15 +-
 .../apache/calcite/interpreter/ProjectNode.java |   2 +-
 .../org/apache/calcite/jdbc/CalcitePrepare.java |  11 +-
 .../org/apache/calcite/materialize/Lattice.java |   2 +-
 .../org/apache/calcite/plan/RelOptTable.java    |   5 +-
 .../org/apache/calcite/plan/RelOptUtil.java     |   7 +-
 .../calcite/prepare/CalciteMaterializer.java    |   2 +-
 .../calcite/prepare/CalcitePrepareImpl.java     | 102 ++++---
 .../calcite/prepare/LixToRelTranslator.java     |   3 +-
 .../org/apache/calcite/prepare/PlannerImpl.java |  29 +-
 .../org/apache/calcite/prepare/Prepare.java     | 103 +++----
 .../calcite/rel/RelCollationTraitDef.java       |   6 +-
 .../org/apache/calcite/rel/RelCollations.java   |   1 +
 .../java/org/apache/calcite/rel/RelInput.java   |   6 +
 .../java/org/apache/calcite/rel/RelRoot.java    | 171 ++++++++++++
 .../java/org/apache/calcite/rel/SingleRel.java  |   2 +-
 .../calcite/rel/externalize/RelJsonReader.java  |  40 ++-
 .../rel/rules/AggregateStarTableRule.java       |   4 +-
 .../java/org/apache/calcite/rex/RexUtil.java    |   4 -
 .../apache/calcite/schema/impl/ViewTable.java   |  16 +-
 .../sql2rel/RelStructuredTypeFlattener.java     |  13 +-
 .../calcite/sql2rel/SqlToRelConverter.java      | 274 ++++++++++---------
 .../java/org/apache/calcite/tools/Planner.java  |   5 +
 .../java/org/apache/calcite/tools/Programs.java |  13 +-
 .../java/org/apache/calcite/tools/RuleSets.java |   3 +-
 .../apache/calcite/util/ImmutableIntList.java   |   6 +-
 .../apache/calcite/test/InterpreterTest.java    |  13 +
 .../calcite/test/JdbcFrontLinqBackTest.java     |  13 +-
 .../java/org/apache/calcite/test/JdbcTest.java  |   8 +-
 .../apache/calcite/test/RelMetadataTest.java    |   9 +-
 .../apache/calcite/test/RelOptRulesTest.java    |  28 +-
 .../org/apache/calcite/test/RelOptTestBase.java |   4 +-
 .../apache/calcite/test/RexTransformerTest.java |   6 +-
 .../calcite/test/SqlToRelConverterTest.java     |   2 +-
 .../apache/calcite/test/SqlToRelTestBase.java   |  19 +-
 .../org/apache/calcite/tools/PlannerTest.java   |  29 +-
 .../calcite/test/SqlToRelConverterTest.xml      |  15 +-
 core/src/test/resources/sql/sort.oq             |  13 +
 39 files changed, 617 insertions(+), 390 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProject.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProject.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProject.java
index 9ab0fb2..e6852f7 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProject.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProject.java
@@ -63,7 +63,8 @@ public class EnumerableProject extends Project implements EnumerableRel {
     Util.discard(flags);
   }
 
-  /** Creates a LogicalProject, specifying row type rather than field names. */
+  /** Creates an EnumerableProject, specifying row type rather than field
+   * names. */
   public static EnumerableProject create(final RelNode input,
       final List<? extends RexNode> projects, RelDataType rowType) {
     final RelOptCluster cluster = input.getCluster();

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectRule.java
index 459e025..3f998da 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectRule.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectRule.java
@@ -18,8 +18,6 @@ package org.apache.calcite.adapter.enumerable;
 
 import org.apache.calcite.plan.Convention;
 import org.apache.calcite.plan.RelOptUtil;
-import org.apache.calcite.rel.RelCollationTraitDef;
-import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.convert.ConverterRule;
 import org.apache.calcite.rel.logical.LogicalProject;
@@ -36,18 +34,7 @@ class EnumerableProjectRule extends ConverterRule {
 
   public RelNode convert(RelNode rel) {
     final LogicalProject project = (LogicalProject) rel;
-    if (rel.getTraitSet().getTrait(RelCollationTraitDef.INSTANCE)
-        != RelCollations.PRESERVE) {
-      return EnumerableProject.create(
-          convert(project.getInput(),
-              project.getInput().getTraitSet()
-                  .replace(EnumerableConvention.INSTANCE)),
-          project.getProjects(),
-          project.getRowType());
-    }
-    // Special case for PRESERVE, to hand-create collation.
-    return new EnumerableProject(rel.getCluster(),
-        rel.getTraitSet().replace(EnumerableConvention.INSTANCE),
+    return EnumerableProject.create(
         convert(project.getInput(),
             project.getInput().getTraitSet()
                 .replace(EnumerableConvention.INSTANCE)),

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/main/java/org/apache/calcite/interpreter/ProjectNode.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/ProjectNode.java b/core/src/main/java/org/apache/calcite/interpreter/ProjectNode.java
index 576bf6f..4c280b7 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/ProjectNode.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/ProjectNode.java
@@ -20,7 +20,7 @@ import org.apache.calcite.rel.core.Project;
 
 /**
  * Interpreter node that implements a
- * {@link org.apache.calcite.rel.logical.LogicalFilter}.
+ * {@link org.apache.calcite.rel.core.Project}.
  */
 public class ProjectNode extends AbstractSingleNode<Project> {
   private final Scalar scalar;

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java b/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
index fe2f898..ae5fba4 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
@@ -32,6 +32,7 @@ import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.prepare.CalcitePrepareImpl;
 import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.RelRoot;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rex.RexNode;
@@ -226,12 +227,12 @@ public interface CalcitePrepare {
   /** The result of parsing and validating a SQL query and converting it to
    * relational algebra. */
   class ConvertResult extends ParseResult {
-    public final RelNode relNode;
+    public final RelRoot root;
 
     public ConvertResult(CalcitePrepareImpl prepare, SqlValidator validator,
-        String sql, SqlNode sqlNode, RelDataType rowType, RelNode relNode) {
+        String sql, SqlNode sqlNode, RelDataType rowType, RelRoot root) {
       super(prepare, validator, sql, sqlNode, rowType);
-      this.relNode = relNode;
+      this.root = root;
     }
   }
 
@@ -245,10 +246,10 @@ public interface CalcitePrepare {
 
     public AnalyzeViewResult(CalcitePrepareImpl prepare,
         SqlValidator validator, String sql, SqlNode sqlNode,
-        RelDataType rowType, RelNode relNode, Table table,
+        RelDataType rowType, RelRoot root, Table table,
         ImmutableList<String> tablePath, RexNode constraint,
         ImmutableIntList columnMapping) {
-      super(prepare, validator, sql, sqlNode, rowType, relNode);
+      super(prepare, validator, sql, sqlNode, rowType, root);
       this.table = table;
       this.tablePath = tablePath;
       this.constraint = constraint;

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/main/java/org/apache/calcite/materialize/Lattice.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/materialize/Lattice.java b/core/src/main/java/org/apache/calcite/materialize/Lattice.java
index c2b07c3..ee7fef6 100644
--- a/core/src/main/java/org/apache/calcite/materialize/Lattice.java
+++ b/core/src/main/java/org/apache/calcite/materialize/Lattice.java
@@ -584,7 +584,7 @@ public class Lattice {
       // Walk the join tree.
       List<RelNode> relNodes = Lists.newArrayList();
       List<int[][]> tempLinks = Lists.newArrayList();
-      populate(relNodes, tempLinks, parsed.relNode);
+      populate(relNodes, tempLinks, parsed.root.rel);
 
       // Get aliases.
       List<String> aliases = Lists.newArrayList();

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/main/java/org/apache/calcite/plan/RelOptTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptTable.java b/core/src/main/java/org/apache/calcite/plan/RelOptTable.java
index 8f34ed4..56d01d7 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptTable.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptTable.java
@@ -20,6 +20,7 @@ import org.apache.calcite.linq4j.tree.Expression;
 import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelDistribution;
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.RelRoot;
 import org.apache.calcite.rel.metadata.RelMetadataQuery;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeField;
@@ -112,9 +113,7 @@ public interface RelOptTable {
 
   /** Can expand a view into relational expressions. */
   interface ViewExpander {
-    RelNode expandView(
-        RelDataType rowType,
-        String queryString,
+    RelRoot expandView(RelDataType rowType, String queryString,
         List<String> schemaPath);
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/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 76af520..7762bf7 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
@@ -19,6 +19,7 @@ package org.apache.calcite.plan;
 import org.apache.calcite.linq4j.Ord;
 import org.apache.calcite.rel.RelHomogeneousShuttle;
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.RelRoot;
 import org.apache.calcite.rel.RelShuttle;
 import org.apache.calcite.rel.RelVisitor;
 import org.apache.calcite.rel.RelWriter;
@@ -385,6 +386,7 @@ public abstract class RelOptUtil {
           AggregateCall.create(minFunction,
               false,
               ImmutableList.of(0),
+              -1,
               0,
               ret,
               null,
@@ -462,6 +464,7 @@ public abstract class RelOptUtil {
           AggregateCall.create(minFunction,
               false,
               ImmutableList.of(projectedKeyCount),
+              -1,
               projectedKeyCount,
               ret,
               null,
@@ -2566,9 +2569,7 @@ public abstract class RelOptUtil {
         return cluster;
       }
 
-      public RelNode expandView(
-          RelDataType rowType,
-          String queryString,
+      public RelRoot expandView(RelDataType rowType, String queryString,
           List<String> schemaPath) {
         throw new UnsupportedOperationException();
       }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/main/java/org/apache/calcite/prepare/CalciteMaterializer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/CalciteMaterializer.java b/core/src/main/java/org/apache/calcite/prepare/CalciteMaterializer.java
index 901dcb8..36f621e 100644
--- a/core/src/main/java/org/apache/calcite/prepare/CalciteMaterializer.java
+++ b/core/src/main/java/org/apache/calcite/prepare/CalciteMaterializer.java
@@ -81,7 +81,7 @@ class CalciteMaterializer extends CalcitePrepareImpl.CalcitePreparingStmt {
         getSqlToRelConverter(getSqlValidator(), catalogReader);
 
     materialization.queryRel =
-        sqlToRelConverter2.convertQuery(node, true, true);
+        sqlToRelConverter2.convertQuery(node, true, true).rel;
 
     // Identify and substitute a StarTable in queryRel.
     //

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
index 524e34f..3f9293c 100644
--- a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
@@ -18,6 +18,7 @@ package org.apache.calcite.prepare;
 
 import org.apache.calcite.DataContext;
 import org.apache.calcite.adapter.enumerable.EnumerableBindable;
+import org.apache.calcite.adapter.enumerable.EnumerableCalc;
 import org.apache.calcite.adapter.enumerable.EnumerableConvention;
 import org.apache.calcite.adapter.enumerable.EnumerableInterpretable;
 import org.apache.calcite.adapter.enumerable.EnumerableInterpreterRule;
@@ -64,7 +65,9 @@ import org.apache.calcite.plan.hep.HepProgramBuilder;
 import org.apache.calcite.plan.volcano.VolcanoPlanner;
 import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelCollationTraitDef;
+import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.RelRoot;
 import org.apache.calcite.rel.core.Filter;
 import org.apache.calcite.rel.core.Project;
 import org.apache.calcite.rel.core.TableScan;
@@ -94,6 +97,7 @@ 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.RexProgram;
 import org.apache.calcite.runtime.Bindable;
 import org.apache.calcite.runtime.Hook;
 import org.apache.calcite.runtime.Typed;
@@ -117,6 +121,7 @@ import org.apache.calcite.sql2rel.SqlToRelConverter;
 import org.apache.calcite.sql2rel.StandardConvertletTable;
 import org.apache.calcite.tools.Frameworks;
 import org.apache.calcite.util.ImmutableIntList;
+import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Util;
 
 import com.google.common.collect.ImmutableList;
@@ -293,17 +298,18 @@ public class CalcitePrepareImpl implements CalcitePrepare {
     if (analyze) {
       converter.enableTableAccessConversion(false);
     }
-    final RelNode relNode = converter.convertQuery(sqlNode1, false, true);
+    final RelRoot root = converter.convertQuery(sqlNode1, false, true);
     if (analyze) {
-      return analyze_(validator, sql, sqlNode1, relNode, fail);
+      return analyze_(validator, sql, sqlNode1, root, fail);
     }
     return new ConvertResult(this, validator, sql, sqlNode1,
-        validator.getValidatedNodeType(sqlNode1), relNode);
+        validator.getValidatedNodeType(sqlNode1), root);
   }
 
   private AnalyzeViewResult analyze_(SqlValidator validator, String sql,
-      SqlNode sqlNode, RelNode rel, boolean fail) {
-    final RexBuilder rexBuilder = rel.getCluster().getRexBuilder();
+      SqlNode sqlNode, RelRoot root, boolean fail) {
+    final RexBuilder rexBuilder = root.rel.getCluster().getRexBuilder();
+    RelNode rel = root.rel;
     final RelNode viewRel = rel;
     Project project;
     if (rel instanceof Project) {
@@ -331,7 +337,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
             RESOURCE.modifiableViewMustBeBasedOnSingleTable());
       }
       return new AnalyzeViewResult(this, validator, sql, sqlNode,
-          validator.getValidatedNodeType(sqlNode), rel, null, null, null,
+          validator.getValidatedNodeType(sqlNode), root, null, null, null,
           null);
     }
     final RelOptTable targetRelTable = scan.getTable();
@@ -357,7 +363,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
                       Util.last(tablePath)));
             }
             return new AnalyzeViewResult(this, validator, sql, sqlNode,
-                validator.getValidatedNodeType(sqlNode), rel, null, null, null,
+                validator.getValidatedNodeType(sqlNode), root, null, null, null,
                 null);
           }
           projectMap.put(index, rexBuilder.makeInputRef(viewRel, node.i));
@@ -396,12 +402,12 @@ public class CalcitePrepareImpl implements CalcitePrepare {
                 Util.last(tablePath)));
       }
       return new AnalyzeViewResult(this, validator, sql, sqlNode,
-          validator.getValidatedNodeType(sqlNode), rel, null, null, null,
+          validator.getValidatedNodeType(sqlNode), root, null, null, null,
           null);
     }
 
     return new AnalyzeViewResult(this, validator, sql, sqlNode,
-        validator.getValidatedNodeType(sqlNode), rel, table,
+        validator.getValidatedNodeType(sqlNode), root, table,
         ImmutableList.copyOf(tablePath),
         constraint, ImmutableIntList.copyOf(columnMapping));
   }
@@ -594,7 +600,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
         getColumnMetaDataList(typeFactory, x, x, origins);
     final Meta.CursorFactory cursorFactory =
         Meta.CursorFactory.deduce(columns, null);
-    return new CalciteSignature<T>(
+    return new CalciteSignature<>(
         sql,
         ImmutableList.<AvaticaParameter>of(),
         ImmutableMap.<String, Object>of(),
@@ -688,7 +694,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
           preparingStmt.prepareQueryable(queryable, x);
     }
 
-    final List<AvaticaParameter> parameters = new ArrayList<AvaticaParameter>();
+    final List<AvaticaParameter> parameters = new ArrayList<>();
     final RelDataType parameterRowType = preparedResult.getParameterRowType();
     for (RelDataTypeField field : parameterRowType.getFieldList()) {
       RelDataType type = field.getType();
@@ -732,7 +738,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
   private List<ColumnMetaData> getColumnMetaDataList(
       JavaTypeFactory typeFactory, RelDataType x, RelDataType jdbcType,
       List<List<String>> originList) {
-    final List<ColumnMetaData> columns = new ArrayList<ColumnMetaData>();
+    final List<ColumnMetaData> columns = new ArrayList<>();
     for (Ord<RelDataTypeField> pair : Ord.zip(jdbcType.getFieldList())) {
       final RelDataTypeField field = pair.e;
       final RelDataType type = field.getType();
@@ -931,9 +937,15 @@ public class CalcitePrepareImpl implements CalcitePrepare {
 
       final RelOptCluster cluster = prepare.createCluster(planner, rexBuilder);
 
-      RelNode rootRel =
+      final RelNode rel =
           new LixToRelTranslator(cluster, CalcitePreparingStmt.this)
               .translate(queryable);
+      final RelDataType rowType = rel.getRowType();
+      final List<Pair<Integer, String>> fields =
+          Pair.zip(ImmutableIntList.identity(rowType.getFieldCount()),
+              rowType.getFieldNames());
+      RelRoot root = new RelRoot(rel, resultType, SqlKind.SELECT, fields,
+          RelCollations.EMPTY);
 
       if (timingTracer != null) {
         timingTracer.traceTime("end sql2rel");
@@ -946,23 +958,20 @@ public class CalcitePrepareImpl implements CalcitePrepare {
 
       // Structured type flattening, view expansion, and plugging in
       // physical storage.
-      rootRel = flattenTypes(rootRel, true);
+      root = root.withRel(flattenTypes(root.rel, true));
 
       // Trim unused fields.
-      rootRel = trimUnusedFields(rootRel);
+      root = trimUnusedFields(root);
 
       final List<Materialization> materializations = ImmutableList.of();
       final List<CalciteSchema.LatticeEntry> lattices = ImmutableList.of();
-      rootRel = optimize(rootRel, materializations, lattices);
+      root = optimize(root, materializations, lattices);
 
       if (timingTracer != null) {
         timingTracer.traceTime("end optimization");
       }
 
-      return implement(
-          resultType,
-          rootRel,
-          SqlKind.SELECT);
+      return implement(root);
     }
 
     @Override protected SqlToRelConverter getSqlToRelConverter(
@@ -991,9 +1000,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
       return sqlToRelConverter.decorrelate(query, rootRel);
     }
 
-    @Override public RelNode expandView(
-        RelDataType rowType,
-        String queryString,
+    @Override public RelRoot expandView(RelDataType rowType, String queryString,
         List<String> schemaPath) {
       expansionDepth++;
 
@@ -1012,11 +1019,11 @@ public class CalcitePrepareImpl implements CalcitePrepare {
 
       SqlToRelConverter sqlToRelConverter =
           getSqlToRelConverter(validator, catalogReader);
-      RelNode relNode =
+      RelRoot root =
           sqlToRelConverter.convertQuery(sqlNode1, true, false);
 
       --expansionDepth;
-      return relNode;
+      return root;
     }
 
     private SqlValidatorImpl createSqlValidator(CatalogReader catalogReader) {
@@ -1035,25 +1042,34 @@ public class CalcitePrepareImpl implements CalcitePrepare {
     @Override protected PreparedResult createPreparedExplanation(
         RelDataType resultType,
         RelDataType parameterRowType,
-        RelNode rootRel,
+        RelRoot root,
         boolean explainAsXml,
         SqlExplainLevel detailLevel) {
       return new CalcitePreparedExplain(
-          resultType, parameterRowType, rootRel, explainAsXml, detailLevel);
+          resultType, parameterRowType, root, explainAsXml, detailLevel);
     }
 
-    @Override protected PreparedResult implement(
-        RelDataType rowType,
-        RelNode rootRel,
-        SqlKind sqlKind) {
-      RelDataType resultType = rootRel.getRowType();
-      boolean isDml = sqlKind.belongsTo(SqlKind.DML);
+    @Override protected PreparedResult implement(RelRoot root) {
+      RelDataType resultType = root.rel.getRowType();
+      boolean isDml = root.kind.belongsTo(SqlKind.DML);
       final Bindable bindable;
       if (resultConvention == BindableConvention.INSTANCE) {
-        bindable = Interpreters.bindable(rootRel);
+        bindable = Interpreters.bindable(root.rel);
       } else {
+        EnumerableRel enumerable = (EnumerableRel) root.rel;
+        if (!root.isRefTrivial()) {
+          final List<RexNode> projects = new ArrayList<>();
+          final RexBuilder rexBuilder = enumerable.getCluster().getRexBuilder();
+          for (int field : Pair.left(root.fields)) {
+            projects.add(rexBuilder.makeInputRef(enumerable, field));
+          }
+          RexProgram program = RexProgram.create(enumerable.getRowType(),
+              projects, null, root.validatedRowType, rexBuilder);
+          enumerable = EnumerableCalc.create(enumerable, program);
+        }
+
         bindable = EnumerableInterpretable.toBindable(internalParameters,
-            context.spark(), (EnumerableRel) rootRel, prefer);
+            context.spark(), enumerable, prefer);
       }
 
       if (timingTracer != null) {
@@ -1068,9 +1084,11 @@ public class CalcitePrepareImpl implements CalcitePrepare {
           resultType,
           parameterRowType,
           fieldOrigins,
-          ImmutableList.copyOf(collations),
-          rootRel,
-          mapTableModOp(isDml, sqlKind),
+          root.collation.getFieldCollations().isEmpty()
+              ? ImmutableList.<RelCollation>of()
+              : ImmutableList.of(root.collation),
+          root.rel,
+          mapTableModOp(isDml, root.kind),
           isDml) {
         public String getCode() {
           throw new UnsupportedOperationException();
@@ -1092,10 +1110,10 @@ public class CalcitePrepareImpl implements CalcitePrepare {
     public CalcitePreparedExplain(
         RelDataType resultType,
         RelDataType parameterRowType,
-        RelNode rootRel,
+        RelRoot root,
         boolean explainAsXml,
         SqlExplainLevel detailLevel) {
-      super(resultType, parameterRowType, rootRel, explainAsXml, detailLevel);
+      super(resultType, parameterRowType, root, explainAsXml, detailLevel);
     }
 
     public Bindable getBindable() {
@@ -1131,7 +1149,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
 
     public List<RexNode> toRexList(BlockStatement statement) {
       final List<Expression> simpleList = simpleList(statement);
-      final List<RexNode> list = new ArrayList<RexNode>();
+      final List<RexNode> list = new ArrayList<>();
       for (Expression expression1 : simpleList) {
         list.add(toRex(expression1));
       }
@@ -1216,7 +1234,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
     }
 
     private List<RexNode> toRex(List<Expression> expressions) {
-      ArrayList<RexNode> list = new ArrayList<RexNode>();
+      final List<RexNode> list = new ArrayList<>();
       for (Expression expression : expressions) {
         list.add(toRex(expression));
       }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/main/java/org/apache/calcite/prepare/LixToRelTranslator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/LixToRelTranslator.java b/core/src/main/java/org/apache/calcite/prepare/LixToRelTranslator.java
index ed1671c..4f6a94f 100644
--- a/core/src/main/java/org/apache/calcite/prepare/LixToRelTranslator.java
+++ b/core/src/main/java/org/apache/calcite/prepare/LixToRelTranslator.java
@@ -28,6 +28,7 @@ import org.apache.calcite.linq4j.tree.Types;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptTable;
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.RelRoot;
 import org.apache.calcite.rel.logical.LogicalFilter;
 import org.apache.calcite.rel.logical.LogicalProject;
 import org.apache.calcite.rel.logical.LogicalTableScan;
@@ -63,7 +64,7 @@ class LixToRelTranslator implements RelOptTable.ToRelContext {
     return cluster;
   }
 
-  public RelNode expandView(RelDataType rowType, String queryString,
+  public RelRoot expandView(RelDataType rowType, String queryString,
       List<String> schemaPath) {
     return preparingStmt.expandView(rowType, queryString, schemaPath);
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java b/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java
index 1c67178..d58cfd8 100644
--- a/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java
@@ -25,6 +25,7 @@ import org.apache.calcite.plan.RelOptTable.ViewExpander;
 import org.apache.calcite.plan.RelTraitDef;
 import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.RelRoot;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.schema.SchemaPlus;
@@ -75,7 +76,7 @@ public class PlannerImpl implements Planner {
   private SqlNode validatedSqlNode;
 
   // set in STATE_5_CONVERT
-  private RelNode rel;
+  private RelRoot root;
 
   /** Creates a planner. Not a public API; call
    * {@link org.apache.calcite.tools.Frameworks#getPlanner} instead. */
@@ -178,7 +179,11 @@ public class PlannerImpl implements Planner {
     return validatedSqlNode;
   }
 
-  public RelNode convert(SqlNode sql) throws RelConversionException {
+  public final RelNode convert(SqlNode sql) throws RelConversionException {
+    return rel(sql).rel;
+  }
+
+  public RelRoot rel(SqlNode sql) throws RelConversionException {
     ensure(State.STATE_4_VALIDATED);
     assert validatedSqlNode != null;
     final RexBuilder rexBuilder = createRexBuilder();
@@ -188,17 +193,18 @@ public class PlannerImpl implements Planner {
             createCatalogReader(), cluster, convertletTable);
     sqlToRelConverter.setTrimUnusedFields(false);
     sqlToRelConverter.enableTableAccessConversion(false);
-    rel = sqlToRelConverter.convertQuery(validatedSqlNode, false, true);
-    rel = sqlToRelConverter.flattenTypes(rel, true);
-    rel = RelDecorrelator.decorrelateQuery(rel);
+    root =
+        sqlToRelConverter.convertQuery(validatedSqlNode, false, true);
+    root = root.withRel(sqlToRelConverter.flattenTypes(root.rel, true));
+    root = root.withRel(RelDecorrelator.decorrelateQuery(root.rel));
     state = State.STATE_5_CONVERTED;
-    return rel;
+    return root;
   }
 
   /** Implements {@link org.apache.calcite.plan.RelOptTable.ViewExpander}
    * interface for {@link org.apache.calcite.tools.Planner}. */
   public class ViewExpanderImpl implements ViewExpander {
-    public RelNode expandView(RelDataType rowType, String queryString,
+    public RelRoot expandView(RelDataType rowType, String queryString,
         List<String> schemaPath) {
       SqlParser parser = SqlParser.create(queryString, parserConfig);
       SqlNode sqlNode;
@@ -224,12 +230,11 @@ public class PlannerImpl implements Planner {
       sqlToRelConverter.setTrimUnusedFields(false);
       sqlToRelConverter.enableTableAccessConversion(false);
 
-      RelNode rel =
-          sqlToRelConverter.convertQuery(validatedSqlNode, true, false);
-      rel = sqlToRelConverter.flattenTypes(rel, true);
-      rel = RelDecorrelator.decorrelateQuery(rel);
+      root = sqlToRelConverter.convertQuery(validatedSqlNode, true, false);
+      root = root.withRel(sqlToRelConverter.flattenTypes(root.rel, true));
+      root = root.withRel(RelDecorrelator.decorrelateQuery(root.rel));
 
-      return rel;
+      return PlannerImpl.this.root;
     }
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/main/java/org/apache/calcite/prepare/Prepare.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/Prepare.java b/core/src/main/java/org/apache/calcite/prepare/Prepare.java
index 403ad76..43ae738 100644
--- a/core/src/main/java/org/apache/calcite/prepare/Prepare.java
+++ b/core/src/main/java/org/apache/calcite/prepare/Prepare.java
@@ -30,7 +30,7 @@ import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelNode;
-import org.apache.calcite.rel.core.Sort;
+import org.apache.calcite.rel.RelRoot;
 import org.apache.calcite.rel.logical.LogicalTableModify;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rex.RexExecutorImpl;
@@ -57,7 +57,6 @@ import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 
 import java.lang.reflect.Type;
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.logging.Level;
@@ -79,8 +78,6 @@ public abstract class Prepare {
   protected final Convention resultConvention;
   protected CalciteTimingTracer timingTracer;
   protected List<List<String>> fieldOrigins;
-  protected final List<RelCollation> collations = new ArrayList<>();
-  protected boolean ordered;
   protected RelDataType parameterRowType;
 
   // temporary. for testing.
@@ -102,26 +99,26 @@ public abstract class Prepare {
   protected abstract PreparedResult createPreparedExplanation(
       RelDataType resultType,
       RelDataType parameterRowType,
-      RelNode rootRel,
+      RelRoot root,
       boolean explainAsXml,
       SqlExplainLevel detailLevel);
 
   /**
    * Optimizes a query plan.
    *
-   * @param rootRel root of a relational expression
+   * @param root Root of relational expression tree
    * @param materializations Tables known to be populated with a given query
    * @param lattices Lattices
    * @return an equivalent optimized relational expression
    */
-  protected RelNode optimize(final RelNode rootRel,
+  protected RelRoot optimize(final RelRoot root,
       final List<Materialization> materializations,
       final List<CalciteSchema.LatticeEntry> lattices) {
-    final RelOptPlanner planner = rootRel.getCluster().getPlanner();
+    final RelOptPlanner planner = root.rel.getCluster().getPlanner();
 
-    planner.setRoot(rootRel);
+    planner.setRoot(root.rel);
 
-    final RelTraitSet desiredTraits = getDesiredRootTraitSet(rootRel);
+    final RelTraitSet desiredTraits = getDesiredRootTraitSet(root);
     final Program program = getProgram();
 
     final DataContext dataContext = context.getDataContext();
@@ -144,14 +141,14 @@ public abstract class Prepare {
           new RelOptLattice(lattice.getLattice(), starRelOptTable));
     }
 
-    final RelNode rootRel4 = program.run(planner, rootRel, desiredTraits);
+    final RelNode rootRel4 = program.run(planner, root.rel, desiredTraits);
     if (LOGGER.isLoggable(Level.FINE)) {
       LOGGER.fine(
           "Plan after physical tweaks: "
           + RelOptUtil.toString(rootRel4, SqlExplainLevel.ALL_ATTRIBUTES));
     }
 
-    return rootRel4;
+    return root.withRel(rootRel4);
   }
 
   private Program getProgram() {
@@ -166,22 +163,21 @@ public abstract class Prepare {
     return Programs.standard();
   }
 
-  protected RelTraitSet getDesiredRootTraitSet(RelNode rootRel) {
+  protected RelTraitSet getDesiredRootTraitSet(RelRoot root) {
     // Make sure non-CallingConvention traits, if any, are preserved
-    return rootRel.getTraitSet()
-        .replace(resultConvention).simplify();
+    return root.rel.getTraitSet()
+        .replace(resultConvention)
+        .replace(root.collation)
+        .simplify();
   }
 
   /**
    * Implements a physical query plan.
    *
-   * @param rowType original row type returned by query validator
-   * @param rootRel root of the relational expression.
-   * @param sqlKind SqlKind of the original statement.
+   * @param root Root of the relational expression tree
    * @return an executable plan
    */
-  protected abstract PreparedResult implement(
-      RelDataType rowType, RelNode rootRel, SqlKind sqlKind);
+  protected abstract PreparedResult implement(RelRoot root);
 
   public PreparedResult prepareSql(
       SqlNode sqlQuery,
@@ -223,23 +219,14 @@ public abstract class Prepare {
       sqlToRelConverter.setIsExplain(sqlExplain.getDynamicParamCount());
     }
 
-    RelNode rootRel =
+    RelRoot root =
         sqlToRelConverter.convertQuery(sqlQuery, needsValidation, true);
-    Hook.CONVERTED.run(rootRel);
+    Hook.CONVERTED.run(root.rel);
 
     if (timingTracer != null) {
       timingTracer.traceTime("end sql2rel");
     }
 
-    // A query can have 0 collations and still be ordered (if it is ordered
-    // on a non-projected expression). But otherwise,
-    // ordered == !collations.isEmpty().
-    ordered = !SqlToRelConverter.isUnordered(sqlQuery);
-    assert collations.isEmpty();
-    if (rootRel instanceof Sort) {
-      collations.add(((Sort) rootRel).getCollation());
-    }
-
     final RelDataType resultType = validator.getValidatedNodeType(sqlQuery);
     fieldOrigins = validator.getFieldOrigins(sqlQuery);
     assert fieldOrigins.size() == resultType.getFieldCount();
@@ -258,24 +245,24 @@ public abstract class Prepare {
             resultType, parameterRowType, null, explainAsXml, detailLevel);
       case LOGICAL:
         return createPreparedExplanation(
-            null, parameterRowType, rootRel, explainAsXml, detailLevel);
+            null, parameterRowType, root, explainAsXml, detailLevel);
       default:
       }
     }
 
     // Structured type flattening, view expansion, and plugging in physical
     // storage.
-    rootRel = flattenTypes(rootRel, true);
+    root = root.withRel(flattenTypes(root.rel, true));
 
     if (this.context.config().forceDecorrelate()) {
       // Subquery decorrelation.
-      rootRel = decorrelate(sqlToRelConverter, sqlQuery, rootRel);
+      root = root.withRel(decorrelate(sqlToRelConverter, sqlQuery, root.rel));
     }
 
     // Trim unused fields.
-    rootRel = trimUnusedFields(rootRel);
+    root = trimUnusedFields(root);
 
-    Hook.TRIMMED.run(rootRel);
+    Hook.TRIMMED.run(root.rel);
 
     // Display physical plan after decorrelation.
     if (sqlExplain != null) {
@@ -285,13 +272,13 @@ public abstract class Prepare {
       switch (explainDepth) {
       case PHYSICAL:
       default:
-        rootRel = optimize(rootRel, materializations, lattices);
+        root = optimize(root, materializations, lattices);
         return createPreparedExplanation(
-            null, parameterRowType, rootRel, explainAsXml, detailLevel);
+            null, parameterRowType, root, explainAsXml, detailLevel);
       }
     }
 
-    rootRel = optimize(rootRel, materializations, lattices);
+    root = optimize(root, materializations, lattices);
 
     if (timingTracer != null) {
       timingTracer.traceTime("end optimization");
@@ -300,14 +287,10 @@ public abstract class Prepare {
     // For transformation from DML -> DML, use result of rewrite
     // (e.g. UPDATE -> MERGE).  For anything else (e.g. CALL -> SELECT),
     // use original kind.
-    SqlKind kind = sqlQuery.getKind();
-    if (!kind.belongsTo(SqlKind.DML)) {
-      kind = sqlNodeOriginal.getKind();
+    if (!root.kind.belongsTo(SqlKind.DML)) {
+      root = root.withKind(sqlNodeOriginal.getKind());
     }
-    return implement(
-        resultType,
-        rootRel,
-        kind);
+    return implement(root);
   }
 
   protected LogicalTableModify.Operation mapTableModOp(
@@ -350,15 +333,17 @@ public abstract class Prepare {
    * expression that projects
    * only the columns required by its consumer.
    *
-   * @param rootRel Relational expression that is at the root of the tree
+   * @param root Root of relational expression tree
    * @return Trimmed relational expression
    */
-  protected RelNode trimUnusedFields(RelNode rootRel) {
+  protected RelRoot trimUnusedFields(RelRoot root) {
     final SqlToRelConverter converter =
         getSqlToRelConverter(
             getSqlValidator(), catalogReader);
-    converter.setTrimUnusedFields(shouldTrim(rootRel));
-    return converter.trimUnusedFields(ordered, rootRel);
+    converter.setTrimUnusedFields(shouldTrim(root.rel));
+    final boolean ordered = !root.collation.getFieldCollations().isEmpty();
+    final boolean dml = SqlKind.DML.contains(root.kind);
+    return root.withRel(converter.trimUnusedFields(dml || ordered, root.rel));
   }
 
   private boolean shouldTrim(RelNode rootRel) {
@@ -377,9 +362,7 @@ public abstract class Prepare {
    * @param schemaPath List of schema names wherein to find referenced tables
    * @return Relational expression
    */
-  public RelNode expandView(
-      RelDataType rowType,
-      String queryString,
+  public RelRoot expandView(RelDataType rowType, String queryString,
       List<String> schemaPath) {
     throw new UnsupportedOperationException();
   }
@@ -413,28 +396,28 @@ public abstract class Prepare {
       implements PreparedResult {
     private final RelDataType rowType;
     private final RelDataType parameterRowType;
-    private final RelNode rel;
+    private final RelRoot root;
     private final boolean asXml;
     private final SqlExplainLevel detailLevel;
 
     public PreparedExplain(
         RelDataType rowType,
         RelDataType parameterRowType,
-        RelNode rel,
+        RelRoot root,
         boolean asXml,
         SqlExplainLevel detailLevel) {
       this.rowType = rowType;
       this.parameterRowType = parameterRowType;
-      this.rel = rel;
+      this.root = root;
       this.asXml = asXml;
       this.detailLevel = detailLevel;
     }
 
     public String getCode() {
-      if (rel == null) {
+      if (root == null) {
         return RelOptUtil.dumpType(rowType);
       } else {
-        return RelOptUtil.dumpPlan("", rel, asXml, detailLevel);
+        return RelOptUtil.dumpPlan("", root.rel, asXml, detailLevel);
       }
     }
 
@@ -455,10 +438,6 @@ public abstract class Prepare {
           Collections.<String>nCopies(4, null));
     }
 
-    public RelNode getRel() {
-      return rel;
-    }
-
     public abstract Bindable getBindable();
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/main/java/org/apache/calcite/rel/RelCollationTraitDef.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/RelCollationTraitDef.java b/core/src/main/java/org/apache/calcite/rel/RelCollationTraitDef.java
index dee2596..aa3e8bf 100644
--- a/core/src/main/java/org/apache/calcite/rel/RelCollationTraitDef.java
+++ b/core/src/main/java/org/apache/calcite/rel/RelCollationTraitDef.java
@@ -64,10 +64,6 @@ public class RelCollationTraitDef extends RelTraitDef<RelCollation> {
       RelNode rel,
       RelCollation toCollation,
       boolean allowInfiniteCostConverters) {
-    if (toCollation == RelCollations.PRESERVE) {
-      return null;
-    }
-
     if (toCollation.getFieldCollations().isEmpty()) {
       // An empty sort doesn't make sense.
       return null;
@@ -87,7 +83,7 @@ public class RelCollationTraitDef extends RelTraitDef<RelCollation> {
 
   public boolean canConvert(
       RelOptPlanner planner, RelCollation fromTrait, RelCollation toTrait) {
-    return toTrait != RelCollations.PRESERVE;
+    return true;
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/main/java/org/apache/calcite/rel/RelCollations.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/RelCollations.java b/core/src/main/java/org/apache/calcite/rel/RelCollations.java
index 36f1327..07a7410 100644
--- a/core/src/main/java/org/apache/calcite/rel/RelCollations.java
+++ b/core/src/main/java/org/apache/calcite/rel/RelCollations.java
@@ -43,6 +43,7 @@ public class RelCollations {
    * A collation that cannot be replicated by applying a sort. The only
    * implementation choice is to apply operations that preserve order.
    */
+  @Deprecated // to be removed before 2.0
   public static final RelCollation PRESERVE =
       RelCollationTraitDef.INSTANCE.canonize(
           new RelCollationImpl(

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/main/java/org/apache/calcite/rel/RelInput.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/RelInput.java b/core/src/main/java/org/apache/calcite/rel/RelInput.java
index a8678cb..6179c04 100644
--- a/core/src/main/java/org/apache/calcite/rel/RelInput.java
+++ b/core/src/main/java/org/apache/calcite/rel/RelInput.java
@@ -78,6 +78,12 @@ public interface RelInput {
 
   List<RexNode> getExpressionList(String tag);
 
+  List<String> getStringList(String tag);
+
+  List<Integer> getIntegerList(String tag);
+
+  List<List<Integer>> getIntegerListList(String tag);
+
   RelDataType getRowType(String tag);
 
   RelDataType getRowType(String expressionsTag, String fieldsTag);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/main/java/org/apache/calcite/rel/RelRoot.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/RelRoot.java b/core/src/main/java/org/apache/calcite/rel/RelRoot.java
new file mode 100644
index 0000000..77f3782
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/rel/RelRoot.java
@@ -0,0 +1,171 @@
+/*
+ * 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.rel;
+
+import org.apache.calcite.rel.logical.LogicalProject;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rex.RexBuilder;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.util.ImmutableIntList;
+import org.apache.calcite.util.Pair;
+import org.apache.calcite.util.mapping.Mappings;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Root of a tree of {@link RelNode}.
+ *
+ * <p>One important reason that RelRoot exists is to deal with queries like
+ *
+ * <blockquote><code>SELECT name
+ * FROM emp
+ * ORDER BY empno DESC</code></blockquote>
+ *
+ * <p>Calcite knows that the result must be sorted, but cannot represent its
+ * sort order as a collation, because {@code empno} is not a field in the
+ * result.
+ *
+ * <p>Instead we represent this as
+ *
+ * <blockquote><code>RelRoot: {
+ *   rel: Sort($1 DESC)
+ *          Project(name, empno)
+ *            TableScan(EMP)
+ *   fields: [0]
+ *   collation: [1 DESC]
+ * }</code></blockquote>
+ *
+ * <p>Note that the {@code empno} field is present in the result, but the
+ * {@code fields} mask tells the consumer to throw it away.
+ *
+ * <p>Another use case is queries like this:
+ *
+ * <blockquote><code>SELECT name AS n, name AS n2, empno AS n
+ * FROM emp</code></blockquote>
+ *
+ * <p>The there are multiple uses of the {@code name} field. and there are
+ * multiple columns aliased as {@code n}. You can represent this as
+ *
+ * <blockquote><code>RelRoot: {
+ *   rel: Project(name, empno)
+ *          TableScan(EMP)
+ *   fields: [(0, "n"), (0, "n2"), (1, "n")]
+ *   collation: []
+ * }</code></blockquote>
+ */
+public class RelRoot {
+  public final RelNode rel;
+  public final RelDataType validatedRowType;
+  public final SqlKind kind;
+  public final ImmutableList<Pair<Integer, String>> fields;
+  public final RelCollation collation;
+
+  /**
+   * Creates a RelRoot.
+   *
+   * @param validatedRowType Original row type returned by query validator
+   * @param kind Type of query (SELECT, UPDATE, ...)
+   */
+
+  public RelRoot(RelNode rel, RelDataType validatedRowType, SqlKind kind,
+       List<Pair<Integer, String>> fields, RelCollation collation) {
+    this.rel = rel;
+    this.validatedRowType = validatedRowType;
+    this.kind = kind;
+    this.fields = ImmutableList.copyOf(fields);
+    this.collation = Preconditions.checkNotNull(collation);
+  }
+
+  /** Creates a simple RelRoot. */
+  public static RelRoot of(RelNode rel, SqlKind kind) {
+    return of(rel, rel.getRowType(), kind);
+  }
+
+  /** Creates a simple RelRoot. */
+  public static RelRoot of(RelNode rel, RelDataType rowType, SqlKind kind) {
+    final ImmutableIntList refs =
+        ImmutableIntList.identity(rowType.getFieldCount());
+    final List<String> names = rowType.getFieldNames();
+    return new RelRoot(rel, rowType, kind, Pair.zip(refs, names),
+        RelCollations.EMPTY);
+  }
+
+  /** Creates a copy of this RelRoot, assigning a {@link RelNode}. */
+  public RelRoot withRel(RelNode rel) {
+    if (rel == this.rel) {
+      return this;
+    }
+    return new RelRoot(rel, validatedRowType, kind, fields, collation);
+  }
+
+  /** Creates a copy, assigning a new kind. */
+  public RelRoot withKind(SqlKind kind) {
+    if (kind == this.kind) {
+      return this;
+    }
+    return new RelRoot(rel, validatedRowType, kind, fields, collation);
+  }
+
+  public RelRoot withCollation(RelCollation collation) {
+    return new RelRoot(rel, validatedRowType, kind, fields, collation);
+  }
+
+  /** Returns the root relational expression, creating a {@link LogicalProject}
+   * if necessary to remove fields that are not needed. */
+  public RelNode project() {
+    if (isRefTrivial()) {
+      return rel;
+    }
+    final List<RexNode> projects = new ArrayList<>();
+    final RexBuilder rexBuilder = rel.getCluster().getRexBuilder();
+    for (Pair<Integer, String> field : fields) {
+      projects.add(rexBuilder.makeInputRef(rel, field.left));
+    }
+    return LogicalProject.create(rel, projects, Pair.right(fields));
+  }
+
+  public boolean isNameTrivial() {
+    final RelDataType inputRowType = rel.getRowType();
+    return Pair.right(fields).equals(inputRowType.getFieldNames());
+  }
+
+  public boolean isRefTrivial() {
+    if (SqlKind.DML.contains(kind)) {
+      // DML statements return a single count column.
+      // The validated type is of the SELECT.
+      // Still, we regard the mapping as trivial.
+      return true;
+    }
+    final RelDataType inputRowType = rel.getRowType();
+    return Mappings.isIdentity(Pair.left(fields), inputRowType.getFieldCount());
+  }
+
+  public boolean isCollationTrivial() {
+    final List<RelCollation> collations = rel.getTraitSet()
+        .getTraits(RelCollationTraitDef.INSTANCE);
+    return collations != null
+        && collations.size() == 1
+        && collations.get(0).equals(collation);
+  }
+}
+
+// End RelRoot.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/main/java/org/apache/calcite/rel/SingleRel.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/SingleRel.java b/core/src/main/java/org/apache/calcite/rel/SingleRel.java
index 27e0bf6..5fbb2c6 100644
--- a/core/src/main/java/org/apache/calcite/rel/SingleRel.java
+++ b/core/src/main/java/org/apache/calcite/rel/SingleRel.java
@@ -35,7 +35,7 @@ import java.util.List;
 public abstract class SingleRel extends AbstractRelNode {
   //~ Instance fields --------------------------------------------------------
 
-  private RelNode input;
+  protected RelNode input;
 
   //~ Constructors -----------------------------------------------------------
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/main/java/org/apache/calcite/rel/externalize/RelJsonReader.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/externalize/RelJsonReader.java b/core/src/main/java/org/apache/calcite/rel/externalize/RelJsonReader.java
index b3f9a56..57a7f76 100644
--- a/core/src/main/java/org/apache/calcite/rel/externalize/RelJsonReader.java
+++ b/core/src/main/java/org/apache/calcite/rel/externalize/RelJsonReader.java
@@ -60,24 +60,24 @@ public class RelJsonReader {
 
   private final RelOptCluster cluster;
   private final RelOptSchema relOptSchema;
-  private final Schema schema;
   private final RelJson relJson = new RelJson(null);
-  private final Map<String, RelNode> relMap =
-      new LinkedHashMap<String, RelNode>();
+  private final Map<String, RelNode> relMap = new LinkedHashMap<>();
   private RelNode lastRel;
 
   public RelJsonReader(RelOptCluster cluster, RelOptSchema relOptSchema,
       Schema schema) {
     this.cluster = cluster;
     this.relOptSchema = relOptSchema;
-    this.schema = schema;
+    Util.discard(schema);
   }
 
   public RelNode read(String s) throws IOException {
     lastRel = null;
     final ObjectMapper mapper = new ObjectMapper();
     Map<String, Object> o = mapper.readValue(s, TYPE_REF);
-    readRels((List<Map<String, Object>>) o.get("rels"));
+    @SuppressWarnings("unchecked")
+    final List<Map<String, Object>> rels = (List) o.get("rels");
+    readRels(rels);
     System.out.println(lastRel);
     return lastRel;
   }
@@ -102,7 +102,7 @@ public class RelJsonReader {
       }
 
       public RelOptTable getTable(String table) {
-        final List<String> list = (List<String>) jsonRel.get(table);
+        final List<String> list = getStringList(table);
         return relOptSchema.getTableForMember(list);
       }
 
@@ -113,11 +113,11 @@ public class RelJsonReader {
       }
 
       public List<RelNode> getInputs() {
-        List<String> jsonInputs = (List<String>) jsonRel.get("inputs");
+        final List<String> jsonInputs = getStringList("inputs");
         if (jsonInputs == null) {
           return ImmutableList.of(lastRel);
         }
-        final List<RelNode> inputs = new ArrayList<RelNode>();
+        final List<RelNode> inputs = new ArrayList<>();
         for (String jsonInput : jsonInputs) {
           inputs.add(lookupInput(jsonInput));
         }
@@ -145,17 +145,25 @@ public class RelJsonReader {
         return builder.build();
       }
 
+      public List<String> getStringList(String tag) {
+        //noinspection unchecked
+        return (List<String>) jsonRel.get(tag);
+      }
+
       public List<Integer> getIntegerList(String tag) {
+        //noinspection unchecked
         return (List<Integer>) jsonRel.get(tag);
       }
 
       public List<List<Integer>> getIntegerListList(String tag) {
+        //noinspection unchecked
         return (List<List<Integer>>) jsonRel.get(tag);
       }
 
       public List<AggregateCall> getAggregateCalls(String tag) {
-        List<Map<String, Object>> jsonAggs = (List) jsonRel.get(tag);
-        final List<AggregateCall> inputs = new ArrayList<AggregateCall>();
+        @SuppressWarnings("unchecked")
+        final List<Map<String, Object>> jsonAggs = (List) jsonRel.get(tag);
+        final List<AggregateCall> inputs = new ArrayList<>();
         for (Map<String, Object> jsonAggCall : jsonAggs) {
           inputs.add(toAggCall(jsonAggCall));
         }
@@ -184,8 +192,9 @@ public class RelJsonReader {
       }
 
       public List<RexNode> getExpressionList(String tag) {
+        @SuppressWarnings("unchecked")
         final List<Object> jsonNodes = (List) jsonRel.get(tag);
-        final List<RexNode> nodes = new ArrayList<RexNode>();
+        final List<RexNode> nodes = new ArrayList<>();
         for (Object jsonNode : jsonNodes) {
           nodes.add(relJson.toRex(this, jsonNode));
         }
@@ -215,6 +224,7 @@ public class RelJsonReader {
       }
 
       public RelCollation getCollation() {
+        //noinspection unchecked
         return relJson.toCollation((List) get("collation"));
       }
 
@@ -223,7 +233,8 @@ public class RelJsonReader {
       }
 
       public ImmutableList<ImmutableList<RexLiteral>> getTuples(String tag) {
-        List<List> jsonTuples = (List) get(tag);
+        //noinspection unchecked
+        final List<List> jsonTuples = (List) get(tag);
         final ImmutableList.Builder<ImmutableList<RexLiteral>> builder =
             ImmutableList.builder();
         for (List jsonTuple : jsonTuples) {
@@ -245,9 +256,7 @@ public class RelJsonReader {
       final RelNode rel = (RelNode) constructor.newInstance(input);
       relMap.put(id, rel);
       lastRel = rel;
-    } catch (InstantiationException e) {
-      throw new RuntimeException(e);
-    } catch (IllegalAccessException e) {
+    } catch (InstantiationException | IllegalAccessException e) {
       throw new RuntimeException(e);
     } catch (InvocationTargetException e) {
       final Throwable e2 = e.getCause();
@@ -263,6 +272,7 @@ public class RelJsonReader {
     final SqlAggFunction aggregation =
         relJson.toAggregation(aggName, jsonAggCall);
     final Boolean distinct = (Boolean) jsonAggCall.get("distinct");
+    @SuppressWarnings("unchecked")
     final List<Integer> operands = (List<Integer>) jsonAggCall.get("operands");
     final Integer filterOperand = (Integer) jsonAggCall.get("filter");
     final RelDataType type =

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/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 de7f67f..e9c7c9c 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
@@ -200,7 +200,7 @@ public class AggregateStarTableRule extends RelOptRule {
       if (roll == null) {
         break tryRoll;
       }
-      return AggregateCall.create(roll, false, ImmutableList.of(offset + i),
+      return AggregateCall.create(roll, false, ImmutableList.of(offset + i), -1,
           groupCount, input, null, aggregateCall.name);
     }
 
@@ -215,7 +215,7 @@ public class AggregateStarTableRule extends RelOptRule {
         }
         newArgs.add(z);
       }
-      return AggregateCall.create(aggregation, false, newArgs,
+      return AggregateCall.create(aggregation, false, newArgs, -1,
           groupCount, input, null, aggregateCall.name);
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/main/java/org/apache/calcite/rex/RexUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexUtil.java b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
index 1cac0f8..f7e6a9e 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexUtil.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
@@ -754,10 +754,6 @@ public class RexUtil {
       List<RelCollation> collationList) {
     final List<RelCollation> newCollationList = new ArrayList<>();
     for (RelCollation collation : collationList) {
-      if (collation == RelCollations.PRESERVE) {
-        newCollationList.add(collation);
-        continue;
-      }
       final List<RelFieldCollation> newFieldCollationList = new ArrayList<>();
       for (RelFieldCollation fieldCollation
           : collation.getFieldCollations()) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/main/java/org/apache/calcite/schema/impl/ViewTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/schema/impl/ViewTable.java b/core/src/main/java/org/apache/calcite/schema/impl/ViewTable.java
index b3a8ff7..1da29ef 100644
--- a/core/src/main/java/org/apache/calcite/schema/impl/ViewTable.java
+++ b/core/src/main/java/org/apache/calcite/schema/impl/ViewTable.java
@@ -25,6 +25,7 @@ import org.apache.calcite.linq4j.Queryable;
 import org.apache.calcite.plan.RelOptTable;
 import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.RelRoot;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rel.type.RelDataTypeImpl;
@@ -116,19 +117,16 @@ public class ViewTable
   public RelNode toRel(
       RelOptTable.ToRelContext context,
       RelOptTable relOptTable) {
-    return expandView(context, relOptTable.getRowType(), viewSql);
+    return expandView(context, relOptTable.getRowType(), viewSql).rel;
   }
 
-  private RelNode expandView(
-      RelOptTable.ToRelContext preparingStmt,
-      RelDataType rowType,
-      String queryString) {
+  private RelRoot expandView(RelOptTable.ToRelContext preparingStmt,
+      RelDataType rowType, String queryString) {
     try {
-      RelNode rel = preparingStmt.expandView(rowType, queryString, schemaPath);
+      RelRoot root = preparingStmt.expandView(rowType, queryString, schemaPath);
 
-      rel = RelOptUtil.createCastRel(rel, rowType, true);
-      //rel = viewExpander.flattenTypes(rel, false);
-      return rel;
+      root = root.withRel(RelOptUtil.createCastRel(root.rel, rowType, true));
+      return root;
     } catch (Throwable e) {
       throw Util.newInternal(
           e, "Error while parsing view definition:  " + queryString);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/main/java/org/apache/calcite/sql2rel/RelStructuredTypeFlattener.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/RelStructuredTypeFlattener.java b/core/src/main/java/org/apache/calcite/sql2rel/RelStructuredTypeFlattener.java
index f4765b4..4d8f0a5 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/RelStructuredTypeFlattener.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/RelStructuredTypeFlattener.java
@@ -343,9 +343,13 @@ public class RelStructuredTypeFlattener implements ReflectiveVisitor {
 
   public void rewriteRel(LogicalTableModify rel) {
     LogicalTableModify newRel =
-        LogicalTableModify.create(rel.getTable(), rel.getCatalogReader(),
-            getNewForOldRel(rel.getInput()), rel.getOperation(),
-            rel.getUpdateColumnList(), true);
+        LogicalTableModify.create(
+            rel.getTable(),
+            rel.getCatalogReader(),
+            getNewForOldRel(rel.getInput()),
+            rel.getOperation(),
+            rel.getUpdateColumnList(),
+            true);
     setNewForOldRel(rel, newRel);
   }
 
@@ -394,8 +398,7 @@ public class RelStructuredTypeFlattener implements ReflectiveVisitor {
 
   public void rewriteRel(LogicalJoin rel) {
     LogicalJoin newRel =
-        LogicalJoin.create(
-            getNewForOldRel(rel.getLeft()),
+        LogicalJoin.create(getNewForOldRel(rel.getLeft()),
             getNewForOldRel(rel.getRight()),
             rel.getCondition().accept(new RewriteRexShuttle()),
             rel.getJoinType(),

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/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 ae73586..50f22c1 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -31,6 +31,7 @@ import org.apache.calcite.rel.RelCollationTraitDef;
 import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.RelFieldCollation;
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.RelRoot;
 import org.apache.calcite.rel.RelShuttle;
 import org.apache.calcite.rel.core.Aggregate;
 import org.apache.calcite.rel.core.AggregateCall;
@@ -42,6 +43,7 @@ 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.Sample;
+import org.apache.calcite.rel.core.Sort;
 import org.apache.calcite.rel.core.Uncollect;
 import org.apache.calcite.rel.logical.LogicalAggregate;
 import org.apache.calcite.rel.logical.LogicalCorrelate;
@@ -56,6 +58,7 @@ import org.apache.calcite.rel.logical.LogicalTableScan;
 import org.apache.calcite.rel.logical.LogicalUnion;
 import org.apache.calcite.rel.logical.LogicalValues;
 import org.apache.calcite.rel.metadata.RelColumnMapping;
+import org.apache.calcite.rel.stream.Delta;
 import org.apache.calcite.rel.stream.LogicalDelta;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
@@ -102,6 +105,7 @@ import org.apache.calcite.sql.SqlNodeList;
 import org.apache.calcite.sql.SqlNumericLiteral;
 import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.SqlOperatorTable;
+import org.apache.calcite.sql.SqlOrderBy;
 import org.apache.calcite.sql.SqlSampleSpec;
 import org.apache.calcite.sql.SqlSelect;
 import org.apache.calcite.sql.SqlSelectKeyword;
@@ -425,26 +429,36 @@ public class SqlToRelConverter {
   }
 
   private void checkConvertedType(SqlNode query, RelNode result) {
-    if (!query.isA(SqlKind.DML)) {
-      // Verify that conversion from SQL to relational algebra did
-      // not perturb any type information.  (We can't do this if the
-      // SQL statement is something like an INSERT which has no
-      // validator type information associated with its result,
-      // hence the namespace check above.)
-      RelDataType convertedRowType = result.getRowType();
-      if (!checkConvertedRowType(query, convertedRowType)) {
-        RelDataType validatedRowType =
-            validator.getValidatedNodeType(query);
-        validatedRowType = uniquifyFields(validatedRowType);
-        throw Util.newInternal("Conversion to relational algebra failed to "
-            + "preserve datatypes:\n"
-            + "validated type:\n"
-            + validatedRowType.getFullTypeString()
-            + "\nconverted type:\n"
-            + convertedRowType.getFullTypeString()
-            + "\nrel:\n"
-            + RelOptUtil.toString(result));
-      }
+    if (query.isA(SqlKind.DML)) {
+      return;
+    }
+    // Verify that conversion from SQL to relational algebra did
+    // not perturb any type information.  (We can't do this if the
+    // SQL statement is something like an INSERT which has no
+    // validator type information associated with its result,
+    // hence the namespace check above.)
+    final List<RelDataTypeField> validatedFields =
+        validator.getValidatedNodeType(query).getFieldList();
+    final RelDataType validatedRowType =
+        validator.getTypeFactory().createStructType(
+            Pair.right(validatedFields),
+            SqlValidatorUtil.uniquify(Pair.left(validatedFields)));
+
+    final List<RelDataTypeField> convertedFields =
+        result.getRowType().getFieldList().subList(0, validatedFields.size());
+    final RelDataType convertedRowType =
+        validator.getTypeFactory().createStructType(convertedFields);
+
+    if (!RelOptUtil.equal("validated row type", validatedRowType,
+        "converted row type", convertedRowType, false)) {
+      throw Util.newInternal("Conversion to relational algebra failed to "
+          + "preserve datatypes:\n"
+          + "validated type:\n"
+          + validatedRowType.getFullTypeString()
+          + "\nconverted type:\n"
+          + convertedRowType.getFullTypeString()
+          + "\nrel:\n"
+          + RelOptUtil.toString(result));
     }
   }
 
@@ -501,7 +515,10 @@ public class SqlToRelConverter {
       final List<RelCollation> collations =
           rootRel.getTraitSet().getTraits(RelCollationTraitDef.INSTANCE);
       rootRel = trimmer.trim(rootRel);
-      if (!ordered && collations != null) {
+      if (!ordered
+          && collations != null
+          && !collations.isEmpty()
+          && !collations.equals(ImmutableList.of(RelCollations.EMPTY))) {
         final RelTraitSet traitSet = rootRel.getTraitSet()
             .replace(RelCollationTraitDef.INSTANCE, collations);
         rootRel = rootRel.copy(traitSet, rootRel.getInputs());
@@ -539,7 +556,7 @@ public class SqlToRelConverter {
    *                        will become a JDBC result set; <code>false</code> if
    *                        the query will be part of a view.
    */
-  public RelNode convertQuery(
+  public RelRoot convertQuery(
       SqlNode query,
       final boolean needsValidation,
       final boolean top) {
@@ -547,13 +564,17 @@ public class SqlToRelConverter {
       query = validator.validate(query);
     }
 
-    RelNode result = convertQueryRecursive(query, top, null);
-    if (top && isStream(query)) {
-      result = new LogicalDelta(cluster, result.getTraitSet(), result);
+    RelNode result = convertQueryRecursive(query, top, null).rel;
+    if (top) {
+      if (isStream(query)) {
+        result = new LogicalDelta(cluster, result.getTraitSet(), result);
+      }
     }
-    if (isUnordered(query)) {
-      result = result.copy(result.getTraitSet().replace(RelCollations.EMPTY),
-          result.getInputs());
+    RelCollation collation = RelCollations.EMPTY;
+    if (!query.isA(SqlKind.DML)) {
+      if (isOrdered(query)) {
+        collation = requiredCollation(result);
+      }
     }
     checkConvertedType(query, result);
 
@@ -567,7 +588,9 @@ public class SqlToRelConverter {
               SqlExplainLevel.EXPPLAN_ATTRIBUTES));
     }
 
-    return result;
+    final RelDataType validatedRowType = validator.getValidatedNodeType(query);
+    return RelRoot.of(result, validatedRowType, query.getKind())
+        .withCollation(collation);
   }
 
   private static boolean isStream(SqlNode query) {
@@ -575,33 +598,39 @@ public class SqlToRelConverter {
         && ((SqlSelect) query).isKeywordPresent(SqlSelectKeyword.STREAM);
   }
 
-  public static boolean isUnordered(SqlNode query) {
-    return query instanceof SqlSelect
-        && ((SqlSelect) query).getOrderList() == null;
-  }
-
-  protected boolean checkConvertedRowType(
-      SqlNode query,
-      RelDataType convertedRowType) {
-    RelDataType validatedRowType = validator.getValidatedNodeType(query);
-    validatedRowType = uniquifyFields(validatedRowType);
-
-    return RelOptUtil.equal("validated row type", validatedRowType,
-        "converted row type", convertedRowType, false);
+  public static boolean isOrdered(SqlNode query) {
+    switch (query.getKind()) {
+    case SELECT:
+      return ((SqlSelect) query).getOrderList() != null
+          && ((SqlSelect) query).getOrderList().size() > 0;
+    case WITH:
+      return isOrdered(((SqlWith) query).body);
+    case ORDER_BY:
+      return ((SqlOrderBy) query).orderList.size() > 0;
+    default:
+      return false;
+    }
   }
 
-  protected RelDataType uniquifyFields(RelDataType rowType) {
-    return validator.getTypeFactory().createStructType(
-        RelOptUtil.getFieldTypeList(rowType),
-        SqlValidatorUtil.uniquify(rowType.getFieldNames()));
+  private RelCollation requiredCollation(RelNode r) {
+    if (r instanceof Sort) {
+      return ((Sort) r).collation;
+    }
+    if (r instanceof Project) {
+      return requiredCollation(((Project) r).getInput());
+    }
+    if (r instanceof Delta) {
+      return requiredCollation(((Delta) r).getInput());
+    }
+    throw new AssertionError();
   }
 
   /**
    * Converts a SELECT statement's parse tree into a relational expression.
    */
-  public RelNode convertSelect(SqlSelect select) {
+  public RelNode convertSelect(SqlSelect select, boolean top) {
     final SqlValidatorScope selectScope = validator.getWhereScope(select);
-    final Blackboard bb = createBlackboard(selectScope, null);
+    final Blackboard bb = createBlackboard(selectScope, null, top);
     convertSelectImpl(bb, select);
     return bb.root;
   }
@@ -609,15 +638,14 @@ public class SqlToRelConverter {
   /**
    * Factory method for creating translation workspace.
    */
-  protected Blackboard createBlackboard(
-      SqlValidatorScope scope,
-      Map<String, RexNode> nameToNodeMap) {
-    return new Blackboard(scope, nameToNodeMap);
+  protected Blackboard createBlackboard(SqlValidatorScope scope,
+      Map<String, RexNode> nameToNodeMap, boolean top) {
+    return new Blackboard(scope, nameToNodeMap, top);
   }
 
   /**
-   * Implementation of {@link #convertSelect(SqlSelect)}; derived class may
-   * override.
+   * Implementation of {@link #convertSelect(SqlSelect, boolean)};
+   * derived class may override.
    */
   protected void convertSelectImpl(
       final Blackboard bb,
@@ -796,8 +824,11 @@ public class SqlToRelConverter {
         false);
 
     // If extra expressions were added to the project list for sorting,
-    // add another project to remove them.
-    if (orderExprList.size() > 0) {
+    // add another project to remove them. But make the collation empty, because
+    // we can't represent the real collation.
+    //
+    // If it is the top node, use the real collation, but don't trim fields.
+    if (orderExprList.size() > 0 && !bb.top) {
       final List<RexNode> exprs = new ArrayList<>();
       final RelDataType rowType = bb.root.getRowType();
       final int fieldCount =
@@ -806,13 +837,8 @@ public class SqlToRelConverter {
         exprs.add(rexBuilder.makeInputRef(bb.root, i));
       }
       bb.setRoot(
-          new LogicalProject(
-              cluster,
-              cluster.traitSetOf(RelCollations.PRESERVE),
-              bb.root,
-              exprs,
-              cluster.getTypeFactory().createStructType(
-                  rowType.getFieldList().subList(0, fieldCount))),
+          LogicalProject.create(bb.root, exprs,
+              rowType.getFieldNames().subList(0, fieldCount)),
           false);
     }
   }
@@ -1437,7 +1463,7 @@ public class SqlToRelConverter {
         (seek instanceof SqlSelect)
             ? validator.getSelectScope((SqlSelect) seek)
             : null;
-    final Blackboard seekBb = createBlackboard(seekScope, null);
+    final Blackboard seekBb = createBlackboard(seekScope, null, false);
     RelNode seekRel = convertQueryOrInList(seekBb, seek, targetDataType);
 
     return RelOptUtil.createExistsPlan(seekRel, subqueryType, logic,
@@ -1462,7 +1488,7 @@ public class SqlToRelConverter {
           false,
           targetRowType);
     } else {
-      return convertQueryRecursive(seek, false, null);
+      return convertQueryRecursive(seek, false, null).project();
     }
   }
 
@@ -1721,10 +1747,9 @@ public class SqlToRelConverter {
   public RexNode convertExpression(
       SqlNode node) {
     Map<String, RelDataType> nameToTypeMap = Collections.emptyMap();
-    Blackboard bb =
-        createBlackboard(
-            new ParameterScope((SqlValidatorImpl) validator, nameToTypeMap),
-            null);
+    final ParameterScope scope =
+        new ParameterScope((SqlValidatorImpl) validator, nameToTypeMap);
+    final Blackboard bb = createBlackboard(scope, null, false);
     return bb.convertExpression(node);
   }
 
@@ -1746,10 +1771,9 @@ public class SqlToRelConverter {
     for (Map.Entry<String, RexNode> entry : nameToNodeMap.entrySet()) {
       nameToTypeMap.put(entry.getKey(), entry.getValue().getType());
     }
-    Blackboard bb =
-        createBlackboard(
-            new ParameterScope((SqlValidatorImpl) validator, nameToTypeMap),
-            nameToNodeMap);
+    final ParameterScope scope =
+        new ParameterScope((SqlValidatorImpl) validator, nameToTypeMap);
+    final Blackboard bb = createBlackboard(scope, nameToNodeMap, false);
     return bb.convertExpression(node);
   }
 
@@ -1925,20 +1949,22 @@ public class SqlToRelConverter {
 
     case JOIN:
       final SqlJoin join = (SqlJoin) from;
-      final Blackboard fromBlackboard =
-          createBlackboard(validator.getJoinScope(from), null);
+      final SqlValidatorScope scope = validator.getJoinScope(from);
+      final Blackboard fromBlackboard = createBlackboard(scope, null, false);
       SqlNode left = join.getLeft();
       SqlNode right = join.getRight();
       final boolean isNatural = join.isNatural();
       final JoinType joinType = join.getJoinType();
+      final SqlValidatorScope leftScope =
+          Util.first(validator.getJoinScope(left),
+              ((DelegatingScope) bb.scope).getParent());
       final Blackboard leftBlackboard =
-          createBlackboard(
-              Util.first(validator.getJoinScope(left),
-                  ((DelegatingScope) bb.scope).getParent()), null);
+          createBlackboard(leftScope, null, false);
+      final SqlValidatorScope rightScope =
+          Util.first(validator.getJoinScope(right),
+              ((DelegatingScope) bb.scope).getParent());
       final Blackboard rightBlackboard =
-          createBlackboard(
-              Util.first(validator.getJoinScope(right),
-                  ((DelegatingScope) bb.scope).getParent()), null);
+          createBlackboard(rightScope, null, false);
       convertFrom(leftBlackboard, left);
       RelNode leftRel = leftBlackboard.root;
       convertFrom(rightBlackboard, right);
@@ -1981,7 +2007,7 @@ public class SqlToRelConverter {
     case INTERSECT:
     case EXCEPT:
     case UNION:
-      final RelNode rel = convertQueryRecursive(from, false, null);
+      final RelNode rel = convertQueryRecursive(from, false, null).project();
       bb.setRoot(rel, true);
       return;
 
@@ -2029,7 +2055,7 @@ public class SqlToRelConverter {
       datasetStack.push(sampleName);
       SqlCall cursorCall = call.operand(1);
       SqlNode query = cursorCall.operand(0);
-      RelNode converted = convertQuery(query, false, false);
+      RelNode converted = convertQuery(query, false, false).rel;
       bb.setRoot(converted, false);
       datasetStack.pop();
       return;
@@ -2788,29 +2814,28 @@ public class SqlToRelConverter {
    * @param targetRowType Target row type, or null
    * @return Relational expression
    */
-  protected RelNode convertQueryRecursive(
-      SqlNode query,
-      boolean top,
+  protected RelRoot convertQueryRecursive(SqlNode query, boolean top,
       RelDataType targetRowType) {
-    switch (query.getKind()) {
+    final SqlKind kind = query.getKind();
+    switch (kind) {
     case SELECT:
-      return convertSelect((SqlSelect) query);
+      return RelRoot.of(convertSelect((SqlSelect) query, top), kind);
     case INSERT:
-      return convertInsert((SqlInsert) query);
+      return RelRoot.of(convertInsert((SqlInsert) query), kind);
     case DELETE:
-      return convertDelete((SqlDelete) query);
+      return RelRoot.of(convertDelete((SqlDelete) query), kind);
     case UPDATE:
-      return convertUpdate((SqlUpdate) query);
+      return RelRoot.of(convertUpdate((SqlUpdate) query), kind);
     case MERGE:
-      return convertMerge((SqlMerge) query);
+      return RelRoot.of(convertMerge((SqlMerge) query), kind);
     case UNION:
     case INTERSECT:
     case EXCEPT:
-      return convertSetOp((SqlCall) query);
+      return RelRoot.of(convertSetOp((SqlCall) query), kind);
     case WITH:
-      return convertWith((SqlWith) query);
+      return convertWith((SqlWith) query, top);
     case VALUES:
-      return convertValues((SqlCall) query, targetRowType);
+      return RelRoot.of(convertValues((SqlCall) query, targetRowType), kind);
     default:
       throw Util.newInternal("not a query: " + query);
     }
@@ -2824,8 +2849,10 @@ public class SqlToRelConverter {
    * @return Relational expression
    */
   protected RelNode convertSetOp(SqlCall call) {
-    final RelNode left = convertQueryRecursive(call.operand(0), false, null);
-    final RelNode right = convertQueryRecursive(call.operand(1), false, null);
+    final RelNode left =
+        convertQueryRecursive(call.operand(0), false, null).project();
+    final RelNode right =
+        convertQueryRecursive(call.operand(1), false, null).project();
     boolean all = false;
     if (call.getOperator() instanceof SqlSetOperator) {
       all = ((SqlSetOperator) (call.getOperator())).isAll();
@@ -2864,8 +2891,7 @@ public class SqlToRelConverter {
         validator.getValidatedNodeType(call);
     assert targetRowType != null;
     RelNode sourceRel =
-        convertQueryRecursive(
-            call.getSource(), false, targetRowType);
+        convertQueryRecursive(call.getSource(), false, targetRowType).project();
     RelNode massagedRel = convertColumnList(call, sourceRel);
 
     return createModify(targetTable, massagedRel);
@@ -2953,9 +2979,7 @@ public class SqlToRelConverter {
         return cluster;
       }
 
-      public RelNode expandView(
-          RelDataType rowType,
-          String queryString,
+      public RelRoot expandView(RelDataType rowType, String queryString,
           List<String> schemaPath) {
         return viewExpander.expandView(rowType, queryString, schemaPath);
       }
@@ -3084,7 +3108,7 @@ public class SqlToRelConverter {
 
   private RelNode convertDelete(SqlDelete call) {
     RelOptTable targetTable = getTargetTable(call);
-    RelNode sourceRel = convertSelect(call.getSourceSelect());
+    RelNode sourceRel = convertSelect(call.getSourceSelect(), false);
     return LogicalTableModify.create(targetTable, catalogReader, sourceRel,
         LogicalTableModify.Operation.DELETE, null, false);
   }
@@ -3100,7 +3124,7 @@ public class SqlToRelConverter {
       targetColumnNameList.add(name);
     }
 
-    RelNode sourceRel = convertSelect(call.getSourceSelect());
+    RelNode sourceRel = convertSelect(call.getSourceSelect(), false);
 
     return LogicalTableModify.create(targetTable, catalogReader, sourceRel,
         LogicalTableModify.Operation.UPDATE, targetColumnNameList, false);
@@ -3129,7 +3153,7 @@ public class SqlToRelConverter {
 
     // first, convert the merge's source select to construct the columns
     // from the target table and the set expressions in the update call
-    RelNode mergeSourceRel = convertSelect(call.getSourceSelect());
+    RelNode mergeSourceRel = convertSelect(call.getSourceSelect(), false);
 
     // then, convert the insert statement so we can get the insert
     // values expressions
@@ -3199,7 +3223,6 @@ public class SqlToRelConverter {
     final SqlQualified qualified;
     if (bb.scope != null) {
       qualified = bb.scope.fullyQualify(identifier);
-      identifier = qualified.identifier;
     } else {
       qualified = SqlQualified.create(null, 1, null, identifier);
     }
@@ -3271,7 +3294,7 @@ public class SqlToRelConverter {
     final SqlCall cursorCall = (SqlCall) subQuery.node;
     assert cursorCall.operandCount() == 1;
     SqlNode query = cursorCall.operand(0);
-    RelNode converted = convertQuery(query, false, false);
+    RelNode converted = convertQuery(query, false, false).rel;
     int iCursor = bb.cursors.size();
     bb.cursors.add(converted);
     subQuery.expr =
@@ -3305,21 +3328,18 @@ public class SqlToRelConverter {
       if (op == SqlStdOperatorTable.MULTISET_VALUE) {
         final SqlNodeList list =
             new SqlNodeList(call.getOperandList(), call.getParserPosition());
-//                assert bb.scope instanceof SelectScope : bb.scope;
         CollectNamespace nss =
             (CollectNamespace) validator.getNamespace(call);
         Blackboard usedBb;
         if (null != nss) {
-          usedBb = createBlackboard(nss.getScope(), null);
+          usedBb = createBlackboard(nss.getScope(), null, false);
         } else {
           usedBb =
-              createBlackboard(
-                  new ListScope(bb.scope) {
-                    public SqlNode getNode() {
-                      return call;
-                    }
-                  },
-                  null);
+              createBlackboard(new ListScope(bb.scope) {
+                public SqlNode getNode() {
+                  return call;
+                }
+              }, null, false);
         }
         RelDataType multisetType = validator.getValidatedNodeType(call);
         validator.setValidatedNodeType(
@@ -3327,7 +3347,8 @@ public class SqlToRelConverter {
             multisetType.getComponentType());
         input = convertQueryOrInList(usedBb, list, null);
       } else {
-        input = convertQuery(call.operand(0), false, true);
+        final RelRoot root = convertQuery(call.operand(0), false, true);
+        input = root.rel;
       }
 
       if (lastList.size() > 0) {
@@ -3492,8 +3513,8 @@ public class SqlToRelConverter {
   /**
    * Converts a WITH sub-query into a relational expression.
    */
-  public RelNode convertWith(SqlWith with) {
-    return convertQuery(with.body, false, false);
+  public RelRoot convertWith(SqlWith with, boolean top) {
+    return convertQuery(with.body, false, top);
   }
 
   /**
@@ -3504,7 +3525,7 @@ public class SqlToRelConverter {
       RelDataType targetRowType) {
     final SqlValidatorScope scope = validator.getOverScope(values);
     assert scope != null;
-    final Blackboard bb = createBlackboard(scope, null);
+    final Blackboard bb = createBlackboard(scope, null, false);
     convertValuesImpl(bb, values, targetRowType);
     return bb.root;
   }
@@ -3538,7 +3559,7 @@ public class SqlToRelConverter {
     final List<RelNode> unionRels = new ArrayList<>();
     for (SqlNode rowConstructor1 : values.getOperandList()) {
       SqlCall rowConstructor = (SqlCall) rowConstructor1;
-      Blackboard tmpBb = createBlackboard(bb.scope, null);
+      Blackboard tmpBb = createBlackboard(bb.scope, null, false);
       replaceSubqueries(tmpBb, rowConstructor,
           RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
       final List<Pair<RexNode, String>> exps = new ArrayList<>();
@@ -3604,7 +3625,7 @@ public class SqlToRelConverter {
     private final Map<String, RexNode> mapCorrelateVariableToRexNode =
         new HashMap<>();
 
-    List<RelNode> cursors;
+    final List<RelNode> cursors = new ArrayList<>();
 
     /**
      * List of <code>IN</code> and <code>EXISTS</code> nodes inside this
@@ -3637,6 +3658,7 @@ public class SqlToRelConverter {
         new ArrayList<>();
 
     private final List<RelDataTypeField> systemFieldList = new ArrayList<>();
+    final boolean top;
 
     /**
      * Creates a Blackboard.
@@ -3647,13 +3669,13 @@ public class SqlToRelConverter {
      * @param nameToNodeMap Map which translates the expression to map a
      *                      given parameter into, if translating expressions;
      *                      null otherwise
+     * @param top           Whether this is the root of the query
      */
-    protected Blackboard(
-        SqlValidatorScope scope,
-        Map<String, RexNode> nameToNodeMap) {
+    protected Blackboard(SqlValidatorScope scope,
+        Map<String, RexNode> nameToNodeMap, boolean top) {
       this.scope = scope;
       this.nameToNodeMap = nameToNodeMap;
-      this.cursors = new ArrayList<>();
+      this.top = top;
       subqueryNeedsOuterJoin = false;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a397063/core/src/main/java/org/apache/calcite/tools/Planner.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/tools/Planner.java b/core/src/main/java/org/apache/calcite/tools/Planner.java
index 98c1649..73c8047 100644
--- a/core/src/main/java/org/apache/calcite/tools/Planner.java
+++ b/core/src/main/java/org/apache/calcite/tools/Planner.java
@@ -18,6 +18,7 @@ package org.apache.calcite.tools;
 
 import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.RelRoot;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.parser.SqlParseException;
@@ -61,6 +62,10 @@ public interface Planner {
    * @throws org.apache.calcite.tools.RelConversionException if the node
    * cannot be converted or has not been validated
    */
+  RelRoot rel(SqlNode sql) throws RelConversionException;
+
+  /** @deprecated Use {@link #rel}. */
+  @Deprecated // to removed before 2.0
   RelNode convert(SqlNode sql) throws RelConversionException;
 
   /** Returns the type factory. */



[18/18] incubator-calcite git commit: [CALCITE-852] DDL statements

Posted by jh...@apache.org.
[CALCITE-852] DDL statements


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

Branch: refs/heads/master
Commit: 3e4d2b5c7eb07cac9c3cc9799de2793d1521b93a
Parents: 3948751
Author: Julian Hyde <jh...@apache.org>
Authored: Thu Aug 20 15:06:22 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Sep 1 16:17:17 2015 -0700

----------------------------------------------------------------------
 .../org/apache/calcite/jdbc/CalcitePrepare.java | 27 +++++++
 .../calcite/prepare/CalcitePrepareImpl.java     | 19 +++++
 .../java/org/apache/calcite/sql/SqlCall.java    |  4 +
 .../java/org/apache/calcite/sql/SqlKind.java    | 82 ++++++++++++++++++--
 .../java/org/apache/calcite/test/JdbcTest.java  | 69 ++++++++++++++++
 5 files changed, 195 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/3e4d2b5c/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java b/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
index ae5fba4..b2c1821 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
@@ -39,6 +39,7 @@ import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.runtime.ArrayBindable;
 import org.apache.calcite.runtime.Bindable;
 import org.apache.calcite.schema.Table;
+import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.validate.SqlValidator;
 import org.apache.calcite.util.ImmutableIntList;
@@ -76,6 +77,12 @@ public interface CalcitePrepare {
 
   ConvertResult convert(Context context, String sql);
 
+  /** Executes a DDL statement.
+   *
+   * <p>The statement identified itself as DDL in the
+   * {@link org.apache.calcite.jdbc.CalcitePrepare.ParseResult#kind} field. */
+  void executeDdl(Context context, SqlNode node);
+
   /** Analyzes a view.
    *
    * @param context Context
@@ -222,6 +229,26 @@ public interface CalcitePrepare {
       this.rowType = rowType;
       this.typeFactory = validator.getTypeFactory();
     }
+
+    /** Returns the kind of statement.
+     *
+     * <p>Possibilities include:
+     *
+     * <ul>
+     *   <li>Queries: usually {@link SqlKind#SELECT}, but
+     *   other query operators such as {@link SqlKind#UNION} and
+     *   {@link SqlKind#ORDER_BY} are possible
+     *   <li>DML statements: {@link SqlKind#INSERT}, {@link SqlKind#UPDATE} etc.
+     *   <li>Session control statements: {@link SqlKind#COMMIT}
+     *   <li>DDL statements: {@link SqlKind#CREATE_TABLE},
+     *   {@link SqlKind#DROP_INDEX}
+     * </ul>
+     *
+     * @return Kind of statement, never null
+     */
+    public SqlKind kind() {
+      return sqlNode.getKind();
+    }
   }
 
   /** The result of parsing and validating a SQL query and converting it to

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/3e4d2b5c/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
index 3f9293c..b787a0f 100644
--- a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
@@ -412,6 +412,10 @@ public class CalcitePrepareImpl implements CalcitePrepare {
         constraint, ImmutableIntList.copyOf(columnMapping));
   }
 
+  @Override public void executeDdl(Context context, SqlNode node) {
+    throw new UnsupportedOperationException();
+  }
+
   /** Factory method for default SQL parser. */
   protected SqlParser createParser(String sql) {
     return createParser(sql, createParserConfig());
@@ -659,6 +663,21 @@ public class CalcitePrepareImpl implements CalcitePrepare {
 
       Hook.PARSE_TREE.run(new Object[] {sql, sqlNode});
 
+      if (sqlNode.getKind().belongsTo(SqlKind.DDL)) {
+        executeDdl(context, sqlNode);
+
+        // Return a dummy signature that contains no rows
+        final Bindable<T> bindable = new Bindable<T>() {
+          public Enumerable<T> bind(DataContext dataContext) {
+            return Linq4j.emptyEnumerable();
+          }
+        };
+        return new CalciteSignature<>(sql, ImmutableList.<AvaticaParameter>of(),
+            ImmutableMap.<String, Object>of(), null,
+            ImmutableList.<ColumnMetaData>of(), Meta.CursorFactory.OBJECT,
+            ImmutableList.<RelCollation>of(), -1, bindable);
+      }
+
       final CalciteSchema rootSchema = context.getRootSchema();
       final ChainedSqlOperatorTable opTab =
           new ChainedSqlOperatorTable(

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/3e4d2b5c/core/src/main/java/org/apache/calcite/sql/SqlCall.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlCall.java b/core/src/main/java/org/apache/calcite/sql/SqlCall.java
index 41e9eb3..3461b2d 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlCall.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlCall.java
@@ -63,6 +63,10 @@ public abstract class SqlCall extends SqlNode {
     throw new UnsupportedOperationException();
   }
 
+  @Override public SqlKind getKind() {
+    return getOperator().getKind();
+  }
+
   public abstract SqlOperator getOperator();
 
   public abstract List<SqlNode> getOperandList();

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/3e4d2b5c/core/src/main/java/org/apache/calcite/sql/SqlKind.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlKind.java b/core/src/main/java/org/apache/calcite/sql/SqlKind.java
index 0bdb82c..fa821f8 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlKind.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlKind.java
@@ -613,7 +613,64 @@ public enum SqlKind {
   GROUPING_ID,
 
   /** The internal {@code GROUP_ID()} function. */
-  GROUP_ID;
+  GROUP_ID,
+
+  // DDL and session control statements follow. The list is not exhaustive: feel
+  // free to add more.
+
+  /** {@code COMMIT} session control statement. */
+  COMMIT,
+
+  /** {@code ROLLBACK} session control statement. */
+  ROLLBACK,
+
+  /** {@code ALTER SESSION} DDL statement. */
+  ALTER_SESSION,
+
+  /** {@code CREATE TABLE} DDL statement. */
+  CREATE_TABLE,
+
+  /** {@code ALTER TABLE} DDL statement. */
+  ALTER_TABLE,
+
+  /** {@code DROP TABLE} DDL statement. */
+  DROP_TABLE,
+
+  /** {@code CREATE VIEW} DDL statement. */
+  CREATE_VIEW,
+
+  /** {@code ALTER VIEW} DDL statement. */
+  ALTER_VIEW,
+
+  /** {@code DROP VIEW} DDL statement. */
+  DROP_VIEW,
+
+  /** {@code CREATE SEQUENCE} DDL statement. */
+  CREATE_SEQUENCE,
+
+  /** {@code ALTER SEQUENCE} DDL statement. */
+  ALTER_SEQUENCE,
+
+  /** {@code DROP SEQUENCE} DDL statement. */
+  DROP_SEQUENCE,
+
+  /** {@code CREATE INDEX} DDL statement. */
+  CREATE_INDEX,
+
+  /** {@code ALTER INDEX} DDL statement. */
+  ALTER_INDEX,
+
+  /** {@code DROP INDEX} DDL statement. */
+  DROP_INDEX,
+
+  /** DDL statement not handled above.
+   *
+   * <p><b>Note to other projects</b>: If you are extending Calcite's SQL parser
+   * and have your own object types you no doubt want to define CREATE and DROP
+   * commands for them. Use OTHER_DDL in the short term, but we are happy to add
+   * new enum values for your object types. Just ask!
+   */
+  OTHER_DDL;
 
   //~ Static fields/initializers ---------------------------------------------
 
@@ -679,6 +736,16 @@ public enum SqlKind {
       EnumSet.of(INSERT, DELETE, UPDATE, MERGE, PROCEDURE_CALL);
 
   /**
+   * Category consisting of all DDL operators.
+   */
+  public static final EnumSet<SqlKind> DDL =
+      EnumSet.of(COMMIT, ROLLBACK, ALTER_SESSION,
+          CREATE_TABLE, ALTER_TABLE, DROP_TABLE,
+          CREATE_VIEW, ALTER_VIEW, DROP_VIEW,
+          CREATE_SEQUENCE, ALTER_SEQUENCE, DROP_SEQUENCE,
+          CREATE_INDEX, ALTER_INDEX, DROP_INDEX);
+
+  /**
    * Category consisting of query node types.
    *
    * <p>Consists of:
@@ -697,9 +764,9 @@ public enum SqlKind {
   /**
    * Category of all SQL statement types.
    *
-   * <p>Consists of all types in {@link #QUERY} and {@link #DML}.
+   * <p>Consists of all types in {@link #QUERY}, {@link #DML} and {@link #DDL}.
    */
-  public static final Set<SqlKind> TOP_LEVEL = plus(QUERY, DML);
+  public static final EnumSet<SqlKind> TOP_LEVEL = concat(QUERY, DML, DDL);
 
   /**
    * Category consisting of regular and special functions.
@@ -762,10 +829,13 @@ public enum SqlKind {
     return category.contains(this);
   }
 
-  private static <E extends Enum<E>> EnumSet<E> plus(EnumSet<E> set0,
-      EnumSet<E> set1) {
+  @SafeVarargs
+  private static <E extends Enum<E>> EnumSet<E> concat(EnumSet<E> set0,
+      EnumSet<E>... sets) {
     EnumSet<E> set = set0.clone();
-    set.addAll(set1);
+    for (EnumSet<E> s : sets) {
+      set.addAll(s);
+    }
     return set;
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/3e4d2b5c/core/src/test/java/org/apache/calcite/test/JdbcTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcTest.java b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
index e1ee242..a024686 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -31,6 +31,7 @@ import org.apache.calcite.avatica.Meta;
 import org.apache.calcite.config.Lex;
 import org.apache.calcite.jdbc.CalciteConnection;
 import org.apache.calcite.jdbc.CalciteMetaImpl;
+import org.apache.calcite.jdbc.CalcitePrepare;
 import org.apache.calcite.jdbc.CalciteSchema;
 import org.apache.calcite.jdbc.Driver;
 import org.apache.calcite.linq4j.BaseQueryable;
@@ -40,6 +41,7 @@ import org.apache.calcite.linq4j.Linq4j;
 import org.apache.calcite.linq4j.Ord;
 import org.apache.calcite.linq4j.QueryProvider;
 import org.apache.calcite.linq4j.Queryable;
+import org.apache.calcite.linq4j.function.Function0;
 import org.apache.calcite.linq4j.function.Function1;
 import org.apache.calcite.linq4j.function.Function2;
 import org.apache.calcite.linq4j.tree.Types;
@@ -74,10 +76,20 @@ import org.apache.calcite.schema.impl.AbstractTableQueryable;
 import org.apache.calcite.schema.impl.TableFunctionImpl;
 import org.apache.calcite.schema.impl.TableMacroImpl;
 import org.apache.calcite.schema.impl.ViewTable;
+import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlDialect;
+import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlNode;
+import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.SqlSelect;
+import org.apache.calcite.sql.SqlSpecialOperator;
 import org.apache.calcite.sql.advise.SqlAdvisorGetHintsFunction;
+import org.apache.calcite.sql.parser.SqlAbstractParserImpl;
+import org.apache.calcite.sql.parser.SqlParser;
+import org.apache.calcite.sql.parser.SqlParserImplFactory;
+import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.sql.parser.SqlParserUtil;
+import org.apache.calcite.sql.parser.impl.SqlParserImpl;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.util.Bug;
 import org.apache.calcite.util.JsonBuilder;
@@ -102,6 +114,7 @@ import java.io.File;
 import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.IOException;
+import java.io.Reader;
 import java.lang.reflect.Method;
 import java.math.BigDecimal;
 import java.net.URL;
@@ -997,6 +1010,19 @@ public class JdbcTest {
     assertTrue(connection.isClosed());
   }
 
+  /** Tests that a driver can be extended with its own parser and can execute
+   * its own flavor of DDL. */
+  @Test public void testMockDdl() throws Exception {
+    final MockDdlDriver driver = new MockDdlDriver();
+    try (Connection connection =
+             driver.connect("jdbc:calcite:", new Properties());
+        Statement statement = connection.createStatement()) {
+      assertThat(driver.counter, is(0));
+      statement.executeQuery("COMMIT");
+      assertThat(driver.counter, is(1));
+    }
+  }
+
   /**
    * The example in the README.
    */
@@ -6811,6 +6837,49 @@ public class JdbcTest {
     }
   }
 
+  /** Mock driver that can execute a trivial DDL statement. */
+  public static class MockDdlDriver extends org.apache.calcite.jdbc.Driver {
+    public int counter;
+
+    public MockDdlDriver() {
+    }
+
+    @Override protected Function0<CalcitePrepare> createPrepareFactory() {
+      return new Function0<CalcitePrepare>() {
+        @Override public CalcitePrepare apply() {
+          return new CalcitePrepareImpl() {
+            @Override protected SqlParser.ConfigBuilder createParserConfig() {
+              return super.createParserConfig().setParserFactory(
+                  new SqlParserImplFactory() {
+                    @Override public SqlAbstractParserImpl
+                    getParser(Reader stream) {
+                      return new SqlParserImpl(stream) {
+                        @Override public SqlNode parseSqlStmtEof() {
+                          return new SqlCall(SqlParserPos.ZERO) {
+                            @Override public SqlOperator getOperator() {
+                              return new SqlSpecialOperator("COMMIT",
+                                  SqlKind.COMMIT);
+                            }
+
+                            @Override public List<SqlNode> getOperandList() {
+                              return ImmutableList.of();
+                            }
+                          };
+                        }
+                      };
+                    }
+                  });
+            }
+
+            @Override public void executeDdl(Context context, SqlNode node) {
+              ++counter;
+            }
+          };
+        }
+      };
+    }
+  }
+
   /** Dummy table. */
   public static class MyTable {
     public String mykey = "foo";


[09/18] incubator-calcite git commit: Lazily create exception only when it needs to be thrown (Marc Prud'hommeaux)

Posted by jh...@apache.org.
Lazily create exception only when it needs to be thrown (Marc Prud'hommeaux)

Exceptions are expensive to create, so don't create a RuntimeException()
unless we are actually going to throw something.

Close apache/incubator-calcite#117


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

Branch: refs/heads/master
Commit: a5688ffc007d3dc15594238e69ec0b2e806358d3
Parents: 54249d0
Author: Marc Prud'hommeaux <mw...@cornell.edu>
Authored: Wed Aug 5 20:35:40 2015 -0400
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Sep 1 16:17:15 2015 -0700

----------------------------------------------------------------------
 .../main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java   | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/a5688ffc/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
index 144755a..b7f444f 100644
--- a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
@@ -562,7 +562,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
     if (plannerFactories.isEmpty()) {
       throw new AssertionError("no planner factories");
     }
-    RuntimeException exception = new RuntimeException();
+    RuntimeException exception = Util.FoundOne.NULL;
     for (Function1<Context, RelOptPlanner> plannerFactory : plannerFactories) {
       final RelOptPlanner planner = plannerFactory.apply(context);
       if (planner == null) {


[07/18] incubator-calcite git commit: [CALCITE-812] Make JSON reader and writer use properly quoted key names (Marc Prud'hommeaux)

Posted by jh...@apache.org.
[CALCITE-812] Make JSON reader and writer use properly quoted key names (Marc Prud'hommeaux)

Fix Mongo test (Julian Hyde)

Close apache/incubator-calcite#116


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

Branch: refs/heads/master
Commit: 54249d04d4b578cfd7cb437e097d848e57737987
Parents: 77674a7
Author: Marc Prud'hommeaux <mw...@cornell.edu>
Authored: Wed Aug 5 13:15:45 2015 -0400
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Sep 1 16:17:15 2015 -0700

----------------------------------------------------------------------
 .../calcite/rel/externalize/RelJsonReader.java  |  3 --
 .../org/apache/calcite/util/JsonBuilder.java    |  2 +-
 .../org/apache/calcite/plan/RelWriterTest.java  | 54 ++++++++++----------
 .../java/org/apache/calcite/util/UtilTest.java  | 10 ++--
 .../org/apache/calcite/test/MongoAdapterIT.java | 42 +++++++--------
 5 files changed, 54 insertions(+), 57 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/54249d04/core/src/main/java/org/apache/calcite/rel/externalize/RelJsonReader.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/externalize/RelJsonReader.java b/core/src/main/java/org/apache/calcite/rel/externalize/RelJsonReader.java
index 12bf70c..b3f9a56 100644
--- a/core/src/main/java/org/apache/calcite/rel/externalize/RelJsonReader.java
+++ b/core/src/main/java/org/apache/calcite/rel/externalize/RelJsonReader.java
@@ -35,7 +35,6 @@ import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Util;
 
-import com.fasterxml.jackson.core.JsonParser;
 import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.common.collect.ImmutableList;
@@ -77,8 +76,6 @@ public class RelJsonReader {
   public RelNode read(String s) throws IOException {
     lastRel = null;
     final ObjectMapper mapper = new ObjectMapper();
-    mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
-    mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
     Map<String, Object> o = mapper.readValue(s, TYPE_REF);
     readRels((List<Map<String, Object>>) o.get("rels"));
     System.out.println(lastRel);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/54249d04/core/src/main/java/org/apache/calcite/util/JsonBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/JsonBuilder.java b/core/src/main/java/org/apache/calcite/util/JsonBuilder.java
index fcf4d30..b4acecb 100644
--- a/core/src/main/java/org/apache/calcite/util/JsonBuilder.java
+++ b/core/src/main/java/org/apache/calcite/util/JsonBuilder.java
@@ -113,7 +113,7 @@ public class JsonBuilder {
         buf.append(",");
         newline(buf, indent + 1);
       }
-      buf.append(entry.getKey());
+      append(buf, 0, entry.getKey());
       buf.append(": ");
       append(buf, indent + 1, entry.getValue());
     }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/54249d04/core/src/test/java/org/apache/calcite/plan/RelWriterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/plan/RelWriterTest.java b/core/src/test/java/org/apache/calcite/plan/RelWriterTest.java
index cff82e9..c766110 100644
--- a/core/src/test/java/org/apache/calcite/plan/RelWriterTest.java
+++ b/core/src/test/java/org/apache/calcite/plan/RelWriterTest.java
@@ -51,55 +51,55 @@ import static org.junit.Assert.assertThat;
  */
 public class RelWriterTest {
   public static final String XX = "{\n"
-      + "  rels: [\n"
+      + "  \"rels\": [\n"
       + "    {\n"
-      + "      id: \"0\",\n"
-      + "      relOp: \"LogicalTableScan\",\n"
-      + "      table: [\n"
+      + "      \"id\": \"0\",\n"
+      + "      \"relOp\": \"LogicalTableScan\",\n"
+      + "      \"table\": [\n"
       + "        \"hr\",\n"
       + "        \"emps\"\n"
       + "      ],\n"
-      + "      inputs: []\n"
+      + "      \"inputs\": []\n"
       + "    },\n"
       + "    {\n"
-      + "      id: \"1\",\n"
-      + "      relOp: \"LogicalFilter\",\n"
-      + "      condition: {\n"
-      + "        op: \"=\",\n"
-      + "        operands: [\n"
+      + "      \"id\": \"1\",\n"
+      + "      \"relOp\": \"LogicalFilter\",\n"
+      + "      \"condition\": {\n"
+      + "        \"op\": \"=\",\n"
+      + "        \"operands\": [\n"
       + "          {\n"
-      + "            input: 1\n"
+      + "            \"input\": 1\n"
       + "          },\n"
       + "          10\n"
       + "        ]\n"
       + "      }\n"
       + "    },\n"
       + "    {\n"
-      + "      id: \"2\",\n"
-      + "      relOp: \"LogicalAggregate\",\n"
-      + "      group: [\n"
+      + "      \"id\": \"2\",\n"
+      + "      \"relOp\": \"LogicalAggregate\",\n"
+      + "      \"group\": [\n"
       + "        0\n"
       + "      ],\n"
-      + "      aggs: [\n"
+      + "      \"aggs\": [\n"
       + "        {\n"
-      + "          agg: \"COUNT\",\n"
-      + "          type: {\n"
-      + "            type: \"BIGINT\",\n"
-      + "            nullable: false\n"
+      + "          \"agg\": \"COUNT\",\n"
+      + "          \"type\": {\n"
+      + "            \"type\": \"BIGINT\",\n"
+      + "            \"nullable\": false\n"
       + "          },\n"
-      + "          distinct: true,\n"
-      + "          operands: [\n"
+      + "          \"distinct\": true,\n"
+      + "          \"operands\": [\n"
       + "            1\n"
       + "          ]\n"
       + "        },\n"
       + "        {\n"
-      + "          agg: \"COUNT\",\n"
-      + "          type: {\n"
-      + "            type: \"BIGINT\",\n"
-      + "            nullable: false\n"
+      + "          \"agg\": \"COUNT\",\n"
+      + "          \"type\": {\n"
+      + "            \"type\": \"BIGINT\",\n"
+      + "            \"nullable\": false\n"
       + "          },\n"
-      + "          distinct: false,\n"
-      + "          operands: []\n"
+      + "          \"distinct\": false,\n"
+      + "          \"operands\": []\n"
       + "        }\n"
       + "      ]\n"
       + "    }\n"

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/54249d04/core/src/test/java/org/apache/calcite/util/UtilTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/util/UtilTest.java b/core/src/test/java/org/apache/calcite/util/UtilTest.java
index 92b5c34..0f0a463 100644
--- a/core/src/test/java/org/apache/calcite/util/UtilTest.java
+++ b/core/src/test/java/org/apache/calcite/util/UtilTest.java
@@ -1011,17 +1011,17 @@ public class UtilTest {
     map.put("nullValue", null);
     assertEquals(
         "{\n"
-            + "  foo: 1,\n"
-            + "  baz: true,\n"
-            + "  bar: \"can't\",\n"
-            + "  list: [\n"
+            + "  \"foo\": 1,\n"
+            + "  \"baz\": true,\n"
+            + "  \"bar\": \"can't\",\n"
+            + "  \"list\": [\n"
             + "    2,\n"
             + "    3,\n"
             + "    [],\n"
             + "    {},\n"
             + "    null\n"
             + "  ],\n"
-            + "  nullValue: null\n"
+            + "  \"nullValue\": null\n"
             + "}",
         builder.toJsonString(map));
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/54249d04/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 2393660..1c37369 100644
--- a/mongodb/src/test/java/org/apache/calcite/test/MongoAdapterIT.java
+++ b/mongodb/src/test/java/org/apache/calcite/test/MongoAdapterIT.java
@@ -317,8 +317,8 @@ public class MongoAdapterIT {
         .queryContains(
             mongoChecker(
                 "{\n"
-                    + "  $match: {\n"
-                    + "    state: \"OK\"\n"
+                    + "  \"$match\": {\n"
+                    + "    \"state\": \"OK\"\n"
                     + "  }\n"
                     + "}",
                 "{$project: {CITY: '$city', LONGITUDE: '$loc[0]', LATITUDE: '$loc[1]', POP: '$pop', STATE: '$state', ID: '$_id'}}"));
@@ -345,8 +345,8 @@ public class MongoAdapterIT {
             // $match must occur before $project for good performance.
             mongoChecker(
                 "{\n"
-                    + "  $match: {\n"
-                    + "    warehouse_state_province: \"CA\"\n"
+                    + "  \"$match\": {\n"
+                    + "    \"warehouse_state_province\": \"CA\"\n"
                     + "  }\n"
                     + "}",
                 "{$project: {warehouse_id: 1, warehouse_state_province: 1}}"));
@@ -371,31 +371,31 @@ public class MongoAdapterIT {
         .queryContains(
             mongoChecker(
                 "{\n"
-                    + "  $match: {\n"
-                    + "    $or: [\n"
+                    + "  \"$match\": {\n"
+                    + "    \"$or\": [\n"
                     + "      {\n"
-                    + "        store_name: \"Store 1\"\n"
+                    + "        \"store_name\": \"Store 1\"\n"
                     + "      },\n"
                     + "      {\n"
-                    + "        store_name: \"Store 10\"\n"
+                    + "        \"store_name\": \"Store 10\"\n"
                     + "      },\n"
                     + "      {\n"
-                    + "        store_name: \"Store 11\"\n"
+                    + "        \"store_name\": \"Store 11\"\n"
                     + "      },\n"
                     + "      {\n"
-                    + "        store_name: \"Store 15\"\n"
+                    + "        \"store_name\": \"Store 15\"\n"
                     + "      },\n"
                     + "      {\n"
-                    + "        store_name: \"Store 16\"\n"
+                    + "        \"store_name\": \"Store 16\"\n"
                     + "      },\n"
                     + "      {\n"
-                    + "        store_name: \"Store 24\"\n"
+                    + "        \"store_name\": \"Store 24\"\n"
                     + "      },\n"
                     + "      {\n"
-                    + "        store_name: \"Store 3\"\n"
+                    + "        \"store_name\": \"Store 3\"\n"
                     + "      },\n"
                     + "      {\n"
-                    + "        store_name: \"Store 7\"\n"
+                    + "        \"store_name\": \"Store 7\"\n"
                     + "      }\n"
                     + "    ]\n"
                     + "  }\n"
@@ -541,9 +541,9 @@ public class MongoAdapterIT {
                 "{$group: {_id: '$STATE', C: {$sum: 1}}}",
                 "{$project: {STATE: '$_id', C: '$C'}}",
                 "{\n"
-                    + "  $match: {\n"
-                    + "    C: {\n"
-                    + "      $gt: 1500\n"
+                    + "  \"$match\": {\n"
+                    + "    \"C\": {\n"
+                    + "      \"$gt\": 1500\n"
                     + "    }\n"
                     + "  }\n"
                     + "}",
@@ -624,13 +624,13 @@ public class MongoAdapterIT {
         .queryContains(
             mongoChecker(
                 "{\n"
-                    + "  $match: {\n"
-                    + "    $or: [\n"
+                    + "  \"$match\": {\n"
+                    + "    \"$or\": [\n"
                     + "      {\n"
-                    + "        state: \"CA\"\n"
+                    + "        \"state\": \"CA\"\n"
                     + "      },\n"
                     + "      {\n"
-                    + "        state: \"TX\"\n"
+                    + "        \"state\": \"TX\"\n"
                     + "      }\n"
                     + "    ]\n"
                     + "  }\n"


[05/18] incubator-calcite git commit: [CALCITE-820] Validate that window functions have OVER clause (Hsuan-Yi Chu)

Posted by jh...@apache.org.
[CALCITE-820] Validate that window functions have OVER clause (Hsuan-Yi Chu)

Close apache/incubator-calcite#113


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

Branch: refs/heads/master
Commit: 77674a7c64dfbe7f45a2fea12bce475a9f96161f
Parents: 5d8a90b
Author: Hsuan-Yi Chu <hs...@usc.edu>
Authored: Tue Jul 28 15:32:33 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Sep 1 16:17:14 2015 -0700

----------------------------------------------------------------------
 .../apache/calcite/runtime/CalciteResource.java |  3 ++
 .../org/apache/calcite/sql/SqlAggFunction.java  | 48 ++++++++++++++++++--
 .../org/apache/calcite/sql/SqlRankFunction.java | 11 ++---
 .../calcite/sql/fun/SqlAvgAggFunction.java      |  5 +-
 .../calcite/sql/fun/SqlCountAggFunction.java    |  5 +-
 .../calcite/sql/fun/SqlCovarAggFunction.java    |  5 +-
 .../sql/fun/SqlFirstLastValueAggFunction.java   | 12 ++---
 .../sql/fun/SqlHistogramAggFunction.java        |  5 +-
 .../calcite/sql/fun/SqlLeadLagAggFunction.java  |  9 ++--
 .../calcite/sql/fun/SqlMinMaxAggFunction.java   |  5 +-
 .../calcite/sql/fun/SqlNtileAggFunction.java    |  9 ++--
 .../sql/fun/SqlSingleValueAggFunction.java      |  5 +-
 .../calcite/sql/fun/SqlSumAggFunction.java      |  5 +-
 .../sql/fun/SqlSumEmptyIsZeroAggFunction.java   |  5 +-
 .../sql/validate/SqlUserDefinedAggFunction.java |  2 +-
 .../calcite/sql/validate/SqlValidatorImpl.java  | 10 ++++
 .../calcite/runtime/CalciteResource.properties  |  1 +
 .../apache/calcite/test/SqlValidatorTest.java   | 26 ++++++++++-
 .../org/apache/calcite/tools/PlannerTest.java   |  4 +-
 19 files changed, 134 insertions(+), 41 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/77674a7c/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
index a511143..e74f915 100644
--- a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
+++ b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
@@ -243,6 +243,9 @@ public interface CalciteResource {
   ExInst<SqlValidatorException> naturalOrUsingColumnNotCompatible(String a0,
       String a1, String a2);
 
+  @BaseMessage("OVER clause is necessary for window functions")
+  ExInst<SqlValidatorException> absentOverClause();
+
   @BaseMessage("Window ''{0}'' not found")
   ExInst<SqlValidatorException> windowNotFound(String a0);
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/77674a7c/core/src/main/java/org/apache/calcite/sql/SqlAggFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlAggFunction.java b/core/src/main/java/org/apache/calcite/sql/SqlAggFunction.java
index 944309a..83fe248 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlAggFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlAggFunction.java
@@ -28,9 +28,13 @@ import org.apache.calcite.sql.validate.SqlValidatorScope;
  * which aggregates sets of values into a result.
  */
 public abstract class SqlAggFunction extends SqlFunction implements Context {
+  private final boolean requiresOrder;
+  private final boolean requiresOver;
+
   //~ Constructors -----------------------------------------------------------
 
   /** Creates a built-in SqlAggFunction. */
+  @Deprecated // to be removed before 2.0
   protected SqlAggFunction(
       String name,
       SqlKind kind,
@@ -40,10 +44,11 @@ public abstract class SqlAggFunction extends SqlFunction implements Context {
       SqlFunctionCategory funcType) {
     // We leave sqlIdentifier as null to indicate that this is a builtin.
     this(name, null, kind, returnTypeInference, operandTypeInference,
-        operandTypeChecker, funcType);
+        operandTypeChecker, funcType, false, false);
   }
 
   /** Creates a user-defined SqlAggFunction. */
+  @Deprecated // to be removed before 2.0
   protected SqlAggFunction(
       String name,
       SqlIdentifier sqlIdentifier,
@@ -52,8 +57,28 @@ public abstract class SqlAggFunction extends SqlFunction implements Context {
       SqlOperandTypeInference operandTypeInference,
       SqlOperandTypeChecker operandTypeChecker,
       SqlFunctionCategory funcType) {
+    this(name, sqlIdentifier, kind, returnTypeInference, operandTypeInference,
+        operandTypeChecker, funcType, false, false);
+  }
+
+  /** Creates a built-in or user-defined SqlAggFunction or window function.
+   *
+   * <p>A user-defined function will have a value for {@code sqlIdentifier}; for
+   * a built-in function it will be null. */
+  protected SqlAggFunction(
+      String name,
+      SqlIdentifier sqlIdentifier,
+      SqlKind kind,
+      SqlReturnTypeInference returnTypeInference,
+      SqlOperandTypeInference operandTypeInference,
+      SqlOperandTypeChecker operandTypeChecker,
+      SqlFunctionCategory funcType,
+      boolean requiresOrder,
+      boolean requireOver) {
     super(name, sqlIdentifier, kind, returnTypeInference, operandTypeInference,
         operandTypeChecker, null, funcType);
+    this.requiresOrder = requiresOrder;
+    this.requiresOver =  requireOver;
   }
 
   //~ Methods ----------------------------------------------------------------
@@ -66,12 +91,11 @@ public abstract class SqlAggFunction extends SqlFunction implements Context {
     return true;
   }
 
-  public boolean isQuantifierAllowed() {
+  @Override public boolean isQuantifierAllowed() {
     return true;
   }
 
-  // override SqlFunction
-  public void validateCall(
+  @Override public void validateCall(
       SqlCall call,
       SqlValidator validator,
       SqlValidatorScope scope,
@@ -79,6 +103,22 @@ public abstract class SqlAggFunction extends SqlFunction implements Context {
     super.validateCall(call, validator, scope, operandScope);
     validator.validateAggregateParams(call, null, scope);
   }
+
+  @Override public final boolean requiresOrder() {
+    return requiresOrder;
+  }
+
+  /** Returns whether this is a window function that requires an OVER clause.
+   *
+   * <p>For example, {@code RANK} and {@code DENSE_RANK} require an OVER clause;
+   * {@code SUM} does not (it can be used as a non-window aggregate function).
+   *
+   * @see #allowsFraming()
+   * @see #requiresOrder()
+   */
+  public final boolean requiresOver() {
+    return requiresOver;
+  }
 }
 
 // End SqlAggFunction.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/77674a7c/core/src/main/java/org/apache/calcite/sql/SqlRankFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlRankFunction.java b/core/src/main/java/org/apache/calcite/sql/SqlRankFunction.java
index 11b5ca1..e2a2490 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlRankFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlRankFunction.java
@@ -31,7 +31,6 @@ import java.util.List;
 public class SqlRankFunction extends SqlAggFunction {
   //~ Instance fields --------------------------------------------------------
 
-  private final boolean requiresOrder;
   private final RelDataType type = null;
 
   //~ Constructors -----------------------------------------------------------
@@ -39,20 +38,18 @@ public class SqlRankFunction extends SqlAggFunction {
   public SqlRankFunction(String name, boolean requiresOrder) {
     super(
         name,
+        null,
         SqlKind.OTHER_FUNCTION,
         ReturnTypes.INTEGER,
         null,
         OperandTypes.NILADIC,
-        SqlFunctionCategory.NUMERIC);
-    this.requiresOrder = requiresOrder;
+        SqlFunctionCategory.NUMERIC,
+        requiresOrder,
+        true);
   }
 
   //~ Methods ----------------------------------------------------------------
 
-  @Override public boolean requiresOrder() {
-    return requiresOrder;
-  }
-
   @Override public boolean allowsFraming() {
     return false;
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/77674a7c/core/src/main/java/org/apache/calcite/sql/fun/SqlAvgAggFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlAvgAggFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlAvgAggFunction.java
index af78e8c..b86d49c 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlAvgAggFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlAvgAggFunction.java
@@ -53,11 +53,14 @@ public class SqlAvgAggFunction extends SqlAggFunction {
       Subtype subtype) {
     super(
         subtype.name(),
+        null,
         SqlKind.OTHER_FUNCTION,
         ReturnTypes.ARG0_NULLABLE_IF_EMPTY,
         null,
         OperandTypes.NUMERIC,
-        SqlFunctionCategory.NUMERIC);
+        SqlFunctionCategory.NUMERIC,
+        false,
+        false);
     this.type = type;
     this.subtype = subtype;
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/77674a7c/core/src/main/java/org/apache/calcite/sql/fun/SqlCountAggFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlCountAggFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlCountAggFunction.java
index 3feefc2..e91f30b 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlCountAggFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlCountAggFunction.java
@@ -47,13 +47,16 @@ public class SqlCountAggFunction extends SqlAggFunction {
   public SqlCountAggFunction() {
     super(
         "COUNT",
+        null,
         SqlKind.OTHER_FUNCTION,
         ReturnTypes.BIGINT,
         null,
         SqlValidator.STRICT
             ? OperandTypes.ANY
             : OperandTypes.ONE_OR_MORE,
-        SqlFunctionCategory.NUMERIC);
+        SqlFunctionCategory.NUMERIC,
+        false,
+        false);
   }
 
   //~ Methods ----------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/77674a7c/core/src/main/java/org/apache/calcite/sql/fun/SqlCovarAggFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlCovarAggFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlCovarAggFunction.java
index be63c1a..df36095 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlCovarAggFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlCovarAggFunction.java
@@ -50,11 +50,14 @@ public class SqlCovarAggFunction extends SqlAggFunction {
    */
   public SqlCovarAggFunction(RelDataType type, Subtype subtype) {
     super(subtype.name(),
+        null,
         SqlKind.OTHER_FUNCTION,
         ReturnTypes.ARG0_NULLABLE_IF_EMPTY,
         null,
         OperandTypes.NUMERIC_NUMERIC,
-        SqlFunctionCategory.NUMERIC);
+        SqlFunctionCategory.NUMERIC,
+        false,
+        false);
     this.type = type;
     this.subtype = subtype;
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/77674a7c/core/src/main/java/org/apache/calcite/sql/fun/SqlFirstLastValueAggFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlFirstLastValueAggFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlFirstLastValueAggFunction.java
index 2ca5375..bc75424 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlFirstLastValueAggFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlFirstLastValueAggFunction.java
@@ -40,22 +40,18 @@ public class SqlFirstLastValueAggFunction extends SqlAggFunction {
   public SqlFirstLastValueAggFunction(boolean firstFlag) {
     super(
         firstFlag ? "FIRST_VALUE" : "LAST_VALUE",
+        null,
         SqlKind.OTHER_FUNCTION,
         ReturnTypes.ARG0_NULLABLE_IF_EMPTY,
         null,
         OperandTypes.ANY,
-        SqlFunctionCategory.NUMERIC);
+        SqlFunctionCategory.NUMERIC,
+        false,
+        true);
   }
 
   //~ Methods ----------------------------------------------------------------
 
-  @Override public boolean requiresOrder() {
-    // Allow the user to shoot herself into the foot by using first_value
-    // and/or last_value without order by. This will result in undefined
-    // behaviour, however lots of databases allow that.
-    return false;
-  }
-
   public List<RelDataType> getParameterTypes(RelDataTypeFactory typeFactory) {
     return ImmutableList.of(
         typeFactory.createTypeWithNullability(

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/77674a7c/core/src/main/java/org/apache/calcite/sql/fun/SqlHistogramAggFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlHistogramAggFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlHistogramAggFunction.java
index 9f2e461..8572338 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlHistogramAggFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlHistogramAggFunction.java
@@ -45,11 +45,14 @@ public class SqlHistogramAggFunction extends SqlAggFunction {
   public SqlHistogramAggFunction(RelDataType type) {
     super(
         "$HISTOGRAM",
+        null,
         SqlKind.OTHER_FUNCTION,
         ReturnTypes.HISTOGRAM,
         null,
         OperandTypes.NUMERIC_OR_STRING,
-        SqlFunctionCategory.NUMERIC);
+        SqlFunctionCategory.NUMERIC,
+        false,
+        false);
     this.type = type;
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/77674a7c/core/src/main/java/org/apache/calcite/sql/fun/SqlLeadLagAggFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlLeadLagAggFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlLeadLagAggFunction.java
index a6d5fec..a2b0c45 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlLeadLagAggFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlLeadLagAggFunction.java
@@ -76,15 +76,14 @@ public class SqlLeadLagAggFunction extends SqlAggFunction {
   public SqlLeadLagAggFunction(boolean isLead) {
     super(
         isLead ? "LEAD" : "LAG",
+        null,
         SqlKind.OTHER_FUNCTION,
         RETURN_TYPE,
         null,
         OPERAND_TYPES,
-        SqlFunctionCategory.NUMERIC);
-  }
-
-  @Override public boolean requiresOrder() {
-    return true;
+        SqlFunctionCategory.NUMERIC,
+        false,
+        true);
   }
 
   @Override public boolean allowsFraming() {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/77674a7c/core/src/main/java/org/apache/calcite/sql/fun/SqlMinMaxAggFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlMinMaxAggFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlMinMaxAggFunction.java
index 2ce8d6f..27a1a8b 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlMinMaxAggFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlMinMaxAggFunction.java
@@ -69,11 +69,14 @@ public class SqlMinMaxAggFunction extends SqlAggFunction {
       int kind) {
     super(
         isMin ? "MIN" : "MAX",
+        null,
         SqlKind.OTHER_FUNCTION,
         ReturnTypes.ARG0_NULLABLE_IF_EMPTY,
         null,
         OperandTypes.COMPARABLE_ORDERED,
-        SqlFunctionCategory.SYSTEM);
+        SqlFunctionCategory.SYSTEM,
+        false,
+        false);
     this.argTypes = argTypes;
     this.isMin = isMin;
     this.kind = kind;

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/77674a7c/core/src/main/java/org/apache/calcite/sql/fun/SqlNtileAggFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlNtileAggFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlNtileAggFunction.java
index 5aaa2c3..524e7d6 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlNtileAggFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlNtileAggFunction.java
@@ -34,15 +34,14 @@ public class SqlNtileAggFunction extends SqlAggFunction {
   public SqlNtileAggFunction() {
     super(
         "NTILE",
+        null,
         SqlKind.OTHER_FUNCTION,
         ReturnTypes.INTEGER,
         null,
         OperandTypes.POSITIVE_INTEGER_LITERAL,
-        SqlFunctionCategory.NUMERIC);
-  }
-
-  @Override public boolean requiresOrder() {
-    return true;
+        SqlFunctionCategory.NUMERIC,
+        false,
+        true);
   }
 
   public List<RelDataType> getParameterTypes(RelDataTypeFactory typeFactory) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/77674a7c/core/src/main/java/org/apache/calcite/sql/fun/SqlSingleValueAggFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlSingleValueAggFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlSingleValueAggFunction.java
index f13f3d8..a27e180 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlSingleValueAggFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlSingleValueAggFunction.java
@@ -43,11 +43,14 @@ public class SqlSingleValueAggFunction extends SqlAggFunction {
       RelDataType type) {
     super(
         "SINGLE_VALUE",
+        null,
         SqlKind.OTHER_FUNCTION,
         ReturnTypes.ARG0,
         null,
         OperandTypes.ANY,
-        SqlFunctionCategory.SYSTEM);
+        SqlFunctionCategory.SYSTEM,
+        false,
+        false);
     this.type = type;
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/77674a7c/core/src/main/java/org/apache/calcite/sql/fun/SqlSumAggFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlSumAggFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlSumAggFunction.java
index 41b9d1d..0fc6606 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlSumAggFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlSumAggFunction.java
@@ -46,11 +46,14 @@ public class SqlSumAggFunction extends SqlAggFunction {
   public SqlSumAggFunction(RelDataType type) {
     super(
         "SUM",
+        null,
         SqlKind.OTHER_FUNCTION,
         ReturnTypes.ARG0_NULLABLE_IF_EMPTY,
         null,
         OperandTypes.NUMERIC,
-        SqlFunctionCategory.NUMERIC);
+        SqlFunctionCategory.NUMERIC,
+        false,
+        false);
     this.type = type;
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/77674a7c/core/src/main/java/org/apache/calcite/sql/fun/SqlSumEmptyIsZeroAggFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlSumEmptyIsZeroAggFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlSumEmptyIsZeroAggFunction.java
index 965ae75..9cb3459 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlSumEmptyIsZeroAggFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlSumEmptyIsZeroAggFunction.java
@@ -41,11 +41,14 @@ public class SqlSumEmptyIsZeroAggFunction extends SqlAggFunction {
 
   SqlSumEmptyIsZeroAggFunction() {
     super("$SUM0",
+        null,
         SqlKind.OTHER_FUNCTION,
         ReturnTypes.ARG0,
         null,
         OperandTypes.NUMERIC,
-        SqlFunctionCategory.NUMERIC);
+        SqlFunctionCategory.NUMERIC,
+        false,
+        false);
   }
 
   //~ Methods ----------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/77674a7c/core/src/main/java/org/apache/calcite/sql/validate/SqlUserDefinedAggFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlUserDefinedAggFunction.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlUserDefinedAggFunction.java
index 6994e97..a5592f3 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlUserDefinedAggFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlUserDefinedAggFunction.java
@@ -49,7 +49,7 @@ public class SqlUserDefinedAggFunction extends SqlAggFunction {
       SqlOperandTypeChecker operandTypeChecker, AggregateFunction function) {
     super(Util.last(opName.names), opName, SqlKind.OTHER_FUNCTION,
         returnTypeInference, operandTypeInference, operandTypeChecker,
-        SqlFunctionCategory.USER_DEFINED_FUNCTION);
+        SqlFunctionCategory.USER_DEFINED_FUNCTION, false, false);
     this.function = function;
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/77674a7c/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
index f210749..90fa0e2 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
@@ -30,6 +30,7 @@ import org.apache.calcite.sql.JoinConditionType;
 import org.apache.calcite.sql.JoinType;
 import org.apache.calcite.sql.SqlAccessEnum;
 import org.apache.calcite.sql.SqlAccessType;
+import org.apache.calcite.sql.SqlAggFunction;
 import org.apache.calcite.sql.SqlBasicCall;
 import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlCallBinding;
@@ -3399,6 +3400,15 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
    * @param scope Scope in which expression occurs
    */
   private void validateExpr(SqlNode expr, SqlValidatorScope scope) {
+    if (expr instanceof SqlCall) {
+      final SqlCall sqlCall = (SqlCall) expr;
+      if (sqlCall.getOperator().isAggregator()
+          && ((SqlAggFunction) sqlCall.getOperator()).requiresOver()) {
+        throw newValidationError(expr,
+            RESOURCE.absentOverClause());
+      }
+    }
+
     // Call on the expression to validate itself.
     expr.validateExpr(this, scope);
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/77674a7c/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
----------------------------------------------------------------------
diff --git a/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties b/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
index 5ab24cc..b3f9cce 100644
--- a/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
+++ b/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
@@ -115,6 +115,7 @@ RowMustBeNonNegativeIntegral=ROWS value must be a non-negative integral constant
 OverMissingOrderBy=Window specification must contain an ORDER BY clause
 PartitionbyShouldNotContainOver=PARTITION BY expression should not contain OVER clause
 OrderbyShouldNotContainOver=ORDER BY expression should not contain OVER clause
+AbsentOverClause=OVER clause is necessary for window functions
 BadLowerBoundary=UNBOUNDED FOLLOWING cannot be specified for the lower frame boundary
 BadUpperBoundary=UNBOUNDED PRECEDING cannot be specified for the upper frame boundary
 CurrentRowPrecedingError=Upper frame boundary cannot be PRECEDING when lower boundary is CURRENT ROW

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/77674a7c/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
index 106ad92..78d9e1c 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
@@ -3804,6 +3804,29 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
     // Test specified collation, window clause syntax rule 4,5.
   }
 
+  /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-820">[CALCITE-820]
+   * Validate that window functions have OVER clause</a>. */
+  @Test public void testWindowFunctionsWithoutOver() {
+    winSql(
+        "select sum(empno) \n"
+        + "from emp \n"
+        + "group by deptno \n"
+        + "order by ^row_number()^")
+        .fails("OVER clause is necessary for window functions");
+
+    winSql(
+        "select ^rank()^ \n"
+        + "from emp")
+        .fails("OVER clause is necessary for window functions");
+
+    winSql(
+        "select cume_dist() over w , ^rank()^\n"
+        + "from emp \n"
+        + "window w as (partition by deptno order by deptno)")
+        .fails("OVER clause is necessary for window functions");
+  }
+
   @Test public void testOverInPartitionBy() {
     winSql(
         "select sum(deptno) over ^(partition by sum(deptno) \n"
@@ -3900,7 +3923,8 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
 
     // rank function type
     if (defined.contains("DENSE_RANK")) {
-      winExp("dense_rank()").ok();
+      winExp("^dense_rank()^")
+          .fails("OVER clause is necessary for window functions");
     } else {
       checkWinFuncExpWithWinClause(
           "^dense_rank()^",

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/77674a7c/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 ff6094a..551a612 100644
--- a/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
+++ b/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
@@ -946,8 +946,8 @@ public class PlannerTest {
   /** User-defined aggregate function. */
   public static class MyCountAggFunction extends SqlAggFunction {
     public MyCountAggFunction() {
-      super("MY_COUNT", SqlKind.OTHER_FUNCTION, ReturnTypes.BIGINT, null,
-          OperandTypes.ANY, SqlFunctionCategory.NUMERIC);
+      super("MY_COUNT", null, SqlKind.OTHER_FUNCTION, ReturnTypes.BIGINT, null,
+          OperandTypes.ANY, SqlFunctionCategory.NUMERIC, false, false);
     }
 
     public List<RelDataType> getParameterTypes(RelDataTypeFactory typeFactory) {


[10/18] incubator-calcite git commit: [CALCITE-809] TableScan does not support large/infinite scans (Jesse Yates)

Posted by jh...@apache.org.
[CALCITE-809] TableScan does not support large/infinite scans (Jesse Yates)


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

Branch: refs/heads/master
Commit: 30d618d5f6254b269f7a6740f78ba9b63ff79040
Parents: 5b02090
Author: Jesse Yates <je...@gmail.com>
Authored: Sun Aug 9 12:04:11 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Sep 1 16:17:15 2015 -0700

----------------------------------------------------------------------
 .../apache/calcite/interpreter/Interpreter.java | 151 +++++++++++++---
 .../org/apache/calcite/interpreter/Sink.java    |   4 +
 .../org/apache/calcite/interpreter/Source.java  |   2 +
 .../calcite/interpreter/TableScanNode.java      |   7 +-
 .../apache/calcite/test/ScannableTableTest.java |   8 +-
 .../org/apache/calcite/test/StreamTest.java     | 170 +++++++++++++------
 .../calcite/linq4j/DelegatingEnumerator.java    |  48 ++++++
 .../java/org/apache/calcite/linq4j/Linq4j.java  |  12 ++
 8 files changed, 318 insertions(+), 84 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/30d618d5/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java b/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java
index deaf061..4c0886e 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java
@@ -18,13 +18,18 @@ package org.apache.calcite.interpreter;
 
 import org.apache.calcite.DataContext;
 import org.apache.calcite.linq4j.AbstractEnumerable;
+import org.apache.calcite.linq4j.DelegatingEnumerator;
+import org.apache.calcite.linq4j.Enumerable;
 import org.apache.calcite.linq4j.Enumerator;
+import org.apache.calcite.linq4j.Linq4j;
+import org.apache.calcite.linq4j.function.Function1;
 import org.apache.calcite.plan.hep.HepPlanner;
 import org.apache.calcite.plan.hep.HepProgram;
 import org.apache.calcite.plan.hep.HepProgramBuilder;
 import org.apache.calcite.prepare.CalcitePrepareImpl;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelVisitor;
+import org.apache.calcite.rel.core.TableScan;
 import org.apache.calcite.rel.rules.CalcSplitRule;
 import org.apache.calcite.rel.rules.FilterTableScanRule;
 import org.apache.calcite.rel.rules.ProjectTableScanRule;
@@ -87,33 +92,31 @@ public class Interpreter extends AbstractEnumerable<Object[]> {
 
   public Enumerator<Object[]> enumerator() {
     start();
-    final ArrayDeque<Row> queue = nodes.get(rootRel).sink.list;
-    return new Enumerator<Object[]>() {
-      Row row;
-
-      public Object[] current() {
-        return row.getValues();
-      }
-
-      public boolean moveNext() {
-        try {
-          row = queue.removeFirst();
-        } catch (NoSuchElementException e) {
-          return false;
-        }
-        return true;
-      }
-
-      public void reset() {
-        row = null;
-      }
+    Sink sink = nodes.get(rootRel).sink;
+    Enumerator<Row> rows;
+    if (sink instanceof EnumerableProxySink) {
+      rows = ((EnumerableProxySink) sink).enumerable.enumerator();
+    } else {
+      final ArrayDeque<Row> queue = ((ListSink) sink).list;
+      rows = Linq4j.asEnumerable(queue).enumerator();
+    }
 
+    return new DelegatingEnumerator<Object[]>(Linq4j.transform(rows, rowConverter)) {
+      @Override
       public void close() {
+        super.close();
         Interpreter.this.close();
       }
     };
   }
 
+  private Function1<Row, Object[]> rowConverter = new Function1<Row, Object[]>() {
+    @Override
+    public Object[] apply(Row row) {
+      return row.getValues();
+    }
+  };
+
   private void start() {
     // We rely on the nodes being ordered leaves first.
     for (Map.Entry<RelNode, NodeInfo> entry : nodes.entrySet()) {
@@ -261,7 +264,14 @@ public class Interpreter extends AbstractEnumerable<Object[]> {
     if (x == null) {
       throw new AssertionError("should be registered: " + rel);
     }
-    return new ListSource(x.sink);
+    Sink sink = x.sink;
+    if (sink instanceof ListSink) {
+      return new ListSource((ListSink) x.sink);
+    } else if (sink instanceof EnumerableProxySink) {
+      return new EnumerableProxySource((EnumerableProxySink) sink);
+    }
+    throw new IllegalStateException(
+      "Got a sink " + sink + " to which there is no match source type!");
   }
 
   private RelNode getInput(RelNode rel, int ordinal) {
@@ -273,9 +283,14 @@ public class Interpreter extends AbstractEnumerable<Object[]> {
   }
 
   public Sink sink(RelNode rel) {
-    final ArrayDeque<Row> queue = new ArrayDeque<Row>(1);
-    final ListSink sink = new ListSink(queue);
-    final NodeInfo nodeInfo = new NodeInfo(rel, sink);
+    final Sink sink;
+    if (rel instanceof TableScan) {
+      sink = new EnumerableProxySink();
+    } else {
+      final ArrayDeque<Row> queue = new ArrayDeque<Row>(1);
+      sink = new ListSink(queue);
+    }
+    NodeInfo nodeInfo = new NodeInfo(rel, sink);
     nodes.put(rel, nodeInfo);
     return sink;
   }
@@ -291,15 +306,83 @@ public class Interpreter extends AbstractEnumerable<Object[]> {
   /** Information about a node registered in the data flow graph. */
   private static class NodeInfo {
     final RelNode rel;
-    final ListSink sink;
+    final Sink sink;
     Node node;
 
-    public NodeInfo(RelNode rel, ListSink sink) {
+    public NodeInfo(RelNode rel, Sink sink) {
       this.rel = rel;
       this.sink = sink;
     }
   }
 
+  /**
+   * A sink that just proxies for an {@link org.apache.calcite.linq4j.Enumerable}. As such, its
+   * not really a "sink" but instead just a thin layer for the {@link EnumerableProxySource} to
+   * get an enumerator.
+   * <p>
+   * It can be little bit slower than the {@link Interpreter.ListSink} when trying to iterate
+   * over the elements of the enumerable, unless the enumerable is backed by an in-memory cache
+   * of the rows.
+   * </p>
+   */
+  private static class EnumerableProxySink implements Sink {
+
+    private Enumerable<Row> enumerable;
+
+    @Override
+    public void send(Row row) throws InterruptedException {
+      throw new UnsupportedOperationException("Row are only added through the enumerable passed "
+                                              + "in through #setSourceEnumerable()!");
+    }
+
+    @Override
+    public void end() throws InterruptedException {
+      // noop
+    }
+
+    @Override
+    public void setSourceEnumerable(Enumerable<Row> enumerable) {
+      this.enumerable = enumerable;
+    }
+  }
+
+  /**
+   * A {@link Source} that is just backed by an {@link Enumerator}. The {@link Enumerator} is closed
+   * when it is finished or by calling {@link #close()}
+   */
+  private static class EnumerableProxySource implements Source {
+
+    private Enumerator<Row> enumerator;
+    private final EnumerableProxySink source;
+
+    public EnumerableProxySource(EnumerableProxySink sink) {
+      this.source = sink;
+    }
+
+    @Override
+    public Row receive() {
+      if (enumerator == null) {
+        enumerator = source.enumerable.enumerator();
+        assert enumerator != null : "Sink did not set enumerable before source was asked for "
+                                    + "a row!";
+      }
+      if (enumerator.moveNext()) {
+        return enumerator.current();
+      }
+      // close the enumerator once we have gone through everything
+      enumerator.close();
+      this.enumerator = null;
+      return null;
+    }
+
+    @Override
+    public void close() {
+      if (this.enumerator != null) {
+        this.enumerator.close();
+      }
+    }
+  }
+
   /** Implementation of {@link Sink} using a {@link java.util.ArrayDeque}. */
   private static class ListSink implements Sink {
     final ArrayDeque<Row> list;
@@ -314,6 +397,17 @@ public class Interpreter extends AbstractEnumerable<Object[]> {
 
     public void end() throws InterruptedException {
     }
+
+    @Override
+    public void setSourceEnumerable(Enumerable<Row> enumerable) throws InterruptedException {
+      // just copy over the source into the local list
+      Enumerator<Row> enumerator = enumerable.enumerator();
+      Row row;
+      while (!enumerator.moveNext()) {
+        this.send(enumerator.current());
+      }
+      enumerator.close();
+    }
   }
 
   /** Implementation of {@link Source} using a {@link java.util.ArrayDeque}. */
@@ -331,6 +425,11 @@ public class Interpreter extends AbstractEnumerable<Object[]> {
         return null;
       }
     }
+
+    @Override
+    public void close() {
+      // noop
+    }
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/30d618d5/core/src/main/java/org/apache/calcite/interpreter/Sink.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/Sink.java b/core/src/main/java/org/apache/calcite/interpreter/Sink.java
index adcbac7..9e49ee5 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/Sink.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/Sink.java
@@ -16,6 +16,8 @@
  */
 package org.apache.calcite.interpreter;
 
+import org.apache.calcite.linq4j.Enumerable;
+
 /**
  * Sink to which to send rows.
  *
@@ -25,6 +27,8 @@ public interface Sink {
   void send(Row row) throws InterruptedException;
 
   void end() throws InterruptedException;
+
+  void setSourceEnumerable(Enumerable<Row> enumerable) throws InterruptedException;
 }
 
 // End Sink.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/30d618d5/core/src/main/java/org/apache/calcite/interpreter/Source.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/Source.java b/core/src/main/java/org/apache/calcite/interpreter/Source.java
index f020343..75b6c1b 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/Source.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/Source.java
@@ -24,6 +24,8 @@ package org.apache.calcite.interpreter;
 public interface Source {
   /** Reads a row. Null means end of data. */
   Row receive();
+
+  void close();
 }
 
 // End Source.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/30d618d5/core/src/main/java/org/apache/calcite/interpreter/TableScanNode.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/TableScanNode.java b/core/src/main/java/org/apache/calcite/interpreter/TableScanNode.java
index 2b1865f..2824b37 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/TableScanNode.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/TableScanNode.java
@@ -18,7 +18,6 @@ package org.apache.calcite.interpreter;
 
 import org.apache.calcite.DataContext;
 import org.apache.calcite.linq4j.Enumerable;
-import org.apache.calcite.linq4j.Enumerator;
 import org.apache.calcite.linq4j.Queryable;
 import org.apache.calcite.linq4j.function.Function1;
 import org.apache.calcite.linq4j.function.Predicate1;
@@ -71,11 +70,7 @@ public class TableScanNode implements Node {
 
 
   public void run() throws InterruptedException {
-    final Enumerator<Row> enumerator = enumerable.enumerator();
-    while (enumerator.moveNext()) {
-      sink.send(enumerator.current());
-    }
-    enumerator.close();
+    sink.setSourceEnumerable(enumerable);
     sink.end();
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/30d618d5/core/src/test/java/org/apache/calcite/test/ScannableTableTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/ScannableTableTest.java b/core/src/test/java/org/apache/calcite/test/ScannableTableTest.java
index 377fe67..2c24295 100644
--- a/core/src/test/java/org/apache/calcite/test/ScannableTableTest.java
+++ b/core/src/test/java/org/apache/calcite/test/ScannableTableTest.java
@@ -205,6 +205,7 @@ public class ScannableTableTest {
     assertThat(CalciteAssert.toString(resultSet),
         equalTo("i=4; k=1942\n"
             + "i=6; k=1943\n"));
+    resultSet.close();
     assertThat(buf.toString(),
         equalTo("returnCount=4, projects=[0, 2]"));
     buf.setLength(0);
@@ -274,9 +275,12 @@ public class ScannableTableTest {
     final Statement statement = connection.createStatement();
     ResultSet resultSet = statement.executeQuery(
         "select \"k\" from \"s\".\"beatles2\" where \"k\" > 1941");
-    assertThat(buf.toString(),
-        equalTo("returnCount=4, projects=[2]"));
     assertThat(CalciteAssert.toString(resultSet), equalTo("k=1942\nk=1943\n"));
+    // have to iterate (CalciteAssert.toString) and then close the result set b/c it is backed by
+    // an enumerable that only populates the info buffer (buf) on close
+    resultSet.close();
+    assertThat(buf.toString(),
+      equalTo("returnCount=4, projects=[2]"));
   }
 
   /** Table that returns one column via the {@link ScannableTable} interface. */

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/30d618d5/core/src/test/java/org/apache/calcite/test/StreamTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/StreamTest.java b/core/src/test/java/org/apache/calcite/test/StreamTest.java
index d4f4117..b8eacdd 100644
--- a/core/src/test/java/org/apache/calcite/test/StreamTest.java
+++ b/core/src/test/java/org/apache/calcite/test/StreamTest.java
@@ -20,6 +20,7 @@ import org.apache.calcite.DataContext;
 import org.apache.calcite.avatica.util.DateTimeUtils;
 import org.apache.calcite.linq4j.Enumerable;
 import org.apache.calcite.linq4j.Linq4j;
+import org.apache.calcite.linq4j.function.Function0;
 import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
@@ -38,6 +39,7 @@ import org.apache.calcite.util.ImmutableBitSet;
 import com.google.common.base.Function;
 import com.google.common.base.Throwables;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
 
 import org.junit.Ignore;
 import org.junit.Test;
@@ -45,6 +47,7 @@ import org.junit.Test;
 import java.sql.ResultSet;
 import java.sql.ResultSetMetaData;
 import java.sql.SQLException;
+import java.util.Iterator;
 import java.util.Map;
 
 import static org.hamcrest.CoreMatchers.equalTo;
@@ -54,23 +57,29 @@ import static org.junit.Assert.assertThat;
  * Tests for streaming queries.
  */
 public class StreamTest {
-  public static final String STREAM_SCHEMA = "     {\n"
-      + "       name: 'STREAMS',\n"
+  public static final String STREAM_SCHEMA_NAME = "STREAMS";
+  public static final String INFINITE_STREAM_SCHEMA_NAME = "INFINITE_STREAMS";
+
+  private static String schemaFor(String name, Class<? extends TableFactory> clazz) {
+    return "     {\n"
+      + "       name: '" + name + "',\n"
       + "       tables: [ {\n"
       + "         type: 'custom',\n"
       + "         name: 'ORDERS',\n"
       + "         stream: {\n"
       + "           stream: true\n"
       + "         },\n"
-      + "         factory: '" + OrdersStreamTableFactory.class.getName() + "'\n"
+      + "         factory: '" + clazz.getName() + "'\n"
       + "       } ]\n"
       + "     }\n";
+  }
 
   public static final String STREAM_MODEL = "{\n"
       + "  version: '1.0',\n"
       + "  defaultSchema: 'foodmart',\n"
       + "   schemas: [\n"
-      + STREAM_SCHEMA
+      + schemaFor(STREAM_SCHEMA_NAME, OrdersStreamTableFactory.class) + ",\n"
+      + schemaFor(INFINITE_STREAM_SCHEMA_NAME, InfiniteOrdersStreamTableFactory.class)
       + "   ]\n"
       + "}";
 
@@ -80,7 +89,7 @@ public class StreamTest {
         .query("select stream * from orders")
         .convertContains("LogicalDelta\n"
             + "  LogicalProject(ROWTIME=[$0], ID=[$1], PRODUCT=[$2], UNITS=[$3])\n"
-            + "    EnumerableTableScan(table=[[STREAMS, ORDERS]])\n")
+            + "    LogicalTableScan(table=[[STREAMS, ORDERS]])\n")
         .explainContains("EnumerableInterpreter\n"
             + "  BindableTableScan(table=[[]])")
         .returns(
@@ -97,7 +106,7 @@ public class StreamTest {
             "LogicalDelta\n"
                 + "  LogicalProject(PRODUCT=[$2])\n"
                 + "    LogicalFilter(condition=[>($3, 6)])\n"
-                + "      EnumerableTableScan(table=[[STREAMS, ORDERS]])\n")
+                + "      LogicalTableScan(table=[[STREAMS, ORDERS]])\n")
         .explainContains(
             "EnumerableCalc(expr#0..3=[{inputs}], expr#4=[6], expr#5=[>($t3, $t4)], PRODUCT=[$t2], $condition=[$t5])\n"
                 + "  EnumerableInterpreter\n"
@@ -120,7 +129,7 @@ public class StreamTest {
                 + "  LogicalFilter(condition=[>($2, 1)])\n"
                 + "    LogicalAggregate(group=[{0, 1}], C=[COUNT()])\n"
                 + "      LogicalProject(ROWTIME=[FLOOR($0, FLAG(HOUR))], PRODUCT=[$2])\n"
-                + "        EnumerableTableScan(table=[[STREAMS, ORDERS]])\n")
+                + "        LogicalTableScan(table=[[STREAMS, ORDERS]])\n")
         .explainContains(
             "EnumerableCalc(expr#0..2=[{inputs}], expr#3=[1], expr#4=[>($t2, $t3)], proj#0..2=[{exprs}], $condition=[$t4])\n"
                 + "  EnumerableAggregate(group=[{0, 1}], C=[COUNT()])\n"
@@ -142,7 +151,7 @@ public class StreamTest {
             "LogicalDelta\n"
                 + "  LogicalSort(sort0=[$0], sort1=[$1], dir0=[ASC], dir1=[DESC])\n"
                 + "    LogicalProject(ROWTIME=[FLOOR($0, FLAG(HOUR))], PRODUCT=[$2], UNITS=[$3])\n"
-                + "      EnumerableTableScan(table=[[STREAMS, ORDERS]])\n")
+                + "      LogicalTableScan(table=[[STREAMS, ORDERS]])\n")
         .explainContains(
             "EnumerableSort(sort0=[$0], sort1=[$1], dir0=[ASC], dir1=[DESC])\n"
                 + "  EnumerableCalc(expr#0..3=[{inputs}], expr#4=[FLAG(HOUR)], expr#5=[FLOOR($t0, $t4)], ROWTIME=[$t5], PRODUCT=[$t2], UNITS=[$t3])\n"
@@ -186,6 +195,19 @@ public class StreamTest {
                 "ROWTIME=2015-02-15 10:00:00; PRODUCT=paint; UNITS=3"));
   }
 
+  /**
+   * Regression test for CALCITE-809
+   */
+  @Test public void testInfiniteStreamsDoNotBufferInMemory() {
+    CalciteAssert.model(STREAM_MODEL)
+                 .withDefaultSchema(INFINITE_STREAM_SCHEMA_NAME)
+                 .query("select stream * from orders")
+                 .limit(100)
+                 .explainContains("EnumerableInterpreter\n"
+                                  + "  BindableTableScan(table=[[]])")
+                 .returnsCount(100);
+  }
+
   private Function<ResultSet, Void> startsWith(String... rows) {
     final ImmutableList<String> rowList = ImmutableList.copyOf(rows);
     return new Function<ResultSet, Void>() {
@@ -210,6 +232,38 @@ public class StreamTest {
     };
   }
 
+  /**
+   * Base table for the Orders table. Manages the base schema used for the test tables and common
+   * functions.
+   */
+  private abstract static class BaseOrderStreamTable implements ScannableTable, StreamableTable {
+    protected final RelProtoDataType protoRowType = new RelProtoDataType() {
+      public RelDataType apply(RelDataTypeFactory a0) {
+        return a0.builder()
+                 .add("ROWTIME", SqlTypeName.TIMESTAMP)
+                 .add("ID", SqlTypeName.INTEGER)
+                 .add("PRODUCT", SqlTypeName.VARCHAR, 10)
+                 .add("UNITS", SqlTypeName.INTEGER)
+                 .build();
+      }
+    };
+
+
+    public RelDataType getRowType(RelDataTypeFactory typeFactory) {
+      return protoRowType.apply(typeFactory);
+    }
+
+    public Statistic getStatistic() {
+      return Statistics.of(100d,
+        ImmutableList.<ImmutableBitSet>of(),
+        RelCollations.createSingleton(0));
+    }
+
+    public Schema.TableType getJdbcTableType() {
+      return Schema.TableType.TABLE;
+    }
+  }
+
   /** Mock table that returns a stream of orders from a fixed array. */
   @SuppressWarnings("UnusedDeclaration")
   public static class OrdersStreamTableFactory implements TableFactory<Table> {
@@ -219,16 +273,6 @@ public class StreamTest {
 
     public Table create(SchemaPlus schema, String name,
         Map<String, Object> operand, RelDataType rowType) {
-      final RelProtoDataType protoRowType = new RelProtoDataType() {
-        public RelDataType apply(RelDataTypeFactory a0) {
-          return a0.builder()
-              .add("ROWTIME", SqlTypeName.TIMESTAMP)
-              .add("ID", SqlTypeName.INTEGER)
-              .add("PRODUCT", SqlTypeName.VARCHAR, 10)
-              .add("UNITS", SqlTypeName.INTEGER)
-              .build();
-        }
-      };
       final ImmutableList<Object[]> rows = ImmutableList.of(
           new Object[] {ts(10, 15, 0), 1, "paint", 10},
           new Object[] {ts(10, 24, 15), 2, "paper", 5},
@@ -236,25 +280,7 @@ public class StreamTest {
           new Object[] {ts(10, 58, 0), 4, "paint", 3},
           new Object[] {ts(11, 10, 0), 5, "paint", 3});
 
-      return new StreamableTable() {
-        public Table stream() {
-          return new OrdersTable(protoRowType, rows);
-        }
-
-        public RelDataType getRowType(RelDataTypeFactory typeFactory) {
-          return protoRowType.apply(typeFactory);
-        }
-
-        public Statistic getStatistic() {
-          return Statistics.of(100d,
-              ImmutableList.<ImmutableBitSet>of(),
-              RelCollations.createSingleton(0));
-        }
-
-        public Schema.TableType getJdbcTableType() {
-          return Schema.TableType.TABLE;
-        }
-      };
+      return new OrdersTable(rows);
     }
 
     private Object ts(int h, int m, int s) {
@@ -263,13 +289,10 @@ public class StreamTest {
   }
 
   /** Table representing the ORDERS stream. */
-  public static class OrdersTable implements ScannableTable {
-    private final RelProtoDataType protoRowType;
+  public static class OrdersTable extends BaseOrderStreamTable {
     private final ImmutableList<Object[]> rows;
 
-    public OrdersTable(RelProtoDataType protoRowType,
-        ImmutableList<Object[]> rows) {
-      this.protoRowType = protoRowType;
+    public OrdersTable(ImmutableList<Object[]> rows) {
       this.rows = rows;
     }
 
@@ -277,18 +300,65 @@ public class StreamTest {
       return Linq4j.asEnumerable(rows);
     }
 
-    public RelDataType getRowType(RelDataTypeFactory typeFactory) {
-      return protoRowType.apply(typeFactory);
+    @Override
+    public Table stream() {
+      return new OrdersTable(rows);
     }
+  }
 
-    public Statistic getStatistic() {
-      return Statistics.of(100d,
-          ImmutableList.<ImmutableBitSet>of(),
-          RelCollations.createSingleton(0));
+  /**
+   * Mock table that returns a stream of orders from a fixed array.
+   */
+  @SuppressWarnings("UnusedDeclaration")
+  public static class InfiniteOrdersStreamTableFactory implements TableFactory<Table> {
+    // public constructor, per factory contract
+    public InfiniteOrdersStreamTableFactory() {
     }
 
-    public Schema.TableType getJdbcTableType() {
-      return Schema.TableType.STREAM;
+    public Table create(SchemaPlus schema, String name,
+      Map<String, Object> operand, RelDataType rowType) {
+      return new InfiniteOrdersTable();
+    }
+  }
+
+  public static final Function0<Object[]> ROW_GENERATOR = new Function0() {
+    private int counter = 0;
+    private Iterator<String> items = Iterables.cycle("paint", "paper", "brush").iterator();
+
+    @Override
+    public Object[] apply() {
+      return new Object[]{System.currentTimeMillis(), counter++, items.next(), 10};
+    }
+  };
+
+
+  /**
+   * Table representing an infinitely larger ORDERS stream.
+   */
+  public static class InfiniteOrdersTable extends BaseOrderStreamTable {
+
+    public Enumerable<Object[]> scan(DataContext root) {
+      return Linq4j.asEnumerable(new Iterable<Object[]>() {
+        @Override
+        public Iterator<Object[]> iterator() {
+          return new Iterator<Object[]>() {
+            @Override
+            public boolean hasNext() {
+              return true;
+            }
+
+            @Override
+            public Object[] next() {
+              return ROW_GENERATOR.apply();
+            }
+          };
+        }
+      });
+    }
+
+    @Override
+    public Table stream() {
+      return this;
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/30d618d5/linq4j/src/main/java/org/apache/calcite/linq4j/DelegatingEnumerator.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/DelegatingEnumerator.java b/linq4j/src/main/java/org/apache/calcite/linq4j/DelegatingEnumerator.java
new file mode 100644
index 0000000..043f094
--- /dev/null
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/DelegatingEnumerator.java
@@ -0,0 +1,48 @@
+/*
+ * 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.linq4j;
+
+/**
+ * Simple enumerator that just delegates all calls to the passed enumerator
+ * @param <T> type of value to return, as passed from the delegate enumerator
+ */
+public class DelegatingEnumerator<T> implements Enumerator<T> {
+
+  private Enumerator<T> delegate;
+
+  public DelegatingEnumerator(Enumerator<T> delegate) {
+    this.delegate = delegate;
+  }
+
+  @Override public T current() {
+    return delegate.current();
+  }
+
+  @Override public boolean moveNext() {
+    return delegate.moveNext();
+  }
+
+  @Override public void reset() {
+    delegate.reset();
+  }
+
+  @Override public void close() {
+    delegate.close();
+  }
+}
+
+// End DelegatingEnumerator.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/30d618d5/linq4j/src/main/java/org/apache/calcite/linq4j/Linq4j.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/Linq4j.java b/linq4j/src/main/java/org/apache/calcite/linq4j/Linq4j.java
index db897d9..eb50cee 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/Linq4j.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/Linq4j.java
@@ -16,6 +16,8 @@
  */
 package org.apache.calcite.linq4j;
 
+import org.apache.calcite.linq4j.function.Function1;
+
 import com.google.common.collect.Lists;
 
 import java.io.Closeable;
@@ -203,6 +205,16 @@ public abstract class Linq4j {
     return new ListEnumerator<V>(list);
   }
 
+  public static <T, R> Enumerator<R> transform(final Enumerator<T> enumerator,
+    final Function1<T, R> func) {
+    return new DelegatingEnumerator<R>((Enumerator<R>) enumerator) {
+      @Override
+      public R current() {
+        return func.apply((T) super.current());
+      }
+    };
+  }
+
   /**
    * Converts the elements of a given Iterable to the specified type.
    *


[03/18] incubator-calcite git commit: [CALCITE-824] Type inference when converting IN clause to semijoin (Josh Wills)

Posted by jh...@apache.org.
[CALCITE-824] Type inference when converting IN clause to semijoin (Josh Wills)


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

Branch: refs/heads/master
Commit: 5d8a90b8da6ed93393df0545dd4e49558dbb6db0
Parents: 24d3620
Author: Josh Wills <jw...@cloudera.com>
Authored: Thu Jul 30 12:36:24 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Sep 1 16:17:14 2015 -0700

----------------------------------------------------------------------
 .../calcite/sql2rel/SqlToRelConverter.java      | 31 +++++++++++------
 .../java/org/apache/calcite/test/CsvTest.java   | 35 ++++++++++++++++----
 2 files changed, 49 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5d8a90b8/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 40e6ed2..541c6ea 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -188,6 +188,10 @@ public class SqlToRelConverter {
 
   private static final BigDecimal TWO = BigDecimal.valueOf(2L);
 
+  /** Size of the smallest IN list that will be converted to a semijoin to a
+   * static table. */
+  public static final int IN_SUBQUERY_THRESHOLD = 20;
+
   //~ Instance fields --------------------------------------------------------
 
   protected final SqlValidator validator;
@@ -1021,9 +1025,12 @@ public class SqlToRelConverter {
       final boolean outerJoin = bb.subqueryNeedsOuterJoin
           || isNotIn
           || subQuery.logic == RelOptUtil.Logic.TRUE_FALSE_UNKNOWN;
+      final RelDataType targetRowType =
+          SqlTypeUtil.promoteToRowType(typeFactory,
+              validator.getValidatedNodeType(leftKeyNode), null);
       converted =
           convertExists(query, RelOptUtil.SubqueryType.IN, subQuery.logic,
-              outerJoin);
+              outerJoin, targetRowType);
       if (converted.right) {
         // Generate
         //    emp CROSS JOIN (SELECT COUNT(*) AS c,
@@ -1072,7 +1079,7 @@ public class SqlToRelConverter {
       call = (SqlBasicCall) subQuery.node;
       query = call.getOperands()[0];
       converted = convertExists(query, RelOptUtil.SubqueryType.EXISTS,
-          subQuery.logic, true);
+          subQuery.logic, true, null);
       assert !converted.right;
       if (convertNonCorrelatedSubQuery(subQuery, bb, converted.left, true)) {
         return;
@@ -1086,7 +1093,7 @@ public class SqlToRelConverter {
       call = (SqlBasicCall) subQuery.node;
       query = call.getOperands()[0];
       converted = convertExists(query, RelOptUtil.SubqueryType.SCALAR,
-          subQuery.logic, true);
+          subQuery.logic, true, null);
       assert !converted.right;
       if (convertNonCorrelatedSubQuery(subQuery, bb, converted.left, false)) {
         return;
@@ -1101,7 +1108,7 @@ public class SqlToRelConverter {
       // select * from unnest(select multiset[deptno] from emps);
       //
       converted = convertExists(subQuery.node, RelOptUtil.SubqueryType.SCALAR,
-          subQuery.logic, true);
+          subQuery.logic, true, null);
       assert !converted.right;
       subQuery.expr = bb.register(converted.left, JoinRelType.LEFT);
       return;
@@ -1377,10 +1384,10 @@ public class SqlToRelConverter {
    * predicate. A threshold of 0 forces usage of an inline table in all cases; a
    * threshold of Integer.MAX_VALUE forces usage of OR in all cases
    *
-   * @return threshold, default 20
+   * @return threshold, default {@link #IN_SUBQUERY_THRESHOLD}
    */
   protected int getInSubqueryThreshold() {
-    return 20;
+    return IN_SUBQUERY_THRESHOLD;
   }
 
   /**
@@ -1404,13 +1411,14 @@ public class SqlToRelConverter {
       SqlNode seek,
       RelOptUtil.SubqueryType subqueryType,
       RelOptUtil.Logic logic,
-      boolean needsOuterJoin) {
+      boolean needsOuterJoin,
+      RelDataType targetDataType) {
     final SqlValidatorScope seekScope =
         (seek instanceof SqlSelect)
             ? validator.getSelectScope((SqlSelect) seek)
             : null;
     final Blackboard seekBb = createBlackboard(seekScope, null);
-    RelNode seekRel = convertQueryOrInList(seekBb, seek);
+    RelNode seekRel = convertQueryOrInList(seekBb, seek, targetDataType);
 
     return RelOptUtil.createExistsPlan(seekRel, subqueryType, logic,
         needsOuterJoin);
@@ -1418,7 +1426,8 @@ public class SqlToRelConverter {
 
   private RelNode convertQueryOrInList(
       Blackboard bb,
-      SqlNode seek) {
+      SqlNode seek,
+      RelDataType targetRowType) {
     // NOTE: Once we start accepting single-row queries as row constructors,
     // there will be an ambiguity here for a case like X IN ((SELECT Y FROM
     // Z)).  The SQL standard resolves the ambiguity by saying that a lone
@@ -1431,7 +1440,7 @@ public class SqlToRelConverter {
           seek,
           ((SqlNodeList) seek).getList(),
           false,
-          null);
+          targetRowType);
     } else {
       return convertQueryRecursive(seek, false, null);
     }
@@ -3296,7 +3305,7 @@ public class SqlToRelConverter {
         validator.setValidatedNodeType(
             list,
             multisetType.getComponentType());
-        input = convertQueryOrInList(usedBb, list);
+        input = convertQueryOrInList(usedBb, list, null);
       } else {
         input = convertQuery(call.operand(0), false, true);
       }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5d8a90b8/example/csv/src/test/java/org/apache/calcite/test/CsvTest.java
----------------------------------------------------------------------
diff --git a/example/csv/src/test/java/org/apache/calcite/test/CsvTest.java b/example/csv/src/test/java/org/apache/calcite/test/CsvTest.java
index ba7c276..f228642 100644
--- a/example/csv/src/test/java/org/apache/calcite/test/CsvTest.java
+++ b/example/csv/src/test/java/org/apache/calcite/test/CsvTest.java
@@ -17,6 +17,7 @@
 package org.apache.calcite.test;
 
 import org.apache.calcite.linq4j.function.Function1;
+import org.apache.calcite.sql2rel.SqlToRelConverter;
 
 import org.junit.Assert;
 import org.junit.Ignore;
@@ -213,7 +214,7 @@ public class CsvTest {
     return new Function1<ResultSet, Void>() {
       public Void apply(ResultSet resultSet) {
         try {
-          final List<String> lines = new ArrayList<String>();
+          final List<String> lines = new ArrayList<>();
           CsvTest.collect(lines, resultSet);
           Assert.assertEquals(Arrays.asList(expected), lines);
         } catch (SQLException e) {
@@ -317,13 +318,37 @@ public class CsvTest {
         expect("NAME=Sales; CNT=1", "NAME=Marketing; CNT=2"));
   }
 
+  /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-824">[CALCITE-824]
+   * Type inference when converting IN clause to semijoin</a>. */
+  @Test public void testInToSemiJoinWithCast() throws SQLException {
+    // Note that the IN list needs at least 20 values to trigger the rewrite
+    // to a semijoin. Try it both ways.
+    final String sql = "SELECT e.name\n"
+        + "FROM emps AS e\n"
+        + "WHERE cast(e.empno as bigint) in ";
+    checkSql(sql + range(130, SqlToRelConverter.IN_SUBQUERY_THRESHOLD - 5),
+        "smart", expect("NAME=Alice"));
+    checkSql(sql + range(130, SqlToRelConverter.IN_SUBQUERY_THRESHOLD),
+        "smart", expect("NAME=Alice"));
+    checkSql(sql + range(130, SqlToRelConverter.IN_SUBQUERY_THRESHOLD + 1000),
+        "smart", expect("NAME=Alice"));
+  }
+
+  private String range(int first, int count) {
+    final StringBuilder sb = new StringBuilder();
+    for (int i = 0; i < count; i++) {
+      sb.append(i == 0 ? "(" : ", ").append(first + i);
+    }
+    return sb.append(')').toString();
+  }
+
   @Test public void testDateType() throws SQLException {
     Properties info = new Properties();
     info.put("model", jsonPath("bug"));
 
-    Connection connection = DriverManager.getConnection("jdbc:calcite:", info);
-
-    try {
+    try (Connection connection
+        = DriverManager.getConnection("jdbc:calcite:", info)) {
       ResultSet res = connection.getMetaData().getColumns(null, null,
           "DATE", "JOINEDAT");
       res.next();
@@ -360,8 +385,6 @@ public class CsvTest {
       Assert.assertEquals(java.sql.Timestamp.valueOf("1996-08-03 00:01:02"),
           resultSet.getTimestamp(3));
 
-    } finally {
-      connection.close();
     }
   }
 }


[04/18] incubator-calcite git commit: In RelBuilder, build expressions by table alias

Posted by jh...@apache.org.
In RelBuilder, build expressions by table alias

RelBuilder.distinct was projecting no fields, should project all

Change some RelBuilder parameters from List to Iterable

RelBuilder.filter must preserve aliases

RelBuilder.field(String, String) must have right nullability post outer join


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

Branch: refs/heads/master
Commit: 24d3620c385a27b83b8cfb95016ad173626d47aa
Parents: 27b359b
Author: Julian Hyde <jh...@apache.org>
Authored: Tue Jun 30 11:48:43 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Sep 1 16:17:14 2015 -0700

----------------------------------------------------------------------
 .../org/apache/calcite/tools/RelBuilder.java    | 139 ++++++++++++++++---
 .../org/apache/calcite/test/RelBuilderTest.java |  91 +++++++++---
 2 files changed, 191 insertions(+), 39 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/24d3620c/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 79fd482..696e22c 100644
--- a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
+++ b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
@@ -31,6 +31,7 @@ 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.Sort;
+import org.apache.calcite.rel.core.TableScan;
 import org.apache.calcite.rel.core.Values;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
@@ -50,10 +51,12 @@ 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.NlsString;
+import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Stacks;
 import org.apache.calcite.util.Util;
 
 import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
@@ -87,8 +90,8 @@ public class RelBuilder {
         }
       };
 
-  private final RelOptCluster cluster;
-  private final RelOptSchema relOptSchema;
+  protected final RelOptCluster cluster;
+  protected final RelOptSchema relOptSchema;
   private final RelFactories.FilterFactory filterFactory;
   private final RelFactories.ProjectFactory projectFactory;
   private final RelFactories.AggregateFactory aggregateFactory;
@@ -97,9 +100,9 @@ public class RelBuilder {
   private final RelFactories.JoinFactory joinFactory;
   private final RelFactories.ValuesFactory valuesFactory;
   private final RelFactories.TableScanFactory scanFactory;
-  private final List<RelNode> stack = new ArrayList<>();
+  private final List<Frame> stack = new ArrayList<>();
 
-  private RelBuilder(Context context, RelOptCluster cluster,
+  protected RelBuilder(Context context, RelOptCluster cluster,
       RelOptSchema relOptSchema) {
     this.cluster = cluster;
     this.relOptSchema = relOptSchema;
@@ -173,7 +176,7 @@ public class RelBuilder {
    * you need to use previously built expressions as inputs, call
    * {@link #build()} to pop those inputs. */
   public RelBuilder push(RelNode node) {
-    Stacks.push(stack, node);
+    Stacks.push(stack, new Frame(node));
     return this;
   }
 
@@ -182,23 +185,25 @@ public class RelBuilder {
    * <p>Throws if the stack is empty.
    */
   public RelNode build() {
-    if (stack.size() < 1) {
-      throw new IllegalArgumentException("expected stack size 1, but was "
-          + stack.size() + ": " + stack);
-    }
-    return Stacks.pop(stack);
+    return Stacks.pop(stack).rel;
   }
 
   /** Returns the relational expression at the top of the stack, but does not
    * remove it. */
   public RelNode peek() {
-    return Stacks.peek(stack);
+    return Stacks.peek(stack).rel;
   }
 
   /** Returns the relational expression {@code n} positions from the top of the
    * stack, but does not remove it. */
   public RelNode peek(int n) {
-    return Stacks.peek(n, stack);
+    return Stacks.peek(n, stack).rel;
+  }
+
+  /** Returns the relational expression {@code n} positions from the top of the
+   * stack, but does not remove it. */
+  public RelNode peek(int inputCount, int inputOrdinal) {
+    return Stacks.peek(inputCount - 1 - inputOrdinal, stack).rel;
   }
 
   // Methods that return scalar expressions
@@ -244,7 +249,7 @@ public class RelBuilder {
    * @param fieldName Field name
    */
   public RexInputRef field(int inputCount, int inputOrdinal, String fieldName) {
-    final RelNode input = peek(inputCount - 1 - inputOrdinal);
+    final RelNode input = peek(inputCount, inputOrdinal);
     final RelDataType rowType = input.getRowType();
     final int ordinal = rowType.getFieldNames().indexOf(fieldName);
     if (ordinal < 0) {
@@ -272,7 +277,7 @@ public class RelBuilder {
    * @param fieldOrdinal Field ordinal within input
    */
   public RexInputRef field(int inputCount, int inputOrdinal, int fieldOrdinal) {
-    final RelNode input = peek(inputCount - 1 - inputOrdinal);
+    final RelNode input = peek(inputCount, inputOrdinal);
     final RelDataType rowType = input.getRowType();
     if (fieldOrdinal < 0 || fieldOrdinal > rowType.getFieldCount()) {
       throw new IllegalArgumentException("field ordinal [" + fieldOrdinal
@@ -281,6 +286,48 @@ public class RelBuilder {
     return cluster.getRexBuilder().makeInputRef(input, fieldOrdinal);
   }
 
+  /** Creates a reference to a field of the current record which originated
+   * in a relation with a given alias. */
+  public RexNode field(String alias, String fieldName) {
+    Preconditions.checkNotNull(alias);
+    Preconditions.checkNotNull(fieldName);
+    final Frame frame = Stacks.peek(stack);
+    final List<String> aliases = new ArrayList<>();
+    int offset = 0;
+    for (Pair<String, RelDataType> pair : frame.right) {
+      if (pair.left != null && pair.left.equals(alias)) {
+        int i = pair.right.getFieldNames().indexOf(fieldName);
+        if (i >= 0) {
+          return field(offset + i);
+        } else {
+          throw new IllegalArgumentException("no field '" + fieldName
+              + "' in relation '" + alias
+              + "'; fields are: " + pair.right.getFieldNames());
+        }
+      }
+      aliases.add(pair.left);
+      offset += pair.right.getFieldCount();
+    }
+    throw new IllegalArgumentException("no relation wtih alias '" + alias
+        + "'; aliases are: " + aliases);
+  }
+
+  /** Returns references to the fields of the top input. */
+  public ImmutableList<RexNode> fields() {
+    return fields(1, 0);
+  }
+
+  /** Returns references to the fields of a given input. */
+  public ImmutableList<RexNode> fields(int inputCount, int inputOrdinal) {
+    final RelNode input = peek(inputCount, inputOrdinal);
+    final RelDataType rowType = input.getRowType();
+    final ImmutableList.Builder<RexNode> nodes = ImmutableList.builder();
+    for (int fieldOrdinal : Util.range(rowType.getFieldCount())) {
+      nodes.add(field(inputCount, inputOrdinal, fieldOrdinal));
+    }
+    return nodes.build();
+  }
+
   /** Creates a call to a scalar operator. */
   public RexNode call(SqlOperator operator, RexNode... operands) {
     final RexBuilder builder = cluster.getRexBuilder();
@@ -425,6 +472,13 @@ public class RelBuilder {
   /** Creates a call to an aggregate function. */
   public AggCall aggregateCall(SqlAggFunction aggFunction,
       boolean distinct, String alias, RexNode... operands) {
+    return aggregateCall(aggFunction, distinct, 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,
         ImmutableList.copyOf(operands));
   }
@@ -498,8 +552,9 @@ public class RelBuilder {
     final RexNode x = RexUtil.composeConjunction(cluster.getRexBuilder(),
         predicates, true);
     if (x != null) {
-      final RelNode filter = filterFactory.createFilter(build(), x);
-      push(filter);
+      final Frame frame = Stacks.pop(stack);
+      final RelNode filter = filterFactory.createFilter(frame.rel, x);
+      Stacks.push(stack, new Frame(filter, frame.right));
     }
     return this;
   }
@@ -517,7 +572,7 @@ public class RelBuilder {
    * call but uses the intended alias.
    * After the field names have been inferred, makes the
    * field names unique by appending numeric suffixes. */
-  public RelBuilder project(List<RexNode> nodes) {
+  public RelBuilder project(Iterable<? extends RexNode> nodes) {
     final List<String> names = new ArrayList<>();
     final List<RexNode> exprList = Lists.newArrayList(nodes);
     for (RexNode node : nodes) {
@@ -567,7 +622,7 @@ public class RelBuilder {
   /** Creates an {@link org.apache.calcite.rel.core.Aggregate} that makes the
    * relational expression distinct on all fields. */
   public RelBuilder distinct() {
-    return aggregate(groupKey());
+    return aggregate(groupKey(fields()));
   }
 
   /** Creates an {@link org.apache.calcite.rel.core.Aggregate} with an array of
@@ -676,11 +731,14 @@ public class RelBuilder {
 
   /** Creates a {@link org.apache.calcite.rel.core.Join}. */
   public RelBuilder join(JoinRelType joinType, RexNode condition) {
-    final RelNode left = build();
-    final RelNode right = build();
-    final RelNode join = joinFactory.createJoin(left, right, condition,
+    final Frame right = Stacks.pop(stack);
+    final Frame left = Stacks.pop(stack);
+    final RelNode join = joinFactory.createJoin(left.rel, right.rel, condition,
         joinType, ImmutableSet.<String>of(), false);
-    push(join);
+    final List<Pair<String, RelDataType>> pairs = new ArrayList<>();
+    pairs.addAll(left.right);
+    pairs.addAll(right.right);
+    Stacks.push(stack, new Frame(join, ImmutableList.copyOf(pairs)));
     return this;
   }
 
@@ -706,6 +764,15 @@ public class RelBuilder {
     return join(joinType, condition);
   }
 
+  /** Assigns a table alias to the top entry on the stack. */
+  public RelBuilder as(String alias) {
+    final Frame pair = Stacks.pop(stack);
+    Stacks.push(stack,
+        new Frame(pair.rel,
+            ImmutableList.of(Pair.of(alias, pair.rel.getRowType()))));
+    return this;
+  }
+
   /** Creates a {@link Values}.
    *
    * <p>The {@code values} array must have the same number of entries as
@@ -968,7 +1035,7 @@ public class RelBuilder {
     private final String alias;
     private final ImmutableList<RexNode> operands;
 
-    public AggCallImpl(SqlAggFunction aggFunction, boolean distinct,
+    AggCallImpl(SqlAggFunction aggFunction, boolean distinct,
         String alias, ImmutableList<RexNode> operands) {
       this.aggFunction = aggFunction;
       this.distinct = distinct;
@@ -992,6 +1059,32 @@ public class RelBuilder {
   public interface ProtoRelBuilder {
     RelBuilder create(RelOptCluster cluster, RelOptSchema schema);
   }
+
+  /** Builder stack frame.
+   *
+   * <p>Describes a previously created relational expression and
+   * information about how table aliases map into its row type. */
+  private static class Frame {
+    final RelNode rel;
+    final ImmutableList<Pair<String, RelDataType>> right;
+
+    private Frame(RelNode rel, ImmutableList<Pair<String, RelDataType>> pairs) {
+      this.rel = rel;
+      this.right = pairs;
+    }
+
+    private Frame(RelNode rel) {
+      this(rel, ImmutableList.of(Pair.of(deriveAlias(rel), rel.getRowType())));
+    }
+
+    private static String deriveAlias(RelNode rel) {
+      if (rel instanceof TableScan) {
+        TableScan scan = (TableScan) rel;
+        return Util.last(scan.getTable().getQualifiedName());
+      }
+      return null;
+    }
+  }
 }
 
 // End RelBuilder.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/24d3620c/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 abf85bb..cafd61e 100644
--- a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
@@ -27,6 +27,7 @@ import org.apache.calcite.rel.core.TableFunctionScan;
 import org.apache.calcite.rel.core.TableModify;
 import org.apache.calcite.rel.core.Window;
 import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeField;
 import org.apache.calcite.rex.RexInputRef;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.schema.SchemaPlus;
@@ -187,7 +188,8 @@ public class RelBuilderTest {
     final RelBuilder builder = RelBuilder.create(config().build());
     try {
       builder.scan("EMP");
-      RexNode call = builder.call(SqlStdOperatorTable.PLUS, builder.field(1),
+      RexNode call = builder.call(SqlStdOperatorTable.PLUS,
+          builder.field(1),
           builder.field(3));
       fail("expected error, got " + call);
     } catch (IllegalArgumentException e) {
@@ -260,9 +262,8 @@ public class RelBuilderTest {
     final RelBuilder builder = RelBuilder.create(config().build());
     RelNode root =
         builder.scan("EMP")
-            .aggregate(
-                builder.groupKey(), builder.aggregateCall(
-                    SqlStdOperatorTable.COUNT,
+            .aggregate(builder.groupKey(),
+                builder.aggregateCall(SqlStdOperatorTable.COUNT,
                     true,
                     "C",
                     builder.field("DEPTNO")))
@@ -282,14 +283,13 @@ public class RelBuilderTest {
         builder.scan("EMP")
             .aggregate(
                 builder.groupKey(builder.field(1),
-                    builder.call(SqlStdOperatorTable.PLUS, builder.field(4),
+                    builder.call(SqlStdOperatorTable.PLUS,
+                        builder.field(4),
                         builder.field(3)),
                     builder.field(1)),
                 builder.aggregateCall(SqlStdOperatorTable.COUNT, false, "C"),
                 builder.aggregateCall(SqlStdOperatorTable.SUM, false, "S",
-                    builder.call(
-                        SqlStdOperatorTable.PLUS,
-                        builder.field(3),
+                    builder.call(SqlStdOperatorTable.PLUS, builder.field(3),
                         builder.literal(1))))
             .build();
     assertThat(str(root),
@@ -302,15 +302,15 @@ public class RelBuilderTest {
   @Test public void testDistinct() {
     // Equivalent SQL:
     //   SELECT DISTINCT *
-    //   FROM emp
+    //   FROM dept
     final RelBuilder builder = RelBuilder.create(config().build());
     RelNode root =
-        builder.scan("EMP")
+        builder.scan("DEPT")
             .distinct()
             .build();
     assertThat(str(root),
-        is("LogicalAggregate(group=[{}])\n"
-                + "  LogicalTableScan(table=[[scott, EMP]])\n"));
+        is("LogicalAggregate(group=[{0, 1, 2}])\n"
+                + "  LogicalTableScan(table=[[scott, DEPT]])\n"));
   }
 
   @Test public void testUnion() {
@@ -412,9 +412,9 @@ public class RelBuilderTest {
             .build();
     final String expected =
         "LogicalJoin(condition=[=($7, $0)], joinType=[inner])\n"
-            + "  LogicalTableScan(table=[[scott, DEPT]])\n"
             + "  LogicalFilter(condition=[IS NULL($6)])\n"
-            + "    LogicalTableScan(table=[[scott, EMP]])\n";
+            + "    LogicalTableScan(table=[[scott, EMP]])\n"
+            + "  LogicalTableScan(table=[[scott, DEPT]])\n";
     assertThat(str(root), is(expected));
 
     // Using USING method
@@ -440,8 +440,67 @@ public class RelBuilderTest {
             .build();
     final String expected =
         "LogicalJoin(condition=[true], joinType=[inner])\n"
-            + "  LogicalTableScan(table=[[scott, DEPT]])\n"
-            + "  LogicalTableScan(table=[[scott, EMP]])\n";
+            + "  LogicalTableScan(table=[[scott, EMP]])\n"
+            + "  LogicalTableScan(table=[[scott, DEPT]])\n";
+    assertThat(str(root), is(expected));
+  }
+
+  @Test public void testAlias() {
+    // Equivalent SQL:
+    //   SELECT *
+    //   FROM emp AS e, dept
+    //   WHERE e.deptno = dept.deptno
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode root =
+        builder.scan("EMP")
+            .as("e")
+            .scan("DEPT")
+            .join(JoinRelType.LEFT)
+            .filter(
+                builder.equals(builder.field("e", "DEPTNO"),
+                    builder.field("DEPT", "DEPTNO")))
+            .project(builder.field("e", "ENAME"),
+                builder.field("DEPT", "DNAME"))
+            .build();
+    final String expected = "LogicalProject(ENAME=[$1], DNAME=[$9])\n"
+        + "  LogicalFilter(condition=[=($7, $8)])\n"
+        + "    LogicalJoin(condition=[true], joinType=[left])\n"
+        + "      LogicalTableScan(table=[[scott, EMP]])\n"
+        + "      LogicalTableScan(table=[[scott, DEPT]])\n";
+    assertThat(str(root), is(expected));
+    final RelDataTypeField field = root.getRowType().getFieldList().get(1);
+    assertThat(field.getName(), is("DNAME"));
+    assertThat(field.getType().isNullable(), is(true));
+  }
+
+  @Test public void testAlias2() {
+    // Equivalent SQL:
+    //   SELECT *
+    //   FROM emp AS e, emp as m, dept
+    //   WHERE e.deptno = dept.deptno
+    //   AND m.empno = e.mgr
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode root =
+        builder.scan("EMP")
+            .as("e")
+            .scan("EMP")
+            .as("m")
+            .scan("DEPT")
+            .join(JoinRelType.INNER)
+            .join(JoinRelType.INNER)
+            .filter(
+                builder.equals(builder.field("e", "DEPTNO"),
+                    builder.field("DEPT", "DEPTNO")),
+                builder.equals(builder.field("m", "EMPNO"),
+                    builder.field("e", "MGR")))
+            .build();
+    final String expected = ""
+        + "LogicalFilter(condition=[AND(=($7, $16), =($8, $3))])\n"
+        + "  LogicalJoin(condition=[true], joinType=[inner])\n"
+        + "    LogicalTableScan(table=[[scott, EMP]])\n"
+        + "    LogicalJoin(condition=[true], joinType=[inner])\n"
+        + "      LogicalTableScan(table=[[scott, EMP]])\n"
+        + "      LogicalTableScan(table=[[scott, DEPT]])\n";
     assertThat(str(root), is(expected));
   }
 


[06/18] incubator-calcite git commit: Fix up [CALCITE-809], deprecating Sink.setSourceEnumerable

Posted by jh...@apache.org.
Fix up [CALCITE-809], deprecating Sink.setSourceEnumerable


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

Branch: refs/heads/master
Commit: a3da69153b030552abf87f279487ebda4a5ae69c
Parents: 30d618d
Author: Julian Hyde <jh...@apache.org>
Authored: Mon Aug 10 15:11:24 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Sep 1 16:17:15 2015 -0700

----------------------------------------------------------------------
 .../apache/calcite/interpreter/Interpreter.java | 60 +++++++----------
 .../org/apache/calcite/interpreter/Sink.java    |  2 +
 .../org/apache/calcite/test/StreamTest.java     | 69 ++++++++++----------
 .../calcite/linq4j/DelegatingEnumerator.java    |  6 +-
 .../java/org/apache/calcite/linq4j/Linq4j.java  | 42 ++++++++++--
 5 files changed, 100 insertions(+), 79 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/a3da6915/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java b/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java
index 4c0886e..e4c2cfe 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java
@@ -102,20 +102,19 @@ public class Interpreter extends AbstractEnumerable<Object[]> {
     }
 
     return new DelegatingEnumerator<Object[]>(Linq4j.transform(rows, rowConverter)) {
-      @Override
-      public void close() {
+      @Override public void close() {
         super.close();
         Interpreter.this.close();
       }
     };
   }
 
-  private Function1<Row, Object[]> rowConverter = new Function1<Row, Object[]>() {
-    @Override
-    public Object[] apply(Row row) {
-      return row.getValues();
-    }
-  };
+  private Function1<Row, Object[]> rowConverter =
+    new Function1<Row, Object[]>() {
+      @Override public Object[] apply(Row row) {
+        return row.getValues();
+      }
+    };
 
   private void start() {
     // We rely on the nodes being ordered leaves first.
@@ -287,7 +286,7 @@ public class Interpreter extends AbstractEnumerable<Object[]> {
     if (rel instanceof TableScan) {
       sink = new EnumerableProxySink();
     } else {
-      final ArrayDeque<Row> queue = new ArrayDeque<Row>(1);
+      final ArrayDeque<Row> queue = new ArrayDeque<>(1);
       sink = new ListSink(queue);
     }
     NodeInfo nodeInfo = new NodeInfo(rel, sink);
@@ -319,36 +318,31 @@ public class Interpreter extends AbstractEnumerable<Object[]> {
    * A sink that just proxies for an {@link org.apache.calcite.linq4j.Enumerable}. As such, its
    * not really a "sink" but instead just a thin layer for the {@link EnumerableProxySource} to
    * get an enumerator.
-   * <p>
-   * It can be little bit slower than the {@link Interpreter.ListSink} when trying to iterate
+   *
+   * <p>It can be little bit slower than the {@link Interpreter.ListSink} when trying to iterate
    * over the elements of the enumerable, unless the enumerable is backed by an in-memory cache
    * of the rows.
-   * </p>
    */
   private static class EnumerableProxySink implements Sink {
-
     private Enumerable<Row> enumerable;
 
-    @Override
-    public void send(Row row) throws InterruptedException {
-      throw new UnsupportedOperationException("Row are only added through the enumerable passed "
-                                              + "in through #setSourceEnumerable()!");
+    @Override public void send(Row row) throws InterruptedException {
+      throw new UnsupportedOperationException("Rows are only added through the "
+          + "enumerable passed in through #setSourceEnumerable()!");
     }
 
-    @Override
-    public void end() throws InterruptedException {
+    @Override public void end() throws InterruptedException {
       // noop
     }
 
-    @Override
-    public void setSourceEnumerable(Enumerable<Row> enumerable) {
+    @Override public void setSourceEnumerable(Enumerable<Row> enumerable) {
       this.enumerable = enumerable;
     }
   }
 
   /**
    * A {@link Source} that is just backed by an {@link Enumerator}. The {@link Enumerator} is closed
-   * when it is finished or by calling {@link #close()}
+   * when it is finished or by calling {@link #close()}.
    */
   private static class EnumerableProxySource implements Source {
 
@@ -359,12 +353,11 @@ public class Interpreter extends AbstractEnumerable<Object[]> {
       this.source = sink;
     }
 
-    @Override
-    public Row receive() {
+    @Override public Row receive() {
       if (enumerator == null) {
         enumerator = source.enumerable.enumerator();
-        assert enumerator != null : "Sink did not set enumerable before source was asked for "
-                                    + "a row!";
+        assert enumerator != null
+            : "Sink did not set enumerable before source was asked for a row!";
       }
       if (enumerator.moveNext()) {
         return enumerator.current();
@@ -375,8 +368,7 @@ public class Interpreter extends AbstractEnumerable<Object[]> {
       return null;
     }
 
-    @Override
-    public void close() {
+    @Override public void close() {
       if (this.enumerator != null) {
         this.enumerator.close();
       }
@@ -398,12 +390,11 @@ public class Interpreter extends AbstractEnumerable<Object[]> {
     public void end() throws InterruptedException {
     }
 
-    @Override
-    public void setSourceEnumerable(Enumerable<Row> enumerable) throws InterruptedException {
+    @Override public void setSourceEnumerable(Enumerable<Row> enumerable)
+        throws InterruptedException {
       // just copy over the source into the local list
-      Enumerator<Row> enumerator = enumerable.enumerator();
-      Row row;
-      while (!enumerator.moveNext()) {
+      final Enumerator<Row> enumerator = enumerable.enumerator();
+      while (enumerator.moveNext()) {
         this.send(enumerator.current());
       }
       enumerator.close();
@@ -426,8 +417,7 @@ public class Interpreter extends AbstractEnumerable<Object[]> {
       }
     }
 
-    @Override
-    public void close() {
+    @Override public void close() {
       // noop
     }
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/a3da6915/core/src/main/java/org/apache/calcite/interpreter/Sink.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/Sink.java b/core/src/main/java/org/apache/calcite/interpreter/Sink.java
index 9e49ee5..6056b96 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/Sink.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/Sink.java
@@ -28,6 +28,8 @@ public interface Sink {
 
   void end() throws InterruptedException;
 
+  /** This method is temporary. It will be removed without notice. */
+  @Deprecated
   void setSourceEnumerable(Enumerable<Row> enumerable) throws InterruptedException;
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/a3da6915/core/src/test/java/org/apache/calcite/test/StreamTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/StreamTest.java b/core/src/test/java/org/apache/calcite/test/StreamTest.java
index b8eacdd..5a6291b 100644
--- a/core/src/test/java/org/apache/calcite/test/StreamTest.java
+++ b/core/src/test/java/org/apache/calcite/test/StreamTest.java
@@ -71,15 +71,17 @@ public class StreamTest {
       + "         },\n"
       + "         factory: '" + clazz.getName() + "'\n"
       + "       } ]\n"
-      + "     }\n";
+      + "     }";
   }
 
   public static final String STREAM_MODEL = "{\n"
       + "  version: '1.0',\n"
       + "  defaultSchema: 'foodmart',\n"
       + "   schemas: [\n"
-      + schemaFor(STREAM_SCHEMA_NAME, OrdersStreamTableFactory.class) + ",\n"
+      + schemaFor(STREAM_SCHEMA_NAME, OrdersStreamTableFactory.class)
+      + ",\n"
       + schemaFor(INFINITE_STREAM_SCHEMA_NAME, InfiniteOrdersStreamTableFactory.class)
+      + "\n"
       + "   ]\n"
       + "}";
 
@@ -196,16 +198,18 @@ public class StreamTest {
   }
 
   /**
-   * Regression test for CALCITE-809
+   * Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-809">[CALCITE-809]
+   * TableScan does not support large/infinite scans</a>.
    */
   @Test public void testInfiniteStreamsDoNotBufferInMemory() {
     CalciteAssert.model(STREAM_MODEL)
-                 .withDefaultSchema(INFINITE_STREAM_SCHEMA_NAME)
-                 .query("select stream * from orders")
-                 .limit(100)
-                 .explainContains("EnumerableInterpreter\n"
-                                  + "  BindableTableScan(table=[[]])")
-                 .returnsCount(100);
+        .withDefaultSchema(INFINITE_STREAM_SCHEMA_NAME)
+        .query("select stream * from orders")
+        .limit(100)
+        .explainContains("EnumerableInterpreter\n"
+            + "  BindableTableScan(table=[[]])")
+        .returnsCount(100);
   }
 
   private Function<ResultSet, Void> startsWith(String... rows) {
@@ -240,15 +244,14 @@ public class StreamTest {
     protected final RelProtoDataType protoRowType = new RelProtoDataType() {
       public RelDataType apply(RelDataTypeFactory a0) {
         return a0.builder()
-                 .add("ROWTIME", SqlTypeName.TIMESTAMP)
-                 .add("ID", SqlTypeName.INTEGER)
-                 .add("PRODUCT", SqlTypeName.VARCHAR, 10)
-                 .add("UNITS", SqlTypeName.INTEGER)
-                 .build();
+            .add("ROWTIME", SqlTypeName.TIMESTAMP)
+            .add("ID", SqlTypeName.INTEGER)
+            .add("PRODUCT", SqlTypeName.VARCHAR, 10)
+            .add("UNITS", SqlTypeName.INTEGER)
+            .build();
       }
     };
 
-
     public RelDataType getRowType(RelDataTypeFactory typeFactory) {
       return protoRowType.apply(typeFactory);
     }
@@ -300,8 +303,7 @@ public class StreamTest {
       return Linq4j.asEnumerable(rows);
     }
 
-    @Override
-    public Table stream() {
+    @Override public Table stream() {
       return new OrdersTable(rows);
     }
   }
@@ -316,48 +318,47 @@ public class StreamTest {
     }
 
     public Table create(SchemaPlus schema, String name,
-      Map<String, Object> operand, RelDataType rowType) {
+        Map<String, Object> operand, RelDataType rowType) {
       return new InfiniteOrdersTable();
     }
   }
 
-  public static final Function0<Object[]> ROW_GENERATOR = new Function0() {
-    private int counter = 0;
-    private Iterator<String> items = Iterables.cycle("paint", "paper", "brush").iterator();
-
-    @Override
-    public Object[] apply() {
-      return new Object[]{System.currentTimeMillis(), counter++, items.next(), 10};
-    }
-  };
+  public static final Function0<Object[]> ROW_GENERATOR =
+      new Function0<Object[]>() {
+        private int counter = 0;
+        private Iterator<String> items =
+            Iterables.cycle("paint", "paper", "brush").iterator();
 
+        @Override public Object[] apply() {
+          return new Object[]{System.currentTimeMillis(), counter++, items.next(), 10};
+        }
+      };
 
   /**
    * Table representing an infinitely larger ORDERS stream.
    */
   public static class InfiniteOrdersTable extends BaseOrderStreamTable {
-
     public Enumerable<Object[]> scan(DataContext root) {
       return Linq4j.asEnumerable(new Iterable<Object[]>() {
-        @Override
-        public Iterator<Object[]> iterator() {
+        @Override public Iterator<Object[]> iterator() {
           return new Iterator<Object[]>() {
-            @Override
             public boolean hasNext() {
               return true;
             }
 
-            @Override
             public Object[] next() {
               return ROW_GENERATOR.apply();
             }
+
+            public void remove() {
+              throw new UnsupportedOperationException();
+            }
           };
         }
       });
     }
 
-    @Override
-    public Table stream() {
+    @Override public Table stream() {
       return this;
     }
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/a3da6915/linq4j/src/main/java/org/apache/calcite/linq4j/DelegatingEnumerator.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/DelegatingEnumerator.java b/linq4j/src/main/java/org/apache/calcite/linq4j/DelegatingEnumerator.java
index 043f094..c4d003b 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/DelegatingEnumerator.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/DelegatingEnumerator.java
@@ -17,12 +17,12 @@
 package org.apache.calcite.linq4j;
 
 /**
- * Simple enumerator that just delegates all calls to the passed enumerator
+ * Simple enumerator that just delegates all calls to the passed enumerator.
+ *
  * @param <T> type of value to return, as passed from the delegate enumerator
  */
 public class DelegatingEnumerator<T> implements Enumerator<T> {
-
-  private Enumerator<T> delegate;
+  protected final Enumerator<T> delegate;
 
   public DelegatingEnumerator(Enumerator<T> delegate) {
     this.delegate = delegate;

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/a3da6915/linq4j/src/main/java/org/apache/calcite/linq4j/Linq4j.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/Linq4j.java b/linq4j/src/main/java/org/apache/calcite/linq4j/Linq4j.java
index eb50cee..85f8bc6 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/Linq4j.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/Linq4j.java
@@ -206,13 +206,8 @@ public abstract class Linq4j {
   }
 
   public static <T, R> Enumerator<R> transform(final Enumerator<T> enumerator,
-    final Function1<T, R> func) {
-    return new DelegatingEnumerator<R>((Enumerator<R>) enumerator) {
-      @Override
-      public R current() {
-        return func.apply((T) super.current());
-      }
-    };
+      final Function1<T, R> func) {
+    return new TransformedEnumerator<>(enumerator, func);
   }
 
   /**
@@ -732,6 +727,39 @@ public abstract class Linq4j {
     public void close() {
     }
   }
+
+  /** Enumerator that applies a transform to each value from a backing
+   * enumerator.
+   *
+   * @param <T> Element type of backing enumerator
+   * @param <R> Element type
+   */
+  private static class TransformedEnumerator<T, R> implements Enumerator<R> {
+    private final Enumerator<T> enumerator;
+    private final Function1<T, R> func;
+
+    public TransformedEnumerator(Enumerator<T> enumerator,
+        Function1<T, R> func) {
+      this.enumerator = enumerator;
+      this.func = func;
+    }
+
+    public boolean moveNext() {
+      return enumerator.moveNext();
+    }
+
+    public R current() {
+      return func.apply(enumerator.current());
+    }
+
+    public void reset() {
+      enumerator.reset();
+    }
+
+    public void close() {
+      enumerator.close();
+    }
+  }
 }
 
 // End Linq4j.java


[11/18] incubator-calcite git commit: [CALCITE-793] Planner requires unnecessary collation when using materialized view (Maryann Xue)

Posted by jh...@apache.org.
[CALCITE-793] Planner requires unnecessary collation when using materialized view (Maryann Xue)

Add test case (Julian Hyde)


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

Branch: refs/heads/master
Commit: 5b02090a5f70804aca3bcc73c5104523664cb86c
Parents: 87e7454
Author: Maryann Xue <we...@intel.com>
Authored: Mon Jul 27 20:46:36 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Sep 1 16:17:15 2015 -0700

----------------------------------------------------------------------
 .../apache/calcite/plan/hep/HepRelVertex.java   |  5 ++--
 .../org/apache/calcite/prepare/Prepare.java     |  7 ++++-
 .../org/apache/calcite/rel/core/Aggregate.java  |  9 ++++++-
 .../calcite/sql2rel/SqlToRelConverter.java      | 22 +++++++++++++++-
 .../java/org/apache/calcite/test/JdbcTest.java  |  2 +-
 .../org/apache/calcite/test/LatticeTest.java    |  2 +-
 .../calcite/test/MaterializationTest.java       | 27 ++++++++++++++++++++
 .../apache/calcite/test/RelOptRulesTest.java    |  2 +-
 .../apache/calcite/test/SqlToRelTestBase.java   |  2 +-
 9 files changed, 68 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5b02090a/core/src/main/java/org/apache/calcite/plan/hep/HepRelVertex.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/hep/HepRelVertex.java b/core/src/main/java/org/apache/calcite/plan/hep/HepRelVertex.java
index 3ee9739..6e08e4b 100644
--- a/core/src/main/java/org/apache/calcite/plan/hep/HepRelVertex.java
+++ b/core/src/main/java/org/apache/calcite/plan/hep/HepRelVertex.java
@@ -25,7 +25,6 @@ import org.apache.calcite.rel.RelWriter;
 import org.apache.calcite.rel.metadata.RelMetadataQuery;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.util.ImmutableBitSet;
-import org.apache.calcite.util.Util;
 
 import java.util.List;
 
@@ -64,8 +63,8 @@ public class HepRelVertex extends AbstractRelNode {
 
   @Override public RelOptCost computeSelfCost(RelOptPlanner planner) {
     // HepRelMetadataProvider is supposed to intercept this
-    // and redirect to the real rels.
-    throw Util.newInternal("should never get here");
+    // and redirect to the real rels. But sometimes it doesn't.
+    return planner.getCostFactory().makeTinyCost();
   }
 
   @Override public double getRows() {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5b02090a/core/src/main/java/org/apache/calcite/prepare/Prepare.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/Prepare.java b/core/src/main/java/org/apache/calcite/prepare/Prepare.java
index 8ff5c0d..403ad76 100644
--- a/core/src/main/java/org/apache/calcite/prepare/Prepare.java
+++ b/core/src/main/java/org/apache/calcite/prepare/Prepare.java
@@ -80,6 +80,7 @@ public abstract class Prepare {
   protected CalciteTimingTracer timingTracer;
   protected List<List<String>> fieldOrigins;
   protected final List<RelCollation> collations = new ArrayList<>();
+  protected boolean ordered;
   protected RelDataType parameterRowType;
 
   // temporary. for testing.
@@ -230,6 +231,10 @@ public abstract class Prepare {
       timingTracer.traceTime("end sql2rel");
     }
 
+    // A query can have 0 collations and still be ordered (if it is ordered
+    // on a non-projected expression). But otherwise,
+    // ordered == !collations.isEmpty().
+    ordered = !SqlToRelConverter.isUnordered(sqlQuery);
     assert collations.isEmpty();
     if (rootRel instanceof Sort) {
       collations.add(((Sort) rootRel).getCollation());
@@ -353,7 +358,7 @@ public abstract class Prepare {
         getSqlToRelConverter(
             getSqlValidator(), catalogReader);
     converter.setTrimUnusedFields(shouldTrim(rootRel));
-    return converter.trimUnusedFields(rootRel);
+    return converter.trimUnusedFields(ordered, rootRel);
   }
 
   private boolean shouldTrim(RelNode rootRel) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5b02090a/core/src/main/java/org/apache/calcite/rel/core/Aggregate.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Aggregate.java b/core/src/main/java/org/apache/calcite/rel/core/Aggregate.java
index 3250ae1..31a9812 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Aggregate.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Aggregate.java
@@ -294,7 +294,14 @@ public abstract class Aggregate extends SingleRel {
     // than what's currently in Join.
     double rowCount = RelMetadataQuery.getRowCount(this);
     // Aggregates with more aggregate functions cost a bit more
-    final float multiplier = 1f + (float) aggCalls.size() * 0.125f;
+    float multiplier = 1f + (float) aggCalls.size() * 0.125f;
+    for (AggregateCall aggCall : aggCalls) {
+      if (aggCall.getAggregation().getName().equals("SUM")) {
+        // Pretend that SUM costs a little bit more than $SUM0,
+        // to make things deterministic.
+        multiplier += 0.0125f;
+      }
+    }
     return planner.getCostFactory().makeCost(rowCount * multiplier, 0, 0);
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5b02090a/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 541c6ea..ae73586 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -23,9 +23,11 @@ import org.apache.calcite.plan.RelOptPlanner;
 import org.apache.calcite.plan.RelOptSamplingParameters;
 import org.apache.calcite.plan.RelOptTable;
 import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.prepare.Prepare;
 import org.apache.calcite.prepare.RelOptTableImpl;
 import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelCollationTraitDef;
 import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.RelFieldCollation;
 import org.apache.calcite.rel.RelNode;
@@ -487,14 +489,23 @@ public class SqlToRelConverter {
    * <p>Currently this functionality is disabled in farrago/luciddb; the
    * default implementation of this method does nothing.
    *
+   * @param ordered Whether the relational expression must produce results in
+   * a particular order (typically because it has an ORDER BY at top level)
    * @param rootRel Relational expression that is at the root of the tree
    * @return Trimmed relational expression
    */
-  public RelNode trimUnusedFields(RelNode rootRel) {
+  public RelNode trimUnusedFields(boolean ordered, RelNode rootRel) {
     // Trim fields that are not used by their consumer.
     if (isTrimUnusedFields()) {
       final RelFieldTrimmer trimmer = newFieldTrimmer();
+      final List<RelCollation> collations =
+          rootRel.getTraitSet().getTraits(RelCollationTraitDef.INSTANCE);
       rootRel = trimmer.trim(rootRel);
+      if (!ordered && collations != null) {
+        final RelTraitSet traitSet = rootRel.getTraitSet()
+            .replace(RelCollationTraitDef.INSTANCE, collations);
+        rootRel = rootRel.copy(traitSet, rootRel.getInputs());
+      }
       boolean dumpPlan = SQL2REL_LOGGER.isLoggable(Level.FINE);
       if (dumpPlan) {
         SQL2REL_LOGGER.fine(
@@ -540,6 +551,10 @@ public class SqlToRelConverter {
     if (top && isStream(query)) {
       result = new LogicalDelta(cluster, result.getTraitSet(), result);
     }
+    if (isUnordered(query)) {
+      result = result.copy(result.getTraitSet().replace(RelCollations.EMPTY),
+          result.getInputs());
+    }
     checkConvertedType(query, result);
 
     boolean dumpPlan = SQL2REL_LOGGER.isLoggable(Level.FINE);
@@ -560,6 +575,11 @@ public class SqlToRelConverter {
         && ((SqlSelect) query).isKeywordPresent(SqlSelectKeyword.STREAM);
   }
 
+  public static boolean isUnordered(SqlNode query) {
+    return query instanceof SqlSelect
+        && ((SqlSelect) query).getOrderList() == null;
+  }
+
   protected boolean checkConvertedRowType(
       SqlNode query,
       RelDataType convertedRowType) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5b02090a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcTest.java b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
index 475ff51..2ff7e99 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -199,7 +199,7 @@ public class JdbcTest {
       + "   ]\n"
       + "}";
 
-  private static final ConnectionSpec SCOTT =
+  public static final ConnectionSpec SCOTT =
       Util.first(CalciteAssert.DB.scott,
           CalciteAssert.DatabaseInstance.HSQLDB.scott);
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5b02090a/core/src/test/java/org/apache/calcite/test/LatticeTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/LatticeTest.java b/core/src/test/java/org/apache/calcite/test/LatticeTest.java
index 77e7943..b1155f0 100644
--- a/core/src/test/java/org/apache/calcite/test/LatticeTest.java
+++ b/core/src/test/java/org/apache/calcite/test/LatticeTest.java
@@ -436,7 +436,7 @@ public class LatticeTest {
                 + "GROUP BY \"s\".\"unit_sales\", \"p\".\"recyclable_package\", \"t\".\"the_day\", \"t\".\"the_year\", \"t\".\"quarter\", \"pc\".\"product_family\"")
         .explainContains(
             "JdbcToEnumerableConverter\n"
-                + "  JdbcAggregate(group=[{7, 16, 25, 27, 31, 37}], m0=[COUNT()], m1=[SUM($5)], m2=[SUM($7)])\n"
+                + "  JdbcAggregate(group=[{7, 16, 25, 27, 31, 37}], m0=[COUNT()], m1=[$SUM0($5)], m2=[$SUM0($7)])\n"
                 + "    JdbcJoin(condition=[=($8, $33)], joinType=[inner])\n"
                 + "      JdbcJoin(condition=[=($1, $23)], joinType=[inner])\n"
                 + "        JdbcJoin(condition=[=($0, $9)], joinType=[inner])\n"

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5b02090a/core/src/test/java/org/apache/calcite/test/MaterializationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/MaterializationTest.java b/core/src/test/java/org/apache/calcite/test/MaterializationTest.java
index f132915..61d49dd 100644
--- a/core/src/test/java/org/apache/calcite/test/MaterializationTest.java
+++ b/core/src/test/java/org/apache/calcite/test/MaterializationTest.java
@@ -65,6 +65,33 @@ public class MaterializationTest {
       new JavaTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
   final RexBuilder rexBuilder = new RexBuilder(typeFactory);
 
+  @Test public void testScan() {
+    CalciteAssert.that()
+        .withMaterializations(
+            "{\n"
+                + "  version: '1.0',\n"
+                + "  defaultSchema: 'SCOTT_CLONE',\n"
+                + "  schemas: [ {\n"
+                + "    name: 'SCOTT_CLONE',\n"
+                + "    type: 'custom',\n"
+                + "    factory: 'org.apache.calcite.adapter.clone.CloneSchema$Factory',\n"
+                + "    operand: {\n"
+                + "      jdbcDriver: '" + JdbcTest.SCOTT.driver + "',\n"
+                + "      jdbcUser: '" + JdbcTest.SCOTT.username + "',\n"
+                + "      jdbcPassword: '" + JdbcTest.SCOTT.password + "',\n"
+                + "      jdbcUrl: '" + JdbcTest.SCOTT.url + "',\n"
+                + "      jdbcSchema: 'SCOTT'\n"
+                + "   } } ]\n"
+                + "}",
+            "m0",
+            "select empno, deptno from emp order by deptno")
+        .query(
+            "select empno, deptno from emp")
+        .enableMaterializations(true)
+        .explainContains("EnumerableTableScan(table=[[SCOTT_CLONE, m0]])")
+        .sameResultWithMaterializationsDisabled();
+  }
+
   @Test public void testFilter() {
     CalciteAssert.that()
         .withMaterializations(

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5b02090a/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 d32c02d..5b60fb4 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -425,7 +425,7 @@ public class RelOptRulesTest extends RelOptTestBase {
     String planBefore = NL + RelOptUtil.toString(rel);
     diffRepos.assertEquals("planBefore", "${planBefore}", planBefore);
     converter.setTrimUnusedFields(true);
-    rel = converter.trimUnusedFields(rel);
+    rel = converter.trimUnusedFields(false, rel);
     String planAfter = NL + RelOptUtil.toString(rel);
     diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5b02090a/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 942c577..f9752e5 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
@@ -495,7 +495,7 @@ public abstract class SqlToRelTestBase {
       }
       if (enableTrim) {
         converter.setTrimUnusedFields(true);
-        rel = converter.trimUnusedFields(rel);
+        rel = converter.trimUnusedFields(false, rel);
       }
       return rel;
     }


[14/18] incubator-calcite git commit: Further fix up [CALCITE-809], eliminating the proxy sink

Posted by jh...@apache.org.
Further fix up [CALCITE-809], eliminating the proxy sink


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

Branch: refs/heads/master
Commit: 5e7d457ae82cc7a0e3bf055fa2e1f45b19186dcf
Parents: a3da691
Author: Julian Hyde <jh...@apache.org>
Authored: Mon Aug 10 17:24:09 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Sep 1 16:17:16 2015 -0700

----------------------------------------------------------------------
 .../apache/calcite/interpreter/Interpreter.java | 130 ++++++++-----------
 .../calcite/interpreter/TableScanNode.java      |  10 +-
 .../java/org/apache/calcite/linq4j/Linq4j.java  |  85 +++++-------
 .../calcite/linq4j/TransformedEnumerator.java   |  51 ++++++++
 .../apache/calcite/linq4j/test/Linq4jTest.java  |  22 ++++
 5 files changed, 161 insertions(+), 137 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5e7d457a/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java b/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java
index e4c2cfe..e14bffe 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java
@@ -18,18 +18,16 @@ package org.apache.calcite.interpreter;
 
 import org.apache.calcite.DataContext;
 import org.apache.calcite.linq4j.AbstractEnumerable;
-import org.apache.calcite.linq4j.DelegatingEnumerator;
 import org.apache.calcite.linq4j.Enumerable;
 import org.apache.calcite.linq4j.Enumerator;
 import org.apache.calcite.linq4j.Linq4j;
-import org.apache.calcite.linq4j.function.Function1;
+import org.apache.calcite.linq4j.TransformedEnumerator;
 import org.apache.calcite.plan.hep.HepPlanner;
 import org.apache.calcite.plan.hep.HepProgram;
 import org.apache.calcite.plan.hep.HepProgramBuilder;
 import org.apache.calcite.prepare.CalcitePrepareImpl;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelVisitor;
-import org.apache.calcite.rel.core.TableScan;
 import org.apache.calcite.rel.rules.CalcSplitRule;
 import org.apache.calcite.rel.rules.FilterTableScanRule;
 import org.apache.calcite.rel.rules.ProjectTableScanRule;
@@ -92,29 +90,21 @@ public class Interpreter extends AbstractEnumerable<Object[]> {
 
   public Enumerator<Object[]> enumerator() {
     start();
-    Sink sink = nodes.get(rootRel).sink;
-    Enumerator<Row> rows;
-    if (sink instanceof EnumerableProxySink) {
-      rows = ((EnumerableProxySink) sink).enumerable.enumerator();
+    final NodeInfo nodeInfo = nodes.get(rootRel);
+    final Enumerator<Row> rows;
+    if (nodeInfo.rowEnumerable != null) {
+      rows = nodeInfo.rowEnumerable.enumerator();
     } else {
-      final ArrayDeque<Row> queue = ((ListSink) sink).list;
-      rows = Linq4j.asEnumerable(queue).enumerator();
+      final ArrayDeque<Row> queue = ((ListSink) nodeInfo.sink).list;
+      rows = Linq4j.iterableEnumerator(queue);
     }
 
-    return new DelegatingEnumerator<Object[]>(Linq4j.transform(rows, rowConverter)) {
-      @Override public void close() {
-        super.close();
-        Interpreter.this.close();
-      }
-    };
-  }
-
-  private Function1<Row, Object[]> rowConverter =
-    new Function1<Row, Object[]>() {
-      @Override public Object[] apply(Row row) {
+    return new TransformedEnumerator<Row, Object[]>(rows) {
+      protected Object[] transform(Row row) {
         return row.getValues();
       }
     };
+  }
 
   private void start() {
     // We rely on the nodes being ordered leaves first.
@@ -259,15 +249,16 @@ public class Interpreter extends AbstractEnumerable<Object[]> {
 
   public Source source(RelNode rel, int ordinal) {
     final RelNode input = getInput(rel, ordinal);
-    final NodeInfo x = nodes.get(input);
-    if (x == null) {
+    final NodeInfo nodeInfo = nodes.get(input);
+    if (nodeInfo == null) {
       throw new AssertionError("should be registered: " + rel);
     }
-    Sink sink = x.sink;
+    if (nodeInfo.rowEnumerable != null) {
+      return new EnumeratorSource(nodeInfo.rowEnumerable.enumerator());
+    }
+    Sink sink = nodeInfo.sink;
     if (sink instanceof ListSink) {
-      return new ListSource((ListSink) x.sink);
-    } else if (sink instanceof EnumerableProxySink) {
-      return new EnumerableProxySource((EnumerableProxySink) sink);
+      return new ListSource((ListSink) nodeInfo.sink);
     }
     throw new IllegalStateException(
       "Got a sink " + sink + " to which there is no match source type!");
@@ -281,19 +272,39 @@ public class Interpreter extends AbstractEnumerable<Object[]> {
     return rel.getInput(ordinal);
   }
 
+  /**
+   * Creates a Sink for a relational expression to write into.
+   *
+   * <p>This method is generally called from the constructor of a {@link Node}.
+   * But a constructor could instead call
+   * {@link #enumerable(RelNode, Enumerable)}.
+   *
+   * @param rel Relational expression
+   * @return Sink
+   */
   public Sink sink(RelNode rel) {
-    final Sink sink;
-    if (rel instanceof TableScan) {
-      sink = new EnumerableProxySink();
-    } else {
-      final ArrayDeque<Row> queue = new ArrayDeque<>(1);
-      sink = new ListSink(queue);
-    }
-    NodeInfo nodeInfo = new NodeInfo(rel, sink);
+    final ArrayDeque<Row> queue = new ArrayDeque<>(1);
+    final Sink sink = new ListSink(queue);
+    NodeInfo nodeInfo = new NodeInfo(rel, sink, null);
     nodes.put(rel, nodeInfo);
     return sink;
   }
 
+  /** Tells the interpreter that a given relational expression wishes to
+   * give its output as an enumerable.
+   *
+   * <p>This is as opposed to the norm, where a relational expression calls
+   * {@link #sink(RelNode)}, then its {@link Node#run()} method writes into that
+   * sink.
+   *
+   * @param rel Relational expression
+   * @param rowEnumerable Contents of relational expression
+   */
+  public void enumerable(RelNode rel, Enumerable<Row> rowEnumerable) {
+    NodeInfo nodeInfo = new NodeInfo(rel, null, rowEnumerable);
+    nodes.put(rel, nodeInfo);
+  }
+
   public Context createContext() {
     return new Context(dataContext);
   }
@@ -306,37 +317,14 @@ public class Interpreter extends AbstractEnumerable<Object[]> {
   private static class NodeInfo {
     final RelNode rel;
     final Sink sink;
+    final Enumerable<Row> rowEnumerable;
     Node node;
 
-    public NodeInfo(RelNode rel, Sink sink) {
+    public NodeInfo(RelNode rel, Sink sink, Enumerable<Row> rowEnumerable) {
       this.rel = rel;
       this.sink = sink;
-    }
-  }
-
-  /**
-   * A sink that just proxies for an {@link org.apache.calcite.linq4j.Enumerable}. As such, its
-   * not really a "sink" but instead just a thin layer for the {@link EnumerableProxySource} to
-   * get an enumerator.
-   *
-   * <p>It can be little bit slower than the {@link Interpreter.ListSink} when trying to iterate
-   * over the elements of the enumerable, unless the enumerable is backed by an in-memory cache
-   * of the rows.
-   */
-  private static class EnumerableProxySink implements Sink {
-    private Enumerable<Row> enumerable;
-
-    @Override public void send(Row row) throws InterruptedException {
-      throw new UnsupportedOperationException("Rows are only added through the "
-          + "enumerable passed in through #setSourceEnumerable()!");
-    }
-
-    @Override public void end() throws InterruptedException {
-      // noop
-    }
-
-    @Override public void setSourceEnumerable(Enumerable<Row> enumerable) {
-      this.enumerable = enumerable;
+      this.rowEnumerable = rowEnumerable;
+      assert (sink != null) != (rowEnumerable != null) : "one or the other";
     }
   }
 
@@ -344,34 +332,24 @@ public class Interpreter extends AbstractEnumerable<Object[]> {
    * A {@link Source} that is just backed by an {@link Enumerator}. The {@link Enumerator} is closed
    * when it is finished or by calling {@link #close()}.
    */
-  private static class EnumerableProxySource implements Source {
+  private static class EnumeratorSource implements Source {
+    private final Enumerator<Row> enumerator;
 
-    private Enumerator<Row> enumerator;
-    private final EnumerableProxySink source;
-
-    public EnumerableProxySource(EnumerableProxySink sink) {
-      this.source = sink;
+    public EnumeratorSource(final Enumerator<Row> enumerator) {
+      this.enumerator = Preconditions.checkNotNull(enumerator);
     }
 
     @Override public Row receive() {
-      if (enumerator == null) {
-        enumerator = source.enumerable.enumerator();
-        assert enumerator != null
-            : "Sink did not set enumerable before source was asked for a row!";
-      }
       if (enumerator.moveNext()) {
         return enumerator.current();
       }
       // close the enumerator once we have gone through everything
       enumerator.close();
-      this.enumerator = null;
       return null;
     }
 
     @Override public void close() {
-      if (this.enumerator != null) {
-        this.enumerator.close();
-      }
+      enumerator.close();
     }
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5e7d457a/core/src/main/java/org/apache/calcite/interpreter/TableScanNode.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/TableScanNode.java b/core/src/main/java/org/apache/calcite/interpreter/TableScanNode.java
index 2824b37..c88627b 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/TableScanNode.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/TableScanNode.java
@@ -59,19 +59,13 @@ import static org.apache.calcite.util.Static.RESOURCE;
  * {@link org.apache.calcite.rel.core.TableScan}.
  */
 public class TableScanNode implements Node {
-  private final Sink sink;
-  private final Enumerable<Row> enumerable;
-
   private TableScanNode(Interpreter interpreter, TableScan rel,
       Enumerable<Row> enumerable) {
-    this.enumerable = enumerable;
-    this.sink = interpreter.sink(rel);
+    interpreter.enumerable(rel, enumerable);
   }
 
-
   public void run() throws InterruptedException {
-    sink.setSourceEnumerable(enumerable);
-    sink.end();
+    // nothing to do
   }
 
   /** Creates a TableScanNode.

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5e7d457a/linq4j/src/main/java/org/apache/calcite/linq4j/Linq4j.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/Linq4j.java b/linq4j/src/main/java/org/apache/calcite/linq4j/Linq4j.java
index 85f8bc6..da46850 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/Linq4j.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/Linq4j.java
@@ -102,7 +102,7 @@ public abstract class Linq4j {
    * @return Iterator
    */
   public static <T> Iterator<T> enumeratorIterator(Enumerator<T> enumerator) {
-    return new EnumeratorIterator<T>(enumerator);
+    return new EnumeratorIterator<>(enumerator);
   }
 
   /**
@@ -120,7 +120,7 @@ public abstract class Linq4j {
           (Enumerable) iterable;
       return enumerable.enumerator();
     }
-    return new IterableEnumerator<T>(iterable);
+    return new IterableEnumerator<>(iterable);
   }
 
   /**
@@ -132,7 +132,7 @@ public abstract class Linq4j {
    * @return enumerable
    */
   public static <T> Enumerable<T> asEnumerable(final List<T> list) {
-    return new ListEnumerable<T>(list);
+    return new ListEnumerable<>(list);
   }
 
   /**
@@ -151,7 +151,7 @@ public abstract class Linq4j {
       //noinspection unchecked
       return asEnumerable((List) collection);
     }
-    return new CollectionEnumerable<T>(collection);
+    return new CollectionEnumerable<>(collection);
   }
 
   /**
@@ -170,7 +170,7 @@ public abstract class Linq4j {
       //noinspection unchecked
       return asEnumerable((Collection) iterable);
     }
-    return new IterableEnumerable<T>(iterable);
+    return new IterableEnumerable<>(iterable);
   }
 
   /**
@@ -182,7 +182,7 @@ public abstract class Linq4j {
    * @return enumerable
    */
   public static <T> Enumerable<T> asEnumerable(final T[] ts) {
-    return new ListEnumerable<T>(Arrays.asList(ts));
+    return new ListEnumerable<>(Arrays.asList(ts));
   }
 
   /**
@@ -202,12 +202,24 @@ public abstract class Linq4j {
   }
 
   private static <V> Enumerator<V> listEnumerator(List<? extends V> list) {
-    return new ListEnumerator<V>(list);
+    return new ListEnumerator<>(list);
   }
 
-  public static <T, R> Enumerator<R> transform(final Enumerator<T> enumerator,
-      final Function1<T, R> func) {
-    return new TransformedEnumerator<>(enumerator, func);
+  /** Applies a function to each element of an Enumerator.
+   *
+   * @param enumerator Backing enumerator
+   * @param func Transform function
+   * @param <F> Backing element type
+   * @param <E> Element type
+   * @return Enumerator
+   */
+  public static <F, E> Enumerator<E> transform(Enumerator<F> enumerator,
+      final Function1<F, E> func) {
+    return new TransformedEnumerator<F, E>(enumerator) {
+      protected E transform(F from) {
+        return func.apply(from);
+      }
+    };
   }
 
   /**
@@ -225,7 +237,7 @@ public abstract class Linq4j {
    * query operators to be invoked on collections
    * (including {@link java.util.List} and {@link java.util.Set}) by supplying
    * the necessary type information. For example, {@link ArrayList} does not
-   * implement {@link Enumerable}&lt;T&gt;, but you can invoke
+   * implement {@link Enumerable}&lt;F&gt;, but you can invoke
    *
    * <blockquote><code>Linq4j.cast(list, Integer.class)</code></blockquote>
    *
@@ -266,7 +278,7 @@ public abstract class Linq4j {
    * query operators to be invoked on collections
    * (including {@link java.util.List} and {@link java.util.Set}) by supplying
    * the necessary type information. For example, {@link ArrayList} does not
-   * implement {@link Enumerable}&lt;T&gt;, but you can invoke
+   * implement {@link Enumerable}&lt;F&gt;, but you can invoke
    *
    * <blockquote><code>Linq4j.ofType(list, Integer.class)</code></blockquote>
    *
@@ -304,7 +316,7 @@ public abstract class Linq4j {
    * @return Singleton enumerator
    */
   public static <T> Enumerator<T> singletonEnumerator(T element) {
-    return new SingletonEnumerator<T>(element);
+    return new SingletonEnumerator<>(element);
   }
 
   /**
@@ -315,7 +327,7 @@ public abstract class Linq4j {
    * @return Singleton enumerator
    */
   public static <T> Enumerator<T> singletonNullEnumerator() {
-    return new SingletonNullEnumerator<T>();
+    return new SingletonNullEnumerator<>();
   }
 
   /**
@@ -353,7 +365,7 @@ public abstract class Linq4j {
    */
   public static <E> Enumerable<E> concat(
       final List<Enumerable<E>> enumerableList) {
-    return new CompositeEnumerable<E>(enumerableList);
+    return new CompositeEnumerable<>(enumerableList);
   }
 
   /**
@@ -379,7 +391,7 @@ public abstract class Linq4j {
    */
   public static <T> Enumerator<List<T>> product(
       List<Enumerator<T>> enumerators) {
-    return new CartesianProductEnumerator<T>(enumerators);
+    return new CartesianProductEnumerator<>(enumerators);
   }
 
   /** Returns the cartesian product of an iterable of iterables. */
@@ -392,7 +404,7 @@ public abstract class Linq4j {
           enumerators.add(iterableEnumerator(iterable));
         }
         return enumeratorIterator(
-            new CartesianProductEnumerator<T>(enumerators));
+            new CartesianProductEnumerator<>(enumerators));
       }
     };
   }
@@ -599,7 +611,7 @@ public abstract class Linq4j {
     @Override public Enumerator<T> enumerator() {
       if (iterable instanceof RandomAccess) {
         //noinspection unchecked
-        return new ListEnumerator<T>((List) iterable);
+        return new ListEnumerator<>((List) iterable);
       }
       return super.enumerator();
     }
@@ -613,7 +625,7 @@ public abstract class Linq4j {
       if (count >= list.size()) {
         return Linq4j.emptyEnumerable();
       }
-      return new ListEnumerable<T>(list.subList(count, list.size()));
+      return new ListEnumerable<>(list.subList(count, list.size()));
     }
 
     @Override public Enumerable<T> take(int count) {
@@ -621,7 +633,7 @@ public abstract class Linq4j {
       if (count >= list.size()) {
         return this;
       }
-      return new ListEnumerable<T>(list.subList(0, count));
+      return new ListEnumerable<>(list.subList(0, count));
     }
 
     @Override public T elementAt(int index) {
@@ -727,39 +739,6 @@ public abstract class Linq4j {
     public void close() {
     }
   }
-
-  /** Enumerator that applies a transform to each value from a backing
-   * enumerator.
-   *
-   * @param <T> Element type of backing enumerator
-   * @param <R> Element type
-   */
-  private static class TransformedEnumerator<T, R> implements Enumerator<R> {
-    private final Enumerator<T> enumerator;
-    private final Function1<T, R> func;
-
-    public TransformedEnumerator(Enumerator<T> enumerator,
-        Function1<T, R> func) {
-      this.enumerator = enumerator;
-      this.func = func;
-    }
-
-    public boolean moveNext() {
-      return enumerator.moveNext();
-    }
-
-    public R current() {
-      return func.apply(enumerator.current());
-    }
-
-    public void reset() {
-      enumerator.reset();
-    }
-
-    public void close() {
-      enumerator.close();
-    }
-  }
 }
 
 // End Linq4j.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5e7d457a/linq4j/src/main/java/org/apache/calcite/linq4j/TransformedEnumerator.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/TransformedEnumerator.java b/linq4j/src/main/java/org/apache/calcite/linq4j/TransformedEnumerator.java
new file mode 100644
index 0000000..839c338
--- /dev/null
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/TransformedEnumerator.java
@@ -0,0 +1,51 @@
+/*
+ * 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.linq4j;
+
+/** Enumerator that applies a transform to each value from a backing
+ * enumerator.
+ *
+ * @param <F> Element type of backing enumerator
+ * @param <E> Element type
+ */
+public abstract class TransformedEnumerator<F, E> implements Enumerator<E> {
+  protected final Enumerator<F> enumerator;
+
+  public TransformedEnumerator(Enumerator<F> enumerator) {
+    this.enumerator = enumerator;
+  }
+
+  protected abstract E transform(F from);
+
+  public boolean moveNext() {
+    return enumerator.moveNext();
+  }
+
+  public E current() {
+    return transform(enumerator.current());
+  }
+
+  public void reset() {
+    enumerator.reset();
+  }
+
+  public void close() {
+    enumerator.close();
+  }
+}
+
+// End TransformedEnumerator.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5e7d457a/linq4j/src/test/java/org/apache/calcite/linq4j/test/Linq4jTest.java
----------------------------------------------------------------------
diff --git a/linq4j/src/test/java/org/apache/calcite/linq4j/test/Linq4jTest.java b/linq4j/src/test/java/org/apache/calcite/linq4j/test/Linq4jTest.java
index 338251b..dfecf68 100644
--- a/linq4j/src/test/java/org/apache/calcite/linq4j/test/Linq4jTest.java
+++ b/linq4j/src/test/java/org/apache/calcite/linq4j/test/Linq4jTest.java
@@ -855,6 +855,28 @@ public class Linq4jTest {
     assertThat(enumerator.moveNext(), is(false));
   }
 
+  @Test public void testTransformEnumerator() {
+    final List<String> strings = Arrays.asList("one", "two", "three");
+    final Function1<String, Integer> func = new Function1<String, Integer>() {
+      public Integer apply(String a0) {
+        return a0.length();
+      }
+    };
+    final Enumerator<Integer> enumerator =
+        Linq4j.transform(Linq4j.enumerator(strings), func);
+    assertThat(enumerator.moveNext(), is(true));
+    assertThat(enumerator.current(), is(3));
+    assertThat(enumerator.moveNext(), is(true));
+    assertThat(enumerator.current(), is(3));
+    assertThat(enumerator.moveNext(), is(true));
+    assertThat(enumerator.current(), is(5));
+    assertThat(enumerator.moveNext(), is(false));
+
+    final Enumerator<Integer> enumerator2 =
+        Linq4j.transform(Linq4j.<String>emptyEnumerator(), func);
+    assertThat(enumerator2.moveNext(), is(false));
+  }
+
   @Test public void testCast() {
     final List<Number> numbers = Arrays.asList((Number) 2, null, 3.14, 5);
     final Enumerator<Integer> enumerator =


[15/18] incubator-calcite git commit: [CALCITE-851] Add original SQL string as a field in the parser

Posted by jh...@apache.org.
[CALCITE-851] Add original SQL string as a field in the parser


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

Branch: refs/heads/master
Commit: 39487512e04cc89ae4f0e6909bf91c552f933659
Parents: 5a39706
Author: Julian Hyde <jh...@apache.org>
Authored: Thu Aug 20 23:53:44 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Sep 1 16:17:16 2015 -0700

----------------------------------------------------------------------
 .../calcite/sql/parser/SqlAbstractParserImpl.java   | 16 ++++++++++++++++
 .../org/apache/calcite/sql/parser/SqlParser.java    |  1 +
 2 files changed, 17 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/39487512/core/src/main/java/org/apache/calcite/sql/parser/SqlAbstractParserImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/parser/SqlAbstractParserImpl.java b/core/src/main/java/org/apache/calcite/sql/parser/SqlAbstractParserImpl.java
index 6876447..bef5da7 100644
--- a/core/src/main/java/org/apache/calcite/sql/parser/SqlAbstractParserImpl.java
+++ b/core/src/main/java/org/apache/calcite/sql/parser/SqlAbstractParserImpl.java
@@ -327,6 +327,8 @@ public abstract class SqlAbstractParserImpl {
 
   protected int nDynamicParams;
 
+  protected String originalSql;
+
   //~ Methods ----------------------------------------------------------------
 
   /**
@@ -442,6 +444,20 @@ public abstract class SqlAbstractParserImpl {
   public abstract void setIdentifierMaxLength(int identifierMaxLength);
 
   /**
+   * Sets the SQL text that is being parsed.
+   */
+  public void setOriginalSql(String originalSql) {
+    this.originalSql = originalSql;
+  }
+
+  /**
+   * Returns the SQL text.
+   */
+  public String getOriginalSql() {
+    return originalSql;
+  }
+
+  /**
    * Change parser state.
    *
    * @param stateName new state.

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/39487512/core/src/main/java/org/apache/calcite/sql/parser/SqlParser.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/parser/SqlParser.java b/core/src/main/java/org/apache/calcite/sql/parser/SqlParser.java
index 1cf71fa..4c14395 100644
--- a/core/src/main/java/org/apache/calcite/sql/parser/SqlParser.java
+++ b/core/src/main/java/org/apache/calcite/sql/parser/SqlParser.java
@@ -42,6 +42,7 @@ public class SqlParser {
       Config config) {
     this.originalInput = s;
     this.parser = parser;
+    parser.setOriginalSql(s);
     parser.setTabSize(1);
     parser.setQuotedCasing(config.quotedCasing());
     parser.setUnquotedCasing(config.unquotedCasing());


[16/18] incubator-calcite git commit: [CALCITE-827] Calcite incorrectly permutes columns of OVER query (Hsuan-Yi Chu)

Posted by jh...@apache.org.
[CALCITE-827] Calcite incorrectly permutes columns of OVER query (Hsuan-Yi Chu)

Close apache/incubator-calcite#115


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

Branch: refs/heads/master
Commit: b9670731e05465fa2a257bab809f9ff71e7213cf
Parents: 5e7d457
Author: Hsuan-Yi Chu <hs...@usc.edu>
Authored: Sun Aug 2 17:29:33 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Sep 1 16:17:16 2015 -0700

----------------------------------------------------------------------
 .../calcite/rel/logical/LogicalWindow.java      | 33 +++++++++++++++-----
 .../apache/calcite/test/RelOptRulesTest.java    | 19 +++++++++++
 .../org/apache/calcite/test/RelOptRulesTest.xml | 24 ++++++++++++++
 core/src/test/resources/sql/winagg.oq           | 23 ++++++++++++++
 4 files changed, 91 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b9670731/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 c1f4a02..2e65115 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
@@ -48,6 +48,7 @@ import java.util.AbstractList;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.IdentityHashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -116,11 +117,13 @@ public final class LogicalWindow extends Window {
     // Build a list of groups, partitions, and aggregate functions. Each
     // aggregate function will add its arguments as outputs of the input
     // program.
+    final Map<RexOver, RexOver> origToNewOver = new IdentityHashMap<>();
     for (RexNode agg : program.getExprList()) {
       if (agg instanceof RexOver) {
-        RexOver over = (RexOver) agg;
-        over = (RexOver) over.accept(replaceConstants);
-        addWindows(windowMap, over, inputFieldCount);
+        final RexOver origOver = (RexOver) agg;
+        final RexOver newOver = (RexOver) origOver.accept(replaceConstants);
+        origToNewOver.put(origOver, newOver);
+        addWindows(windowMap, newOver, inputFieldCount);
       }
     }
 
@@ -199,7 +202,7 @@ public final class LogicalWindow extends Window {
           public RexNode visitOver(RexOver over) {
             // Look up the aggCall which this expr was translated to.
             final Window.RexWinAggCall aggCall =
-                aggMap.get(over);
+                aggMap.get(origToNewOver.get(over));
             assert aggCall != null;
             assert RelOptUtil.eq(
                 "over",
@@ -238,18 +241,32 @@ public final class LogicalWindow extends Window {
                 localRef.getType());
           }
         };
-    // TODO: The order that the "over" calls occur in the groups and
-    // partitions may not match the order in which they occurred in the
-    // original expression. We should add a project to permute them.
 
     LogicalWindow window =
         new LogicalWindow(
             cluster, traitSet, child, constants, intermediateRowType,
             groups);
 
+    // The order that the "over" calls occur in the groups and
+    // partitions may not match the order in which they occurred in the
+    // original expression.
+    // Add a project to permute them.
+    final List<RexNode> rexNodesWindow = new ArrayList<>();
+    for (RexNode rexNode : program.getExprList()) {
+      rexNodesWindow.add(rexNode.accept(shuttle));
+    }
+    final List<RexNode> refToWindow = toInputRefs(rexNodesWindow);
+
+    final List<RexNode> projectList = new ArrayList<>();
+    for (RexLocalRef inputRef : program.getProjectList()) {
+      final int index = inputRef.getIndex();
+      final RexInputRef ref = (RexInputRef) refToWindow.get(index);
+      projectList.add(ref);
+    }
+
     return RelOptUtil.createProject(
         window,
-        toInputRefs(program.getProjectList()),
+        projectList,
         outRowType.getFieldNames());
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b9670731/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 5b60fb4..8c1f678 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -62,6 +62,7 @@ import org.apache.calcite.rel.rules.ProjectMergeRule;
 import org.apache.calcite.rel.rules.ProjectRemoveRule;
 import org.apache.calcite.rel.rules.ProjectSetOpTransposeRule;
 import org.apache.calcite.rel.rules.ProjectToCalcRule;
+import org.apache.calcite.rel.rules.ProjectToWindowRule;
 import org.apache.calcite.rel.rules.PruneEmptyRules;
 import org.apache.calcite.rel.rules.ReduceExpressionsRule;
 import org.apache.calcite.rel.rules.SemiJoinFilterTransposeRule;
@@ -139,6 +140,24 @@ public class RelOptRulesTest extends RelOptTestBase {
     return DiffRepository.lookup(RelOptRulesTest.class);
   }
 
+  @Test public void testProjectToWindowRuleForMultipleWindows() {
+    HepProgram preProgram =  new HepProgramBuilder()
+        .build();
+
+    HepProgramBuilder builder = new HepProgramBuilder();
+    builder.addRuleClass(ProjectToWindowRule.class);
+    HepPlanner hepPlanner = new HepPlanner(builder.build());
+    hepPlanner.addRule(ProjectToWindowRule.PROJECT);
+
+    checkPlanning(tester,
+        preProgram,
+        hepPlanner,
+        "select count(*) over(partition by empno order by sal) as count1,\n"
+            + "count(*) over(partition by deptno order by sal) as count2, \n"
+            + "sum(deptno) over(partition by empno order by sal) as sum1, \n"
+            + "sum(deptno) over(partition by deptno order by sal) as sum2 \n"
+            + "from emp");
+  }
 
   @Test public void testUnionToDistinctRule() {
     checkPlanning(UnionToDistinctRule.INSTANCE,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b9670731/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 bd650ce..542f153 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,30 @@ See the License for the specific language governing permissions and
 limitations under the License.
 -->
 <Root>
+    <TestCase name="testProjectToWindowRuleForMultipleWindows">
+        <Resource name="sql">
+            <![CDATA[
+select count(*) over(partition by empno order by sal) as count1,
+    count(*) over(partition by deptno order by sal) as count2,
+    sum(deptno)  over(partition by empno order by sal) as sum1,
+    sum(deptno)  over(partition by deptno order by sal) as sum2
+    from emp
+]]>
+        </Resource>
+        <Resource name="planAfter">
+            <![CDATA[
+LogicalProject($0=[$9], $1=[$11], $2=[$10], $3=[$12])
+  LogicalWindow(window#0=[window(partition {0} order by [5] range between UNBOUNDED PRECEDING and CURRENT ROW aggs [COUNT(), SUM($7)])], window#1=[window(partition {7} order by [5] range between UNBOUNDED PRECEDING and CURRENT ROW aggs [COUNT(), SUM($7)])])
+    LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+        <Resource name="planBefore">
+            <![CDATA[
+LogicalProject(COUNT1=[COUNT() OVER (PARTITION BY $0 ORDER BY $5 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)], COUNT2=[COUNT() OVER (PARTITION BY $7 ORDER BY $5 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)], SUM1=[SUM($7) OVER (PARTITION BY $0 ORDER BY $5 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)], SUM2=[SUM($7) OVER (PARTITION BY $7 ORDER BY $5 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)])
+  LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+    </TestCase>
     <TestCase name="testUnionToDistinctRule">
         <Resource name="sql">
             <![CDATA[select * from dept union select * from dept]]>

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b9670731/core/src/test/resources/sql/winagg.oq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/winagg.oq b/core/src/test/resources/sql/winagg.oq
index 590af75..44bc186 100644
--- a/core/src/test/resources/sql/winagg.oq
+++ b/core/src/test/resources/sql/winagg.oq
@@ -17,6 +17,29 @@
 #
 !use post
 !set outputformat psql
+
+# Multiple window functions sharing a single window
+select count(*) over(partition by gender order by ename) as count1,
+  count(*) over(partition by deptno order by ename) as count2,
+  sum(deptno) over(partition by gender order by ename) as sum1,
+  sum(deptno) over(partition by deptno order by ename) as sum2
+from emp
+order by sum1, sum2;
+ COUNT1 | COUNT2 | SUM1 | SUM2
+--------+--------+------+------
+      1 |      1 |   30 |   30
+      1 |      1 |   50 |   50
+      2 |      1 |   60 |   10
+      3 |      1 |   80 |   20
+      2 |      2 |   80 |  100
+      3 |      1 |  140 |   60
+      4 |      2 |  150 |   20
+      5 |      2 |  180 |   60
+      6 |      1 |  180 |     
+(9 rows)
+
+!ok
+
 !if (false) {
 select *, first_value(deptno) over () from emp;
  ename | deptno | gender | first_value