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/02/08 18:25:00 UTC

[1/9] incubator-calcite git commit: [CALCITE-581] Add LogicalSort relational expression, and make Sort abstract

Repository: incubator-calcite
Updated Branches:
  refs/heads/master 44650d4fe -> e237804b0


[CALCITE-581] Add LogicalSort relational expression, and make Sort abstract


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

Branch: refs/heads/master
Commit: c0a3085ce9f5f5de1d2c9d3656ad740a35a5a91e
Parents: 5a6d32a
Author: Julian Hyde <jh...@apache.org>
Authored: Fri Jan 30 17:10:55 2015 -0800
Committer: julianhyde <jh...@apache.org>
Committed: Fri Feb 6 12:10:34 2015 -0800

----------------------------------------------------------------------
 .../apache/calcite/adapter/jdbc/JdbcRules.java  |  5 +-
 .../calcite/plan/SubstitutionVisitor.java       |  6 +-
 .../calcite/rel/RelCollationTraitDef.java       |  9 +--
 .../apache/calcite/rel/core/RelFactories.java   |  4 +-
 .../java/org/apache/calcite/rel/core/Sort.java  | 28 ++-----
 .../apache/calcite/rel/logical/LogicalSort.java | 77 ++++++++++++++++++++
 .../apache/calcite/sql2rel/RelDecorrelator.java | 12 +--
 .../sql2rel/RelStructuredTypeFlattener.java     | 10 +--
 .../calcite/sql2rel/SqlToRelConverter.java      |  8 +-
 .../org/apache/calcite/test/LatticeTest.java    |  2 +-
 .../org/apache/calcite/tools/PlannerTest.java   |  2 +-
 .../org/apache/calcite/test/RelOptRulesTest.xml |  6 +-
 .../calcite/test/SqlToRelConverterTest.xml      | 56 +++++++-------
 13 files changed, 134 insertions(+), 91 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c0a3085c/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java
index 3716730..a08eb9d 100644
--- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java
+++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java
@@ -642,7 +642,10 @@ public class JdbcRules {
     }
 
     @Override public JdbcSort copy(RelTraitSet traitSet, RelNode newInput,
-        RelCollation newCollation) {
+        RelCollation newCollation, RexNode offset, RexNode fetch) {
+      if (offset != null || fetch != null) {
+        throw new IllegalArgumentException("not supported: offset or fetch");
+      }
       return new JdbcSort(getCluster(), traitSet, newInput, newCollation);
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c0a3085c/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java b/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
index de9cb22..97e2605 100644
--- a/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
+++ b/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
@@ -27,12 +27,12 @@ import org.apache.calcite.rel.core.Aggregate;
 import org.apache.calcite.rel.core.AggregateCall;
 import org.apache.calcite.rel.core.Filter;
 import org.apache.calcite.rel.core.Project;
-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.logical.LogicalAggregate;
 import org.apache.calcite.rel.logical.LogicalFilter;
 import org.apache.calcite.rel.logical.LogicalProject;
+import org.apache.calcite.rel.logical.LogicalSort;
 import org.apache.calcite.rel.logical.LogicalUnion;
 import org.apache.calcite.rel.rules.ProjectRemoveRule;
 import org.apache.calcite.rel.type.RelDataType;
@@ -605,8 +605,8 @@ public class SubstitutionVisitor {
           aggregate.aggCalls);
     case SORT:
       final MutableSort sort = (MutableSort) node;
-      return new Sort(node.cluster, node.cluster.traitSetOf(sort.collation),
-          fromMutable(sort.input), sort.collation, sort.offset, sort.fetch);
+      return LogicalSort.create(fromMutable(sort.input), sort.collation,
+          sort.offset, sort.fetch);
     case UNION:
       final MutableUnion union = (MutableUnion) node;
       return new LogicalUnion(union.cluster, fromMutables(union.inputs),

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c0a3085c/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 dc935fd..23a94ee 100644
--- a/core/src/main/java/org/apache/calcite/rel/RelCollationTraitDef.java
+++ b/core/src/main/java/org/apache/calcite/rel/RelCollationTraitDef.java
@@ -16,11 +16,11 @@
  */
 package org.apache.calcite.rel;
 
-import org.apache.calcite.plan.Convention;
 import org.apache.calcite.plan.RelOptPlanner;
 import org.apache.calcite.plan.RelTraitDef;
 import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.core.Sort;
+import org.apache.calcite.rel.logical.LogicalSort;
 
 /**
  * Definition of the ordering trait.
@@ -76,12 +76,7 @@ public class RelCollationTraitDef extends RelTraitDef<RelCollation> {
     // Create a logical sort, then ask the planner to convert its remaining
     // traits (e.g. convert it to an EnumerableSortRel if rel is enumerable
     // convention)
-    final Sort sort =
-        new Sort(
-            rel.getCluster(),
-            rel.getCluster().traitSetOf(Convention.NONE, toCollation),
-            rel,
-            toCollation);
+    final Sort sort = LogicalSort.create(rel, toCollation, null, null);
     RelNode newRel = sort;
     final RelTraitSet newTraitSet = rel.getTraitSet().replace(toCollation);
     if (!newRel.getTraitSet().equals(newTraitSet)) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c0a3085c/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java b/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java
index b975daf..5967f30 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java
@@ -27,6 +27,7 @@ import org.apache.calcite.rel.logical.LogicalFilter;
 import org.apache.calcite.rel.logical.LogicalIntersect;
 import org.apache.calcite.rel.logical.LogicalJoin;
 import org.apache.calcite.rel.logical.LogicalMinus;
+import org.apache.calcite.rel.logical.LogicalSort;
 import org.apache.calcite.rel.logical.LogicalUnion;
 import org.apache.calcite.rel.type.RelDataTypeField;
 import org.apache.calcite.rex.RexNode;
@@ -105,8 +106,7 @@ public class RelFactories {
   private static class SortFactoryImpl implements SortFactory {
     public RelNode createSort(RelTraitSet traits, RelNode child,
         RelCollation collation, RexNode offset, RexNode fetch) {
-      return new Sort(child.getCluster(), traits, child, collation,
-          offset, fetch);
+      return LogicalSort.create(child, collation, offset, fetch);
     }
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c0a3085c/core/src/main/java/org/apache/calcite/rel/core/Sort.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Sort.java b/core/src/main/java/org/apache/calcite/rel/core/Sort.java
index 445afb2..7a75303 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Sort.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Sort.java
@@ -17,7 +17,6 @@
 package org.apache.calcite.rel.core;
 
 import org.apache.calcite.linq4j.Ord;
-import org.apache.calcite.plan.Convention;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptCost;
 import org.apache.calcite.plan.RelOptPlanner;
@@ -44,7 +43,7 @@ import java.util.List;
  * Relational expression that imposes a particular sort order on its input
  * without otherwise changing its content.
  */
-public class Sort extends SingleRel {
+public abstract class Sort extends SingleRel {
   //~ Instance fields --------------------------------------------------------
 
   protected final RelCollation collation;
@@ -119,32 +118,17 @@ public class Sort extends SingleRel {
 
   //~ Methods ----------------------------------------------------------------
 
-  @Override public Sort copy(RelTraitSet traitSet, List<RelNode> inputs) {
-    return copy(traitSet, sole(inputs), collation);
+  @Override public final Sort copy(RelTraitSet traitSet, List<RelNode> inputs) {
+    return copy(traitSet, sole(inputs), collation, offset, fetch);
   }
 
-  public Sort copy(
-      RelTraitSet traitSet,
-      RelNode newInput,
+  public final Sort copy(RelTraitSet traitSet, RelNode newInput,
       RelCollation newCollation) {
     return copy(traitSet, newInput, newCollation, offset, fetch);
   }
 
-  public Sort copy(
-      RelTraitSet traitSet,
-      RelNode newInput,
-      RelCollation newCollation,
-      RexNode offset,
-      RexNode fetch) {
-    assert traitSet.containsIfApplicable(Convention.NONE);
-    return new Sort(
-        getCluster(),
-        traitSet,
-        newInput,
-        newCollation,
-        offset,
-        fetch);
-  }
+  public abstract Sort copy(RelTraitSet traitSet, RelNode newInput,
+      RelCollation newCollation, RexNode offset, RexNode fetch);
 
   @Override public RelOptCost computeSelfCost(RelOptPlanner planner) {
     // Higher cost if rows are wider discourages pushing a project through a

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c0a3085c/core/src/main/java/org/apache/calcite/rel/logical/LogicalSort.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalSort.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalSort.java
new file mode 100644
index 0000000..8d88cfa
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalSort.java
@@ -0,0 +1,77 @@
+/*
+ * 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.logical;
+
+import org.apache.calcite.plan.Convention;
+import org.apache.calcite.plan.RelOptCluster;
+import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelInput;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.RelShuttle;
+import org.apache.calcite.rel.core.Sort;
+import org.apache.calcite.rex.RexNode;
+
+/**
+ * Sub-class of {@link org.apache.calcite.rel.core.Sort} not
+ * targeted at any particular engine or calling convention.
+ */
+public final class LogicalSort extends Sort {
+  private LogicalSort(RelOptCluster cluster, RelTraitSet traitSet,
+      RelNode input, RelCollation collation, RexNode offset, RexNode fetch) {
+    super(cluster, traitSet, input, collation, offset, fetch);
+    assert traitSet.containsIfApplicable(Convention.NONE);
+  }
+
+  /**
+   * Creates a LogicalSort by parsing serialized output.
+   */
+  public LogicalSort(RelInput input) {
+    super(input);
+  }
+
+  /**
+   * Creates a LogicalSort.
+   *
+   * @param input     Input relational expression
+   * @param collation array of sort specifications
+   * @param offset    Expression for number of rows to discard before returning
+   *                  first row
+   * @param fetch     Expression for number of rows to fetch
+   */
+  public static LogicalSort create(RelNode input, RelCollation collation,
+      RexNode offset, RexNode fetch) {
+    RelOptCluster cluster = input.getCluster();
+    RelTraitSet traitSet =
+        input.getTraitSet().replace(Convention.NONE).replace(collation);
+    return new LogicalSort(cluster, traitSet, input, collation, offset, fetch);
+  }
+
+  //~ Methods ----------------------------------------------------------------
+
+  @Override public Sort copy(RelTraitSet traitSet, RelNode newInput,
+      RelCollation newCollation, RexNode offset, RexNode fetch) {
+    return new LogicalSort(getCluster(), traitSet, newInput, newCollation,
+        offset, fetch);
+  }
+
+  @Override public RelNode accept(RelShuttle shuttle) {
+    return shuttle.visit(this);
+  }
+}
+
+// End LogicalSort.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c0a3085c/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java b/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
index bff404f..8521ce2 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
@@ -19,7 +19,6 @@ package org.apache.calcite.sql2rel;
 import org.apache.calcite.linq4j.Ord;
 import org.apache.calcite.linq4j.function.Function2;
 import org.apache.calcite.plan.Context;
-import org.apache.calcite.plan.Convention;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptCostImpl;
 import org.apache.calcite.plan.RelOptRule;
@@ -43,6 +42,7 @@ import org.apache.calcite.rel.logical.LogicalCorrelate;
 import org.apache.calcite.rel.logical.LogicalFilter;
 import org.apache.calcite.rel.logical.LogicalJoin;
 import org.apache.calcite.rel.logical.LogicalProject;
+import org.apache.calcite.rel.logical.LogicalSort;
 import org.apache.calcite.rel.metadata.RelMdUtil;
 import org.apache.calcite.rel.rules.FilterJoinRule;
 import org.apache.calcite.rel.type.RelDataType;
@@ -406,14 +406,8 @@ public class RelDecorrelator implements ReflectiveVisitor {
     RelCollation oldCollation = rel.getCollation();
     RelCollation newCollation = RexUtil.apply(mapping, oldCollation);
 
-    Sort newRel =
-        new Sort(
-            rel.getCluster(),
-            rel.getCluster().traitSetOf(Convention.NONE).plus(newCollation),
-            newChildRel,
-            newCollation,
-            rel.offset,
-            rel.fetch);
+    final Sort newRel =
+        LogicalSort.create(newChildRel, newCollation, rel.offset, rel.fetch);
 
     mapOldToNewRel.put(rel, newRel);
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c0a3085c/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 bf25d60..aa8e548 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/RelStructuredTypeFlattener.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/RelStructuredTypeFlattener.java
@@ -16,7 +16,6 @@
  */
 package org.apache.calcite.sql2rel;
 
-import org.apache.calcite.plan.Convention;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptTable;
 import org.apache.calcite.plan.RelOptUtil;
@@ -37,6 +36,7 @@ import org.apache.calcite.rel.logical.LogicalIntersect;
 import org.apache.calcite.rel.logical.LogicalJoin;
 import org.apache.calcite.rel.logical.LogicalMinus;
 import org.apache.calcite.rel.logical.LogicalProject;
+import org.apache.calcite.rel.logical.LogicalSort;
 import org.apache.calcite.rel.logical.LogicalTableFunctionScan;
 import org.apache.calcite.rel.logical.LogicalTableModify;
 import org.apache.calcite.rel.logical.LogicalTableScan;
@@ -384,13 +384,7 @@ public class RelStructuredTypeFlattener implements ReflectiveVisitor {
     }
     RelCollation newCollation = RexUtil.apply(mapping, oldCollation);
     Sort newRel =
-        new Sort(
-            rel.getCluster(),
-            rel.getCluster().traitSetOf(Convention.NONE).plus(newCollation),
-            newChild,
-            newCollation,
-            rel.offset,
-            rel.fetch);
+        LogicalSort.create(newChild, newCollation, rel.offset, rel.fetch);
     setNewForOldRel(rel, newRel);
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c0a3085c/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 4723114..2eb7d2c 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -40,7 +40,6 @@ import org.apache.calcite.rel.core.JoinInfo;
 import org.apache.calcite.rel.core.JoinRelType;
 import org.apache.calcite.rel.core.Project;
 import org.apache.calcite.rel.core.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;
@@ -48,6 +47,7 @@ import org.apache.calcite.rel.logical.LogicalIntersect;
 import org.apache.calcite.rel.logical.LogicalJoin;
 import org.apache.calcite.rel.logical.LogicalMinus;
 import org.apache.calcite.rel.logical.LogicalProject;
+import org.apache.calcite.rel.logical.LogicalSort;
 import org.apache.calcite.rel.logical.LogicalTableFunctionScan;
 import org.apache.calcite.rel.logical.LogicalTableModify;
 import org.apache.calcite.rel.logical.LogicalTableScan;
@@ -762,11 +762,7 @@ public class SqlToRelConverter {
 
     // Create a sorter using the previously constructed collations.
     bb.setRoot(
-        new Sort(
-            cluster,
-            cluster.traitSetOf(Convention.NONE, collation),
-            bb.root,
-            collation,
+        LogicalSort.create(bb.root, collation,
             offset == null ? null : convertExpression(offset),
             fetch == null ? null : convertExpression(fetch)),
         false);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c0a3085c/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 4f53fbb..86e8007 100644
--- a/core/src/test/java/org/apache/calcite/test/LatticeTest.java
+++ b/core/src/test/java/org/apache/calcite/test/LatticeTest.java
@@ -124,7 +124,7 @@ public class LatticeTest {
   @Test public void testLatticeSqlWithOrderByFails() {
     modelWithLattice("star",
         "select 1 from \"foodmart\".\"sales_fact_1997\" as s order by \"product_id\"")
-        .connectThrows("Invalid node type Sort in lattice query");
+        .connectThrows("Invalid node type LogicalSort in lattice query");
   }
 
   /** Tests a lattice whose SQL is invalid because it contains a UNION ALL. */

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c0a3085c/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 4342c19..c7650c4 100644
--- a/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
+++ b/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
@@ -138,7 +138,7 @@ public class PlannerTest {
             + "ORDER BY `emps`.`deptno`\n"
             + "OFFSET 10 ROWS",
 
-        "Sort(sort0=[$1], dir0=[ASC], offset=[10])\n"
+        "LogicalSort(sort0=[$1], dir0=[ASC], offset=[10])\n"
             + "  LogicalProject(empid=[$0], deptno=[$1], name=[$2], salary=[$3], commission=[$4])\n"
             + "    EnumerableTableScan(table=[[hr, emps]])\n");
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c0a3085c/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 a3b2c67..a81cfdc 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -929,7 +929,7 @@ EmptyRel
         </Resource>
         <Resource name="planBefore">
             <![CDATA[
-Sort(sort0=[$7], dir0=[ASC])
+LogicalSort(sort0=[$7], dir0=[ASC])
   LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
     LogicalFilter(condition=[false])
       LogicalTableScan(table=[[CATALOG, SALES, EMP]])
@@ -937,7 +937,7 @@ Sort(sort0=[$7], dir0=[ASC])
         </Resource>
         <Resource name="planAfter">
             <![CDATA[
-Sort(sort0=[$7], dir0=[ASC])
+LogicalSort(sort0=[$7], dir0=[ASC])
   LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
     LogicalValues(tuples=[[]])
 ]]>
@@ -949,7 +949,7 @@ Sort(sort0=[$7], dir0=[ASC])
         </Resource>
         <Resource name="planBefore">
             <![CDATA[
-Sort(sort0=[$7], dir0=[ASC], fetch=[0])
+LogicalSort(sort0=[$7], dir0=[ASC], fetch=[0])
   LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
     LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c0a3085c/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 db79eb8..22ea262 100644
--- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
@@ -902,7 +902,7 @@ LogicalProject(NAME=[$0])
         </Resource>
         <Resource name="plan">
             <![CDATA[
-Sort(sort0=[$0], dir0=[ASC])
+LogicalSort(sort0=[$0], dir0=[ASC])
   LogicalProject(EMPNO=[$0])
     LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
@@ -914,7 +914,7 @@ Sort(sort0=[$0], dir0=[ASC])
         </Resource>
         <Resource name="plan">
             <![CDATA[
-Sort(sort0=[$0], dir0=[DESC-nulls-last])
+LogicalSort(sort0=[$0], dir0=[DESC-nulls-last])
   LogicalProject(EMPNO=[$0])
     LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
@@ -926,7 +926,7 @@ Sort(sort0=[$0], dir0=[DESC-nulls-last])
         </Resource>
         <Resource name="plan">
             <![CDATA[
-Sort(sort0=[$1], dir0=[ASC])
+LogicalSort(sort0=[$1], dir0=[ASC])
   LogicalProject(X=[+($0, 1)], Y=[-($0, 2)])
     LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
@@ -934,11 +934,11 @@ Sort(sort0=[$1], dir0=[ASC])
     </TestCase>
     <TestCase name="testOrderByOrdinalDesc">
         <Resource name="sql">
-            <![CDATA[select empno + 1, deptno, empno from emp order by 2.5 desc]]>
+            <![CDATA[select empno + 1, deptno, empno from emp order by 2 desc]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
-Sort(sort0=[$1], dir0=[DESC])
+LogicalSort(sort0=[$1], dir0=[DESC])
   LogicalProject(EXPR$0=[+($0, 1)], DEPTNO=[$7], EMPNO=[$0])
     LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
@@ -951,7 +951,7 @@ Sort(sort0=[$1], dir0=[DESC])
         <Resource name="plan">
             <![CDATA[
 LogicalProject(EXPR$0=[$0])
-  Sort(sort0=[$1], sort1=[$0], dir0=[ASC], dir1=[DESC])
+  LogicalSort(sort0=[$1], sort1=[$0], dir0=[ASC], dir1=[DESC])
     LogicalProject(EXPR$0=[+($0, 1)], DEPTNO=[$7])
       LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
@@ -964,7 +964,7 @@ LogicalProject(EXPR$0=[$0])
         <Resource name="plan">
             <![CDATA[
 LogicalProject(EXPR$0=[$0], DEPTNO=[$1], EMPNO=[$2])
-  Sort(sort0=[$3], dir0=[DESC])
+  LogicalSort(sort0=[$3], dir0=[DESC])
     LogicalProject(EXPR$0=[+($0, 1)], DEPTNO=[$7], EMPNO=[$0], EXPR$3=[-1])
       LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
@@ -977,7 +977,7 @@ LogicalProject(EXPR$0=[$0], DEPTNO=[$1], EMPNO=[$2])
         <Resource name="plan">
             <![CDATA[
 LogicalProject(EXPR$0=[$0], DEPTNO=[$1], EMPNO=[$2])
-  Sort(sort0=[$3], dir0=[DESC])
+  LogicalSort(sort0=[$3], dir0=[DESC])
     LogicalProject(EXPR$0=[+($0, 1)], DEPTNO=[$7], EMPNO=[$0], EXPR$3=[+(1, 2)])
       LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
@@ -1003,7 +1003,7 @@ ProjectRel(EMPNO=[$0], Y=[$1])
         <Resource name="plan">
             <![CDATA[
 LogicalProject(X=[$0], Y=[$1])
-  Sort(sort0=[$2], dir0=[ASC])
+  LogicalSort(sort0=[$2], dir0=[ASC])
     LogicalProject(X=[+($0, 1)], Y=[-($0, 2)], EXPR$2=[+(-($0, 2), 3)])
       LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
@@ -1016,7 +1016,7 @@ LogicalProject(X=[$0], Y=[$1])
         <Resource name="plan">
             <![CDATA[
 LogicalProject(EMPNO=[$0], Y=[$1])
-  Sort(sort0=[$2], dir0=[ASC])
+  LogicalSort(sort0=[$2], dir0=[ASC])
     LogicalProject(EMPNO=[+($0, 1)], Y=[-($0, 2)], EXPR$2=[+(+($0, 1), 3)])
       LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
@@ -1028,7 +1028,7 @@ LogicalProject(EMPNO=[$0], Y=[$1])
         </Resource>
         <Resource name="plan">
             <![CDATA[
-Sort(sort0=[$1], sort1=[$0], dir0=[DESC], dir1=[ASC])
+LogicalSort(sort0=[$1], sort1=[$0], dir0=[DESC], dir1=[ASC])
   LogicalProject(EMPNO=[$0], SAL=[$1])
     LogicalUnion(all=[true])
       LogicalProject(EMPNO=[$0], SAL=[$5])
@@ -1045,7 +1045,7 @@ Sort(sort0=[$1], sort1=[$0], dir0=[DESC], dir1=[ASC])
         <Resource name="plan">
             <![CDATA[
 LogicalProject(EMPNO=[$0], SAL=[$1])
-  Sort(sort0=[$2], dir0=[ASC])
+  LogicalSort(sort0=[$2], dir0=[ASC])
     LogicalProject(EMPNO=[$0], SAL=[$1], EXPR$2=[+(*($0, $1), 2)])
       LogicalUnion(all=[true])
         LogicalProject(EMPNO=[$0], SAL=[$5])
@@ -1062,7 +1062,7 @@ LogicalProject(EMPNO=[$0], SAL=[$1])
         <Resource name="plan">
             <![CDATA[
 LogicalProject(DEPTNO=[$0], EXPR$1=[$1])
-  Sort(sort0=[$2], sort1=[$3], dir0=[DESC], dir1=[ASC])
+  LogicalSort(sort0=[$2], sort1=[$3], dir0=[DESC], dir1=[ASC])
     LogicalProject(DEPTNO=[$0], EXPR$1=[$1], EXPR$2=[*($0, $2)], EXPR$3=[$3])
       LogicalAggregate(group=[{0}], EXPR$1=[COUNT()], agg#1=[SUM($1)], agg#2=[MIN($2)])
         LogicalProject(DEPTNO=[$7], SAL=[$5], EMPNO=[$0])
@@ -1077,7 +1077,7 @@ LogicalProject(DEPTNO=[$0], EXPR$1=[$1])
         <Resource name="plan">
             <![CDATA[
 LogicalProject(EMPNO=[$0], EXPR$1=[$1])
-  Sort(sort0=[$2], dir0=[ASC])
+  LogicalSort(sort0=[$2], dir0=[ASC])
     LogicalAggregate(group=[{0, 1, 2}])
       LogicalProject(EMPNO=[$0], EXPR$1=[+($7, 1)], EXPR$2=[+(+($7, 1), $0)])
         LogicalTableScan(table=[[CATALOG, SALES, EMP]])
@@ -1091,7 +1091,7 @@ LogicalProject(EMPNO=[$0], EXPR$1=[$1])
         <Resource name="plan">
             <![CDATA[
 LogicalProject(EMPNO=[$0])
-  Sort(sort0=[$1], sort1=[$2], sort2=[$1], dir0=[DESC], dir1=[ASC], dir2=[ASC])
+  LogicalSort(sort0=[$1], sort1=[$2], sort2=[$1], dir0=[DESC], dir1=[ASC], dir2=[ASC])
     LogicalProject(EMPNO=[$0], EXPR$1=[+($5, $0)], EXPR$2=[*($5, $0)])
       LogicalJoin(condition=[true], joinType=[inner])
         LogicalTableScan(table=[[CATALOG, SALES, EMP]])
@@ -1105,7 +1105,7 @@ LogicalProject(EMPNO=[$0])
         </Resource>
         <Resource name="plan">
             <![CDATA[
-Sort(sort0=[$1], dir0=[ASC])
+LogicalSort(sort0=[$1], dir0=[ASC])
   LogicalProject(EMPNO=[$0], SAL=[$1])
     LogicalUnion(all=[true])
       LogicalProject(EMPNO=[$0], SAL=[$5])
@@ -1376,7 +1376,7 @@ order by c + a]]>
         <Resource name="plan">
             <![CDATA[
 LogicalProject(A=[$0], B=[$1], C=[$2], DEPTNO=[$3], NAME=[$4])
-  Sort(sort0=[$5], dir0=[ASC])
+  LogicalSort(sort0=[$5], dir0=[ASC])
     LogicalProject(A=[$0], B=[$1], C=[$2], DEPTNO=[$3], NAME=[$4], EXPR$5=[+($2, $0)])
       LogicalJoin(condition=[=($3, $2)], joinType=[inner])
         LogicalProject(A=[$2], B=[$1], C=[$0])
@@ -1449,7 +1449,7 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
         </Resource>
         <Resource name="plan">
             <![CDATA[
-Sort(sort0=[$0], dir0=[ASC], offset=[10], fetch=[5])
+LogicalSort(sort0=[$0], dir0=[ASC], offset=[10], fetch=[5])
   LogicalProject(EMPNO=[$0])
     LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
@@ -1461,7 +1461,7 @@ Sort(sort0=[$0], dir0=[ASC], offset=[10], fetch=[5])
         </Resource>
         <Resource name="plan">
             <![CDATA[
-Sort(fetch=[5])
+LogicalSort(fetch=[5])
   LogicalProject(EMPNO=[$0])
     LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
@@ -1473,7 +1473,7 @@ Sort(fetch=[5])
         </Resource>
         <Resource name="plan">
             <![CDATA[
-Sort(offset=[10], fetch=[5])
+LogicalSort(offset=[10], fetch=[5])
   LogicalProject(EMPNO=[$0])
     LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
@@ -1485,7 +1485,7 @@ Sort(offset=[10], fetch=[5])
         </Resource>
         <Resource name="plan">
             <![CDATA[
-Sort(offset=[10])
+LogicalSort(offset=[10])
   LogicalProject(EMPNO=[$0])
     LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
@@ -1836,7 +1836,7 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
       LogicalTableScan(table=[[CATALOG, SALES, EMP]])
       LogicalAggregate(group=[{}], agg#0=[MIN($0)])
         LogicalProject($f0=[true])
-          Sort(fetch=[1])
+          LogicalSort(fetch=[1])
             LogicalProject(EXPR$0=[1])
               LogicalFilter(condition=[=($cor0.DEPTNO, $0)])
                 LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
@@ -1857,7 +1857,7 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
         LogicalTableScan(table=[[CATALOG, SALES, EMP]])
         LogicalAggregate(group=[{}], agg#0=[MIN($0)])
           LogicalProject($f0=[true])
-            Sort(fetch=[1])
+            LogicalSort(fetch=[1])
               LogicalProject(EXPR$0=[1])
                 LogicalFilter(condition=[=($cor0.DEPTNO, $0)])
                   LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
@@ -1907,7 +1907,7 @@ select * from emp2 order by deptno]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
-Sort(sort0=[$7], dir0=[ASC])
+LogicalSort(sort0=[$7], dir0=[ASC])
   LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
     LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
       LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
@@ -1926,7 +1926,7 @@ order by empno + x]]>
         <Resource name="plan">
             <![CDATA[
 LogicalProject(EMPNO=[$0], X=[$1])
-  Sort(sort0=[$2], dir0=[ASC])
+  LogicalSort(sort0=[$2], dir0=[ASC])
     LogicalProject(EMPNO=[$0], X=[$1], EXPR$2=[+($0, $1)])
       LogicalUnion(all=[true])
         LogicalProject(EMPNO=[$0], X=[$1])
@@ -2035,7 +2035,7 @@ LogicalProject(EMPNO=[$0], EXPR$1=[NOT(true)])
         <Resource name="plan">
             <![CDATA[
 LogicalProject(ENAME=[$0])
-  Sort(sort0=[$1], dir0=[ASC])
+  LogicalSort(sort0=[$1], dir0=[ASC])
     LogicalProject(ENAME=[$1], SAL=[$5])
       LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
@@ -2100,7 +2100,7 @@ order by 2]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
-Sort(sort0=[$1], dir0=[ASC])
+LogicalSort(sort0=[$1], dir0=[ASC])
   LogicalProject(DEPTNO=[$0], ENAME=[$1], EXPR$2=[$4])
     LogicalProject(DEPTNO=[$0], ENAME=[CASE($3, null, $1)], i$DEPTNO=[$2], i$ENAME=[$3], EXPR$2=[$4])
       LogicalAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}]], indicator=[true], EXPR$2=[SUM($2)])
@@ -2268,7 +2268,7 @@ order by 2]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
-Sort(sort0=[$1], dir0=[ASC])
+LogicalSort(sort0=[$1], dir0=[ASC])
   LogicalProject(DEPTNO=[$1], EXPR$1=[1], EXPR$2=[$2], EXPR$3=[1])
     LogicalAggregate(group=[{0, 1}], EXPR$2=[COUNT()])
       LogicalProject(EMPNO=[$0], DEPTNO=[$7])


[7/9] incubator-calcite git commit: [CALCITE-88] Add collation as a trait and a kind of RelNode metadata

Posted by jh...@apache.org.
[CALCITE-88] Add collation as a trait and a kind of RelNode metadata

[CALCITE-526] Add EnumerableMergeJoin, which exploits sorted inputs

[CALCITE-71] Provide a way to declare that tables are sorted

[CALCITE-576] Make RelCollation trait and AbstractRelNode.getCollationList consistent

[CALCITE-581] Add LogicalSort relational expression, and make Sort abstract

[CALCITE-254] Propagate RelCollation on aliased columns in JoinRule

[CALCITE-569] ArrayIndexOutOfBoundsException when deducing collation

More efficient algorithm to check for cycles in the tree of equivalence sets.

FilterJoinRule now propagates traits.

Ord.zip returns random-access list.

Replace references to "Bug#upgrade" with "Deprecated // to be removed before ..."

Add composite traits (RelCompositeTrait); subsets only ever have a simple trait, but other RelNodes can have multiple traits, and appear in each subset that those traits. Each composite trait is canonized within its trait definition, and each of the component traits.

Rename RelTraitSet.subsumes and RelTrait.subsumes to satisfies.


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

Branch: refs/heads/master
Commit: 2709896eb176c14605b1ddc4be57d916ebeb0fe8
Parents: c0120dd
Author: Julian Hyde <jh...@apache.org>
Authored: Sat Dec 13 23:49:02 2014 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Sun Feb 8 00:45:51 2015 -0800

----------------------------------------------------------------------
 .../calcite/adapter/clone/ArrayTable.java       |  12 +-
 .../adapter/enumerable/EnumerableCalc.java      |  46 ++-
 .../adapter/enumerable/EnumerableCalcRule.java  |  14 +-
 .../enumerable/EnumerableConvention.java        |   2 +-
 .../adapter/enumerable/EnumerableFilter.java    |  25 ++
 .../enumerable/EnumerableFilterToCalcRule.java  |  15 +-
 .../adapter/enumerable/EnumerableJoin.java      |  20 ++
 .../adapter/enumerable/EnumerableLimit.java     |  29 +-
 .../adapter/enumerable/EnumerableMergeJoin.java | 150 +++++++++
 .../enumerable/EnumerableMergeJoinRule.java     | 116 +++++++
 .../enumerable/EnumerableProjectToCalcRule.java |  15 +-
 .../adapter/enumerable/EnumerableRules.java     |   3 +
 .../adapter/enumerable/EnumerableSort.java      |  22 +-
 .../adapter/enumerable/EnumerableSortRule.java  |   7 +-
 .../adapter/enumerable/EnumerableValues.java    |  25 +-
 .../enumerable/EnumerableValuesRule.java        |   7 +-
 .../adapter/enumerable/PhysTypeImpl.java        |   3 +-
 .../calcite/interpreter/BindableConvention.java |   2 +-
 .../interpreter/InterpretableConvention.java    |   2 +-
 .../apache/calcite/interpreter/SortNode.java    |  37 +--
 .../org/apache/calcite/plan/Convention.java     |   2 +-
 .../apache/calcite/plan/RelCompositeTrait.java  | 149 +++++++++
 .../apache/calcite/plan/RelMultipleTrait.java   |  32 ++
 .../calcite/plan/RelOptAbstractTable.java       |   2 +-
 .../org/apache/calcite/plan/RelOptCluster.java  |  14 +-
 .../calcite/plan/RelOptMaterialization.java     |   4 +-
 .../org/apache/calcite/plan/RelOptUtil.java     | 108 ++-----
 .../java/org/apache/calcite/plan/RelTrait.java  |  20 +-
 .../org/apache/calcite/plan/RelTraitDef.java    |  37 ++-
 .../org/apache/calcite/plan/RelTraitSet.java    | 138 ++++++++-
 .../calcite/plan/SubstitutionVisitor.java       |  14 +-
 .../calcite/plan/volcano/AbstractConverter.java |   3 +-
 .../org/apache/calcite/plan/volcano/RelSet.java |  10 +-
 .../apache/calcite/plan/volcano/RelSubset.java  |  24 +-
 .../calcite/plan/volcano/VolcanoPlanner.java    |  68 ++--
 .../calcite/prepare/CalcitePrepareImpl.java     |   3 +-
 .../calcite/prepare/LixToRelTranslator.java     |  36 +--
 .../org/apache/calcite/prepare/Prepare.java     |  12 +-
 .../calcite/prepare/QueryableRelBuilder.java    |  10 +-
 .../apache/calcite/prepare/RelOptTableImpl.java |  26 +-
 .../org/apache/calcite/rel/AbstractRelNode.java |   2 +
 .../org/apache/calcite/rel/RelCollation.java    |   4 +-
 .../apache/calcite/rel/RelCollationImpl.java    | 110 ++-----
 .../calcite/rel/RelCollationTraitDef.java       |  10 +-
 .../org/apache/calcite/rel/RelCollations.java   | 166 ++++++++++
 .../apache/calcite/rel/RelFieldCollation.java   |  35 ++-
 .../java/org/apache/calcite/rel/RelNode.java    |   2 +-
 .../org/apache/calcite/rel/core/Aggregate.java  |   4 +-
 .../java/org/apache/calcite/rel/core/Calc.java  |  67 ++--
 .../org/apache/calcite/rel/core/Correlate.java  |   8 +-
 .../org/apache/calcite/rel/core/JoinInfo.java   |   5 +
 .../org/apache/calcite/rel/core/Project.java    |  34 +-
 .../apache/calcite/rel/core/RelFactories.java   |  15 +-
 .../org/apache/calcite/rel/core/Window.java     |   4 +-
 .../apache/calcite/rel/externalize/RelJson.java |   3 +-
 .../calcite/rel/logical/LogicalAggregate.java   |  40 ++-
 .../apache/calcite/rel/logical/LogicalCalc.java |  39 ++-
 .../calcite/rel/logical/LogicalCorrelate.java   |  38 ++-
 .../calcite/rel/logical/LogicalFilter.java      |  39 ++-
 .../calcite/rel/logical/LogicalIntersect.java   |  29 +-
 .../apache/calcite/rel/logical/LogicalJoin.java |  75 ++---
 .../calcite/rel/logical/LogicalMinus.java       |  38 ++-
 .../calcite/rel/logical/LogicalProject.java     |  71 +++--
 .../apache/calcite/rel/logical/LogicalSort.java |   2 +
 .../rel/logical/LogicalTableFunctionScan.java   |  32 +-
 .../calcite/rel/logical/LogicalTableModify.java |  49 +--
 .../calcite/rel/logical/LogicalTableScan.java   |  23 +-
 .../calcite/rel/logical/LogicalUnion.java       |  33 +-
 .../calcite/rel/logical/LogicalValues.java      |  44 ++-
 .../calcite/rel/metadata/BuiltInMetadata.java   |   9 +
 .../metadata/DefaultRelMetadataProvider.java    |   3 +-
 .../calcite/rel/metadata/RelMdCollation.java    | 308 +++++++++++++++++++
 .../calcite/rel/metadata/RelMetadataQuery.java  |  18 ++
 .../AggregateExpandDistinctAggregatesRule.java  |   5 +-
 .../AggregateProjectPullUpConstantsRule.java    |  20 +-
 .../rel/rules/AggregateReduceFunctionsRule.java |  12 +-
 .../rel/rules/AggregateUnionAggregateRule.java  |   8 +-
 .../rel/rules/AggregateUnionTransposeRule.java  |  10 +-
 .../calcite/rel/rules/CalcRelSplitter.java      |   8 +-
 .../calcite/rel/rules/FilterCalcMergeRule.java  |  10 +-
 .../calcite/rel/rules/FilterJoinRule.java       |   3 +-
 .../rules/FilterTableFunctionTransposeRule.java |   9 +-
 .../calcite/rel/rules/FilterToCalcRule.java     |  13 +-
 .../calcite/rel/rules/JoinToCorrelateRule.java  |   4 +-
 .../calcite/rel/rules/ProjectCalcMergeRule.java |  18 +-
 .../calcite/rel/rules/ProjectRemoveRule.java    |  15 +-
 .../calcite/rel/rules/ProjectToCalcRule.java    |  15 +-
 .../calcite/rel/rules/ProjectToWindowRule.java  |  18 +-
 .../calcite/rel/rules/PruneEmptyRules.java      |   6 +-
 .../calcite/rel/rules/ReduceDecimalsRule.java   |  13 +-
 .../rel/rules/ReduceExpressionsRule.java        |  13 +-
 .../rel/rules/SortProjectTransposeRule.java     |  16 +-
 .../calcite/rel/rules/UnionMergeRule.java       |   7 +-
 .../calcite/rel/rules/UnionToDistinctRule.java  |   6 +-
 .../calcite/rel/rules/ValuesReduceRule.java     |   2 +-
 .../java/org/apache/calcite/rex/RexNode.java    |   2 +-
 .../java/org/apache/calcite/rex/RexOver.java    |   4 +-
 .../java/org/apache/calcite/rex/RexProgram.java |  28 +-
 .../java/org/apache/calcite/rex/RexUtil.java    |  14 +-
 .../org/apache/calcite/schema/Statistic.java    |   6 +
 .../org/apache/calcite/schema/Statistics.java   |  17 +
 .../java/org/apache/calcite/sql/SqlWindow.java  |   3 +-
 .../apache/calcite/sql/advise/SqlAdvisor.java   |   2 +-
 .../sql/fun/SqlLiteralChainOperator.java        |   3 +-
 .../org/apache/calcite/sql/util/SqlShuttle.java |   5 +-
 .../apache/calcite/sql2rel/RelDecorrelator.java |  70 ++---
 .../apache/calcite/sql2rel/RelFieldTrimmer.java |  16 +-
 .../sql2rel/RelStructuredTypeFlattener.java     |  36 +--
 .../calcite/sql2rel/SqlToRelConverter.java      | 126 ++------
 .../java/org/apache/calcite/tools/Programs.java |   5 +-
 .../main/java/org/apache/calcite/util/Bug.java  |   4 +
 .../org/apache/calcite/util/BuiltInMethod.java  |  28 +-
 .../apache/calcite/util/ImmutableBitSet.java    |   5 +
 .../apache/calcite/util/ImmutableIntList.java   |   2 +-
 .../main/java/org/apache/calcite/util/Util.java |  21 +-
 .../org/apache/calcite/plan/RelWriterTest.java  |  10 +-
 .../plan/volcano/VolcanoPlannerTraitTest.java   |  15 +-
 .../apache/calcite/rel/RelCollationTest.java    |  74 +++++
 .../calcite/sql/parser/SqlParserTest.java       |  16 +
 .../org/apache/calcite/test/CalciteAssert.java  |  15 +-
 .../org/apache/calcite/test/CalciteSuite.java   |   2 +
 .../test/JdbcFrontJdbcBackLinqMiddleTest.java   |   2 +-
 .../calcite/test/JdbcFrontLinqBackTest.java     |  11 +-
 .../java/org/apache/calcite/test/JdbcTest.java  |  66 +++-
 .../org/apache/calcite/test/LatticeTest.java    |  26 ++
 .../apache/calcite/test/MockCatalogReader.java  |  10 +-
 .../apache/calcite/test/RelMetadataTest.java    | 158 ++++++++++
 .../apache/calcite/test/ScannableTableTest.java |  10 +-
 .../apache/calcite/test/SqlToRelTestBase.java   |  15 +-
 .../apache/calcite/tools/FrameworksTest.java    |   6 +-
 .../org/apache/calcite/tools/PlannerTest.java   |   8 +-
 .../calcite/util/ImmutableBitSetTest.java       |  16 +
 core/src/test/resources/sql/sort.oq             |  71 +++++
 .../java/org/apache/calcite/linq4j/Ord.java     |  65 +++-
 .../calcite/adapter/mongodb/MongoRules.java     |   4 +-
 .../adapter/splunk/SplunkPushDownRule.java      |   9 +-
 136 files changed, 2729 insertions(+), 1131 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/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 5d1c58a..b9bdba8 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
@@ -25,6 +25,9 @@ import org.apache.calcite.linq4j.Ord;
 import org.apache.calcite.linq4j.QueryProvider;
 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;
@@ -77,7 +80,14 @@ class ArrayTable extends AbstractQueryableTable implements ScannableTable {
         keys.add(ImmutableBitSet.of(ord.i));
       }
     }
-    return Statistics.of(content.size, keys);
+    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);
   }
 
   public Enumerable<Object[]> scan(DataContext root) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalc.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalc.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalc.java
index b93256d..967d4dd 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalc.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalc.java
@@ -30,12 +30,16 @@ import org.apache.calcite.linq4j.tree.Types;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelCollationTraitDef;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Calc;
+import org.apache.calcite.rel.metadata.RelMdCollation;
 import org.apache.calcite.rex.RexProgram;
 import org.apache.calcite.util.BuiltInMethod;
 import org.apache.calcite.util.Pair;
+import org.apache.calcite.util.Util;
 
+import com.google.common.base.Supplier;
 import com.google.common.collect.ImmutableList;
 
 import java.lang.reflect.Modifier;
@@ -50,22 +54,50 @@ import static org.apache.calcite.adapter.enumerable.EnumUtils.NO_PARAMS;
 /** Implementation of {@link org.apache.calcite.rel.core.Calc} in
  * {@link org.apache.calcite.adapter.enumerable.EnumerableConvention enumerable calling convention}. */
 public class EnumerableCalc extends Calc implements EnumerableRel {
+  /**
+   * Creates an EnumerableCalc.
+   *
+   * <p>Use {@link #create} unless you know what you're doing.
+   */
+  public EnumerableCalc(RelOptCluster cluster,
+      RelTraitSet traitSet,
+      RelNode input,
+      RexProgram program) {
+    super(cluster, traitSet, input, program);
+    assert getConvention() instanceof EnumerableConvention;
+    assert !program.containsAggs();
+  }
+
+  @Deprecated // to be removed before 2.0
   public EnumerableCalc(
       RelOptCluster cluster,
       RelTraitSet traitSet,
-      RelNode child,
+      RelNode input,
       RexProgram program,
       List<RelCollation> collationList) {
-    super(cluster, traitSet, child, program, collationList);
-    assert getConvention() instanceof EnumerableConvention;
-    assert !program.containsAggs();
+    this(cluster, traitSet, input, program);
+    Util.discard(collationList);
+  }
+
+  /** Creates an EnumerableCalc. */
+  public static EnumerableCalc create(final RelNode input,
+      final RexProgram program) {
+    final RelOptCluster cluster = input.getCluster();
+    final RelTraitSet traitSet = cluster.traitSet()
+        .replace(EnumerableConvention.INSTANCE)
+        .replaceIf(RelCollationTraitDef.INSTANCE,
+            new Supplier<List<RelCollation>>() {
+              public List<RelCollation> get() {
+                return RelMdCollation.calc(input, program);
+              }
+            });
+    return new EnumerableCalc(cluster, traitSet, input, program);
   }
 
   @Override public EnumerableCalc copy(RelTraitSet traitSet, RelNode child,
-      RexProgram program, List<RelCollation> collationList) {
+      RexProgram program) {
     // we do not need to copy program; it is immutable
-    return new EnumerableCalc(getCluster(), traitSet, child,
-        program, collationList);
+    return new EnumerableCalc(getCluster(), traitSet, child, program);
   }
 
   public Result implement(EnumerableRelImplementor implementor, Prefer pref) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalcRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalcRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalcRule.java
index 793dcf8..b94ff57 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalcRule.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalcRule.java
@@ -36,15 +36,11 @@ class EnumerableCalcRule extends ConverterRule {
 
   public RelNode convert(RelNode rel) {
     final LogicalCalc calc = (LogicalCalc) rel;
-    return new EnumerableCalc(
-        rel.getCluster(),
-        rel.getTraitSet().replace(EnumerableConvention.INSTANCE),
-        convert(
-            calc.getInput(),
-            calc.getInput().getTraitSet()
-                .replace(EnumerableConvention.INSTANCE)),
-        calc.getProgram(),
-        calc.getCollationList());
+    final RelNode input = calc.getInput();
+    return EnumerableCalc.create(
+        convert(input,
+            input.getTraitSet().replace(EnumerableConvention.INSTANCE)),
+        calc.getProgram());
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableConvention.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableConvention.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableConvention.java
index ac1533a..946afae 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableConvention.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableConvention.java
@@ -49,7 +49,7 @@ public enum EnumerableConvention implements Convention {
     return ConventionTraitDef.INSTANCE;
   }
 
-  public boolean subsumes(RelTrait trait) {
+  public boolean satisfies(RelTrait trait) {
     return this == trait;
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilter.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilter.java
index ae68216..f4cc5e9 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilter.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilter.java
@@ -18,15 +18,25 @@ package org.apache.calcite.adapter.enumerable;
 
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelTraitSet;
+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;
+import org.apache.calcite.rel.metadata.RelMdCollation;
 import org.apache.calcite.rex.RexNode;
 
+import com.google.common.base.Supplier;
+
+import java.util.List;
+
 /** Implementation of {@link org.apache.calcite.rel.core.Filter} in
  * {@link org.apache.calcite.adapter.enumerable.EnumerableConvention enumerable calling convention}. */
 public class EnumerableFilter
     extends Filter
     implements EnumerableRel {
+  /** Creates an EnumerableFilter.
+   *
+   * <p>Use {@link #create} unless you know what you're doing. */
   public EnumerableFilter(
       RelOptCluster cluster,
       RelTraitSet traitSet,
@@ -36,6 +46,21 @@ public class EnumerableFilter
     assert getConvention() instanceof EnumerableConvention;
   }
 
+  /** Creates an EnumerableFilter. */
+  public static EnumerableFilter create(final RelNode input,
+      RexNode condition) {
+    final RelOptCluster cluster = input.getCluster();
+    final RelTraitSet traitSet =
+        cluster.traitSetOf(EnumerableConvention.INSTANCE)
+            .replaceIf(RelCollationTraitDef.INSTANCE,
+                new Supplier<List<RelCollation>>() {
+                public List<RelCollation> get() {
+                  return RelMdCollation.filter(input);
+                }
+              });
+    return new EnumerableFilter(cluster, traitSet, input, condition);
+  }
+
   public EnumerableFilter copy(RelTraitSet traitSet, RelNode input,
       RexNode condition) {
     return new EnumerableFilter(getCluster(), traitSet, input, condition);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilterToCalcRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilterToCalcRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilterToCalcRule.java
index 09ad78b..9a61124 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilterToCalcRule.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilterToCalcRule.java
@@ -18,15 +18,12 @@ package org.apache.calcite.adapter.enumerable;
 
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexProgram;
 import org.apache.calcite.rex.RexProgramBuilder;
 
-import com.google.common.collect.ImmutableList;
-
 /** Variant of {@link org.apache.calcite.rel.rules.FilterToCalcRule} for
  * {@link org.apache.calcite.adapter.enumerable.EnumerableConvention enumerable calling convention}. */
 public class EnumerableFilterToCalcRule extends RelOptRule {
@@ -36,24 +33,18 @@ public class EnumerableFilterToCalcRule extends RelOptRule {
 
   public void onMatch(RelOptRuleCall call) {
     final EnumerableFilter filter = call.rel(0);
-    final RelNode rel = filter.getInput();
+    final RelNode input = filter.getInput();
 
     // Create a program containing a filter.
     final RexBuilder rexBuilder = filter.getCluster().getRexBuilder();
-    final RelDataType inputRowType = rel.getRowType();
+    final RelDataType inputRowType = input.getRowType();
     final RexProgramBuilder programBuilder =
         new RexProgramBuilder(inputRowType, rexBuilder);
     programBuilder.addIdentity();
     programBuilder.addCondition(filter.getCondition());
     final RexProgram program = programBuilder.getProgram();
 
-    final EnumerableCalc calc =
-        new EnumerableCalc(
-            filter.getCluster(),
-            filter.getTraitSet(),
-            rel,
-            program,
-            ImmutableList.<RelCollation>of());
+    final EnumerableCalc calc = EnumerableCalc.create(input, program);
     call.transformTo(calc);
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableJoin.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableJoin.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableJoin.java
index ef93c17..052979f 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableJoin.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableJoin.java
@@ -42,6 +42,9 @@ import java.util.Set;
 /** Implementation of {@link org.apache.calcite.rel.core.Join} in
  * {@link org.apache.calcite.adapter.enumerable.EnumerableConvention enumerable calling convention}. */
 public class EnumerableJoin extends EquiJoin implements EnumerableRel {
+  /** Creates an EnumerableJoin.
+   *
+   * <p>Use {@link #create} unless you know what you're doing. */
   EnumerableJoin(
       RelOptCluster cluster,
       RelTraitSet traits,
@@ -65,6 +68,23 @@ public class EnumerableJoin extends EquiJoin implements EnumerableRel {
         variablesStopped);
   }
 
+  /** Creates an EnumerableJoin. */
+  public static EnumerableJoin create(
+      RelNode left,
+      RelNode right,
+      RexNode condition,
+      ImmutableIntList leftKeys,
+      ImmutableIntList rightKeys,
+      JoinRelType joinType,
+      Set<String> variablesStopped)
+      throws InvalidRelException {
+    final RelOptCluster cluster = left.getCluster();
+    final RelTraitSet traitSet =
+        cluster.traitSetOf(EnumerableConvention.INSTANCE);
+    return new EnumerableJoin(cluster, traitSet, left, right, condition,
+        leftKeys, rightKeys, joinType, variablesStopped);
+  }
+
   @Override public EnumerableJoin copy(RelTraitSet traitSet, RexNode condition,
       RelNode left, RelNode right, JoinRelType joinType,
       boolean semiJoinDone) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableLimit.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableLimit.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableLimit.java
index bdbeaad..2bef8c8 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableLimit.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableLimit.java
@@ -21,13 +21,18 @@ import org.apache.calcite.linq4j.tree.Expression;
 import org.apache.calcite.linq4j.tree.Expressions;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelCollationTraitDef;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelWriter;
 import org.apache.calcite.rel.SingleRel;
+import org.apache.calcite.rel.metadata.RelMdCollation;
 import org.apache.calcite.rex.RexLiteral;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.util.BuiltInMethod;
 
+import com.google.common.base.Supplier;
+
 import java.util.List;
 
 /** Relational expression that applies a limit and/or offset to its input. */
@@ -35,17 +40,35 @@ public class EnumerableLimit extends SingleRel implements EnumerableRel {
   private final RexNode offset;
   private final RexNode fetch;
 
+  /** Creates an EnumerableLimit.
+   *
+   * <p>Use {@link #create} unless you know what you're doing. */
   public EnumerableLimit(
       RelOptCluster cluster,
       RelTraitSet traitSet,
-      RelNode child,
+      RelNode input,
       RexNode offset,
       RexNode fetch) {
-    super(cluster, traitSet, child);
+    super(cluster, traitSet, input);
     this.offset = offset;
     this.fetch = fetch;
     assert getConvention() instanceof EnumerableConvention;
-    assert getConvention() == child.getConvention();
+    assert getConvention() == input.getConvention();
+  }
+
+  /** Creates an EnumerableLimit. */
+  public static EnumerableLimit create(final RelNode input, RexNode offset,
+      RexNode fetch) {
+    final RelOptCluster cluster = input.getCluster();
+    final RelTraitSet traitSet =
+        cluster.traitSetOf(EnumerableConvention.INSTANCE)
+            .replaceIf(RelCollationTraitDef.INSTANCE,
+                new Supplier<List<RelCollation>>() {
+                  public List<RelCollation> get() {
+                    return RelMdCollation.filter(input);
+                  }
+                });
+    return new EnumerableLimit(cluster, traitSet, input, offset, fetch);
   }
 
   @Override public EnumerableLimit copy(

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeJoin.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeJoin.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeJoin.java
new file mode 100644
index 0000000..c370eb9
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeJoin.java
@@ -0,0 +1,150 @@
+/*
+ * 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.adapter.enumerable;
+
+import org.apache.calcite.linq4j.tree.BlockBuilder;
+import org.apache.calcite.linq4j.tree.Expression;
+import org.apache.calcite.linq4j.tree.Expressions;
+import org.apache.calcite.plan.RelOptCluster;
+import org.apache.calcite.plan.RelOptCost;
+import org.apache.calcite.plan.RelOptPlanner;
+import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.rel.InvalidRelException;
+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.core.JoinInfo;
+import org.apache.calcite.rel.core.JoinRelType;
+import org.apache.calcite.rel.metadata.RelMdCollation;
+import org.apache.calcite.rel.metadata.RelMetadataQuery;
+import org.apache.calcite.rel.rules.EquiJoin;
+import org.apache.calcite.rex.RexLiteral;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.util.BuiltInMethod;
+import org.apache.calcite.util.ImmutableIntList;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+import java.util.List;
+import java.util.Set;
+
+/** Implementation of {@link org.apache.calcite.rel.core.Join} in
+ * {@link EnumerableConvention enumerable calling convention} using
+ * a merge algorithm. */
+public class EnumerableMergeJoin extends EquiJoin implements EnumerableRel {
+  EnumerableMergeJoin(
+      RelOptCluster cluster,
+      RelTraitSet traits,
+      RelNode left,
+      RelNode right,
+      RexNode condition,
+      ImmutableIntList leftKeys,
+      ImmutableIntList rightKeys,
+      JoinRelType joinType,
+      Set<String> variablesStopped)
+      throws InvalidRelException {
+    super(cluster, traits, left, right, condition, leftKeys, rightKeys,
+        joinType, variablesStopped);
+    final List<RelCollation> collations =
+        traits.getTraits(RelCollationTraitDef.INSTANCE);
+    assert collations == null || RelCollations.contains(collations, leftKeys);
+  }
+
+  public static EnumerableMergeJoin create(RelNode left, RelNode right,
+      RexLiteral condition, ImmutableIntList leftKeys,
+      ImmutableIntList rightKeys, JoinRelType joinType)
+      throws InvalidRelException {
+    final RelOptCluster cluster = right.getCluster();
+    RelTraitSet traitSet = cluster.traitSet();
+    if (traitSet.isEnabled(RelCollationTraitDef.INSTANCE)) {
+      final List<RelCollation> collations =
+          RelMdCollation.mergeJoin(left, right, leftKeys, rightKeys);
+      traitSet = traitSet.replace(collations);
+    }
+    return new EnumerableMergeJoin(cluster, traitSet, left, right, condition,
+        leftKeys, rightKeys, joinType, ImmutableSet.<String>of());
+  }
+
+  @Override public EnumerableMergeJoin copy(RelTraitSet traitSet,
+      RexNode condition, RelNode left, RelNode right, JoinRelType joinType,
+      boolean semiJoinDone) {
+    final JoinInfo joinInfo = JoinInfo.of(left, right, condition);
+    assert joinInfo.isEqui();
+    try {
+      return new EnumerableMergeJoin(getCluster(), traitSet, left, right,
+          condition, joinInfo.leftKeys, joinInfo.rightKeys, joinType,
+          variablesStopped);
+    } catch (InvalidRelException e) {
+      // Semantic error not possible. Must be a bug. Convert to
+      // internal error.
+      throw new AssertionError(e);
+    }
+  }
+
+  @Override public RelOptCost computeSelfCost(RelOptPlanner planner) {
+    // We assume that the inputs are sorted. The price of sorting them has
+    // already been paid. The cost of the join is therefore proportional to the
+    // input and output size.
+    final double rightRowCount = right.getRows();
+    final double leftRowCount = left.getRows();
+    final double rowCount = RelMetadataQuery.getRowCount(this);
+    final double d = leftRowCount + rightRowCount + rowCount;
+    return planner.getCostFactory().makeCost(d, 0, 0);
+  }
+
+  public Result implement(EnumerableRelImplementor implementor, Prefer pref) {
+    BlockBuilder builder = new BlockBuilder();
+    final Result leftResult =
+        implementor.visitChild(this, 0, (EnumerableRel) left, pref);
+    Expression leftExpression =
+        builder.append(
+            "left", leftResult.block);
+    final Result rightResult =
+        implementor.visitChild(this, 1, (EnumerableRel) right, pref);
+    Expression rightExpression =
+        builder.append(
+            "right", rightResult.block);
+    final PhysType physType =
+        PhysTypeImpl.of(
+            implementor.getTypeFactory(), getRowType(), pref.preferArray());
+    final PhysType keyPhysType =
+        leftResult.physType.project(
+            leftKeys, JavaRowFormat.LIST);
+    return implementor.result(
+        physType,
+        builder.append(
+            Expressions.call(
+                BuiltInMethod.MERGE_JOIN.method,
+                Expressions.list(
+                    leftExpression,
+                    rightExpression,
+                    leftResult.physType.generateAccessor(leftKeys),
+                    rightResult.physType.generateAccessor(rightKeys),
+                    EnumUtils.joinSelector(joinType,
+                        physType,
+                        ImmutableList.of(
+                            leftResult.physType, rightResult.physType)),
+                    Expressions.constant(
+                        joinType.generatesNullsOnLeft()),
+                    Expressions.constant(
+                        joinType.generatesNullsOnRight())))).toBlock());
+  }
+}
+
+// End EnumerableMergeJoin.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeJoinRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeJoinRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeJoinRule.java
new file mode 100644
index 0000000..51f09f4
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeJoinRule.java
@@ -0,0 +1,116 @@
+/*
+ * 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.adapter.enumerable;
+
+import org.apache.calcite.linq4j.Ord;
+import org.apache.calcite.plan.Convention;
+import org.apache.calcite.plan.RelOptCluster;
+import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.rel.InvalidRelException;
+import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelCollations;
+import org.apache.calcite.rel.RelFieldCollation;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.convert.ConverterRule;
+import org.apache.calcite.rel.core.JoinInfo;
+import org.apache.calcite.rel.core.JoinRelType;
+import org.apache.calcite.rel.logical.LogicalJoin;
+
+import com.google.common.collect.Lists;
+
+import java.util.List;
+
+/** Planner rule that converts a
+ * {@link org.apache.calcite.rel.logical.LogicalJoin} relational expression
+ * {@link EnumerableConvention enumerable calling convention}.
+ *
+ * @see org.apache.calcite.adapter.enumerable.EnumerableJoinRule
+ */
+class EnumerableMergeJoinRule extends ConverterRule {
+  EnumerableMergeJoinRule() {
+    super(LogicalJoin.class,
+        Convention.NONE,
+        EnumerableConvention.INSTANCE,
+        "EnumerableMergeJoinRule");
+  }
+
+  @Override public RelNode convert(RelNode rel) {
+    LogicalJoin join = (LogicalJoin) rel;
+    final JoinInfo info =
+        JoinInfo.of(join.getLeft(), join.getRight(), join.getCondition());
+    if (join.getJoinType() != JoinRelType.INNER) {
+      // EnumerableMergeJoin only supports inner join.
+      // (It supports non-equi join, using a post-filter; see below.)
+      return null;
+    }
+    if (info.pairs().size() == 0) {
+      // EnumerableMergeJoin CAN support cartesian join, but disable it for now.
+      return null;
+    }
+    final List<RelNode> newInputs = Lists.newArrayList();
+    final List<RelCollation> collations = Lists.newArrayList();
+    int offset = 0;
+    for (Ord<RelNode> ord : Ord.zip(join.getInputs())) {
+      RelTraitSet traits = ord.e.getTraitSet()
+          .replace(EnumerableConvention.INSTANCE);
+      if (!info.pairs().isEmpty()) {
+        final List<RelFieldCollation> fieldCollations = Lists.newArrayList();
+        for (int key : info.keys().get(ord.i)) {
+          fieldCollations.add(
+              new RelFieldCollation(key,
+                  RelFieldCollation.Direction.ASCENDING,
+                  RelFieldCollation.NullDirection.LAST));
+        }
+        final RelCollation collation = RelCollations.of(fieldCollations);
+        collations.add(RelCollations.shift(collation, offset));
+        traits = traits.replace(collation);
+      }
+      newInputs.add(convert(ord.e, traits));
+      offset += ord.e.getRowType().getFieldCount();
+    }
+    final RelNode left = newInputs.get(0);
+    final RelNode right = newInputs.get(1);
+    final RelOptCluster cluster = join.getCluster();
+    RelNode newRel;
+    try {
+      RelTraitSet traits = join.getTraitSet()
+          .replace(EnumerableConvention.INSTANCE);
+      if (!collations.isEmpty()) {
+        traits = traits.replace(collations);
+      }
+      newRel = new EnumerableMergeJoin(cluster,
+          traits,
+          left,
+          right,
+          info.getEquiCondition(left, right, cluster.getRexBuilder()),
+          info.leftKeys,
+          info.rightKeys,
+          join.getJoinType(),
+          join.getVariablesStopped());
+    } catch (InvalidRelException e) {
+      EnumerableRules.LOGGER.fine(e.toString());
+      return null;
+    }
+    if (!info.isEqui()) {
+      newRel = new EnumerableFilter(cluster, newRel.getTraitSet(),
+          newRel, info.getRemaining(cluster.getRexBuilder()));
+    }
+    return newRel;
+  }
+}
+
+// End EnumerableMergeJoinRule.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectToCalcRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectToCalcRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectToCalcRule.java
index c654d19..2e1a4a8 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectToCalcRule.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectToCalcRule.java
@@ -18,12 +18,9 @@ package org.apache.calcite.adapter.enumerable;
 
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rex.RexProgram;
 
-import com.google.common.collect.ImmutableList;
-
 /** Variant of {@link org.apache.calcite.rel.rules.ProjectToCalcRule} for
  * {@link org.apache.calcite.adapter.enumerable.EnumerableConvention enumerable calling convention}. */
 public class EnumerableProjectToCalcRule extends RelOptRule {
@@ -33,20 +30,14 @@ public class EnumerableProjectToCalcRule extends RelOptRule {
 
   public void onMatch(RelOptRuleCall call) {
     final EnumerableProject project = call.rel(0);
-    final RelNode child = project.getInput();
+    final RelNode input = project.getInput();
     final RexProgram program =
-        RexProgram.create(child.getRowType(),
+        RexProgram.create(input.getRowType(),
             project.getProjects(),
             null,
             project.getRowType(),
             project.getCluster().getRexBuilder());
-    final EnumerableCalc calc =
-        new EnumerableCalc(
-            project.getCluster(),
-            project.getTraitSet(),
-            child,
-            program,
-            ImmutableList.<RelCollation>of());
+    final EnumerableCalc calc = EnumerableCalc.create(input, program);
     call.transformTo(calc);
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRules.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRules.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRules.java
index 700e7e2..37fe2de 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRules.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRules.java
@@ -33,6 +33,9 @@ public class EnumerableRules {
   public static final RelOptRule ENUMERABLE_JOIN_RULE =
       new EnumerableJoinRule();
 
+  public static final RelOptRule ENUMERABLE_MERGE_JOIN_RULE =
+      new EnumerableMergeJoinRule();
+
   public static final RelOptRule ENUMERABLE_SEMI_JOIN_RULE =
       new EnumerableSemiJoinRule();
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSort.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSort.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSort.java
index a20279c..8046d64 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSort.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSort.java
@@ -31,11 +31,27 @@ import org.apache.calcite.util.Pair;
 /** Implementation of {@link org.apache.calcite.rel.core.Sort} in
  * {@link org.apache.calcite.adapter.enumerable.EnumerableConvention enumerable calling convention}. */
 public class EnumerableSort extends Sort implements EnumerableRel {
+  /**
+   * Creates an EnumerableSort.
+   *
+   * <p>Use {@link #create} unless you know what you're doing.
+   */
   public EnumerableSort(RelOptCluster cluster, RelTraitSet traitSet,
-      RelNode child, RelCollation collation, RexNode offset, RexNode fetch) {
-    super(cluster, traitSet, child, collation, offset, fetch);
+      RelNode input, RelCollation collation, RexNode offset, RexNode fetch) {
+    super(cluster, traitSet, input, collation, offset, fetch);
     assert getConvention() instanceof EnumerableConvention;
-    assert getConvention() == child.getConvention();
+    assert getConvention() == input.getConvention();
+  }
+
+  /** Creates an EnumerableSort. */
+  public static EnumerableSort create(RelNode child, RelCollation collation,
+      RexNode offset, RexNode fetch) {
+    final RelOptCluster cluster = child.getCluster();
+    final RelTraitSet traitSet =
+        cluster.traitSetOf(EnumerableConvention.INSTANCE)
+            .replace(collation);
+    return new EnumerableSort(cluster, traitSet, child, collation, offset,
+        fetch);
   }
 
   @Override public EnumerableSort copy(

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSortRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSortRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSortRule.java
index 35a7e33..eb3d737 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSortRule.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSortRule.java
@@ -17,7 +17,6 @@
 package org.apache.calcite.adapter.enumerable;
 
 import org.apache.calcite.plan.Convention;
-import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.convert.ConverterRule;
 import org.apache.calcite.rel.core.Sort;
@@ -37,12 +36,8 @@ class EnumerableSortRule extends ConverterRule {
     if (sort.offset != null || sort.fetch != null) {
       return null;
     }
-    final RelTraitSet traitSet =
-        sort.getTraitSet().replace(EnumerableConvention.INSTANCE);
     final RelNode input = sort.getInput();
-    return new EnumerableSort(
-        rel.getCluster(),
-        traitSet,
+    return EnumerableSort.create(
         convert(
             input,
             input.getTraitSet().replace(EnumerableConvention.INSTANCE)),

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValues.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValues.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValues.java
index e4eeeee..76e08e2 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValues.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValues.java
@@ -23,14 +23,18 @@ import org.apache.calcite.linq4j.tree.Expressions;
 import org.apache.calcite.linq4j.tree.Primitive;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelCollationTraitDef;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Values;
+import org.apache.calcite.rel.metadata.RelMdCollation;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeField;
 import org.apache.calcite.rex.RexLiteral;
 import org.apache.calcite.util.BuiltInMethod;
 import org.apache.calcite.util.Pair;
 
+import com.google.common.base.Supplier;
 import com.google.common.collect.ImmutableList;
 
 import java.lang.reflect.Type;
@@ -40,15 +44,30 @@ import java.util.List;
 /** Implementation of {@link org.apache.calcite.rel.core.Values} in
  * {@link org.apache.calcite.adapter.enumerable.EnumerableConvention enumerable calling convention}. */
 public class EnumerableValues extends Values implements EnumerableRel {
-  EnumerableValues(RelOptCluster cluster, RelDataType rowType,
+  /** Creates an EnumerableValues. */
+  private EnumerableValues(RelOptCluster cluster, RelDataType rowType,
       ImmutableList<ImmutableList<RexLiteral>> tuples, RelTraitSet traitSet) {
     super(cluster, rowType, tuples, traitSet);
   }
 
+  /** Creates an EnumerableValues. */
+  public static EnumerableValues create(RelOptCluster cluster,
+      final RelDataType rowType,
+      final ImmutableList<ImmutableList<RexLiteral>> tuples) {
+    final RelTraitSet traitSet =
+        cluster.traitSetOf(EnumerableConvention.INSTANCE)
+            .replaceIf(RelCollationTraitDef.INSTANCE,
+                new Supplier<List<RelCollation>>() {
+                  public List<RelCollation> get() {
+                    return RelMdCollation.values(rowType, tuples);
+                  }
+                });
+    return new EnumerableValues(cluster, rowType, tuples, traitSet);
+  }
+
   @Override public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) {
     assert inputs.isEmpty();
-    return new EnumerableValues(
-        getCluster(), rowType, tuples, traitSet);
+    return create(getCluster(), rowType, tuples);
   }
 
   public Result implement(EnumerableRelImplementor implementor, Prefer pref) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValuesRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValuesRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValuesRule.java
index ed1b3ca..6e14bcc 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValuesRule.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValuesRule.java
@@ -33,11 +33,8 @@ public class EnumerableValuesRule extends ConverterRule {
 
   @Override public RelNode convert(RelNode rel) {
     LogicalValues values = (LogicalValues) rel;
-    return new EnumerableValues(
-        values.getCluster(),
-        values.getRowType(),
-        values.getTuples(),
-        values.getTraitSet().replace(EnumerableConvention.INSTANCE));
+    return EnumerableValues.create(values.getCluster(), values.getRowType(),
+        values.getTuples());
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/adapter/enumerable/PhysTypeImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/PhysTypeImpl.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/PhysTypeImpl.java
index 59ec646..6d51b97 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/PhysTypeImpl.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/PhysTypeImpl.java
@@ -517,8 +517,7 @@ public class PhysTypeImpl implements PhysType {
           Function1.class,
           Expressions.field(
               null,
-              Collections.class,
-              "EMPTY_LIST"),
+              BuiltInMethod.COMPARABLE_EMPTY_LIST.field),
           v1);
     case 1:
       int field0 = fields.get(0);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/interpreter/BindableConvention.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/BindableConvention.java b/core/src/main/java/org/apache/calcite/interpreter/BindableConvention.java
index d74745c..46dad77 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/BindableConvention.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/BindableConvention.java
@@ -54,7 +54,7 @@ public enum BindableConvention implements Convention {
     return ConventionTraitDef.INSTANCE;
   }
 
-  public boolean subsumes(RelTrait trait) {
+  public boolean satisfies(RelTrait trait) {
     return this == trait;
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/interpreter/InterpretableConvention.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/InterpretableConvention.java b/core/src/main/java/org/apache/calcite/interpreter/InterpretableConvention.java
index fb41d9d..e0e2fde 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/InterpretableConvention.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/InterpretableConvention.java
@@ -48,7 +48,7 @@ public enum InterpretableConvention implements Convention {
     return ConventionTraitDef.INSTANCE;
   }
 
-  public boolean subsumes(RelTrait trait) {
+  public boolean satisfies(RelTrait trait) {
     return this == trait;
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/interpreter/SortNode.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/SortNode.java b/core/src/main/java/org/apache/calcite/interpreter/SortNode.java
index 1e5f07b..e2c0eeb 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/SortNode.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/SortNode.java
@@ -97,55 +97,28 @@ public class SortNode extends AbstractSingleNode<Sort> {
             }));
   }
 
-  private static int compare(Comparable c1, Comparable c2,
-      int nullComparison) {
-    if (c1 == c2) {
-      return 0;
-    } else if (c1 == null) {
-      return nullComparison;
-    } else if (c2 == null) {
-      return -nullComparison;
-    } else {
-      //noinspection unchecked
-      return c1.compareTo(c2);
-    }
-  }
-
-  private Comparator<Row> comparator(final RelFieldCollation fieldCollation) {
-    final int nullComparison = getNullComparison(fieldCollation.nullDirection);
+  private Comparator<Row> comparator(RelFieldCollation fieldCollation) {
+    final int nullComparison = fieldCollation.nullDirection.nullComparison;
+    final int x = fieldCollation.getFieldIndex();
     switch (fieldCollation.direction) {
     case ASCENDING:
       return new Comparator<Row>() {
         public int compare(Row o1, Row o2) {
-          final int x = fieldCollation.getFieldIndex();
           final Comparable c1 = (Comparable) o1.getValues()[x];
           final Comparable c2 = (Comparable) o2.getValues()[x];
-          return SortNode.compare(c1, c2, nullComparison);
+          return RelFieldCollation.compare(c1, c2, nullComparison);
         }
       };
     default:
       return new Comparator<Row>() {
         public int compare(Row o1, Row o2) {
-          final int x = fieldCollation.getFieldIndex();
           final Comparable c1 = (Comparable) o1.getValues()[x];
           final Comparable c2 = (Comparable) o2.getValues()[x];
-          return SortNode.compare(c2, c1, -nullComparison);
+          return RelFieldCollation.compare(c2, c1, -nullComparison);
         }
       };
     }
   }
-
-  private int getNullComparison(RelFieldCollation.NullDirection nullDirection) {
-    switch (nullDirection) {
-    case FIRST:
-      return -1;
-    case UNSPECIFIED:
-    case LAST:
-      return 1;
-    default:
-      throw new AssertionError(nullDirection);
-    }
-  }
 }
 
 // End SortNode.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/plan/Convention.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/Convention.java b/core/src/main/java/org/apache/calcite/plan/Convention.java
index dbd1a5c..46750c2 100644
--- a/core/src/main/java/org/apache/calcite/plan/Convention.java
+++ b/core/src/main/java/org/apache/calcite/plan/Convention.java
@@ -55,7 +55,7 @@ public interface Convention extends RelTrait {
 
     public void register(RelOptPlanner planner) {}
 
-    public boolean subsumes(RelTrait trait) {
+    public boolean satisfies(RelTrait trait) {
       return this == trait;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/plan/RelCompositeTrait.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelCompositeTrait.java b/core/src/main/java/org/apache/calcite/plan/RelCompositeTrait.java
new file mode 100644
index 0000000..e2bf62f
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/plan/RelCompositeTrait.java
@@ -0,0 +1,149 @@
+/*
+ * 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.plan;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Ordering;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * A trait that consists of a list of traits, all of the same type.
+ *
+ * <p>It exists so that multiple traits of the same type
+ * ({@link org.apache.calcite.plan.RelTraitDef}) can be stored in the same
+ * {@link org.apache.calcite.plan.RelTraitSet}.
+ *
+ * @param <T> Member trait
+ */
+class RelCompositeTrait<T extends RelMultipleTrait> implements RelTrait {
+  private final RelTraitDef traitDef;
+  private final T[] traits;
+
+  /** Creates a RelCompositeTrait. */
+  // Must remain private. Does not copy the array.
+  private RelCompositeTrait(RelTraitDef traitDef, T[] traits) {
+    this.traitDef = traitDef;
+    this.traits = Preconditions.checkNotNull(traits);
+    //noinspection unchecked
+    assert Ordering.natural()
+        .isStrictlyOrdered(Arrays.asList((Comparable[]) traits))
+        : Arrays.toString(traits);
+    for (T trait : traits) {
+      assert trait.getTraitDef() == this.traitDef;
+    }
+  }
+
+  /** Creates a RelCompositeTrait. The constituent traits are canonized. */
+  @SuppressWarnings("unchecked")
+  static <T extends RelMultipleTrait> RelCompositeTrait<T> of(RelTraitDef def,
+      List<T> traitList) {
+    final RelCompositeTrait<T> compositeTrait;
+    if (traitList.isEmpty()) {
+      compositeTrait = new EmptyCompositeTrait<T>(def);
+    } else {
+      final RelMultipleTrait[] traits =
+          traitList.toArray(new RelMultipleTrait[traitList.size()]);
+      for (int i = 0; i < traits.length; i++) {
+        traits[i] = (T) def.canonize(traits[i]);
+      }
+      compositeTrait = new RelCompositeTrait<T>(def, (T[]) traits);
+    }
+    return def.canonizeComposite(compositeTrait);
+  }
+
+  public RelTraitDef getTraitDef() {
+    return traitDef;
+  }
+
+  @Override public int hashCode() {
+    return Arrays.hashCode(traits);
+  }
+
+  @Override public boolean equals(Object obj) {
+    return this == obj
+        || obj instanceof RelCompositeTrait
+        && Arrays.equals(traits, ((RelCompositeTrait) obj).traits);
+  }
+
+  @Override public String toString() {
+    return Arrays.toString(traits);
+  }
+
+  public boolean satisfies(RelTrait trait) {
+    for (T t : traits) {
+      if (t.satisfies(trait)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  public void register(RelOptPlanner planner) {
+  }
+
+  /** Returns an immutable list of the traits in this composite trait. */
+  public List<T> traitList() {
+    return ImmutableList.copyOf(traits);
+  }
+
+  RelCompositeTrait<T> canonize(RelTraitDef<T> traitDef) {
+    T[] newTraits = null;
+    for (int i = 0; i < traits.length; i++) {
+      final T trait = traits[i];
+      final T trait2 = traitDef.canonize(trait);
+      if (trait2 != trait) {
+        if (newTraits == null) {
+          newTraits = traits.clone();
+        }
+        newTraits[i] = trait2;
+      }
+    }
+    if (newTraits == null) {
+      return this;
+    }
+    assert false;
+    // TODO: cache duplicate composites
+    return new RelCompositeTrait<T>(traitDef, newTraits);
+  }
+
+  public T trait(int i) {
+    return traits[i];
+  }
+
+  public int size() {
+    return traits.length;
+  }
+
+  /** Composite trait with 0 elements. */
+  private static class EmptyCompositeTrait<T extends RelMultipleTrait>
+      extends RelCompositeTrait<T> {
+    private EmptyCompositeTrait(RelTraitDef traitDef) {
+      //noinspection unchecked
+      super(traitDef, (T[]) new RelMultipleTrait[0]);
+    }
+
+    @Override public boolean satisfies(RelTrait trait) {
+      //noinspection unchecked
+      return ((T) trait).isTop();
+    }
+  }
+}
+
+// End RelCompositeTrait.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/plan/RelMultipleTrait.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelMultipleTrait.java b/core/src/main/java/org/apache/calcite/plan/RelMultipleTrait.java
new file mode 100644
index 0000000..fbbc32f
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/plan/RelMultipleTrait.java
@@ -0,0 +1,32 @@
+/*
+ * 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.plan;
+
+/**
+ * Trait for which a given relational expression can have multiple values.
+ *
+ * <p>The most common example is sorted-ness (collation). The TIME dimension
+ * table might be sorted by [year, month, date] and also by [time_id].
+ */
+public interface RelMultipleTrait
+    extends RelTrait, Comparable<RelMultipleTrait> {
+  /** Returns whether this trait is satisfied by every instance of the trait
+   * (including itself). */
+  boolean isTop();
+}
+
+// End RelMultipleTrait.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/plan/RelOptAbstractTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptAbstractTable.java b/core/src/main/java/org/apache/calcite/plan/RelOptAbstractTable.java
index f672ef3..4252a25 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptAbstractTable.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptAbstractTable.java
@@ -89,7 +89,7 @@ public abstract class RelOptAbstractTable implements RelOptTable {
   }
 
   public RelNode toRel(ToRelContext context) {
-    return new LogicalTableScan(context.getCluster(), this);
+    return LogicalTableScan.create(context.getCluster(), this);
   }
 
   public Expression getExpression(Class clazz) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/plan/RelOptCluster.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptCluster.java b/core/src/main/java/org/apache/calcite/plan/RelOptCluster.java
index d1171ab..2071a8e 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptCluster.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptCluster.java
@@ -108,13 +108,13 @@ public class RelOptCluster {
     return metadataFactory;
   }
 
-  public RelTraitSet traitSetOf(RelTrait... traits) {
-    RelTraitSet traitSet = emptyTraitSet;
-    assert traitSet.size() == planner.getRelTraitDefs().size();
-    for (RelTrait trait : traits) {
-      traitSet = traitSet.replace(trait);
-    }
-    return traitSet;
+  /** Returns the default trait set for this cluster. */
+  public RelTraitSet traitSet() {
+    return emptyTraitSet;
+  }
+
+  public RelTraitSet traitSetOf(RelTrait trait) {
+    return emptyTraitSet.replace(trait);
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/plan/RelOptMaterialization.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptMaterialization.java b/core/src/main/java/org/apache/calcite/plan/RelOptMaterialization.java
index f09e5fd..8c9eaae 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptMaterialization.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptMaterialization.java
@@ -149,7 +149,7 @@ public class RelOptMaterialization {
                           Mappings.offsetSource(rightMapping, offset),
                           leftMapping.getTargetCount()));
               final RelNode project = RelOptUtil.createProject(
-                  new LogicalTableScan(cluster, leftRelOptTable),
+                  LogicalTableScan.create(cluster, leftRelOptTable),
                   Mappings.asList(mapping.inverse()));
               final List<RexNode> conditions = Lists.newArrayList();
               if (left.condition != null) {
@@ -173,7 +173,7 @@ public class RelOptMaterialization {
                       Mappings.offsetSource(leftMapping, offset),
                       Mappings.offsetTarget(rightMapping, leftCount));
               final RelNode project = RelOptUtil.createProject(
-                  new LogicalTableScan(cluster, rightRelOptTable),
+                  LogicalTableScan.create(cluster, rightRelOptTable),
                   Mappings.asList(mapping.inverse()));
               final List<RexNode> conditions = Lists.newArrayList();
               if (left.condition != null) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/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 88ad2ff..bbcb75d 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
@@ -17,8 +17,6 @@
 package org.apache.calcite.plan;
 
 import org.apache.calcite.linq4j.Ord;
-import org.apache.calcite.rel.RelCollation;
-import org.apache.calcite.rel.RelCollationImpl;
 import org.apache.calcite.rel.RelHomogeneousShuttle;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelShuttle;
@@ -73,7 +71,6 @@ import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.type.MultisetSqlType;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.sql.validate.SqlValidatorUtil;
-import org.apache.calcite.util.Holder;
 import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Permutation;
@@ -394,7 +391,7 @@ public abstract class RelOptUtil {
               extraName);
 
       ret =
-          new LogicalAggregate(ret.getCluster(), ret, false,
+          LogicalAggregate.create(ret, false,
               ImmutableBitSet.of(), null, ImmutableList.of(aggCall));
     }
 
@@ -435,7 +432,7 @@ public abstract class RelOptUtil {
       final int keyCount = ret.getRowType().getFieldCount();
       if (!needsOuterJoin) {
         return Pair.<RelNode, Boolean>of(
-            new LogicalAggregate(cluster, ret, false,
+            LogicalAggregate.create(ret, false,
                 ImmutableBitSet.range(keyCount), null,
                 ImmutableList.<AggregateCall>of()),
             false);
@@ -470,7 +467,7 @@ public abstract class RelOptUtil {
               null,
               null);
 
-      ret = new LogicalAggregate(cluster, ret, false,
+      ret = LogicalAggregate.create(ret, false,
           ImmutableBitSet.range(projectedKeyCount), null,
           ImmutableList.of(aggCall));
 
@@ -713,7 +710,7 @@ public abstract class RelOptUtil {
               null));
     }
 
-    return new LogicalAggregate(rel.getCluster(), rel, false,
+    return LogicalAggregate.create(rel, false,
         ImmutableBitSet.of(), null, aggCalls);
   }
 
@@ -725,7 +722,7 @@ public abstract class RelOptUtil {
    * @return rel implementing DISTINCT
    */
   public static RelNode createDistinctRel(RelNode rel) {
-    return new LogicalAggregate(rel.getCluster(), rel, false,
+    return LogicalAggregate.create(rel, false,
         ImmutableBitSet.range(rel.getRowType().getFieldCount()), null,
         ImmutableList.<AggregateCall>of());
   }
@@ -2072,54 +2069,6 @@ public abstract class RelOptUtil {
    * @param joinFilters  list of filters to push to the join
    * @param leftFilters  list of filters to push to the left child
    * @param rightFilters list of filters to push to the right child
-   * @param smart        Whether to try to strengthen the join type
-   * @return whether at least one filter was pushed, or join type was
-   * strengthened
-   *
-   * @deprecated Use the other {@link #classifyFilters};
-   * very short-term; will be removed before
-   * {@link org.apache.calcite.util.Bug#upgrade(String) calcite-0.9.2}.
-   */
-  public static boolean classifyFilters(
-      RelNode joinRel,
-      List<RexNode> filters,
-      JoinRelType joinType,
-      boolean pushInto,
-      boolean pushLeft,
-      boolean pushRight,
-      List<RexNode> joinFilters,
-      List<RexNode> leftFilters,
-      List<RexNode> rightFilters,
-      Holder<JoinRelType> joinTypeHolder,
-      boolean smart) {
-    final JoinRelType oldJoinType = joinType;
-    final int filterCount = filters.size();
-    if (smart) {
-      joinType = simplifyJoin(joinRel, ImmutableList.copyOf(joinFilters),
-          joinType);
-      joinTypeHolder.set(joinType);
-    }
-    classifyFilters(joinRel, filters, joinType, pushInto, pushLeft, pushRight,
-        joinFilters, leftFilters, rightFilters);
-
-    return filters.size() < filterCount || joinType != oldJoinType;
-  }
-
-  /**
-   * Classifies filters according to where they should be processed. They
-   * either stay where they are, are pushed to the join (if they originated
-   * from above the join), or are pushed to one of the children. Filters that
-   * are pushed are added to list passed in as input parameters.
-   *
-   * @param joinRel      join node
-   * @param filters      filters to be classified
-   * @param joinType     join type
-   * @param pushInto     whether filters can be pushed into the ON clause
-   * @param pushLeft     true if filters can be pushed to the left
-   * @param pushRight    true if filters can be pushed to the right
-   * @param joinFilters  list of filters to push to the join
-   * @param leftFilters  list of filters to push to the left child
-   * @param rightFilters list of filters to push to the right child
    * @return whether at least one filter was pushed
    */
   public static boolean classifyFilters(
@@ -2496,8 +2445,7 @@ public abstract class RelOptUtil {
       nodes.add(new RexInputRef(source, field.getType()));
       names.add(field.getName());
     }
-    return new LogicalProject(
-        child.getCluster(), child, nodes, names);
+    return LogicalProject.create(child, nodes, names);
   }
 
   /** Returns whether relational expression {@code target} occurs within a
@@ -2673,38 +2621,27 @@ public abstract class RelOptUtil {
       List<String> fieldNames,
       boolean optimize) {
     final RelOptCluster cluster = child.getCluster();
-    final RexProgram program =
-        RexProgram.create(
-            child.getRowType(), exprs, null, fieldNames,
-            cluster.getRexBuilder());
-    final List<RelCollation> collationList =
-        program.getCollations(child.getCollationList());
-    final RelDataType rowType =
-        RexUtil.createStructType(
-            cluster.getTypeFactory(),
-            exprs,
-            fieldNames == null
-                ? null
-                : SqlValidatorUtil.uniquify(
-                    fieldNames, SqlValidatorUtil.F_SUGGESTER));
+    final List<String> fieldNames2 =
+        fieldNames == null
+            ? null
+            : SqlValidatorUtil.uniquify(fieldNames,
+                SqlValidatorUtil.F_SUGGESTER);
     if (optimize
         && ProjectRemoveRule.isIdentity(exprs, child.getRowType())) {
       if (child instanceof Project && fieldNames != null) {
+        final RelDataType rowType =
+            RexUtil.createStructType(
+                cluster.getTypeFactory(),
+                exprs,
+                fieldNames2);
         // Rename columns of child projection if desired field names are given.
         Project childProject = (Project) child;
         child = childProject.copy(childProject.getTraitSet(),
-            childProject.getInput(), childProject.getProjects(),
-            rowType);
+            childProject.getInput(), childProject.getProjects(), rowType);
       }
       return child;
     }
-    return new LogicalProject(cluster,
-        cluster.traitSetOf(collationList.isEmpty()
-            ? RelCollationImpl.EMPTY
-            : collationList.get(0)),
-        child,
-        exprs,
-        rowType);
+    return LogicalProject.create(child, exprs, fieldNames2);
   }
 
   /**
@@ -2813,12 +2750,7 @@ public abstract class RelOptUtil {
             rel.getCluster().getTypeFactory().createStructType(
                 outputTypeList,
                 outputNameList));
-    return new LogicalCalc(
-        rel.getCluster(),
-        rel.getTraitSet(),
-        rel,
-        program,
-        ImmutableList.<RelCollation>of());
+    return LogicalCalc.create(rel, program);
   }
 
   /**
@@ -3079,7 +3011,7 @@ public abstract class RelOptUtil {
      */
     public static ImmutableBitSet bits(List<RexNode> exprs, RexNode expr) {
       final InputFinder inputFinder = new InputFinder();
-      RexProgram.apply(inputFinder, exprs, expr);
+      RexUtil.apply(inputFinder, exprs, expr);
       return inputFinder.inputBitSet.build();
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/plan/RelTrait.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelTrait.java b/core/src/main/java/org/apache/calcite/plan/RelTrait.java
index ccbd963..e611e95 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelTrait.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelTrait.java
@@ -52,21 +52,23 @@ public interface RelTrait {
   boolean equals(Object o);
 
   /**
-   * Returns whether this trait subsumes a given trait.
+   * Returns whether this trait satisfies a given trait.
    *
-   * <p>Must form a partial order: must be reflective (t subsumes t),
-   * anti-symmetric (if t1 subsumes t2 and t1 != t2 then t2 does not subsume
-   * t1),
-   * and transitive (if t1 subsumes t2 and t2 subsumes t3, then t1 subsumes
-   * t3)</p>
+   * <p>A trait satisfies another if it is the same or stricter. For example,
+   * {@code ORDER BY x, y} satisfies {@code ORDER BY x}.
    *
-   * <p>Many traits cannot be substituted, in which case, this method should
-   * return {@code equals(trait)}.</p>
+   * <p>A trait's {@code satisfies} relation must be a partial order (reflexive,
+   * anti-symmetric, transitive). Many traits cannot be "loosened"; their
+   * {@code satisfies} is an equivalence relation, where only X satisfies X.
+   *
+   * <p>If a trait has multiple values
+   * (see {@link org.apache.calcite.plan.RelCompositeTrait})
+   * a collection (T0, T1, ...) satisfies T if any Ti satisfies T.
    *
    * @param trait Given trait
    * @return Whether this trait subsumes a given trait
    */
-  boolean subsumes(RelTrait trait);
+  boolean satisfies(RelTrait trait);
 
   /**
    * Returns a succinct name for this trait. The planner may use this String

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/plan/RelTraitDef.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelTraitDef.java b/core/src/main/java/org/apache/calcite/plan/RelTraitDef.java
index 0273568..1f26b38 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelTraitDef.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelTraitDef.java
@@ -23,6 +23,9 @@ import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
 
+import java.util.List;
+import javax.annotation.Nonnull;
+
 /**
  * RelTraitDef represents a class of {@link RelTrait}s. Implementations of
  * RelTraitDef may be singletons under the following conditions:
@@ -58,11 +61,35 @@ public abstract class RelTraitDef<T extends RelTrait> {
           .softValues()
           .build(
               new CacheLoader<T, T>() {
-                @Override public T load(T key) throws Exception {
+                @Override public T load(@Nonnull T key) throws Exception {
                   return key;
                 }
               });
 
+  /** Cache of composite traits.
+   *
+   * <p>Uses soft values to allow GC.
+   *
+   * <p>You can look up using a {@link RelCompositeTrait} whose constituent
+   * traits are not canonized.
+   */
+  private final LoadingCache<Object, RelCompositeTrait> canonicalCompositeMap =
+      CacheBuilder.newBuilder()
+          .softValues()
+          .build(
+              new CacheLoader<Object, RelCompositeTrait>() {
+                @Override public RelCompositeTrait load(@Nonnull Object key) {
+                  if (key instanceof RelCompositeTrait) {
+                    return (RelCompositeTrait) key;
+                  }
+                  @SuppressWarnings("unchecked")
+                  final List<RelMultipleTrait> list =
+                      (List<RelMultipleTrait>) key;
+                  final RelTraitDef def = list.get(0).getTraitDef();
+                  return (RelCompositeTrait) RelCompositeTrait.of(def, list);
+                }
+              });
+
   //~ Constructors -----------------------------------------------------------
 
   protected RelTraitDef() {
@@ -104,6 +131,10 @@ public abstract class RelTraitDef<T extends RelTrait> {
    * @return a canonical RelTrait.
    */
   public final T canonize(T trait) {
+    if (trait instanceof RelCompositeTrait) {
+      RelCompositeTrait relCompositeTrait = (RelCompositeTrait) trait;
+      return (T) canonizeComposite(relCompositeTrait);
+    }
     assert getTraitClass().isInstance(trait)
         : getClass().getName()
         + " cannot canonize a "
@@ -112,6 +143,10 @@ public abstract class RelTraitDef<T extends RelTrait> {
     return canonicalMap.getUnchecked(trait);
   }
 
+  final RelCompositeTrait canonizeComposite(RelCompositeTrait compositeTrait) {
+    return canonicalCompositeMap.getUnchecked(compositeTrait);
+  }
+
   /**
    * Converts the given RelNode to the given RelTrait.
    *

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/plan/RelTraitSet.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelTraitSet.java b/core/src/main/java/org/apache/calcite/plan/RelTraitSet.java
index d055a40..bc80ea1 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelTraitSet.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelTraitSet.java
@@ -19,6 +19,7 @@ package org.apache.calcite.plan;
 import org.apache.calcite.runtime.FlatLists;
 import org.apache.calcite.util.Pair;
 
+import com.google.common.base.Supplier;
 import com.google.common.collect.ImmutableList;
 
 import java.util.AbstractList;
@@ -81,11 +82,37 @@ public final class RelTraitSet extends AbstractList<RelTrait> {
     return traits[index];
   }
 
+  /**
+   * Retrieves a list of traits from the set.
+   *
+   * @param index 0-based index into ordered RelTraitSet
+   * @return the RelTrait
+   * @throws ArrayIndexOutOfBoundsException if index greater than or equal to
+   *                                        {@link #size()} or less than 0.
+   */
+  public <E extends RelMultipleTrait> List<E> getTraits(int index) {
+    final RelTrait trait = traits[index];
+    if (trait instanceof RelCompositeTrait) {
+      //noinspection unchecked
+      return ((RelCompositeTrait<E>) trait).traitList();
+    } else {
+      //noinspection unchecked
+      return ImmutableList.of((E) trait);
+    }
+  }
+
   public RelTrait get(int index) {
     return getTrait(index);
   }
 
   /**
+   * Returns whether a given kind of trait is enabled.
+   */
+  public <T extends RelTrait> boolean isEnabled(RelTraitDef<T> traitDef) {
+    return getTrait(traitDef) != null;
+  }
+
+  /**
    * Retrieves a RelTrait of the given type from the set.
    *
    * @param traitDef the type of RelTrait to retrieve
@@ -102,6 +129,25 @@ public final class RelTraitSet extends AbstractList<RelTrait> {
   }
 
   /**
+   * Retrieves a list of traits of the given type from the set.
+   *
+   * <p>Only valid for traits that support multiple entries. (E.g. collation.)
+   *
+   * @param traitDef the type of RelTrait to retrieve
+   * @return the RelTrait, or null if not found
+   */
+  public <T extends RelMultipleTrait> List<T> getTraits(
+      RelTraitDef<T> traitDef) {
+    int index = findIndex(traitDef);
+    if (index >= 0) {
+      //noinspection unchecked
+      return (List<T>) getTraits(index);
+    }
+
+    return null;
+  }
+
+  /**
    * Replaces an existing RelTrait in the set.
    * Returns a different trait set; does not modify this trait set.
    *
@@ -144,6 +190,38 @@ public final class RelTraitSet extends AbstractList<RelTrait> {
     return replace(index, trait);
   }
 
+  /** Replaces the trait(s) of a given type with a list of traits of the same
+   * type.
+   *
+   * <p>The list must not be empty, and all traits must be of the same type.
+   */
+  public <T extends RelMultipleTrait> RelTraitSet replace(List<T> traits) {
+    assert !traits.isEmpty();
+    final RelTraitDef def = traits.get(0).getTraitDef();
+    return replace(RelCompositeTrait.of(def, traits));
+  }
+
+  /** Replaces the trait(s) of a given type with a list of traits of the same
+   * type.
+   *
+   * <p>The list must not be empty, and all traits must be of the same type.
+   */
+  public <T extends RelMultipleTrait> RelTraitSet replace(RelTraitDef<T> def,
+      List<T> traits) {
+    return replace(RelCompositeTrait.of(def, traits));
+  }
+
+  /** If a given trait is enabled, replaces it by calling the given function. */
+  public <T extends RelMultipleTrait> RelTraitSet replaceIf(RelTraitDef<T> def,
+      Supplier<List<T>> traitSupplier) {
+    int index = findIndex(def);
+    if (index < 0) {
+      return this; // trait is not enabled; ignore it
+    }
+    final List<T> traitList = traitSupplier.get();
+    return replace(index, RelCompositeTrait.of(def, traitList));
+  }
+
   /**
    * Returns the size of the RelTraitSet.
    *
@@ -166,6 +244,12 @@ public final class RelTraitSet extends AbstractList<RelTrait> {
       return null;
     }
 
+    if (trait instanceof RelCompositeTrait) {
+      // Composite traits are canonized on creation
+      //noinspection unchecked
+      return (T) trait;
+    }
+
     //noinspection unchecked
     return (T) trait.getTraitDef().canonize(trait);
   }
@@ -187,24 +271,29 @@ public final class RelTraitSet extends AbstractList<RelTrait> {
   }
 
   /**
-   * Returns whether this trait set subsumes another trait set.
+   * Returns whether this trait set satisfies another trait set.
    *
-   * <p>For that to happen, each trait subsumes the corresponding trait in the
-   * other set. In particular, each trait set subsumes itself, because each
-   * trait subsumes itself.</p>
+   * <p>For that to happen, each trait satisfies the corresponding trait in the
+   * other set. In particular, each trait set satisfies itself, because each
+   * trait subsumes itself.
    *
    * <p>Intuitively, if a relational expression is needed that has trait set
-   * S, and trait set S1 subsumes S, then a relational expression R in S1
-   * meets that need. For example, if we need a relational expression that has
+   * S (A, B), and trait set S1 (A1, B1) subsumes S, then any relational
+   * expression R in S1 meets that need.
+   *
+   * <p>For example, if we need a relational expression that has
    * trait set S = {enumerable convention, sorted on [C1 asc]}, and R
-   * has {enumerable convention, sorted on [C1 asc, C2]}</p>
+   * has {enumerable convention, sorted on [C3], [C1, C2]}. R has two
+   * sort keys, but one them [C1, C2] satisfies S [C1], and that is enough.
    *
    * @param that another RelTraitSet
-   * @return whether this trait set subsumes other trait set
+   * @return whether this trait set satisfies other trait set
+   *
+   * @see org.apache.calcite.plan.RelTrait#satisfies(RelTrait)
    */
-  public boolean subsumes(RelTraitSet that) {
+  public boolean satisfies(RelTraitSet that) {
     for (Pair<RelTrait, RelTrait> pair : Pair.zip(traits, that.traits)) {
-      if (!pair.left.subsumes(pair.right)) {
+      if (!pair.left.satisfies(pair.right)) {
         return false;
       }
     }
@@ -393,6 +482,35 @@ public final class RelTraitSet extends AbstractList<RelTrait> {
     return builder.build();
   }
 
+  /** Returns whether there are any composite traits in this set. */
+  public boolean allSimple() {
+    for (RelTrait trait : traits) {
+      if (trait instanceof RelCompositeTrait) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /** Returns a trait set similar to this one but with all composite traits
+   * flattened. */
+  public RelTraitSet simplify() {
+    RelTraitSet x = this;
+    for (int i = 0; i < traits.length; i++) {
+      final RelTrait trait = traits[i];
+      if (trait instanceof RelCompositeTrait) {
+        //noinspection unchecked
+        final RelCompositeTrait<RelMultipleTrait> compositeTrait =
+            (RelCompositeTrait<RelMultipleTrait>) trait;
+        x = x.replace(i,
+            compositeTrait.size() == 0
+                ?  trait.getTraitDef().getDefault()
+                : compositeTrait.trait(0));
+      }
+    }
+    return x;
+  }
+
   /** Cache of trait sets. */
   private static class Cache {
     final Map<List<RelTrait>, RelTraitSet> map =

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java b/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
index 97e2605..e0ad056 100644
--- a/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
+++ b/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
@@ -20,7 +20,6 @@ import org.apache.calcite.avatica.util.Spaces;
 import org.apache.calcite.linq4j.Ord;
 import org.apache.calcite.prepare.CalcitePrepareImpl;
 import org.apache.calcite.rel.RelCollation;
-import org.apache.calcite.rel.RelCollationImpl;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.SingleRel;
 import org.apache.calcite.rel.core.Aggregate;
@@ -590,17 +589,15 @@ public class SubstitutionVisitor {
       return ((MutableLeafRel) node).rel;
     case PROJECT:
       final MutableProject project = (MutableProject) node;
-      return new LogicalProject(node.cluster,
-          node.cluster.traitSetOf(RelCollationImpl.EMPTY),
-          fromMutable(project.input),
+      return LogicalProject.create(fromMutable(project.input),
           project.projects, project.rowType);
     case FILTER:
       final MutableFilter filter = (MutableFilter) node;
-      return new LogicalFilter(node.cluster, fromMutable(filter.input),
+      return LogicalFilter.create(fromMutable(filter.input),
           filter.condition);
     case AGGREGATE:
       final MutableAggregate aggregate = (MutableAggregate) node;
-      return new LogicalAggregate(node.cluster, fromMutable(aggregate.input),
+      return LogicalAggregate.create(fromMutable(aggregate.input),
           aggregate.indicator, aggregate.groupSet, aggregate.groupSets,
           aggregate.aggCalls);
     case SORT:
@@ -609,8 +606,7 @@ public class SubstitutionVisitor {
           sort.offset, sort.fetch);
     case UNION:
       final MutableUnion union = (MutableUnion) node;
-      return new LogicalUnion(union.cluster, fromMutables(union.inputs),
-          union.all);
+      return LogicalUnion.create(fromMutables(union.inputs), union.all);
     default:
       throw new AssertionError(node.deep());
     }
@@ -2114,7 +2110,7 @@ public class SubstitutionVisitor {
           cluster.getRexBuilder().makeInputRef(newProject,
               newProjects.size() - 1);
 
-      call.transformTo(new LogicalFilter(cluster, newProject, newCondition));
+      call.transformTo(LogicalFilter.create(newProject, newCondition));
     }
   }
 }


[6/9] incubator-calcite git commit: [CALCITE-88] Add collation as a trait and a kind of RelNode metadata

Posted by jh...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/plan/volcano/AbstractConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/AbstractConverter.java b/core/src/main/java/org/apache/calcite/plan/volcano/AbstractConverter.java
index a4097bb..96b7c19 100644
--- a/core/src/main/java/org/apache/calcite/plan/volcano/AbstractConverter.java
+++ b/core/src/main/java/org/apache/calcite/plan/volcano/AbstractConverter.java
@@ -52,6 +52,7 @@ public class AbstractConverter extends ConverterImpl {
       RelTraitDef traitDef,
       RelTraitSet traits) {
     super(cluster, traitDef, traits, rel);
+    assert traits.allSimple();
   }
 
   //~ Methods ----------------------------------------------------------------
@@ -83,7 +84,7 @@ public class AbstractConverter extends ConverterImpl {
    * Rule which converts an {@link AbstractConverter} into a chain of
    * converters from the source relation to the target traits.
    *
-   * <p>The chain produced is mimimal: we have previously built the transitive
+   * <p>The chain produced is minimal: we have previously built the transitive
    * closure of the graph of conversions, so we choose the shortest chain.</p>
    *
    * <p>Unlike the {@link AbstractConverter} they are replacing, these

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java b/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java
index 2adfb0e..93d8509 100644
--- a/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java
+++ b/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java
@@ -19,6 +19,7 @@ package org.apache.calcite.plan.volcano;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptListener;
 import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.plan.RelTrait;
 import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.util.trace.CalciteTrace;
@@ -139,10 +140,8 @@ class RelSet {
    */
   public RelSubset add(RelNode rel) {
     assert equivalentSet == null : "adding to a dead set";
-    RelSubset subset =
-        getOrCreateSubset(
-            rel.getCluster(),
-            rel.getTraitSet());
+    final RelTraitSet traitSet = rel.getTraitSet().simplify();
+    final RelSubset subset = getOrCreateSubset(rel.getCluster(), traitSet);
     subset.add(rel);
     return subset;
   }
@@ -191,6 +190,9 @@ class RelSet {
   void addInternal(RelNode rel) {
     if (!rels.contains(rel)) {
       rels.add(rel);
+      for (RelTrait trait : rel.getTraitSet()) {
+        assert trait == trait.getTraitDef().canonize(trait);
+      }
 
       VolcanoPlanner planner =
           (VolcanoPlanner) rel.getCluster().getPlanner();

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/plan/volcano/RelSubset.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/RelSubset.java b/core/src/main/java/org/apache/calcite/plan/volcano/RelSubset.java
index 1ce04d0..d8ebb55 100644
--- a/core/src/main/java/org/apache/calcite/plan/volcano/RelSubset.java
+++ b/core/src/main/java/org/apache/calcite/plan/volcano/RelSubset.java
@@ -48,9 +48,20 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
- * A <code>RelSubset</code> is set of expressions in a set which have the same
- * calling convention. An expression may be in more than one sub-set of a set;
- * the same expression is used.
+ * Subset of an equivalence class where all relational expressions have the
+ * same physical properties.
+ *
+ * <p>Physical properties are instances of the {@link RelTraitSet}, and consist
+ * of traits such as calling convention and collation (sort-order).
+ *
+ * <p>For some traits, a relational expression can have more than one instance.
+ * For example, R can be sorted on both [X] and [Y, Z]. In which case, R would
+ * belong to the sub-sets for [X] and [Y, Z]; and also the leading edges [Y] and
+ * [].
+ *
+ * @see RelNode
+ * @see RelSet
+ * @see RelTrait
  */
 public class RelSubset extends AbstractRelNode {
   //~ Static fields/initializers ---------------------------------------------
@@ -94,6 +105,7 @@ public class RelSubset extends AbstractRelNode {
     super(cluster, traits);
     this.set = set;
     this.boosted = false;
+    assert traits.allSimple();
     computeBestCost(cluster.getPlanner());
     recomputeDigest();
   }
@@ -328,7 +340,7 @@ public class RelSubset extends AbstractRelNode {
       RelNode rel,
       Set<RelSubset> activeSet) {
     for (RelSubset subset : set.subsets) {
-      if (rel.getTraitSet().subsumes(subset.traitSet)) {
+      if (rel.getTraitSet().satisfies(subset.traitSet)) {
         subset.propagateCostImprovements0(planner, rel, activeSet);
       }
     }
@@ -406,7 +418,7 @@ public class RelSubset extends AbstractRelNode {
             .where(
                 new Predicate1<RelNode>() {
                   public boolean apply(RelNode v1) {
-                    return v1.getTraitSet().subsumes(traitSet);
+                    return v1.getTraitSet().satisfies(traitSet);
                   }
                 })
             .iterator();
@@ -420,7 +432,7 @@ public class RelSubset extends AbstractRelNode {
   public List<RelNode> getRelList() {
     final List<RelNode> list = new ArrayList<RelNode>();
     for (RelNode rel : set.rels) {
-      if (rel.getTraitSet().subsumes(traitSet)) {
+      if (rel.getTraitSet().satisfies(traitSet)) {
         list.add(rel);
       }
     }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
index d8e26ae..e21cdbb 100644
--- a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
+++ b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
@@ -1184,7 +1184,7 @@ public class VolcanoPlanner extends AbstractRelOptPlanner {
               toTrait,
               allowInfiniteCostConverters);
       if (rel != null) {
-        assert rel.getTraitSet().getTrait(traitDef).subsumes(toTrait);
+        assert rel.getTraitSet().getTrait(traitDef).satisfies(toTrait);
         rel =
             completeConversion(
                 rel, allowInfiniteCostConverters, toTraits,
@@ -1206,7 +1206,7 @@ public class VolcanoPlanner extends AbstractRelOptPlanner {
 
     // make sure final converted traitset subsumes what was required
     if (converted != null) {
-      assert converted.getTraitSet().subsumes(toTraits);
+      assert converted.getTraitSet().satisfies(toTraits);
     }
 
     return converted;
@@ -1351,8 +1351,7 @@ public class VolcanoPlanner extends AbstractRelOptPlanner {
                   inputSubset.getRels().iterator();
               if (rels.hasNext()) {
                 input = rels.next();
-                assert input.getTraitSet().subsumes(
-                    inputSubset.getTraitSet());
+                assert input.getTraitSet().satisfies(inputSubset.getTraitSet());
                 assert inputSet.rels.contains(input);
                 assert inputSet.subsets.contains(inputSubset);
               }
@@ -1462,7 +1461,7 @@ public class VolcanoPlanner extends AbstractRelOptPlanner {
     }
 
     // Add the relational expression into the correct set and subset.
-    RelSubset subset2 = asd(rel, set);
+    RelSubset subset2 = addRelToSet(rel, set);
   }
 
   /**
@@ -1533,27 +1532,15 @@ public class VolcanoPlanner extends AbstractRelOptPlanner {
 
   private RelSet merge(RelSet set, RelSet set2) {
     assert set != set2 : "pre: set != set2";
-    assert set.equivalentSet == null;
 
     // Find the root of set2's equivalence tree.
-    if (set2.equivalentSet != null) {
-      Set<RelSet> seen = new HashSet<RelSet>();
-      while (true) {
-        if (!seen.add(set2)) {
-          throw Util.newInternal("cycle in equivalence tree");
-        }
-        if (set2.equivalentSet == null) {
-          break;
-        } else {
-          set2 = set2.equivalentSet;
-        }
-      }
+    set = equivRoot(set);
+    set2 = equivRoot(set2);
 
-      // Looks like set2 was already marked as equivalent to set. Nothing
-      // to do.
-      if (set2 == set) {
-        return set;
-      }
+    // Looks like set2 was already marked as equivalent to set. Nothing
+    // to do.
+    if (set2 == set) {
+      return set;
     }
 
     // If necessary, swap the sets, so we're always merging the newer set
@@ -1580,6 +1567,33 @@ public class VolcanoPlanner extends AbstractRelOptPlanner {
     return set;
   }
 
+  private static RelSet equivRoot(RelSet s) {
+    RelSet p = s; // iterates at twice the rate, to detect cycles
+    while (s.equivalentSet != null) {
+      p = forward2(s, p);
+      s = s.equivalentSet;
+    }
+    return s;
+  }
+
+  /** Moves forward two links, checking for a cycle at each. */
+  private static RelSet forward2(RelSet s, RelSet p) {
+    p = forward1(s, p);
+    p = forward1(s, p);
+    return p;
+  }
+
+  /** Moves forward one link, checking for a cycle. */
+  private static RelSet forward1(RelSet s, RelSet p) {
+    if (p != null) {
+      p = p.equivalentSet;
+      if (p == s) {
+        throw Util.newInternal("cycle in equivalence tree");
+      }
+    }
+    return p;
+  }
+
   /**
    * Registers a new expression <code>exp</code> and queues up rule matches.
    * If <code>set</code> is not null, makes the expression part of that
@@ -1652,8 +1666,6 @@ public class VolcanoPlanner extends AbstractRelOptPlanner {
     } else if (equivExp == rel) {
       return getSubset(rel);
     } else {
-      assert equivExp.getTraitSet().equals(traits)
-          && (equivExp.getClass() == rel.getClass());
       assert RelOptUtil.equal(
           "left", equivExp.getRowType(),
           "right", rel.getRowType(),
@@ -1730,7 +1742,7 @@ public class VolcanoPlanner extends AbstractRelOptPlanner {
 
     registerCount++;
     final int subsetBeforeCount = set.subsets.size();
-    RelSubset subset = asd(rel, set);
+    RelSubset subset = addRelToSet(rel, set);
 
     final RelNode xx = mapDigestToRel.put(key, rel);
     assert xx == null || xx == rel : rel.getDigest();
@@ -1787,7 +1799,7 @@ public class VolcanoPlanner extends AbstractRelOptPlanner {
     return subset;
   }
 
-  private RelSubset asd(RelNode rel, RelSet set) {
+  private RelSubset addRelToSet(RelNode rel, RelSet set) {
     RelSubset subset = set.add(rel);
     mapRel2Subset.put(rel, subset);
 
@@ -1807,7 +1819,7 @@ public class VolcanoPlanner extends AbstractRelOptPlanner {
       RelSubset subset) {
     if ((set != subset.set)
         && (set != null)
-        && (subset.set.equivalentSet == null)) {
+        && (set.equivalentSet == null)) {
       LOGGER.finer("Register #" + subset.getId() + " " + subset
           + ", and merge sets");
       merge(set, subset.set);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/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 e075996..1b2e75f 100644
--- a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
@@ -165,6 +165,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
   private static final List<RelOptRule> ENUMERABLE_RULES =
       ImmutableList.of(
           EnumerableRules.ENUMERABLE_JOIN_RULE,
+          EnumerableRules.ENUMERABLE_MERGE_JOIN_RULE,
           EnumerableRules.ENUMERABLE_SEMI_JOIN_RULE,
           EnumerableRules.ENUMERABLE_CORRELATE_RULE,
           EnumerableRules.ENUMERABLE_PROJECT_RULE,
@@ -781,7 +782,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
 
       final List<Materialization> materializations = ImmutableList.of();
       final List<CalciteSchema.LatticeEntry> lattices = ImmutableList.of();
-      rootRel = optimize(resultType, rootRel, materializations, lattices);
+      rootRel = optimize(rootRel, materializations, lattices);
 
       if (timingTracer != null) {
         timingTracer.traceTime("end optimization");

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/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 a4de2c0..ed1671c 100644
--- a/core/src/main/java/org/apache/calcite/prepare/LixToRelTranslator.java
+++ b/core/src/main/java/org/apache/calcite/prepare/LixToRelTranslator.java
@@ -82,32 +82,22 @@ class LixToRelTranslator implements RelOptTable.ToRelContext {
         throw new UnsupportedOperationException(
             "unknown method " + call.method);
       }
-      RelNode child;
+      RelNode input;
       switch (method) {
       case SELECT:
-        child = translate(call.targetExpression);
-        return new LogicalProject(
-            cluster,
-            child,
-            toRex(
-                child,
-                (FunctionExpression) call.expressions.get(0)),
-            null);
+        input = translate(call.targetExpression);
+        return LogicalProject.create(input,
+            toRex(input, (FunctionExpression) call.expressions.get(0)),
+            (List<String>) null);
 
       case WHERE:
-        child = translate(call.targetExpression);
-        return new LogicalFilter(
-            cluster,
-            child,
-            toRex(
-                (FunctionExpression) call.expressions.get(0),
-                child));
+        input = translate(call.targetExpression);
+        return LogicalFilter.create(input,
+            toRex((FunctionExpression) call.expressions.get(0), input));
 
       case AS_QUERYABLE:
-        return new LogicalTableScan(
-            cluster,
-            RelOptTableImpl.create(
-                null,
+        return LogicalTableScan.create(cluster,
+            RelOptTableImpl.create(null,
                 typeFactory.createJavaType(
                     Types.toClass(
                         Types.getElementType(call.targetExpression.getType()))),
@@ -115,10 +105,8 @@ class LixToRelTranslator implements RelOptTable.ToRelContext {
                 call.targetExpression));
 
       case SCHEMA_GET_TABLE:
-        return new LogicalTableScan(
-            cluster,
-            RelOptTableImpl.create(
-                null,
+        return LogicalTableScan.create(cluster,
+            RelOptTableImpl.create(null,
                 typeFactory.createJavaType((Class)
                     ((ConstantExpression) call.expressions.get(1)).value),
                 ImmutableList.<String>of(),

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/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 25181ea..5892fa9 100644
--- a/core/src/main/java/org/apache/calcite/prepare/Prepare.java
+++ b/core/src/main/java/org/apache/calcite/prepare/Prepare.java
@@ -104,15 +104,12 @@ public abstract class Prepare {
   /**
    * Optimizes a query plan.
    *
-   * @param logicalRowType logical row type of relational expression (before
-   * struct fields are flattened, or field names are renamed for uniqueness)
    * @param rootRel root of a relational expression
-   *
    * @param materializations Tables known to be populated with a given query
    * @param lattices Lattices
    * @return an equivalent optimized relational expression
    */
-  protected RelNode optimize(RelDataType logicalRowType, final RelNode rootRel,
+  protected RelNode optimize(final RelNode rootRel,
       final List<Materialization> materializations,
       final List<CalciteSchema.LatticeEntry> lattices) {
     final RelOptPlanner planner = rootRel.getCluster().getPlanner();
@@ -167,7 +164,7 @@ public abstract class Prepare {
   protected RelTraitSet getDesiredRootTraitSet(RelNode rootRel) {
     // Make sure non-CallingConvention traits, if any, are preserved
     return rootRel.getTraitSet()
-        .replace(resultConvention);
+        .replace(resultConvention).simplify();
   }
 
   /**
@@ -274,14 +271,13 @@ public abstract class Prepare {
       switch (explainDepth) {
       case PHYSICAL:
       default:
-        rootRel = optimize(rootRel.getRowType(), rootRel, materializations,
-            lattices);
+        rootRel = optimize(rootRel, materializations, lattices);
         return createPreparedExplanation(
             null, parameterRowType, rootRel, explainAsXml, detailLevel);
       }
     }
 
-    rootRel = optimize(resultType, rootRel, materializations, lattices);
+    rootRel = optimize(rootRel, materializations, lattices);
 
     if (timingTracer != null) {
       timingTracer.traceTime("end optimization");

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/prepare/QueryableRelBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/QueryableRelBuilder.java b/core/src/main/java/org/apache/calcite/prepare/QueryableRelBuilder.java
index 57afc4d..edc3cfe 100644
--- a/core/src/main/java/org/apache/calcite/prepare/QueryableRelBuilder.java
+++ b/core/src/main/java/org/apache/calcite/prepare/QueryableRelBuilder.java
@@ -101,7 +101,7 @@ class QueryableRelBuilder<T> implements QueryableFactory<T> {
       if (table instanceof TranslatableTable) {
         return ((TranslatableTable) table).toRel(translator, relOptTable);
       } else {
-        return new LogicalTableScan(translator.cluster, relOptTable);
+        return LogicalTableScan.create(translator.cluster, relOptTable);
       }
     }
     return translator.translate(queryable.getExpression());
@@ -510,11 +510,7 @@ class QueryableRelBuilder<T> implements QueryableFactory<T> {
     RelNode child = toRel(source);
     List<RexNode> nodes = translator.toRexList(selector, child);
     setRel(
-        new LogicalProject(
-            translator.cluster,
-            child,
-            nodes,
-            null));
+        LogicalProject.create(child, nodes, (List<String>)  null));
     return null;
   }
 
@@ -721,7 +717,7 @@ class QueryableRelBuilder<T> implements QueryableFactory<T> {
       FunctionExpression<? extends Predicate1<T>> predicate) {
     RelNode child = toRel(source);
     RexNode node = translator.toRex(predicate, child);
-    setRel(new LogicalFilter(translator.cluster, child, node));
+    setRel(LogicalFilter.create(child, node));
     return source;
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java b/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java
index b616979..efbe0bf 100644
--- a/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java
@@ -24,6 +24,7 @@ import org.apache.calcite.linq4j.tree.Expression;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptSchema;
 import org.apache.calcite.plan.RelOptTable;
+import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.logical.LogicalTableScan;
@@ -47,7 +48,6 @@ import com.google.common.base.Functions;
 import com.google.common.collect.ImmutableList;
 
 import java.lang.reflect.Type;
-import java.util.Collections;
 import java.util.List;
 
 /**
@@ -198,13 +198,21 @@ public class RelOptTableImpl implements Prepare.PreparingTable {
       return ((TranslatableTable) table).toRel(context, this);
     }
     if (CalcitePrepareImpl.ENABLE_BINDABLE) {
-      return new LogicalTableScan(context.getCluster(), this);
+      return LogicalTableScan.create(context.getCluster(), this);
     }
     if (CalcitePrepareImpl.ENABLE_ENUMERABLE) {
       RelOptCluster cluster = context.getCluster();
       Class elementType = deduceElementType();
-      final RelNode scan = new EnumerableTableScan(cluster,
-          cluster.traitSetOf(EnumerableConvention.INSTANCE), this, elementType);
+      RelTraitSet traits = cluster.traitSetOf(EnumerableConvention.INSTANCE);
+      if (table != null) {
+        final List<RelCollation> collations =
+            table.getStatistic().getCollations();
+        if (!collations.isEmpty()) {
+          traits = traits.replace(collations);
+        }
+      }
+      final RelNode scan =
+          new EnumerableTableScan(cluster, traits, this, elementType);
       if (table instanceof FilterableTable
           || table instanceof ProjectableFilterableTable) {
         return new EnumerableInterpreter(cluster, scan.getTraitSet(),
@@ -234,11 +242,17 @@ public class RelOptTableImpl implements Prepare.PreparingTable {
   }
 
   public List<RelCollation> getCollationList() {
-    return Collections.emptyList();
+    if (table != null) {
+      return table.getStatistic().getCollations();
+    }
+    return ImmutableList.of();
   }
 
   public boolean isKey(ImmutableBitSet columns) {
-    return table.getStatistic().isKey(columns);
+    if (table != null) {
+      return table.getStatistic().isKey(columns);
+    }
+    return false;
   }
 
   public RelDataType getRowType() {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/AbstractRelNode.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/AbstractRelNode.java b/core/src/main/java/org/apache/calcite/rel/AbstractRelNode.java
index 7b24e46..c9c2007 100644
--- a/core/src/main/java/org/apache/calcite/rel/AbstractRelNode.java
+++ b/core/src/main/java/org/apache/calcite/rel/AbstractRelNode.java
@@ -200,6 +200,8 @@ public abstract class AbstractRelNode implements RelNode {
     return true;
   }
 
+  /** @deprecated Use {@link RelMetadataQuery#collations(RelNode)} */
+  @Deprecated // to be removed before 2.0
   public List<RelCollation> getCollationList() {
     return ImmutableList.of();
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/RelCollation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/RelCollation.java b/core/src/main/java/org/apache/calcite/rel/RelCollation.java
index 3aed2e9..6ab6702 100644
--- a/core/src/main/java/org/apache/calcite/rel/RelCollation.java
+++ b/core/src/main/java/org/apache/calcite/rel/RelCollation.java
@@ -16,7 +16,7 @@
  */
 package org.apache.calcite.rel;
 
-import org.apache.calcite.plan.RelTrait;
+import org.apache.calcite.plan.RelMultipleTrait;
 
 import java.util.List;
 
@@ -26,7 +26,7 @@ import java.util.List;
  * <p>An ordering consists of a list of one or more column ordinals and the
  * direction of the ordering.
  */
-public interface RelCollation extends RelTrait {
+public interface RelCollation extends RelMultipleTrait {
   //~ Methods ----------------------------------------------------------------
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/RelCollationImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/RelCollationImpl.java b/core/src/main/java/org/apache/calcite/rel/RelCollationImpl.java
index 363c190..6d0c782 100644
--- a/core/src/main/java/org/apache/calcite/rel/RelCollationImpl.java
+++ b/core/src/main/java/org/apache/calcite/rel/RelCollationImpl.java
@@ -16,18 +16,19 @@
  */
 package org.apache.calcite.rel;
 
+import org.apache.calcite.plan.RelMultipleTrait;
 import org.apache.calcite.plan.RelOptPlanner;
 import org.apache.calcite.plan.RelTrait;
 import org.apache.calcite.plan.RelTraitDef;
-import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.runtime.Utilities;
 import org.apache.calcite.util.Util;
 
-import com.google.common.base.Function;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
+import com.google.common.collect.UnmodifiableIterator;
 
 import java.util.Iterator;
 import java.util.List;
+import javax.annotation.Nonnull;
 
 /**
  * Simple implementation of {@link RelCollation}.
@@ -35,27 +36,6 @@ import java.util.List;
 public class RelCollationImpl implements RelCollation {
   //~ Static fields/initializers ---------------------------------------------
 
-  /**
-   * A collation indicating that a relation is not sorted. Ordering by no
-   * columns.
-   */
-  public static final RelCollation EMPTY =
-      RelCollationTraitDef.INSTANCE.canonize(
-          new RelCollationImpl(ImmutableList.<RelFieldCollation>of()));
-
-  /**
-   * A collation that cannot be replicated by applying a sort. The only
-   * implementation choice is to apply operations that preserve order.
-   */
-  public static final RelCollation PRESERVE =
-      RelCollationTraitDef.INSTANCE.canonize(
-          new RelCollationImpl(
-              ImmutableList.of(new RelFieldCollation(-1))) {
-            public String toString() {
-              return "PRESERVE";
-            }
-          });
-
   //~ Instance fields --------------------------------------------------------
 
   private final ImmutableList<RelFieldCollation> fieldCollations;
@@ -66,14 +46,6 @@ public class RelCollationImpl implements RelCollation {
     this.fieldCollations = fieldCollations;
   }
 
-  public static RelCollation of(RelFieldCollation... fieldCollations) {
-    return new RelCollationImpl(ImmutableList.copyOf(fieldCollations));
-  }
-
-  public static RelCollation of(List<RelFieldCollation> fieldCollations) {
-    return new RelCollationImpl(ImmutableList.copyOf(fieldCollations));
-  }
-
   //~ Methods ----------------------------------------------------------------
 
   public RelTraitDef getTraitDef() {
@@ -99,9 +71,30 @@ public class RelCollationImpl implements RelCollation {
     return false;
   }
 
+  public boolean isTop() {
+    return fieldCollations.isEmpty();
+  }
+
+  public int compareTo(@Nonnull RelMultipleTrait o) {
+    final RelCollationImpl that = (RelCollationImpl) o;
+    final UnmodifiableIterator<RelFieldCollation> iterator =
+        that.fieldCollations.iterator();
+    for (RelFieldCollation f : fieldCollations) {
+      if (!iterator.hasNext()) {
+        return 1;
+      }
+      final RelFieldCollation f2 = iterator.next();
+      int c = Utilities.compare(f.getFieldIndex(), f2.getFieldIndex());
+      if (c != 0) {
+        return c;
+      }
+    }
+    return iterator.hasNext() ? -1 : 0;
+  }
+
   public void register(RelOptPlanner planner) {}
 
-  public boolean subsumes(RelTrait trait) {
+  public boolean satisfies(RelTrait trait) {
     return this == trait
         || trait instanceof RelCollationImpl
         && Util.startsWith(fieldCollations,
@@ -132,57 +125,6 @@ public class RelCollationImpl implements RelCollation {
     }
   }
 
-  /**
-   * 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)));
-  }
-
-  /**
-   * Checks that a collection of collations is valid.
-   *
-   * @param rowType       Row type of the relational expression
-   * @param collationList List of collations
-   * @param fail          Whether to fail if invalid
-   * @return Whether valid
-   */
-  public static boolean isValid(
-      RelDataType rowType,
-      List<RelCollation> collationList,
-      boolean fail) {
-    final int fieldCount = rowType.getFieldCount();
-    for (RelCollation collation : collationList) {
-      for (RelFieldCollation fieldCollation : collation.getFieldCollations()) {
-        final int index = fieldCollation.getFieldIndex();
-        if (index < 0 || index >= fieldCount) {
-          assert !fail;
-          return false;
-        }
-      }
-    }
-    return true;
-  }
-
-  public static boolean equal(
-      List<RelCollation> collationList1,
-      List<RelCollation> collationList2) {
-    return collationList1.equals(collationList2);
-  }
-
-  /** Returns the indexes of the field collations in a given collation. */
-  public static List<Integer> ordinals(RelCollation collation) {
-    return Lists.transform(collation.getFieldCollations(),
-        new Function<RelFieldCollation, Integer>() {
-          public Integer apply(RelFieldCollation input) {
-            return input.getFieldIndex();
-          }
-        });
-  }
 }
 
 // End RelCollationImpl.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/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 23a94ee..dee2596 100644
--- a/core/src/main/java/org/apache/calcite/rel/RelCollationTraitDef.java
+++ b/core/src/main/java/org/apache/calcite/rel/RelCollationTraitDef.java
@@ -56,7 +56,7 @@ public class RelCollationTraitDef extends RelTraitDef<RelCollation> {
   }
 
   public RelCollation getDefault() {
-    return RelCollationImpl.EMPTY;
+    return RelCollations.EMPTY;
   }
 
   public RelNode convert(
@@ -64,7 +64,7 @@ public class RelCollationTraitDef extends RelTraitDef<RelCollation> {
       RelNode rel,
       RelCollation toCollation,
       boolean allowInfiniteCostConverters) {
-    if (toCollation == RelCollationImpl.PRESERVE) {
+    if (toCollation == RelCollations.PRESERVE) {
       return null;
     }
 
@@ -77,17 +77,17 @@ public class RelCollationTraitDef extends RelTraitDef<RelCollation> {
     // traits (e.g. convert it to an EnumerableSortRel if rel is enumerable
     // convention)
     final Sort sort = LogicalSort.create(rel, toCollation, null, null);
-    RelNode newRel = sort;
+    RelNode newRel = planner.register(sort, rel);
     final RelTraitSet newTraitSet = rel.getTraitSet().replace(toCollation);
     if (!newRel.getTraitSet().equals(newTraitSet)) {
-      newRel = planner.changeTraits(sort, newTraitSet);
+      newRel = planner.changeTraits(newRel, newTraitSet);
     }
     return newRel;
   }
 
   public boolean canConvert(
       RelOptPlanner planner, RelCollation fromTrait, RelCollation toTrait) {
-    return toTrait != RelCollationImpl.PRESERVE;
+    return toTrait != RelCollations.PRESERVE;
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/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
new file mode 100644
index 0000000..2ee3b59
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/rel/RelCollations.java
@@ -0,0 +1,166 @@
+/*
+ * 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.type.RelDataType;
+import org.apache.calcite.util.ImmutableIntList;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Utilities concerning {@link org.apache.calcite.rel.RelCollation}
+ * and {@link org.apache.calcite.rel.RelFieldCollation}.
+ */
+public class RelCollations {
+  /**
+   * A collation indicating that a relation is not sorted. Ordering by no
+   * columns.
+   */
+  public static final RelCollation EMPTY =
+      RelCollationTraitDef.INSTANCE.canonize(
+          new RelCollationImpl(ImmutableList.<RelFieldCollation>of()));
+
+  /**
+   * A collation that cannot be replicated by applying a sort. The only
+   * implementation choice is to apply operations that preserve order.
+   */
+  public static final RelCollation PRESERVE =
+      RelCollationTraitDef.INSTANCE.canonize(
+          new RelCollationImpl(
+              ImmutableList.of(new RelFieldCollation(-1))) {
+            public String toString() {
+              return "PRESERVE";
+            }
+          });
+
+  private RelCollations() {}
+
+  public static RelCollation of(RelFieldCollation... fieldCollations) {
+    return new RelCollationImpl(ImmutableList.copyOf(fieldCollations));
+  }
+
+  public static RelCollation of(List<RelFieldCollation> fieldCollations) {
+    return new RelCollationImpl(ImmutableList.copyOf(fieldCollations));
+  }
+
+  /**
+   * 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)));
+  }
+
+  /**
+   * Checks that a collection of collations is valid.
+   *
+   * @param rowType       Row type of the relational expression
+   * @param collationList List of collations
+   * @param fail          Whether to fail if invalid
+   * @return Whether valid
+   */
+  public static boolean isValid(
+      RelDataType rowType,
+      List<RelCollation> collationList,
+      boolean fail) {
+    final int fieldCount = rowType.getFieldCount();
+    for (RelCollation collation : collationList) {
+      for (RelFieldCollation fieldCollation : collation.getFieldCollations()) {
+        final int index = fieldCollation.getFieldIndex();
+        if (index < 0 || index >= fieldCount) {
+          assert !fail;
+          return false;
+        }
+      }
+    }
+    return true;
+  }
+
+  public static boolean equal(
+      List<RelCollation> collationList1,
+      List<RelCollation> collationList2) {
+    return collationList1.equals(collationList2);
+  }
+
+  /** Returns the indexes of the field collations in a given collation. */
+  public static List<Integer> ordinals(RelCollation collation) {
+    return Lists.transform(collation.getFieldCollations(),
+        new Function<RelFieldCollation, Integer>() {
+          public Integer apply(RelFieldCollation input) {
+            return input.getFieldIndex();
+          }
+        });
+  }
+
+  /** Returns whether a collation indicates that the collection is sorted on
+   * a given list of keys.
+   *
+   * @param collation Collation
+   * @param keys List of keys
+   * @return Whether the collection is sorted on the given keys
+   */
+  public static boolean contains(RelCollation collation,
+      Iterable<Integer> keys) {
+    final int n = collation.getFieldCollations().size();
+    final Iterator<Integer> iterator = keys.iterator();
+    for (int i = 0; i < n; i++) {
+      final RelFieldCollation fieldCollation =
+          collation.getFieldCollations().get(i);
+      if (!iterator.hasNext()) {
+        return true;
+      }
+      if (fieldCollation.getFieldIndex() != iterator.next()) {
+        return false;
+      }
+    }
+    return !iterator.hasNext();
+  }
+
+  /** Returns whether one of a list of collations indicates that the collection
+   * is sorted on the given list of keys. */
+  public static boolean contains(List<RelCollation> collations,
+      ImmutableIntList keys) {
+    for (RelCollation collation : collations) {
+      if (contains(collation, keys)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  public static RelCollation shift(RelCollation collation, int offset) {
+    if (offset == 0) {
+      return collation; // save some effort
+    }
+    final ImmutableList.Builder<RelFieldCollation> fieldCollations =
+        ImmutableList.builder();
+    for (RelFieldCollation fc : collation.getFieldCollations()) {
+      fieldCollations.add(fc.shift(offset));
+    }
+    return new RelCollationImpl(fieldCollations.build());
+  }
+}
+
+// End RelCollations.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/RelFieldCollation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/RelFieldCollation.java b/core/src/main/java/org/apache/calcite/rel/RelFieldCollation.java
index dba73f8..fb54412 100644
--- a/core/src/main/java/org/apache/calcite/rel/RelFieldCollation.java
+++ b/core/src/main/java/org/apache/calcite/rel/RelFieldCollation.java
@@ -23,6 +23,21 @@ package org.apache.calcite.rel;
  * @see RelCollation
  */
 public class RelFieldCollation {
+  /** Utility method that compares values taking into account null
+   * direction. */
+  public static int compare(Comparable c1, Comparable c2, int nullComparison) {
+    if (c1 == c2) {
+      return 0;
+    } else if (c1 == null) {
+      return nullComparison;
+    } else if (c2 == null) {
+      return -nullComparison;
+    } else {
+      //noinspection unchecked
+      return c1.compareTo(c2);
+    }
+  }
+
   //~ Enums ------------------------------------------------------------------
 
   /**
@@ -72,9 +87,15 @@ public class RelFieldCollation {
    * Ordering of nulls.
    */
   public enum NullDirection {
-    FIRST,
-    LAST,
-    UNSPECIFIED
+    FIRST(-1),
+    LAST(1),
+    UNSPECIFIED(1);
+
+    public final int nullComparison;
+
+    NullDirection(int nullComparison) {
+      this.nullComparison = nullComparison;
+    }
   }
 
   //~ Instance fields --------------------------------------------------------
@@ -136,6 +157,14 @@ public class RelFieldCollation {
     return new RelFieldCollation(target, direction, nullDirection);
   }
 
+  /**
+   * Returns a copy of this RelFieldCollation with the field index shifted
+   * {@code offset} to the right.
+   */
+  public RelFieldCollation shift(int offset) {
+    return copy(fieldIndex + offset);
+  }
+
   // implement Object
   public boolean equals(Object obj) {
     if (!(obj instanceof RelFieldCollation)) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/RelNode.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/RelNode.java b/core/src/main/java/org/apache/calcite/rel/RelNode.java
index c4a2aca..d747809 100644
--- a/core/src/main/java/org/apache/calcite/rel/RelNode.java
+++ b/core/src/main/java/org/apache/calcite/rel/RelNode.java
@@ -90,7 +90,7 @@ public interface RelNode extends RelOptNode, Cloneable {
    * @return List of this relational expression's child expressions
    * @see #accept(org.apache.calcite.rex.RexShuttle)
    */
-  @Deprecated
+  @Deprecated // to be removed before 2.0
   List<RexNode> getChildExps();
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/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 ed0a0f2..d84ef8f 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
@@ -276,7 +276,9 @@ public abstract class Aggregate extends SingleRel {
     // REVIEW jvs 24-Aug-2008:  This is bogus, but no more bogus
     // than what's currently in Join.
     double rowCount = RelMetadataQuery.getRowCount(this);
-    return planner.getCostFactory().makeCost(rowCount, 0, 0);
+    // Aggregates with more aggregate functions cost a bit more
+    final float multiplier = 1f + (float) aggCalls.size() * 0.125f;
+    return planner.getCostFactory().makeCost(rowCount * multiplier, 0, 0);
   }
 
   protected RelDataType deriveRowType() {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/core/Calc.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Calc.java b/core/src/main/java/org/apache/calcite/rel/core/Calc.java
index b8b9b5c..ea2f7d1 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Calc.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Calc.java
@@ -22,7 +22,6 @@ import org.apache.calcite.plan.RelOptPlanner;
 import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.RelCollation;
-import org.apache.calcite.rel.RelCollationImpl;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelWriter;
 import org.apache.calcite.rel.SingleRel;
@@ -33,7 +32,7 @@ import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexProgram;
 import org.apache.calcite.rex.RexShuttle;
 
-import com.google.common.collect.ImmutableList;
+import org.apache.calcite.util.Util;
 
 import java.util.List;
 
@@ -45,37 +44,43 @@ public abstract class Calc extends SingleRel {
   //~ Instance fields --------------------------------------------------------
 
   protected final RexProgram program;
-  private final ImmutableList<RelCollation> collationList;
 
   //~ Constructors -----------------------------------------------------------
 
   /**
-   * Creates calc node.
+   * Creates a Calc.
    *
    * @param cluster Cluster
    * @param traits Traits
    * @param child Input relation
    * @param program Calc program
-   * @param collationList Description of the physical ordering (or orderings)
-   *                      of this relational expression. Never null
    */
   protected Calc(
       RelOptCluster cluster,
       RelTraitSet traits,
       RelNode child,
-      RexProgram program,
-      List<RelCollation> collationList) {
+      RexProgram program) {
     super(cluster, traits, child);
     this.rowType = program.getOutputRowType();
     this.program = program;
-    this.collationList = ImmutableList.copyOf(collationList);
     assert isValid(true);
   }
 
+  @Deprecated // to be removed before 2.0
+  protected Calc(
+      RelOptCluster cluster,
+      RelTraitSet traits,
+      RelNode child,
+      RexProgram program,
+      List<RelCollation> collationList) {
+    this(cluster, traits, child, program);
+    Util.discard(collationList);
+  }
+
   //~ Methods ----------------------------------------------------------------
 
   @Override public final Calc copy(RelTraitSet traitSet, List<RelNode> inputs) {
-    return copy(traitSet, sole(inputs), program, collationList);
+    return copy(traitSet, sole(inputs), program);
   }
 
   /**
@@ -84,18 +89,25 @@ public abstract class Calc extends SingleRel {
    * @param traitSet Traits
    * @param child Input relation
    * @param program Calc program
-   * @param collationList Description of the physical ordering (or orderings)
-   *                      of this relational expression. Never null
    * @return New {@code Calc} if any parameter differs from the value of this
    *   {@code Calc}, or just {@code this} if all the parameters are the same
-
+   *
    * @see #copy(org.apache.calcite.plan.RelTraitSet, java.util.List)
    */
   public abstract Calc copy(
       RelTraitSet traitSet,
       RelNode child,
+      RexProgram program);
+
+  @Deprecated // to be removed before 2.0
+  public Calc copy(
+      RelTraitSet traitSet,
+      RelNode child,
       RexProgram program,
-      List<RelCollation> collationList);
+      List<RelCollation> collationList) {
+    Util.discard(collationList);
+    return copy(traitSet, child, program);
+  }
 
   public boolean isValid(boolean fail) {
     if (!RelOptUtil.equal(
@@ -112,12 +124,6 @@ public abstract class Calc extends SingleRel {
     if (!program.isNormalized(fail, getCluster().getRexBuilder())) {
       return false;
     }
-    if (!RelCollationImpl.isValid(
-        getRowType(),
-        collationList,
-        fail)) {
-      return false;
-    }
     return true;
   }
 
@@ -131,10 +137,6 @@ public abstract class Calc extends SingleRel {
         program);
   }
 
-  public List<RelCollation> getCollationList() {
-    return collationList;
-  }
-
   public RelOptCost computeSelfCost(RelOptPlanner planner) {
     double dRows = RelMetadataQuery.getRowCount(this);
     double dCpu =
@@ -154,23 +156,26 @@ public abstract class Calc extends SingleRel {
     List<RexLocalRef> oldProjects = program.getProjectList();
     List<RexLocalRef> projects = shuttle.apply(oldProjects);
     RexLocalRef oldCondition = program.getCondition();
-    RexNode condition = shuttle.apply(oldCondition);
-    assert condition instanceof RexLocalRef
-        : "Invalid condition after rewrite. Expected RexLocalRef, got "
+    RexNode condition;
+    if (oldCondition != null) {
+      condition = shuttle.apply(oldCondition);
+      assert condition instanceof RexLocalRef
+          : "Invalid condition after rewrite. Expected RexLocalRef, got "
           + condition;
+    } else {
+      condition = null;
+    }
     if (exprs == oldExprs
         && projects == oldProjects
         && condition == oldCondition) {
       return this;
     }
     return copy(traitSet, getInput(),
-        new RexProgram(
-            program.getInputRowType(),
+        new RexProgram(program.getInputRowType(),
             exprs,
             projects,
             (RexLocalRef) condition,
-            program.getOutputRowType()),
-        collationList);
+            program.getOutputRowType()));
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/core/Correlate.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Correlate.java b/core/src/main/java/org/apache/calcite/rel/core/Correlate.java
index 68cbb9e..b1c0e04 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Correlate.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Correlate.java
@@ -132,10 +132,10 @@ public abstract class Correlate extends BiRel {
     case LEFT:
     case INNER:
       // LogicalJoin is used to share the code of column names deduplication
-      return new LogicalJoin(getCluster(), left, right,
-          getCluster().getRexBuilder().makeLiteral(true),
-          joinType.toJoinType(), ImmutableSet.<String>of())
-          .deriveRowType();
+      final LogicalJoin join = LogicalJoin.create(left, right,
+          getCluster().getRexBuilder().makeLiteral(true), joinType.toJoinType(),
+          ImmutableSet.<String>of());
+      return join.deriveRowType();
     case ANTI:
     case SEMI:
       return left.getRowType();

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/core/JoinInfo.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/JoinInfo.java b/core/src/main/java/org/apache/calcite/rel/core/JoinInfo.java
index 03a955e..8c20bd9 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/JoinInfo.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/JoinInfo.java
@@ -20,6 +20,7 @@ import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.runtime.FlatLists;
 import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.ImmutableIntList;
 import org.apache.calcite.util.mapping.IntPair;
@@ -97,6 +98,10 @@ public abstract class JoinInfo {
         rexBuilder);
   }
 
+  public List<ImmutableIntList> keys() {
+    return FlatLists.of(leftKeys, rightKeys);
+  }
+
   /** JoinInfo that represents an equi-join. */
   private static class EquiJoinInfo extends JoinInfo {
     protected EquiJoinInfo(ImmutableIntList leftKeys,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/core/Project.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Project.java b/core/src/main/java/org/apache/calcite/rel/core/Project.java
index ebd2544..704f081 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Project.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Project.java
@@ -24,8 +24,6 @@ import org.apache.calcite.plan.RelOptCost;
 import org.apache.calcite.plan.RelOptPlanner;
 import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.plan.RelTraitSet;
-import org.apache.calcite.rel.RelCollation;
-import org.apache.calcite.rel.RelCollationTraitDef;
 import org.apache.calcite.rel.RelInput;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelWriter;
@@ -67,8 +65,6 @@ public abstract class Project extends SingleRel {
 
   protected final ImmutableList<RexNode> exps;
 
-  protected final ImmutableList<RelCollation> collationList;
-
   //~ Constructors -----------------------------------------------------------
 
   /**
@@ -90,12 +86,6 @@ public abstract class Project extends SingleRel {
     assert rowType != null;
     this.exps = ImmutableList.copyOf(exps);
     this.rowType = rowType;
-    final RelCollation collation =
-        traits.getTrait(RelCollationTraitDef.INSTANCE);
-    this.collationList =
-        collation == null
-            ? ImmutableList.<RelCollation>of()
-            : ImmutableList.of(collation);
     assert isValid(true);
   }
 
@@ -103,7 +93,9 @@ public abstract class Project extends SingleRel {
    * Creates a Project by parsing serialized output.
    */
   protected Project(RelInput input) {
-    this(input.getCluster(), input.getTraitSet(), input.getInput(),
+    this(input.getCluster(),
+        input.getTraitSet(),
+        input.getInput(),
         input.getExpressionList("exprs"),
         input.getRowType("exprs", "fields"));
   }
@@ -131,10 +123,6 @@ public abstract class Project extends SingleRel {
   public abstract Project copy(RelTraitSet traitSet, RelNode input,
       List<RexNode> exps, RelDataType rowType);
 
-  public List<RelCollation> getCollationList() {
-    return collationList;
-  }
-
   @Override public List<RexNode> getChildExps() {
     return exps;
   }
@@ -188,16 +176,6 @@ public abstract class Project extends SingleRel {
       assert !fail;
       return false;
     }
-    if (collationList == null) {
-      assert !fail;
-      return false;
-    }
-    if (!collationList.isEmpty()
-        && collationList.get(0)
-        != traitSet.getTrait(RelCollationTraitDef.INSTANCE)) {
-      assert !fail;
-      return false;
-    }
     if (!Util.isDistinct(rowType.getFieldNames())) {
       assert !fail : rowType;
       return false;
@@ -274,7 +252,7 @@ public abstract class Project extends SingleRel {
    * Every target has a source field, but
    * a source field may appear as zero, one, or more target fields.
    * Thus you can safely call
-   * {@link Mappings.TargetMapping#getTarget(int)}.
+   * {@link org.apache.calcite.util.mapping.Mappings.TargetMapping#getTarget(int)}.
    *
    * @param inputFieldCount Number of input fields
    * @param projects Project expressions
@@ -283,8 +261,8 @@ public abstract class Project extends SingleRel {
   public static Mappings.TargetMapping getMapping(int inputFieldCount,
       List<RexNode> projects) {
     Mappings.TargetMapping mapping =
-        Mappings.create(MappingType.INVERSE_SURJECTION, inputFieldCount,
-            projects.size());
+        Mappings.create(
+            MappingType.INVERSE_SURJECTION, inputFieldCount, projects.size());
     for (Ord<RexNode> exp : Ord.zip(projects)) {
       if (!(exp.e instanceof RexInputRef)) {
         return null;

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java b/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java
index 5967f30..eaa2c43 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java
@@ -17,7 +17,6 @@
 
 package org.apache.calcite.rel.core;
 
-import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.RelCollation;
@@ -128,14 +127,13 @@ public class RelFactories {
   private static class SetOpFactoryImpl implements SetOpFactory {
     public RelNode createSetOp(SqlKind kind, List<RelNode> inputs,
         boolean all) {
-      final RelOptCluster cluster = inputs.get(0).getCluster();
       switch (kind) {
       case UNION:
-        return new LogicalUnion(cluster, inputs, all);
+        return LogicalUnion.create(inputs, all);
       case EXCEPT:
-        return new LogicalMinus(cluster, inputs, all);
+        return LogicalMinus.create(inputs, all);
       case INTERSECT:
-        return new LogicalIntersect(cluster, inputs, all);
+        return LogicalIntersect.create(inputs, all);
       default:
         throw new AssertionError("not a set op: " + kind);
       }
@@ -161,7 +159,7 @@ public class RelFactories {
     public RelNode createAggregate(RelNode child, boolean indicator,
         ImmutableBitSet groupSet, ImmutableList<ImmutableBitSet> groupSets,
         List<AggregateCall> aggCalls) {
-      return new LogicalAggregate(child.getCluster(), child, indicator,
+      return LogicalAggregate.create(child, indicator,
           groupSet, groupSets, aggCalls);
     }
   }
@@ -181,7 +179,7 @@ public class RelFactories {
    */
   private static class FilterFactoryImpl implements FilterFactory {
     public RelNode createFilter(RelNode child, RexNode condition) {
-      return new LogicalFilter(child.getCluster(), child, condition);
+      return LogicalFilter.create(child, condition);
     }
   }
 
@@ -217,8 +215,7 @@ public class RelFactories {
     public RelNode createJoin(RelNode left, RelNode right,
         RexNode condition, JoinRelType joinType,
         Set<String> variablesStopped, boolean semiJoinDone) {
-      final RelOptCluster cluster = left.getCluster();
-      return new LogicalJoin(cluster, left, right, condition, joinType,
+      return LogicalJoin.create(left, right, condition, joinType,
           variablesStopped, semiJoinDone, ImmutableList.<RelDataTypeField>of());
     }
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/core/Window.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Window.java b/core/src/main/java/org/apache/calcite/rel/core/Window.java
index b8885b4..df7510d 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Window.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Window.java
@@ -22,7 +22,7 @@ import org.apache.calcite.plan.RelOptCost;
 import org.apache.calcite.plan.RelOptPlanner;
 import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.RelCollation;
-import org.apache.calcite.rel.RelCollationImpl;
+import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.RelFieldCollation;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelWriter;
@@ -146,7 +146,7 @@ public abstract class Window extends SingleRel {
 
   public static RelCollation getCollation(
       final List<RexFieldCollation> collations) {
-    return RelCollationImpl.of(
+    return RelCollations.of(
         new AbstractList<RelFieldCollation>() {
           public RelFieldCollation get(int index) {
             final RexFieldCollation collation = collations.get(index);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/externalize/RelJson.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/externalize/RelJson.java b/core/src/main/java/org/apache/calcite/rel/externalize/RelJson.java
index fb85247..754589e 100644
--- a/core/src/main/java/org/apache/calcite/rel/externalize/RelJson.java
+++ b/core/src/main/java/org/apache/calcite/rel/externalize/RelJson.java
@@ -19,6 +19,7 @@ package org.apache.calcite.rel.externalize;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelCollationImpl;
+import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.RelFieldCollation;
 import org.apache.calcite.rel.RelInput;
 import org.apache.calcite.rel.RelNode;
@@ -166,7 +167,7 @@ public class RelJson {
     for (Map<String, Object> map : jsonFieldCollations) {
       fieldCollations.add(toFieldCollation(map));
     }
-    return RelCollationImpl.of(fieldCollations);
+    return RelCollations.of(fieldCollations);
   }
 
   public RelFieldCollation toFieldCollation(Map<String, Object> map) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/logical/LogicalAggregate.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalAggregate.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalAggregate.java
index 72744ad..e0bca76 100644
--- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalAggregate.java
+++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalAggregate.java
@@ -46,6 +46,8 @@ public final class LogicalAggregate extends Aggregate {
   /**
    * Creates a LogicalAggregate.
    *
+   * <p>Use {@link #create} unless you know what you're doing.
+   *
    * @param cluster  Cluster that this relational expression belongs to
    * @param child    input relational expression
    * @param groupSet Bit set of grouping fields
@@ -54,19 +56,25 @@ public final class LogicalAggregate extends Aggregate {
    */
   public LogicalAggregate(
       RelOptCluster cluster,
+      RelTraitSet traitSet,
+      RelNode child,
+      boolean indicator,
+      ImmutableBitSet groupSet,
+      List<ImmutableBitSet> groupSets,
+      List<AggregateCall> aggCalls) {
+    super(cluster, traitSet, child, indicator, groupSet, groupSets, aggCalls);
+  }
+
+  @Deprecated // to be removed before 2.0
+  public LogicalAggregate(
+      RelOptCluster cluster,
       RelNode child,
       boolean indicator,
       ImmutableBitSet groupSet,
       List<ImmutableBitSet> groupSets,
       List<AggregateCall> aggCalls) {
-    super(
-        cluster,
-        cluster.traitSetOf(Convention.NONE),
-        child,
-        indicator,
-        groupSet,
-        groupSets,
-        aggCalls);
+    this(cluster, cluster.traitSetOf(Convention.NONE), child, indicator,
+        groupSet, groupSets, aggCalls);
   }
 
   /**
@@ -76,14 +84,26 @@ public final class LogicalAggregate extends Aggregate {
     super(input);
   }
 
+  /** Creates a LogicalAggregate. */
+  public static LogicalAggregate create(RelNode input,
+      boolean indicator,
+      ImmutableBitSet groupSet,
+      List<ImmutableBitSet> groupSets,
+      List<AggregateCall> aggCalls) {
+    final RelOptCluster cluster = input.getCluster();
+    final RelTraitSet traitSet = cluster.traitSetOf(Convention.NONE);
+    return new LogicalAggregate(cluster, traitSet, input, indicator, groupSet,
+        groupSets, aggCalls);
+  }
+
   //~ Methods ----------------------------------------------------------------
 
   @Override public LogicalAggregate copy(RelTraitSet traitSet, RelNode input,
       boolean indicator, ImmutableBitSet groupSet,
       List<ImmutableBitSet> groupSets, List<AggregateCall> aggCalls) {
     assert traitSet.containsIfApplicable(Convention.NONE);
-    return new LogicalAggregate(getCluster(), input, indicator, groupSet,
-        groupSets, aggCalls);
+    return new LogicalAggregate(getCluster(), traitSet, input, indicator,
+        groupSet, groupSets, aggCalls);
   }
 
   @Override public RelNode accept(RelShuttle shuttle) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/logical/LogicalCalc.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalCalc.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalCalc.java
index 1f7dfbe..54af6e6 100644
--- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalCalc.java
+++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalCalc.java
@@ -16,16 +16,22 @@
  */
 package org.apache.calcite.rel.logical;
 
+import org.apache.calcite.plan.Convention;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelCollationTraitDef;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Calc;
+import org.apache.calcite.rel.metadata.RelMdCollation;
 import org.apache.calcite.rel.rules.FilterToCalcRule;
 import org.apache.calcite.rel.rules.ProjectToCalcRule;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexProgram;
+import org.apache.calcite.util.Util;
+
+import com.google.common.base.Supplier;
 
 import java.util.List;
 import java.util.Set;
@@ -60,19 +66,42 @@ public final class LogicalCalc extends Calc {
   /** Creates a LogicalCalc. */
   public LogicalCalc(
       RelOptCluster cluster,
-      RelTraitSet traits,
+      RelTraitSet traitSet,
+      RelNode child,
+      RexProgram program) {
+    super(cluster, traitSet, child, program);
+  }
+
+  @Deprecated // to be removed before 2.0
+  public LogicalCalc(
+      RelOptCluster cluster,
+      RelTraitSet traitSet,
       RelNode child,
       RexProgram program,
       List<RelCollation> collationList) {
-    super(cluster, traits, child, program, collationList);
+    this(cluster, traitSet, child, program);
+    Util.discard(collationList);
+  }
+
+  public static LogicalCalc create(final RelNode input,
+      final RexProgram program) {
+    final RelOptCluster cluster = input.getCluster();
+    final RelTraitSet traitSet = cluster.traitSet()
+        .replace(Convention.NONE)
+        .replaceIf(RelCollationTraitDef.INSTANCE,
+            new Supplier<List<RelCollation>>() {
+              public List<RelCollation> get() {
+                return RelMdCollation.calc(input, program);
+              }
+            });
+    return new LogicalCalc(cluster, traitSet, input, program);
   }
 
   //~ Methods ----------------------------------------------------------------
 
   @Override public LogicalCalc copy(RelTraitSet traitSet, RelNode child,
-      RexProgram program, List<RelCollation> collationList) {
-    return new LogicalCalc(getCluster(), traitSet, child,
-        program, collationList);
+      RexProgram program) {
+    return new LogicalCalc(getCluster(), traitSet, child, program);
   }
 
   @Override public void collectVariablesUsed(Set<String> variableSet) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/logical/LogicalCorrelate.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalCorrelate.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalCorrelate.java
index e5d3bd7..fd403e0 100644
--- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalCorrelate.java
+++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalCorrelate.java
@@ -50,18 +50,20 @@ public final class LogicalCorrelate extends Correlate {
    * @param left         left input relational expression
    * @param right        right input relational expression
    * @param correlationId variable name for the row of left input
-   * @param requiredColumns
+   * @param requiredColumns Required columns
    * @param joinType     join type
    */
   public LogicalCorrelate(
       RelOptCluster cluster,
+      RelTraitSet traitSet,
       RelNode left,
       RelNode right,
       CorrelationId correlationId,
-      ImmutableBitSet requiredColumns, SemiJoinType joinType) {
+      ImmutableBitSet requiredColumns,
+      SemiJoinType joinType) {
     super(
         cluster,
-        cluster.traitSetOf(Convention.NONE),
+        traitSet,
         left,
         right,
         correlationId,
@@ -69,31 +71,43 @@ public final class LogicalCorrelate extends Correlate {
         joinType);
   }
 
+  @Deprecated // to be removed before 2.0
+  public LogicalCorrelate(RelOptCluster cluster, RelNode left, RelNode right,
+      CorrelationId correlationId,
+      ImmutableBitSet requiredColumns, SemiJoinType joinType) {
+    this(cluster, cluster.traitSetOf(Convention.NONE), left, right,
+        correlationId, requiredColumns, joinType);
+  }
+
   /**
    * Creates a LogicalCorrelate by parsing serialized output.
    */
   public LogicalCorrelate(RelInput input) {
-    this(
-        input.getCluster(), input.getInputs().get(0),
+    this(input.getCluster(), input.getTraitSet(), input.getInputs().get(0),
         input.getInputs().get(1),
         new CorrelationId((Integer) input.get("correlationId")),
         input.getBitSet("requiredColumns"),
         input.getEnum("joinType", SemiJoinType.class));
   }
 
+  /** Creates a LogicalCorrelate. */
+  public static LogicalCorrelate create(RelNode left, RelNode right,
+      CorrelationId correlationId, ImmutableBitSet requiredColumns,
+      SemiJoinType joinType) {
+    final RelOptCluster cluster = left.getCluster();
+    final RelTraitSet traitSet = cluster.traitSetOf(Convention.NONE);
+    return new LogicalCorrelate(cluster, traitSet, left, right, correlationId,
+        requiredColumns, joinType);
+  }
+
   //~ Methods ----------------------------------------------------------------
 
   @Override public LogicalCorrelate copy(RelTraitSet traitSet,
       RelNode left, RelNode right, CorrelationId correlationId,
       ImmutableBitSet requiredColumns, SemiJoinType joinType) {
     assert traitSet.containsIfApplicable(Convention.NONE);
-    return new LogicalCorrelate(
-        getCluster(),
-        left,
-        right,
-        correlationId,
-        requiredColumns,
-        joinType);
+    return new LogicalCorrelate(getCluster(), traitSet, left, right,
+        correlationId, requiredColumns, joinType);
   }
 
   @Override public RelNode accept(RelShuttle shuttle) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/logical/LogicalFilter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalFilter.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalFilter.java
index 6766a78..afaf275 100644
--- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalFilter.java
+++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalFilter.java
@@ -19,12 +19,19 @@ package org.apache.calcite.rel.logical;
 import org.apache.calcite.plan.Convention;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelCollationTraitDef;
 import org.apache.calcite.rel.RelInput;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelShuttle;
 import org.apache.calcite.rel.core.Filter;
+import org.apache.calcite.rel.metadata.RelMdCollation;
 import org.apache.calcite.rex.RexNode;
 
+import com.google.common.base.Supplier;
+
+import java.util.List;
+
 /**
  * Sub-class of {@link org.apache.calcite.rel.core.Filter}
  * not targeted at any particular engine or calling convention.
@@ -35,6 +42,8 @@ public final class LogicalFilter extends Filter {
   /**
    * Creates a LogicalFilter.
    *
+   * <p>Use {@link #create} unless you know what you're doing.
+   *
    * @param cluster   Cluster that this relational expression belongs to
    * @param child     Input relational expression
    * @param condition Boolean expression which determines whether a row is
@@ -42,13 +51,18 @@ public final class LogicalFilter extends Filter {
    */
   public LogicalFilter(
       RelOptCluster cluster,
+      RelTraitSet traitSet,
       RelNode child,
       RexNode condition) {
-    super(
-        cluster,
-        cluster.traitSetOf(Convention.NONE),
-        child,
-        condition);
+    super(cluster, traitSet, child, condition);
+  }
+
+  @Deprecated // to be removed before 2.0
+  public LogicalFilter(
+      RelOptCluster cluster,
+      RelNode child,
+      RexNode condition) {
+    this(cluster, cluster.traitSetOf(Convention.NONE), child, condition);
   }
 
   /**
@@ -58,12 +72,25 @@ public final class LogicalFilter extends Filter {
     super(input);
   }
 
+  /** Creates a LogicalFilter. */
+  public static LogicalFilter create(final RelNode input, RexNode condition) {
+    final RelOptCluster cluster = input.getCluster();
+    final RelTraitSet traitSet = cluster.traitSetOf(Convention.NONE)
+        .replaceIf(RelCollationTraitDef.INSTANCE,
+            new Supplier<List<RelCollation>>() {
+              public List<RelCollation> get() {
+                return RelMdCollation.filter(input);
+              }
+            });
+    return new LogicalFilter(cluster, traitSet, input, condition);
+  }
+
   //~ Methods ----------------------------------------------------------------
 
   public LogicalFilter copy(RelTraitSet traitSet, RelNode input,
       RexNode condition) {
     assert traitSet.containsIfApplicable(Convention.NONE);
-    return new LogicalFilter(getCluster(), input, condition);
+    return new LogicalFilter(getCluster(), traitSet, input, condition);
   }
 
   @Override public RelNode accept(RelShuttle shuttle) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/logical/LogicalIntersect.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalIntersect.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalIntersect.java
index 5147b73..2c7f07f 100644
--- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalIntersect.java
+++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalIntersect.java
@@ -33,28 +33,43 @@ import java.util.List;
 public final class LogicalIntersect extends Intersect {
   //~ Constructors -----------------------------------------------------------
 
+  /**
+   * Creates a LogicalIntersect.
+   *
+   * <p>Use {@link #create} unless you know what you're doing.
+   */
   public LogicalIntersect(
       RelOptCluster cluster,
+      RelTraitSet traitSet,
       List<RelNode> inputs,
       boolean all) {
-    super(
-        cluster,
-        cluster.traitSetOf(Convention.NONE),
-        inputs,
-        all);
+    super(cluster, traitSet, inputs, all);
   }
 
+  @Deprecated // to be removed before 2.0
+  public LogicalIntersect(RelOptCluster cluster, List<RelNode> inputs,
+      boolean all) {
+    this(cluster, cluster.traitSetOf(Convention.NONE), inputs, all);
+  }
+
+
   /** Creates a LogicalIntersect by parsing serialized output. */
   public LogicalIntersect(RelInput input) {
     super(input);
   }
 
+  /** Creates a LogicalIntersect. */
+  public static LogicalIntersect create(List<RelNode> inputs, boolean all) {
+    final RelOptCluster cluster = inputs.get(0).getCluster();
+    final RelTraitSet traitSet = cluster.traitSetOf(Convention.NONE);
+    return new LogicalIntersect(cluster, traitSet, inputs, all);
+  }
+
   //~ Methods ----------------------------------------------------------------
 
   @Override public LogicalIntersect copy(RelTraitSet traitSet,
       List<RelNode> inputs, boolean all) {
-    assert traitSet.containsIfApplicable(Convention.NONE);
-    return new LogicalIntersect(getCluster(), inputs, all);
+    return new LogicalIntersect(getCluster(), traitSet, inputs, all);
   }
 
   @Override public RelNode accept(RelShuttle shuttle) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/logical/LogicalJoin.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalJoin.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalJoin.java
index 1dcea6f..c65499a 100644
--- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalJoin.java
+++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalJoin.java
@@ -65,38 +65,10 @@ public final class LogicalJoin extends Join {
   /**
    * Creates a LogicalJoin.
    *
-   * @param cluster          Cluster
-   * @param left             Left input
-   * @param right            Right input
-   * @param condition        Join condition
-   * @param joinType         Join type
-   * @param variablesStopped Set of names of variables which are set by the
-   *                         LHS and used by the RHS and are not available to
-   *                         nodes above this LogicalJoin in the tree
-   */
-  public LogicalJoin(
-      RelOptCluster cluster,
-      RelNode left,
-      RelNode right,
-      RexNode condition,
-      JoinRelType joinType,
-      Set<String> variablesStopped) {
-    this(
-        cluster,
-        left,
-        right,
-        condition,
-        joinType,
-        variablesStopped,
-        false,
-        ImmutableList.<RelDataTypeField>of());
-  }
-
-  /**
-   * Creates a LogicalJoin, flagged with whether it has been translated to a
-   * semi-join.
+   * <p>Use {@link #create} unless you know what you're doing.
    *
    * @param cluster          Cluster
+   * @param traitSet         Trait set
    * @param left             Left input
    * @param right            Right input
    * @param condition        Join condition
@@ -113,6 +85,7 @@ public final class LogicalJoin extends Join {
    */
   public LogicalJoin(
       RelOptCluster cluster,
+      RelTraitSet traitSet,
       RelNode left,
       RelNode right,
       RexNode condition,
@@ -120,19 +93,29 @@ public final class LogicalJoin extends Join {
       Set<String> variablesStopped,
       boolean semiJoinDone,
       ImmutableList<RelDataTypeField> systemFieldList) {
-    super(
-        cluster,
-        cluster.traitSetOf(Convention.NONE),
-        left,
-        right,
-        condition,
-        joinType,
+    super(cluster, traitSet, left, right, condition, joinType,
         variablesStopped);
     assert systemFieldList != null;
     this.semiJoinDone = semiJoinDone;
     this.systemFieldList = systemFieldList;
   }
 
+  @Deprecated // to be removed before 2.0
+  public LogicalJoin(RelOptCluster cluster, RelNode left, RelNode right,
+      RexNode condition, JoinRelType joinType, Set<String> variablesStopped) {
+    this(cluster, cluster.traitSetOf(Convention.NONE), left, right, condition,
+        joinType, variablesStopped, false,
+        ImmutableList.<RelDataTypeField>of());
+  }
+
+  @Deprecated // to be removed before 2.0
+  public LogicalJoin(RelOptCluster cluster, RelNode left, RelNode right,
+      RexNode condition, JoinRelType joinType, Set<String> variablesStopped,
+      boolean semiJoinDone, ImmutableList<RelDataTypeField> systemFieldList) {
+    this(cluster, cluster.traitSetOf(Convention.NONE), left, right, condition,
+        joinType, variablesStopped, semiJoinDone, systemFieldList);
+  }
+
   /**
    * Creates a LogicalJoin by parsing serialized output.
    */
@@ -145,6 +128,24 @@ public final class LogicalJoin extends Join {
         ImmutableList.<RelDataTypeField>of());
   }
 
+  /** Creates a LogicalJoin, flagged with whether it has been translated to a
+   * semi-join. */
+  public static LogicalJoin create(RelNode left, RelNode right,
+      RexNode condition, JoinRelType joinType, Set<String> variablesStopped,
+      boolean semiJoinDone, ImmutableList<RelDataTypeField> systemFieldList) {
+    final RelOptCluster cluster = left.getCluster();
+    final RelTraitSet traitSet = cluster.traitSetOf(Convention.NONE);
+    return new LogicalJoin(cluster, traitSet, left, right, condition, joinType,
+        variablesStopped, semiJoinDone, systemFieldList);
+  }
+
+  /** Creates a LogicalJoin. */
+  public static LogicalJoin create(RelNode left, RelNode right,
+      RexNode condition, JoinRelType joinType, Set<String> variablesStopped) {
+    return create(left, right, condition, joinType, variablesStopped, false,
+        ImmutableList.<RelDataTypeField>of());
+  }
+
   //~ Methods ----------------------------------------------------------------
 
   @Override public LogicalJoin copy(RelTraitSet traitSet, RexNode conditionExpr,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/logical/LogicalMinus.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalMinus.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalMinus.java
index 9db2a1b..b8e8057 100644
--- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalMinus.java
+++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalMinus.java
@@ -33,17 +33,23 @@ import java.util.List;
 public final class LogicalMinus extends Minus {
   //~ Constructors -----------------------------------------------------------
 
-  public LogicalMinus(
-      RelOptCluster cluster,
-      List<RelNode> inputs,
+  /**
+   * Creates a LogicalMinus.
+   *
+   * <p>Use {@link #create} unless you know what you're doing.
+   */
+  public LogicalMinus(RelOptCluster cluster, RelTraitSet traitSet,
+      List<RelNode> inputs, boolean all) {
+    super(cluster, traitSet, inputs, all);
+  }
+
+  @Deprecated // to be removed before 2.0
+  public LogicalMinus(RelOptCluster cluster, List<RelNode> inputs,
       boolean all) {
-    super(
-        cluster,
-        cluster.traitSetOf(Convention.NONE),
-        inputs,
-        all);
+    this(cluster, cluster.traitSetOf(Convention.NONE), inputs, all);
   }
 
+
   /**
    * Creates a LogicalMinus by parsing serialized output.
    */
@@ -51,15 +57,19 @@ public final class LogicalMinus extends Minus {
     super(input);
   }
 
+  /** Creates a LogicalMinus. */
+  public static LogicalMinus create(List<RelNode> inputs, boolean all) {
+    final RelOptCluster cluster = inputs.get(0).getCluster();
+    final RelTraitSet traitSet = cluster.traitSetOf(Convention.NONE);
+    return new LogicalMinus(cluster, traitSet, inputs, all);
+  }
+
   //~ Methods ----------------------------------------------------------------
 
-  @Override public LogicalMinus copy(
-      RelTraitSet traitSet, List<RelNode> inputs, boolean all) {
+  @Override public LogicalMinus copy(RelTraitSet traitSet, List<RelNode> inputs,
+      boolean all) {
     assert traitSet.containsIfApplicable(Convention.NONE);
-    return new LogicalMinus(
-        getCluster(),
-        inputs,
-        all);
+    return new LogicalMinus(getCluster(), traitSet, inputs, all);
   }
 
   @Override public RelNode accept(RelShuttle shuttle) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/logical/LogicalProject.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalProject.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalProject.java
index d60324a..79cd386 100644
--- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalProject.java
+++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalProject.java
@@ -19,15 +19,20 @@ package org.apache.calcite.rel.logical;
 import org.apache.calcite.plan.Convention;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelTraitSet;
-import org.apache.calcite.rel.RelCollationImpl;
+import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelCollationTraitDef;
+import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.RelInput;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelShuttle;
 import org.apache.calcite.rel.core.Project;
+import org.apache.calcite.rel.metadata.RelMdCollation;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexUtil;
 
+import com.google.common.base.Supplier;
+
 import java.util.List;
 
 /**
@@ -38,48 +43,33 @@ public final class LogicalProject extends Project {
   //~ Constructors -----------------------------------------------------------
 
   /**
-   * Creates a LogicalProject with no sort keys.
-   *
-   * @param cluster    Cluster this relational expression belongs to
-   * @param child      input relational expression
-   * @param exps       set of expressions for the input columns
-   * @param fieldNames aliases of the expressions
-   */
-  public LogicalProject(
-      RelOptCluster cluster,
-      RelNode child,
-      List<RexNode> exps,
-      List<String> fieldNames) {
-    this(
-        cluster,
-        cluster.traitSetOf(RelCollationImpl.EMPTY),
-        child,
-        exps,
-        RexUtil.createStructType(
-            cluster.getTypeFactory(),
-            exps,
-            fieldNames));
-  }
-
-  /**
    * Creates a LogicalProject.
    *
+   * <p>Use {@link #create} unless you know what you're doing.
+   *
    * @param cluster  Cluster this relational expression belongs to
    * @param traitSet traits of this rel
-   * @param child    input relational expression
+   * @param input    input relational expression
    * @param exps     List of expressions for the input columns
    * @param rowType  output row type
    */
   public LogicalProject(
       RelOptCluster cluster,
       RelTraitSet traitSet,
-      RelNode child,
+      RelNode input,
       List<? extends RexNode> exps,
       RelDataType rowType) {
-    super(cluster, traitSet, child, exps, rowType);
+    super(cluster, traitSet, input, exps, rowType);
     assert traitSet.containsIfApplicable(Convention.NONE);
   }
 
+  @Deprecated // to be removed before 2.0
+  public LogicalProject(RelOptCluster cluster, RelNode child,
+      List<RexNode> exps, List<String> fieldNames) {
+    this(cluster, cluster.traitSetOf(RelCollations.EMPTY), child, exps,
+        RexUtil.createStructType(cluster.getTypeFactory(), exps, fieldNames));
+  }
+
   /**
    * Creates a LogicalProject by parsing serialized output.
    */
@@ -89,6 +79,31 @@ public final class LogicalProject extends Project {
 
   //~ Methods ----------------------------------------------------------------
 
+  /** Creates a LogicalProject. */
+  public static LogicalProject create(final RelNode input,
+      final List<? extends RexNode> projects, List<String> fieldNames) {
+    final RelOptCluster cluster = input.getCluster();
+    final RelDataType rowType =
+        RexUtil.createStructType(cluster.getTypeFactory(), projects,
+            fieldNames);
+    return create(input, projects, rowType);
+  }
+
+  /** Creates a LogicalProject, specifying row type rather than field names. */
+  public static LogicalProject create(final RelNode input,
+      final List<? extends RexNode> projects, RelDataType rowType) {
+    final RelOptCluster cluster = input.getCluster();
+    final RelTraitSet traitSet =
+        cluster.traitSet().replace(Convention.NONE)
+            .replaceIf(RelCollationTraitDef.INSTANCE,
+                new Supplier<List<RelCollation>>() {
+                  public List<RelCollation> get() {
+                    return RelMdCollation.project(input, projects);
+                  }
+                });
+    return new LogicalProject(cluster, traitSet, input, projects, rowType);
+  }
+
   @Override public LogicalProject copy(RelTraitSet traitSet, RelNode input,
       List<RexNode> exps, RelDataType rowType) {
     return new LogicalProject(getCluster(), traitSet, input, exps, rowType);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/logical/LogicalSort.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalSort.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalSort.java
index 8d88cfa..2d61cc4 100644
--- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalSort.java
+++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalSort.java
@@ -20,6 +20,7 @@ import org.apache.calcite.plan.Convention;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelCollationTraitDef;
 import org.apache.calcite.rel.RelInput;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelShuttle;
@@ -56,6 +57,7 @@ public final class LogicalSort extends Sort {
   public static LogicalSort create(RelNode input, RelCollation collation,
       RexNode offset, RexNode fetch) {
     RelOptCluster cluster = input.getCluster();
+    collation = RelCollationTraitDef.INSTANCE.canonize(collation);
     RelTraitSet traitSet =
         input.getTraitSet().replace(Convention.NONE).replace(collation);
     return new LogicalSort(cluster, traitSet, input, collation, offset, fetch);


[3/9] incubator-calcite git commit: [CALCITE-569] ArrayIndexOutOfBoundsException when deducing collation (Aman Sinha)

Posted by jh...@apache.org.
[CALCITE-569] ArrayIndexOutOfBoundsException when deducing collation (Aman Sinha)

This commit adds a test case. Although Aman's patch provided a fix, Julian Hyde had already fixed the issue as part of [CALCITE-88].


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

Branch: refs/heads/master
Commit: c0120dd80bfe5e5fb077a5b631efbccb35afd9eb
Parents: c0a3085
Author: Julian Hyde <jh...@apache.org>
Authored: Fri Feb 6 12:47:45 2015 -0800
Committer: julianhyde <jh...@apache.org>
Committed: Sun Feb 8 00:23:01 2015 -0800

----------------------------------------------------------------------
 .../org/apache/calcite/tools/PlannerTest.java   | 39 ++++++++++++++++++++
 1 file changed, 39 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c0120dd8/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 c7650c4..54bee88 100644
--- a/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
+++ b/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
@@ -908,6 +908,45 @@ public class PlannerTest {
       return super.deriveType(validator, scope, call);
     }
   }
+
+  /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-569">[CALCITE-569],
+   * ArrayIndexOutOfBoundsException when deducing collation</a>. */
+  @Test public void testOrderByNonSelectColumn() throws Exception {
+    final SchemaPlus schema = Frameworks.createRootSchema(true)
+        .add("tpch", new ReflectiveSchema(new TpchSchema()));
+
+    String query = "select t.psPartkey from \n"
+      + "(select ps.psPartkey from `tpch`.`partsupp` ps \n"
+      + "order by ps.psPartkey, ps.psSupplyCost) t \n"
+      + "order by t.psPartkey";
+
+    List<RelTraitDef> traitDefs = new ArrayList<RelTraitDef>();
+    traitDefs.add(ConventionTraitDef.INSTANCE);
+    traitDefs.add(RelCollationTraitDef.INSTANCE);
+    final SqlParser.Config parserConfig =
+        SqlParser.configBuilder().setLex(Lex.MYSQL).build();
+    Planner p = Frameworks.getPlanner(
+        Frameworks.newConfigBuilder()
+            .parserConfig(parserConfig)
+            .defaultSchema(schema)
+            .traitDefs(traitDefs)
+            .programs(Programs.ofRules(Programs.RULE_SET))
+            .build());
+    SqlNode n = p.parse(query);
+    n = p.validate(n);
+    RelNode r = p.convert(n);
+    String plan = RelOptUtil.toString(r);
+    plan = Util.toLinux(plan);
+    p.close();
+    assertThat(plan,
+        equalTo("LogicalSort(sort0=[$0], dir0=[ASC])\n"
+        + "  LogicalProject(psPartkey=[$0])\n"
+        + "    LogicalProject(psPartkey=[$0])\n"
+        + "      LogicalSort(sort0=[$0], sort1=[$1], dir0=[ASC], dir1=[ASC])\n"
+        + "        LogicalProject(psPartkey=[$0], psSupplyCost=[$1])\n"
+        + "          EnumerableTableScan(table=[[tpch, partsupp]])\n"));
+  }
 }
 
 // End PlannerTest.java


[9/9] incubator-calcite git commit: [CALCITE-573] Use user-given names in RelOptUtil.createProject and createRename

Posted by jh...@apache.org.
[CALCITE-573] Use user-given names in RelOptUtil.createProject and createRename

Close apache/incubator-calcite#46

Close apache/incubator-calcite#45 (went in a few commits back)


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

Branch: refs/heads/master
Commit: e237804b0e4d7ac17249708a5cf823e0c1fe1625
Parents: 8f1e3b2
Author: Trevor Hartman <tr...@gmail.com>
Authored: Wed Feb 4 09:53:25 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Sun Feb 8 01:26:23 2015 -0800

----------------------------------------------------------------------
 .../java/org/apache/calcite/avatica/Meta.java   | 27 ++++++++++++++------
 1 file changed, 19 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/e237804b/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/Meta.java b/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
index 2e1f823..107c4c9 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
@@ -23,6 +23,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import java.lang.reflect.Field;
 import java.sql.SQLException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
@@ -315,16 +316,15 @@ public interface Meta {
     public final List<ColumnMetaData> columns;
     public final String sql;
     public final List<AvaticaParameter> parameters;
-    public final Map<String, Object> internalParameters;
+    public final transient Map<String, Object> internalParameters;
     public final CursorFactory cursorFactory;
 
-    @JsonCreator
-    public Signature(@JsonProperty("columns") List<ColumnMetaData> columns,
-        @JsonProperty("sql") String sql,
-        @JsonProperty("parameters") List<AvaticaParameter> parameters,
-        @JsonProperty("internalParameters") Map<String, Object>
-            internalParameters,
-        @JsonProperty("cursorFactory") CursorFactory cursorFactory) {
+    /** Creates a Signature. */
+    public Signature(List<ColumnMetaData> columns,
+        String sql,
+        List<AvaticaParameter> parameters,
+        Map<String, Object> internalParameters,
+        CursorFactory cursorFactory) {
       this.columns = columns;
       this.sql = sql;
       this.parameters = parameters;
@@ -332,6 +332,17 @@ public interface Meta {
       this.cursorFactory = cursorFactory;
     }
 
+    /** Used by Jackson to create a Signature by de-serializing JSON. */
+    @JsonCreator
+    public static Signature create(
+        @JsonProperty("columns") List<ColumnMetaData> columns,
+        @JsonProperty("sql") String sql,
+        @JsonProperty("parameters") List<AvaticaParameter> parameters,
+        @JsonProperty("cursorFactory") CursorFactory cursorFactory) {
+      return new Signature(columns, sql, parameters,
+          Collections.<String, Object>emptyMap(), cursorFactory);
+    }
+
     /** Returns a copy of this Signature, substituting given CursorFactory. */
     public Signature setCursorFactory(CursorFactory cursorFactory) {
       return new Signature(columns, sql, parameters, internalParameters,


[8/9] incubator-calcite git commit: [CALCITE-573] Use user-given names in RelOptUtil.createProject and createRename

Posted by jh...@apache.org.
[CALCITE-573] Use user-given names in RelOptUtil.createProject and createRename

Close apache/incubator-calcite#46


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

Branch: refs/heads/master
Commit: 8f1e3b2803edda876c31a0a491e901b33c92da34
Parents: 2709896
Author: Vladimir Sitnikov <si...@gmail.com>
Authored: Thu Jan 29 22:06:55 2015 +0300
Committer: Julian Hyde <jh...@apache.org>
Committed: Sun Feb 8 01:17:58 2015 -0800

----------------------------------------------------------------------
 .../org/apache/calcite/plan/RelOptUtil.java     |  38 +++----
 .../rel/rules/AggregateStarTableRule.java       |   2 +-
 .../calcite/sql2rel/SqlToRelConverter.java      |   2 +-
 .../org/apache/calcite/test/CalciteAssert.java  |   9 ++
 .../org/apache/calcite/test/LatticeTest.java    |   6 +-
 .../enumerable/EnumerableCorrelateTest.java     |   4 +-
 .../org/apache/calcite/tools/PlannerTest.java   | 106 ++++++++++++++-----
 .../org/apache/calcite/test/RelOptRulesTest.xml |  20 ++--
 .../calcite/test/SqlToRelConverterTest.xml      |  42 ++++----
 core/src/test/resources/sql/misc.oq             |  22 ++--
 10 files changed, 157 insertions(+), 94 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/8f1e3b28/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 bbcb75d..d09bf1f 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
@@ -2433,19 +2433,10 @@ public abstract class RelOptUtil {
    * Creates a {@link org.apache.calcite.rel.logical.LogicalProject} that
    * projects particular fields of its input, according to a mapping.
    */
-  public static LogicalProject project(
+  public static RelNode createProject(
       RelNode child,
       Mappings.TargetMapping mapping) {
-    List<RexNode> nodes = new ArrayList<RexNode>();
-    List<String> names = new ArrayList<String>();
-    final List<RelDataTypeField> fields = child.getRowType().getFieldList();
-    for (int i = 0; i < mapping.getTargetCount(); i++) {
-      int source = mapping.getSourceOpt(i);
-      RelDataTypeField field = fields.get(source);
-      nodes.add(new RexInputRef(source, field.getType()));
-      names.add(field.getName());
-    }
-    return LogicalProject.create(child, nodes, names);
+    return createProject(child, Mappings.asList(mapping.inverse()));
   }
 
   /** Returns whether relational expression {@code target} occurs within a
@@ -2657,17 +2648,17 @@ public abstract class RelOptUtil {
       List<String> fieldNames) {
     final List<RelDataTypeField> fields = rel.getRowType().getFieldList();
     assert fieldNames.size() == fields.size();
-    final List<Pair<RexNode, String>> refs =
-        new AbstractList<Pair<RexNode, String>>() {
+    final List<RexNode> refs =
+        new AbstractList<RexNode>() {
           public int size() {
             return fields.size();
           }
 
-          public Pair<RexNode, String> get(int index) {
-            return RexInputRef.of2(index, fields);
+          public RexNode get(int index) {
+            return RexInputRef.of(index, fields);
           }
         };
-    return createProject(rel, refs, true);
+    return createProject(rel, refs, fieldNames, true);
   }
 
   /**
@@ -2769,9 +2760,11 @@ public abstract class RelOptUtil {
    */
   public static RelNode createProject(final RelFactories.ProjectFactory factory,
       final RelNode child, final List<Integer> posList) {
-    if (Mappings.isIdentity(posList, child.getRowType().getFieldCount())) {
+    RelDataType rowType = child.getRowType();
+    if (Mappings.isIdentity(posList, rowType.getFieldCount())) {
       return child;
     }
+    final List<String> fieldNames = rowType.getFieldNames();
     final RexBuilder rexBuilder = child.getCluster().getRexBuilder();
     return factory.createProject(child,
         new AbstractList<RexNode>() {
@@ -2784,7 +2777,16 @@ public abstract class RelOptUtil {
             return rexBuilder.makeInputRef(child, pos);
           }
         },
-        null);
+        new AbstractList<String>() {
+          public int size() {
+            return posList.size();
+          }
+
+          public String get(int index) {
+            final int pos = posList.get(index);
+            return fieldNames.get(pos);
+          }
+        });
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/8f1e3b28/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 fd66ddf..10dfafc 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
@@ -156,7 +156,7 @@ public class AggregateStarTableRule extends RelOptRule {
           + aggregateRelOptTable.getQualifiedName()
           + ", right granularity, but different measures "
           + aggregate.getAggCallList());
-      rel = RelOptUtil.project(rel,
+      rel = RelOptUtil.createProject(rel,
           new AbstractSourceMapping(
               tileKey.dimensions.cardinality() + tileKey.measures.size(),
               aggregate.getRowType().getFieldCount()) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/8f1e3b28/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 0ace1e9..ad3f7c0 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -2212,7 +2212,7 @@ public class SqlToRelConverter {
                   + rightCount + extraRightExprs.size(),
               0, 0, leftCount,
               leftCount, leftCount + extraLeftExprs.size(), rightCount);
-      return RelOptUtil.project(join, mapping);
+      return RelOptUtil.createProject(join, mapping);
     }
     return join;
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/8f1e3b28/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/CalciteAssert.java b/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
index 77faaf0..4ac014b 100644
--- a/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
+++ b/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
@@ -469,6 +469,15 @@ public class CalciteAssert {
       statement.close();
       connection.close();
     } catch (Throwable e) {
+      // We ignore extended message for non-runtime exception, however
+      // it does not matter much since it is better to have AssertionError
+      // at the very top level of the exception stack.
+      if (e instanceof RuntimeException) {
+        throw (RuntimeException) e;
+      }
+      if (e instanceof Error) {
+        throw (Error) e;
+      }
       throw new RuntimeException(message, e);
     } finally {
       for (Hook.Closeable closeable : closeableList) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/8f1e3b28/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 b51e51c..c68cf5f 100644
--- a/core/src/test/java/org/apache/calcite/test/LatticeTest.java
+++ b/core/src/test/java/org/apache/calcite/test/LatticeTest.java
@@ -191,7 +191,7 @@ public class LatticeTest {
         .substitutionMatches(
             CalciteAssert.checkRel(
                 "LogicalProject(unit_sales=[$7], brand_name=[$10])\n"
-                    + "  LogicalProject($f0=[$0], $f1=[$1], $f2=[$2], $f3=[$3], $f4=[$4], $f5=[$5], $f6=[$6], $f7=[$7], $f8=[$8], $f9=[$9], $f10=[$10], $f11=[$11], $f12=[$12], $f13=[$13], $f14=[$14], $f15=[$15], $f16=[$16], $f17=[$17], $f18=[$18], $f19=[$19], $f20=[$20], $f21=[$21], $f22=[$22])\n"
+                    + "  LogicalProject(product_id=[$0], time_id=[$1], customer_id=[$2], promotion_id=[$3], store_id=[$4], store_sales=[$5], store_cost=[$6], unit_sales=[$7], product_class_id=[$8], product_id0=[$9], brand_name=[$10], product_name=[$11], SKU=[$12], SRP=[$13], gross_weight=[$14], net_weight=[$15], recyclable_package=[$16], low_fat=[$17], units_per_case=[$18], cases_per_pallet=[$19], shelf_width=[$20], shelf_height=[$21], shelf_depth=[$22])\n"
                     + "    LogicalTableScan(table=[[adhoc, star]])\n",
                 counter));
     assertThat(counter.intValue(), equalTo(1));
@@ -213,7 +213,7 @@ public class LatticeTest {
                 assertThat(s,
                     anyOf(
                         containsString(
-                            "LogicalProject($f0=[$1], $f1=[$0])\n"
+                            "LogicalProject(brand_name=[$1], customer_id=[$0])\n"
                             + "  LogicalAggregate(group=[{2, 10}])\n"
                             + "    LogicalTableScan(table=[[adhoc, star]])\n"),
                         containsString(
@@ -224,7 +224,7 @@ public class LatticeTest {
             });
     assertThat(counter.intValue(), equalTo(2));
     that.explainContains(""
-        + "EnumerableCalc(expr#0..1=[{inputs}], $f0=[$t1], $f1=[$t0])\n"
+        + "EnumerableCalc(expr#0..1=[{inputs}], brand_name=[$t1], customer_id=[$t0])\n"
         + "  EnumerableTableScan(table=[[adhoc, m{2, 10}]])")
         .returnsCount(69203);
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/8f1e3b28/core/src/test/java/org/apache/calcite/test/enumerable/EnumerableCorrelateTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/enumerable/EnumerableCorrelateTest.java b/core/src/test/java/org/apache/calcite/test/enumerable/EnumerableCorrelateTest.java
index c90bc92..710d1c1 100644
--- a/core/src/test/java/org/apache/calcite/test/enumerable/EnumerableCorrelateTest.java
+++ b/core/src/test/java/org/apache/calcite/test/enumerable/EnumerableCorrelateTest.java
@@ -35,10 +35,10 @@ public class EnumerableCorrelateTest {
             "EnumerableCalc(expr#0..4=[{inputs}], empid=[$t0], name=[$t2])\n"
             + "  EnumerableSemiJoin(condition=[=($1, $5)], joinType=[inner])\n"
             + "    EnumerableTableScan(table=[[s, emps]])\n"
-            + "    EnumerableCalc(expr#0..4=[{inputs}], expr#5=[true], $f01=[$t0], $f0=[$t5])\n"
+            + "    EnumerableCalc(expr#0..4=[{inputs}], expr#5=[true], deptno0=[$t0], $f0=[$t5])\n"
             + "      EnumerableJoin(condition=[=($0, $1)], joinType=[inner])\n"
             + "        EnumerableAggregate(group=[{0}])\n"
-            + "          EnumerableCalc(expr#0..4=[{inputs}], $f0=[$t1])\n"
+            + "          EnumerableCalc(expr#0..4=[{inputs}], deptno=[$t1])\n"
             + "            EnumerableTableScan(table=[[s, emps]])\n"
             + "        EnumerableTableScan(table=[[s, depts]])")
         .returnsUnordered(

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/8f1e3b28/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 701d66a..55f287c 100644
--- a/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
+++ b/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
@@ -41,6 +41,7 @@ import org.apache.calcite.rel.convert.ConverterRule;
 import org.apache.calcite.rel.core.TableScan;
 import org.apache.calcite.rel.metadata.RelMetadataQuery;
 import org.apache.calcite.rel.rules.FilterMergeRule;
+import org.apache.calcite.rel.rules.ProjectToWindowRule;
 import org.apache.calcite.rel.rules.SortRemoveRule;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
@@ -69,6 +70,7 @@ import org.apache.calcite.util.Util;
 
 import com.google.common.collect.ImmutableList;
 
+import org.junit.Ignore;
 import org.junit.Test;
 
 import java.util.ArrayList;
@@ -105,8 +107,8 @@ public class PlannerTest {
             + "WHERE `name` LIKE '%e%'",
 
         "LogicalProject(empid=[$0], deptno=[$1], name=[$2], salary=[$3], commission=[$4])\n"
-            + "  LogicalFilter(condition=[LIKE($2, '%e%')])\n"
-            + "    EnumerableTableScan(table=[[hr, emps]])\n");
+        + "  LogicalFilter(condition=[LIKE($2, '%e%')])\n"
+        + "    EnumerableTableScan(table=[[hr, emps]])\n");
   }
 
   @Test(expected = SqlParseException.class)
@@ -139,8 +141,8 @@ public class PlannerTest {
             + "OFFSET 10 ROWS",
 
         "LogicalSort(sort0=[$1], dir0=[ASC], offset=[10])\n"
-            + "  LogicalProject(empid=[$0], deptno=[$1], name=[$2], salary=[$3], commission=[$4])\n"
-            + "    EnumerableTableScan(table=[[hr, emps]])\n");
+        + "  LogicalProject(empid=[$0], deptno=[$1], name=[$2], salary=[$3], commission=[$4])\n"
+        + "    EnumerableTableScan(table=[[hr, emps]])\n");
   }
 
   private String toString(RelNode rel) {
@@ -324,7 +326,7 @@ public class PlannerTest {
     assertThat(toString(transform),
         equalTo(
             "EnumerableProject(empid=[$0], deptno=[$1], name=[$2], salary=[$3], commission=[$4])\n"
-                + "  EnumerableTableScan(table=[[hr, emps]])\n"));
+            + "  EnumerableTableScan(table=[[hr, emps]])\n"));
   }
 
   /** Unit test that parses, validates, converts and
@@ -354,18 +356,75 @@ public class PlannerTest {
    * plans for query using two duplicate order by.
    * The duplicate order by should be removed by SortRemoveRule. */
   @Test public void testDuplicateSortPlan() throws Exception {
+    runDuplicateSortCheck(
+        "select empid from ( "
+        + "select * "
+        + "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");
+  }
+
+  /** Unit test that parses, validates, converts and
+   * plans for query using two duplicate order by.
+   * The duplicate order by should be removed by SortRemoveRule*/
+  @Test public void testDuplicateSortPlanWithExpr() throws Exception {
+    runDuplicateSortCheck("select empid+deptno from ( "
+        + "select empid, deptno "
+        + "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");
+  }
+
+  /** Tests that outer order by is not removed since window function
+   * might reorder the rows in-between */
+  @Ignore("RelOptPlanner$CannotPlanException: Node [rel#27:Subset#6"
+      + ".ENUMERABLE.[]] could not be implemented; planner state:\n"
+      + "\n"
+      + "Root: rel#27:Subset#6.ENUMERABLE.[]")
+  @Test public void testDuplicateSortPlanWithOver() throws Exception {
+    runDuplicateSortCheck("select empid+deptno from ( "
+        + "select empid, deptno, count(*) over (partition by deptno) emp_cnt from ( "
+        + "  select empid, deptno "
+        + "    from emps "
+        + "   order by emps.deptno) "
+        + ")"
+        + "order by deptno",
+        "EnumerableProject(EXPR$0=[$0])\n"
+        + "  EnumerableSort(sort0=[$1], dir0=[ASC])\n"
+        + "    EnumerableProject(EXPR$0=[+($0, $1)], deptno=[$1])\n"
+        + "      EnumerableProject(empid=[$0], deptno=[$1], $2=[$2])\n"
+        + "        EnumerableWindow(window#0=[window(partition {1} order by [] range between UNBOUNDED PRECEDING and UNBOUNDED FOLLOWING aggs [COUNT()])])\n"
+        + "          EnumerableSort(sort0=[$1], dir0=[ASC])\n"
+        + "            EnumerableProject(empid=[$0], deptno=[$1])\n"
+        + "              EnumerableTableScan(table=[[hr, emps]])\n");
+  }
+
+  // If proper "SqlParseException, ValidationException, RelConversionException"
+  // is used, then checkstyle fails with
+  // "Redundant throws: 'ValidationException' listed more then one time"
+  // "Redundant throws: 'RelConversionException' listed more then one time"
+  private void runDuplicateSortCheck(String sql, String plan) throws Exception {
     RuleSet ruleSet =
         RuleSets.ofList(
             SortRemoveRule.INSTANCE,
             EnumerableRules.ENUMERABLE_PROJECT_RULE,
-            EnumerableRules.ENUMERABLE_SORT_RULE);
-    Planner planner = getPlanner(null, Programs.of(ruleSet));
-    SqlNode parse = planner.parse(
-        "select \"empid\" from ( "
-            + "select * "
-            + "from \"emps\" "
-            + "order by \"emps\".\"deptno\") "
-            + "order by \"deptno\"");
+            EnumerableRules.ENUMERABLE_WINDOW_RULE,
+            EnumerableRules.ENUMERABLE_SORT_RULE,
+            ProjectToWindowRule.PROJECT);
+    Planner planner = getPlanner(null,
+        SqlParser.configBuilder().setLex(Lex.JAVA).build(),
+        Programs.of(ruleSet));
+    SqlNode parse = planner.parse(sql);
     SqlNode validate = planner.validate(parse);
     RelNode convert = planner.convert(validate);
     RelTraitSet traitSet = planner.getEmptyTraitSet()
@@ -375,12 +434,7 @@ public class PlannerTest {
       return;
     }
     RelNode transform = planner.transform(0, traitSet, convert);
-    assertThat(toString(transform),
-        equalTo("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"));
+    assertThat(toString(transform), equalTo(plan));
   }
 
   /** Unit test that parses, validates, converts and
@@ -655,7 +709,7 @@ public class PlannerTest {
             + "where c.\"city\" = 'San Francisco'\n"
             + "and p.\"brand_name\" = 'Washington'",
         "EnumerableProject(product_id=[$0], time_id=[$1], customer_id=[$2], promotion_id=[$3], store_id=[$4], store_sales=[$5], store_cost=[$6], unit_sales=[$7], customer_id0=[$8], account_num=[$9], lname=[$10], fname=[$11], mi=[$12], address1=[$13], address2=[$14], address3=[$15], address4=[$16], city=[$17], state_province=[$18], postal_code=[$19], country=[$20], customer_region_id=[$21], phone1=[$22], phone2=[$23], birthdate=[$24], marital_status=[$25], yearly_income=[$26], gender=[$27], total_children=[$28], num_children_at_home=[$29], education=[$30], date_accnt_opened=[$31], member_card=[$32], occupation=[$33], houseowner=[$34], num_cars_owned=[$35], fullname=[$36], product_class_id=[$37], product_id0=[$38], brand_name=[$39], product_name=[$40], SKU=[$41], SRP=[$42], gross_weight=[$43], net_weight=[$44], recyclable_package=[$45], low_fat=[$46], units_per_case=[$47], cases_per_pallet=[$48], shelf_width=[$49], shelf_height=[$50], shelf_depth=[$51])\n"
-            + "  EnumerableProject($f0=[$44], $f1=[$45], $f2=[$46], $f3=[$47], $f4=[$48], $f5=[$49], $f6=[$50], $f7=[$51], $f8=[$15], $f9=[$16], $f10=[$17], $f11=[$18], $f12=[$19], $f13=[$20], $f14=[$21], $f15=[$22], $f16=[$23], $f17=[$24], $f18=[$25], $f19=[$26], $f20=[$27], $f21=[$28], $f22=[$29], $f23=[$30], $f24=[$31], $f25=[$32], $f26=[$33], $f27=[$34], $f28=[$35], $f29=[$36], $f30=[$37], $f31=[$38], $f32=[$39], $f33=[$40], $f34=[$41], $f35=[$42], $f36=[$43], $f37=[$0], $f38=[$1], $f39=[$2], $f40=[$3], $f41=[$4], $f42=[$5], $f43=[$6], $f44=[$7], $f45=[$8], $f46=[$9], $f47=[$10], $f48=[$11], $f49=[$12], $f50=[$13], $f51=[$14])\n"
+            + "  EnumerableProject(product_id0=[$44], time_id=[$45], customer_id0=[$46], promotion_id=[$47], store_id=[$48], store_sales=[$49], store_cost=[$50], unit_sales=[$51], customer_id=[$15], account_num=[$16], lname=[$17], fname=[$18], mi=[$19], address1=[$20], address2=[$21], address3=[$22], address4=[$23], city=[$24], state_province=[$25], postal_code=[$26], country=[$27], customer_region_id=[$28], phone1=[$29], phone2=[$30], birthdate=[$31], marital_status=[$32], yearly_income=[$33], gender=[$34], total_children=[$35], num_children_at_home=[$36], education=[$37], date_accnt_opened=[$38], member_card=[$39], occupation=[$40], houseowner=[$41], num_cars_owned=[$42], fullname=[$43], product_class_id=[$0], product_id=[$1], brand_name=[$2], product_name=[$3], SKU=[$4], SRP=[$5], gross_weight=[$6], net_weight=[$7], recyclable_package=[$8], low_fat=[$9], units_per_case=[$10], cases_per_pallet=[$11], shelf_width=[$12], shelf_height=[$13], shelf_depth=[$14])\n"
             + "    EnumerableJoin(condition=[=($1, $44)], joinType=[inner])\n"
             + "      EnumerableFilter(condition=[=($2, 'Washington')])\n"
             + "        EnumerableTableScan(table=[[foodmart2, product]])\n"
@@ -681,7 +735,7 @@ public class PlannerTest {
             + "where c.\"city\" = 'San Francisco'\n"
             + "and p.\"brand_name\" = 'Washington'",
         "EnumerableProject(product_id=[$0], time_id=[$1], customer_id=[$2], promotion_id=[$3], store_id=[$4], store_sales=[$5], store_cost=[$6], unit_sales=[$7], customer_id0=[$8], account_num=[$9], lname=[$10], fname=[$11], mi=[$12], address1=[$13], address2=[$14], address3=[$15], address4=[$16], city=[$17], state_province=[$18], postal_code=[$19], country=[$20], customer_region_id=[$21], phone1=[$22], phone2=[$23], birthdate=[$24], marital_status=[$25], yearly_income=[$26], gender=[$27], total_children=[$28], num_children_at_home=[$29], education=[$30], date_accnt_opened=[$31], member_card=[$32], occupation=[$33], houseowner=[$34], num_cars_owned=[$35], fullname=[$36], product_class_id=[$37], product_id0=[$38], brand_name=[$39], product_name=[$40], SKU=[$41], SRP=[$42], gross_weight=[$43], net_weight=[$44], recyclable_package=[$45], low_fat=[$46], units_per_case=[$47], cases_per_pallet=[$48], shelf_width=[$49], shelf_height=[$50], shelf_depth=[$51], product_class_id0=[$52], produc
 t_subcategory=[$53], product_category=[$54], product_department=[$55], product_family=[$56])\n"
-            + "  EnumerableProject($f0=[$49], $f1=[$50], $f2=[$51], $f3=[$52], $f4=[$53], $f5=[$54], $f6=[$55], $f7=[$56], $f8=[$0], $f9=[$1], $f10=[$2], $f11=[$3], $f12=[$4], $f13=[$5], $f14=[$6], $f15=[$7], $f16=[$8], $f17=[$9], $f18=[$10], $f19=[$11], $f20=[$12], $f21=[$13], $f22=[$14], $f23=[$15], $f24=[$16], $f25=[$17], $f26=[$18], $f27=[$19], $f28=[$20], $f29=[$21], $f30=[$22], $f31=[$23], $f32=[$24], $f33=[$25], $f34=[$26], $f35=[$27], $f36=[$28], $f37=[$34], $f38=[$35], $f39=[$36], $f40=[$37], $f41=[$38], $f42=[$39], $f43=[$40], $f44=[$41], $f45=[$42], $f46=[$43], $f47=[$44], $f48=[$45], $f49=[$46], $f50=[$47], $f51=[$48], $f52=[$29], $f53=[$30], $f54=[$31], $f55=[$32], $f56=[$33])\n"
+            + "  EnumerableProject(product_id0=[$49], time_id=[$50], customer_id0=[$51], promotion_id=[$52], store_id=[$53], store_sales=[$54], store_cost=[$55], unit_sales=[$56], customer_id=[$0], account_num=[$1], lname=[$2], fname=[$3], mi=[$4], address1=[$5], address2=[$6], address3=[$7], address4=[$8], city=[$9], state_province=[$10], postal_code=[$11], country=[$12], customer_region_id=[$13], phone1=[$14], phone2=[$15], birthdate=[$16], marital_status=[$17], yearly_income=[$18], gender=[$19], total_children=[$20], num_children_at_home=[$21], education=[$22], date_accnt_opened=[$23], member_card=[$24], occupation=[$25], houseowner=[$26], num_cars_owned=[$27], fullname=[$28], product_class_id0=[$34], product_id=[$35], brand_name=[$36], product_name=[$37], SKU=[$38], SRP=[$39], gross_weight=[$40], net_weight=[$41], recyclable_package=[$42], low_fat=[$43], units_per_case=[$44], cases_per_pallet=[$45], shelf_width=[$46], shelf_height=[$47], shelf_depth=[$48], product_class_id=[$29]
 , product_subcategory=[$30], product_category=[$31], product_department=[$32], product_family=[$33])\n"
             + "    EnumerableJoin(condition=[=($0, $51)], joinType=[inner])\n"
             + "      EnumerableFilter(condition=[=($9, 'San Francisco')])\n"
             + "        EnumerableTableScan(table=[[foodmart2, customer]])\n"
@@ -704,7 +758,7 @@ public class PlannerTest {
             + "  join \"store\" as st using (\"store_id\")\n"
             + "where c.\"city\" = 'San Francisco'\n",
         "EnumerableProject(product_id=[$0], time_id=[$1], customer_id=[$2], promotion_id=[$3], store_id=[$4], store_sales=[$5], store_cost=[$6], unit_sales=[$7], customer_id0=[$8], account_num=[$9], lname=[$10], fname=[$11], mi=[$12], address1=[$13], address2=[$14], address3=[$15], address4=[$16], city=[$17], state_province=[$18], postal_code=[$19], country=[$20], customer_region_id=[$21], phone1=[$22], phone2=[$23], birthdate=[$24], marital_status=[$25], yearly_income=[$26], gender=[$27], total_children=[$28], num_children_at_home=[$29], education=[$30], date_accnt_opened=[$31], member_card=[$32], occupation=[$33], houseowner=[$34], num_cars_owned=[$35], fullname=[$36], product_class_id=[$37], product_id0=[$38], brand_name=[$39], product_name=[$40], SKU=[$41], SRP=[$42], gross_weight=[$43], net_weight=[$44], recyclable_package=[$45], low_fat=[$46], units_per_case=[$47], cases_per_pallet=[$48], shelf_width=[$49], shelf_height=[$50], shelf_depth=[$51], product_class_id0=[$52], produc
 t_subcategory=[$53], product_category=[$54], product_department=[$55], product_family=[$56], store_id0=[$57], store_type=[$58], region_id=[$59], store_name=[$60], store_number=[$61], store_street_address=[$62], store_city=[$63], store_state=[$64], store_postal_code=[$65], store_country=[$66], store_manager=[$67], store_phone=[$68], store_fax=[$69], first_opened_date=[$70], last_remodel_date=[$71], store_sqft=[$72], grocery_sqft=[$73], frozen_sqft=[$74], meat_sqft=[$75], coffee_bar=[$76], video_store=[$77], salad_bar=[$78], prepared_food=[$79], florist=[$80])\n"
-            + "  EnumerableProject($f0=[$73], $f1=[$74], $f2=[$75], $f3=[$76], $f4=[$77], $f5=[$78], $f6=[$79], $f7=[$80], $f8=[$24], $f9=[$25], $f10=[$26], $f11=[$27], $f12=[$28], $f13=[$29], $f14=[$30], $f15=[$31], $f16=[$32], $f17=[$33], $f18=[$34], $f19=[$35], $f20=[$36], $f21=[$37], $f22=[$38], $f23=[$39], $f24=[$40], $f25=[$41], $f26=[$42], $f27=[$43], $f28=[$44], $f29=[$45], $f30=[$46], $f31=[$47], $f32=[$48], $f33=[$49], $f34=[$50], $f35=[$51], $f36=[$52], $f37=[$58], $f38=[$59], $f39=[$60], $f40=[$61], $f41=[$62], $f42=[$63], $f43=[$64], $f44=[$65], $f45=[$66], $f46=[$67], $f47=[$68], $f48=[$69], $f49=[$70], $f50=[$71], $f51=[$72], $f52=[$53], $f53=[$54], $f54=[$55], $f55=[$56], $f56=[$57], $f57=[$0], $f58=[$1], $f59=[$2], $f60=[$3], $f61=[$4], $f62=[$5], $f63=[$6], $f64=[$7], $f65=[$8], $f66=[$9], $f67=[$10], $f68=[$11], $f69=[$12], $f70=[$13], $f71=[$14], $f72=[$15], $f73=[$16], $f74=[$17], $f75=[$18], $f76=[$19], $f77=[$20], $f78=[$21], $f79=[$22], $f80=[$23])\n"
+            + "  EnumerableProject(product_id0=[$73], time_id=[$74], customer_id0=[$75], promotion_id=[$76], store_id0=[$77], store_sales=[$78], store_cost=[$79], unit_sales=[$80], customer_id=[$24], account_num=[$25], lname=[$26], fname=[$27], mi=[$28], address1=[$29], address2=[$30], address3=[$31], address4=[$32], city=[$33], state_province=[$34], postal_code=[$35], country=[$36], customer_region_id=[$37], phone1=[$38], phone2=[$39], birthdate=[$40], marital_status=[$41], yearly_income=[$42], gender=[$43], total_children=[$44], num_children_at_home=[$45], education=[$46], date_accnt_opened=[$47], member_card=[$48], occupation=[$49], houseowner=[$50], num_cars_owned=[$51], fullname=[$52], product_class_id0=[$58], product_id=[$59], brand_name=[$60], product_name=[$61], SKU=[$62], SRP=[$63], gross_weight=[$64], net_weight=[$65], recyclable_package=[$66], low_fat=[$67], units_per_case=[$68], cases_per_pallet=[$69], shelf_width=[$70], shelf_height=[$71], shelf_depth=[$72], product_cla
 ss_id=[$53], product_subcategory=[$54], product_category=[$55], product_department=[$56], product_family=[$57], store_id=[$0], store_type=[$1], region_id=[$2], store_name=[$3], store_number=[$4], store_street_address=[$5], store_city=[$6], store_state=[$7], store_postal_code=[$8], store_country=[$9], store_manager=[$10], store_phone=[$11], store_fax=[$12], first_opened_date=[$13], last_remodel_date=[$14], store_sqft=[$15], grocery_sqft=[$16], frozen_sqft=[$17], meat_sqft=[$18], coffee_bar=[$19], video_store=[$20], salad_bar=[$21], prepared_food=[$22], florist=[$23])\n"
             + "    EnumerableJoin(condition=[=($0, $77)], joinType=[inner])\n"
             + "      EnumerableTableScan(table=[[foodmart2, store]])\n"
             + "      EnumerableJoin(condition=[=($0, $51)], joinType=[inner])\n"
@@ -724,8 +778,7 @@ public class PlannerTest {
             + "join \"customer\" using (\"customer_id\")\n"
             + "cross join \"department\"",
         "EnumerableProject(product_id=[$0], time_id=[$1], customer_id=[$2], promotion_id=[$3], store_id=[$4], store_sales=[$5], store_cost=[$6], unit_sales=[$7], customer_id0=[$8], account_num=[$9], lname=[$10], fname=[$11], mi=[$12], address1=[$13], address2=[$14], address3=[$15], address4=[$16], city=[$17], state_province=[$18], postal_code=[$19], country=[$20], customer_region_id=[$21], phone1=[$22], phone2=[$23], birthdate=[$24], marital_status=[$25], yearly_income=[$26], gender=[$27], total_children=[$28], num_children_at_home=[$29], education=[$30], date_accnt_opened=[$31], member_card=[$32], occupation=[$33], houseowner=[$34], num_cars_owned=[$35], fullname=[$36], department_id=[$37], department_description=[$38])\n"
-            + "  EnumerableProject($f0=[$31], $f1=[$32], $f2=[$33], $f3=[$34], $f4=[$35], $f5=[$36], $f6=[$37], $f7=[$38], $f8=[$2], $f9=[$3], $f10=[$4], $f11=[$5], $f12=[$6], $f13=[$7], $f14=[$8], $f15=[$9], $f16=[$10], $f17=[$11], $f18=[$12], $f19=[$13], $f20=[$14], $f21=[$15], $f22=[$16], $f23=[$17], $f24=[$18], $f25=[$19], $f26=[$20], $f27=[$21], $f28=[$22], $f29=[$23], $f30=[$24], $f31=[$25], $f32=[$26], $f33=[$27], $f34=[$28], $f35=[$29], $f36=[$30], $f37=[$0], $f38=[$1])\n"
-            //+ "    EnumerableMergeJoin(condition=[true], joinType=[inner])\n"
+            + "  EnumerableProject(product_id=[$31], time_id=[$32], customer_id0=[$33], promotion_id=[$34], store_id=[$35], store_sales=[$36], store_cost=[$37], unit_sales=[$38], customer_id=[$2], account_num=[$3], lname=[$4], fname=[$5], mi=[$6], address1=[$7], address2=[$8], address3=[$9], address4=[$10], city=[$11], state_province=[$12], postal_code=[$13], country=[$14], customer_region_id=[$15], phone1=[$16], phone2=[$17], birthdate=[$18], marital_status=[$19], yearly_income=[$20], gender=[$21], total_children=[$22], num_children_at_home=[$23], education=[$24], date_accnt_opened=[$25], member_card=[$26], occupation=[$27], houseowner=[$28], num_cars_owned=[$29], fullname=[$30], department_id=[$0], department_description=[$1])\n"
             + "    EnumerableJoin(condition=[true], joinType=[inner])\n"
             + "      EnumerableTableScan(table=[[foodmart2, department]])\n"
             + "      EnumerableJoin(condition=[=($0, $31)], joinType=[inner])\n"
@@ -741,8 +794,7 @@ public class PlannerTest {
             + "cross join \"department\"\n"
             + "join \"employee\" using (\"department_id\")",
         "EnumerableProject(product_id=[$0], time_id=[$1], customer_id=[$2], promotion_id=[$3], store_id=[$4], store_sales=[$5], store_cost=[$6], unit_sales=[$7], customer_id0=[$8], account_num=[$9], lname=[$10], fname=[$11], mi=[$12], address1=[$13], address2=[$14], address3=[$15], address4=[$16], city=[$17], state_province=[$18], postal_code=[$19], country=[$20], customer_region_id=[$21], phone1=[$22], phone2=[$23], birthdate=[$24], marital_status=[$25], yearly_income=[$26], gender=[$27], total_children=[$28], num_children_at_home=[$29], education=[$30], date_accnt_opened=[$31], member_card=[$32], occupation=[$33], houseowner=[$34], num_cars_owned=[$35], fullname=[$36], department_id=[$37], department_description=[$38], employee_id=[$39], full_name=[$40], first_name=[$41], last_name=[$42], position_id=[$43], position_title=[$44], store_id0=[$45], department_id0=[$46], birth_date=[$47], hire_date=[$48], end_date=[$49], salary=[$50], supervisor_id=[$51], education_level=[$52], marita
 l_status0=[$53], gender0=[$54], management_role=[$55])\n"
-            + "  EnumerableProject($f0=[$48], $f1=[$49], $f2=[$50], $f3=[$51], $f4=[$52], $f5=[$53], $f6=[$54], $f7=[$55], $f8=[$19], $f9=[$20], $f10=[$21], $f11=[$22], $f12=[$23], $f13=[$24], $f14=[$25], $f15=[$26], $f16=[$27], $f17=[$28], $f18=[$29], $f19=[$30], $f20=[$31], $f21=[$32], $f22=[$33], $f23=[$34], $f24=[$35], $f25=[$36], $f26=[$37], $f27=[$38], $f28=[$39], $f29=[$40], $f30=[$41], $f31=[$42], $f32=[$43], $f33=[$44], $f34=[$45], $f35=[$46], $f36=[$47], $f37=[$0], $f38=[$1], $f39=[$2], $f40=[$3], $f41=[$4], $f42=[$5], $f43=[$6], $f44=[$7], $f45=[$8], $f46=[$9], $f47=[$10], $f48=[$11], $f49=[$12], $f50=[$13], $f51=[$14], $f52=[$15], $f53=[$16], $f54=[$17], $f55=[$18])\n"
-            // + "    EnumerableMergeJoin(condition=[true], joinType=[inner])\n"
+            + "  EnumerableProject(product_id=[$48], time_id=[$49], customer_id0=[$50], promotion_id=[$51], store_id0=[$52], store_sales=[$53], store_cost=[$54], unit_sales=[$55], customer_id=[$19], account_num=[$20], lname=[$21], fname=[$22], mi=[$23], address1=[$24], address2=[$25], address3=[$26], address4=[$27], city=[$28], state_province=[$29], postal_code=[$30], country=[$31], customer_region_id=[$32], phone1=[$33], phone2=[$34], birthdate=[$35], marital_status0=[$36], yearly_income=[$37], gender0=[$38], total_children=[$39], num_children_at_home=[$40], education=[$41], date_accnt_opened=[$42], member_card=[$43], occupation=[$44], houseowner=[$45], num_cars_owned=[$46], fullname=[$47], department_id=[$0], department_description=[$1], employee_id=[$2], full_name=[$3], first_name=[$4], last_name=[$5], position_id=[$6], position_title=[$7], store_id=[$8], department_id0=[$9], birth_date=[$10], hire_date=[$11], end_date=[$12], salary=[$13], supervisor_id=[$14], education_level=[$1
 5], marital_status=[$16], gender=[$17], management_role=[$18])\n"
             + "    EnumerableJoin(condition=[true], joinType=[inner])\n"
             + "      EnumerableJoin(condition=[=($0, $9)], joinType=[inner])\n"
             + "        EnumerableTableScan(table=[[foodmart2, department]])\n"
@@ -867,7 +919,7 @@ public class PlannerTest {
             + "    where\n"
             + "      p.`pPartkey` = ps.`psPartkey`\n"
             + "  )\n")
-            .contains("Correlator"));
+            .contains("Correlat"));
   }
 
   public String checkTpchQuery(String tpchTestQuery) throws Exception {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/8f1e3b28/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 a81cfdc..e305849 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -2808,7 +2808,7 @@ LogicalProject(DEPTNO=[$0], NAME=[$1])
       LogicalJoin(condition=[=($0, $2)], joinType=[left])
         LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
         LogicalAggregate(group=[{0}], agg#0=[MIN($1)])
-          LogicalProject($f01=[$2], $f0=[true])
+          LogicalProject(DEPTNO0=[$2], $f0=[true])
             LogicalFilter(condition=[AND(=($1, $2), >($0, 100))])
               LogicalJoin(condition=[true], joinType=[inner])
                 LogicalProject(SAL=[$5], DEPTNO=[$7])
@@ -2822,11 +2822,11 @@ LogicalProject(DEPTNO=[$0], NAME=[$1])
             <![CDATA[
 LogicalProject(DEPTNO=[$0], NAME=[$1])
   LogicalProject(DEPTNO=[$0], NAME=[$1], $f0=[$3])
-    LogicalProject(DEPTNO=[$0], NAME=[$1], $f01=[CAST($2):INTEGER], $f1=[CAST($3):BOOLEAN])
+    LogicalProject(DEPTNO=[$0], NAME=[$1], DEPTNO0=[CAST($2):INTEGER], $f1=[CAST($3):BOOLEAN])
       LogicalJoin(condition=[=($0, $2)], joinType=[inner])
         LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
         LogicalAggregate(group=[{0}], agg#0=[MIN($1)])
-          LogicalProject($f01=[$2], $f0=[true])
+          LogicalProject(DEPTNO0=[$2], $f0=[true])
             LogicalJoin(condition=[=($1, $2)], joinType=[inner])
               LogicalFilter(condition=[>($0, 100)])
                 LogicalProject(SAL=[$5], DEPTNO=[$7])
@@ -2850,7 +2850,7 @@ LogicalProject(DEPTNO=[$0], NAME=[$1])
   LogicalJoin(condition=[=($0, $2)], joinType=[inner])
     LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
     LogicalAggregate(group=[{0}], agg#0=[MIN($1)])
-      LogicalProject($f01=[$2], $f0=[true])
+      LogicalProject(DEPTNO0=[$2], $f0=[true])
         LogicalJoin(condition=[=($1, $2)], joinType=[inner])
           LogicalFilter(condition=[>($0, 100)])
             LogicalProject(SAL=[$5], DEPTNO=[$7])
@@ -2864,7 +2864,7 @@ LogicalProject(DEPTNO=[$0], NAME=[$1])
             <![CDATA[
 SemiJoin(condition=[=($0, $2)], joinType=[inner])
   LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
-  LogicalProject($f01=[$2], $f0=[true])
+  LogicalProject(DEPTNO0=[$2], $f0=[true])
     LogicalJoin(condition=[=($1, $2)], joinType=[inner])
       LogicalFilter(condition=[>($0, 100)])
         LogicalProject(SAL=[$5], DEPTNO=[$7])
@@ -2888,12 +2888,12 @@ LogicalProject(DEPTNO=[$0])
   LogicalJoin(condition=[=($0, $2)], joinType=[inner])
     SemiJoin(condition=[=($0, $2)], joinType=[inner])
       LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
-      LogicalProject($f01=[$9], $f0=[true])
+      LogicalProject(DEPTNO0=[$9], $f0=[true])
         LogicalJoin(condition=[=($7, $9)], joinType=[inner])
           LogicalFilter(condition=[>($5, 100)])
             LogicalTableScan(table=[[CATALOG, SALES, EMP]])
           LogicalAggregate(group=[{0}])
-            LogicalProject($f0=[$0])
+            LogicalProject(DEPTNO=[$0])
               LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
     LogicalTableScan(table=[[CATALOG, CUSTOMER, ACCOUNT]])
 ]]>
@@ -2905,7 +2905,7 @@ LogicalProject(DEPTNO=[$0])
     SemiJoin(condition=[=($0, $1)], joinType=[inner])
       LogicalProject(DEPTNO=[$0])
         LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
-      LogicalProject($f01=[$2])
+      LogicalProject(DEPTNO0=[$2])
         LogicalJoin(condition=[=($1, $2)], joinType=[inner])
           LogicalFilter(condition=[>($0, 100)])
             LogicalProject(SAL=[$5], DEPTNO=[$7])
@@ -2937,7 +2937,7 @@ LogicalProject(X=[$0], EXPR$1=[$2], Y=[$1])
         <Resource name="planAfter">
             <![CDATA[
 LogicalProject(X=[$0], EXPR$1=[$2], Y=[$1])
-  LogicalProject($f0=[$1], $f1=[$0], $f2=[$2])
+  LogicalProject(DEPTNO=[$1], EMPNO=[$0], EXPR$1=[$2])
     LogicalAggregate(group=[{0, 7}], EXPR$1=[SUM($5)])
       LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
@@ -2964,7 +2964,7 @@ LogicalProject(X=[$0], EXPR$1=[$4], Y=[$1])
             <![CDATA[
 LogicalProject(X=[$0], EXPR$1=[$4], Y=[$1])
   LogicalProject(X=[CASE($2, null, $0)], Y=[CASE($3, null, $1)], i$X=[$2], i$Y=[$3], EXPR$1=[$4])
-    LogicalProject($f0=[$1], $f1=[$0], $f2=[$3], $f3=[$2], $f4=[$4])
+    LogicalProject(DEPTNO=[$1], EMPNO=[$0], i$DEPTNO=[$3], i$EMPNO=[$2], EXPR$1=[$4])
       LogicalAggregate(group=[{0, 7}], groups=[[{0, 7}, {7}, {}]], indicator=[true], EXPR$1=[SUM($5)])
         LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/8f1e3b28/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 22ea262..551c9ec 100644
--- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
@@ -1678,12 +1678,12 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
 LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], DEPTNO0=[$9], NAME=[$10])
   LogicalJoin(condition=[=($7, $11)], joinType=[inner])
     LogicalTableScan(table=[[CATALOG, SALES, EMP]])
-    LogicalProject(DEPTNO=[$0], NAME=[$1], $f0=[$2])
+    LogicalProject(DEPTNO=[$0], NAME=[$1], DEPTNO0=[$2])
       LogicalFilter(condition=[=($2, $0)])
         LogicalJoin(condition=[true], joinType=[inner])
           LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
           LogicalAggregate(group=[{0}])
-            LogicalProject($f0=[$7])
+            LogicalProject(DEPTNO=[$7])
               LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
         </Resource>
@@ -1734,19 +1734,19 @@ LogicalProject(D2=[$0], D3=[$1])
         LogicalProject(D2=[+(2, $7)], D3=[+(3, $7)])
           LogicalTableScan(table=[[CATALOG, SALES, EMP]])
         LogicalAggregate(group=[{0, 1}], agg#0=[MIN($2)])
-          LogicalProject($f00=[$1], $f03=[$2], $f0=[$0])
-            LogicalProject($f0=[true], $f00=[$1], $f03=[$2])
-              LogicalProject(EXPR$0=[1], $f00=[$3], $f03=[$2])
+          LogicalProject(D2=[$1], D3=[$2], $f0=[$0])
+            LogicalProject($f0=[true], D2=[$1], D3=[$2])
+              LogicalProject(EXPR$0=[1], D2=[$3], D3=[$2])
                 LogicalFilter(condition=[AND(=($0, $3), IS NOT NULL($1))])
                   LogicalJoin(condition=[true], joinType=[inner])
-                    LogicalProject(D1=[$0], $f0=[$4], $f03=[$3])
+                    LogicalProject(D1=[$0], $f0=[$4], D3=[$3])
                       LogicalJoin(condition=[AND(=($0, $1), =($0, $2))], joinType=[left])
                         LogicalProject(D1=[+($0, 1)])
                           LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
                         LogicalAggregate(group=[{0, 1, 2}], agg#0=[MIN($3)])
-                          LogicalProject(D1=[$1], D12=[$2], $f03=[$3], $f0=[$0])
-                            LogicalProject($f0=[true], D1=[$1], D12=[$2], $f03=[$3])
-                              LogicalProject(EXPR$0=[2], D1=[$3], D12=[$3], $f0=[$4])
+                          LogicalProject(D1=[$1], D12=[$2], D3=[$3], $f0=[$0])
+                            LogicalProject($f0=[true], D1=[$1], D12=[$2], D3=[$3])
+                              LogicalProject(EXPR$0=[2], D1=[$3], D12=[$3], D3=[$4])
                                 LogicalFilter(condition=[AND(=($0, $3), =($1, $3), =($2, $4))])
                                   LogicalJoin(condition=[true], joinType=[inner])
                                     LogicalProject(D4=[+($0, 4)], D5=[+($0, 5)], D6=[+($0, 6)])
@@ -1756,11 +1756,11 @@ LogicalProject(D2=[$0], D3=[$1])
                                         LogicalProject(D1=[+($0, 1)])
                                           LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
                                       LogicalAggregate(group=[{0}])
-                                        LogicalProject($f0=[$1])
+                                        LogicalProject(D3=[$1])
                                           LogicalProject(D2=[+(2, $7)], D3=[+(3, $7)])
                                             LogicalTableScan(table=[[CATALOG, SALES, EMP]])
                     LogicalAggregate(group=[{0}])
-                      LogicalProject($f0=[$0])
+                      LogicalProject(D2=[$0])
                         LogicalProject(D2=[+(2, $7)], D3=[+(3, $7)])
                           LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
@@ -1781,20 +1781,20 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
       LogicalJoin(condition=[AND(=($7, $9), =($7, $10))], joinType=[left])
         LogicalTableScan(table=[[CATALOG, SALES, EMP]])
         LogicalAggregate(group=[{0, 1}], agg#0=[MIN($2)])
-          LogicalProject($f00=[$1], $f02=[$2], $f0=[$0])
-            LogicalProject($f0=[true], $f00=[$1], $f02=[$2])
-              LogicalProject(EXPR$0=[1], $f00=[$3], $f0=[$2])
+          LogicalProject(DEPTNO1=[$1], DEPTNO0=[$2], $f0=[$0])
+            LogicalProject($f0=[true], DEPTNO1=[$1], DEPTNO0=[$2])
+              LogicalProject(EXPR$0=[1], DEPTNO1=[$3], DEPTNO0=[$2])
                 LogicalFilter(condition=[<=($0, $3)])
                   LogicalJoin(condition=[true], joinType=[inner])
-                    LogicalProject(DEPTNO=[$0], NAME=[$1], $f0=[$2])
+                    LogicalProject(DEPTNO=[$0], NAME=[$1], DEPTNO0=[$2])
                       LogicalFilter(condition=[>=($0, $2)])
                         LogicalJoin(condition=[true], joinType=[inner])
                           LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
                           LogicalAggregate(group=[{0}])
-                            LogicalProject($f0=[$7])
+                            LogicalProject(DEPTNO=[$7])
                               LogicalTableScan(table=[[CATALOG, SALES, EMP]])
                     LogicalAggregate(group=[{0}])
-                      LogicalProject($f0=[$7])
+                      LogicalProject(DEPTNO=[$7])
                         LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
         </Resource>
@@ -1811,14 +1811,14 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
       LogicalJoin(condition=[=($7, $9)], joinType=[left])
         LogicalTableScan(table=[[CATALOG, SALES, EMP]])
         LogicalAggregate(group=[{0}], agg#0=[MIN($1)])
-          LogicalProject($f01=[$1], $f0=[$0])
-            LogicalProject($f0=[true], $f01=[$1])
-              LogicalProject(EXPR$0=[1], $f0=[$2])
+          LogicalProject(DEPTNO0=[$1], $f0=[$0])
+            LogicalProject($f0=[true], DEPTNO0=[$1])
+              LogicalProject(EXPR$0=[1], DEPTNO0=[$2])
                 LogicalFilter(condition=[=($2, $0)])
                   LogicalJoin(condition=[true], joinType=[inner])
                     LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
                     LogicalAggregate(group=[{0}])
-                      LogicalProject($f0=[$7])
+                      LogicalProject(DEPTNO=[$7])
                         LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
         </Resource>

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/8f1e3b28/core/src/test/resources/sql/misc.oq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/misc.oq b/core/src/test/resources/sql/misc.oq
index 142eba6..7b8ccb7 100644
--- a/core/src/test/resources/sql/misc.oq
+++ b/core/src/test/resources/sql/misc.oq
@@ -244,10 +244,10 @@ where exists (
 !ok
 EnumerableSemiJoin(condition=[=($1, $5)], joinType=[inner])
   EnumerableTableScan(table=[[hr, emps]])
-  EnumerableCalc(expr#0..4=[{inputs}], expr#5=[true], $f01=[$t0], $f0=[$t5])
+  EnumerableCalc(expr#0..4=[{inputs}], expr#5=[true], deptno0=[$t0], $f0=[$t5])
     EnumerableJoin(condition=[=($0, $1)], joinType=[inner])
       EnumerableAggregate(group=[{0}])
-        EnumerableCalc(expr#0..4=[{inputs}], $f0=[$t1])
+        EnumerableCalc(expr#0..4=[{inputs}], deptno=[$t1])
           EnumerableTableScan(table=[[hr, emps]])
       EnumerableTableScan(table=[[hr, depts]])
 !plan
@@ -269,10 +269,10 @@ EnumerableCalc(expr#0..6=[{inputs}], expr#7=[IS NOT NULL($t6)], expr#8=[NOT($t7)
   EnumerableJoin(condition=[=($1, $5)], joinType=[left])
     EnumerableTableScan(table=[[hr, emps]])
     EnumerableAggregate(group=[{0}], agg#0=[MIN($1)])
-      EnumerableCalc(expr#0..4=[{inputs}], expr#5=[true], $f01=[$t0], $f0=[$t5])
+      EnumerableCalc(expr#0..4=[{inputs}], expr#5=[true], deptno0=[$t0], $f0=[$t5])
         EnumerableJoin(condition=[=($0, $1)], joinType=[inner])
           EnumerableAggregate(group=[{0}])
-            EnumerableCalc(expr#0..4=[{inputs}], $f0=[$t1])
+            EnumerableCalc(expr#0..4=[{inputs}], deptno=[$t1])
               EnumerableTableScan(table=[[hr, emps]])
           EnumerableTableScan(table=[[hr, depts]])
 !plan
@@ -301,23 +301,23 @@ EnumerableCalc(expr#0..7=[{inputs}], expr#8=[IS NOT NULL($t5)], expr#9=[NOT($t8)
       EnumerableJoin(condition=[=($1, $5)], joinType=[left])
         EnumerableTableScan(table=[[hr, emps]])
         EnumerableAggregate(group=[{0}], agg#0=[MIN($1)])
-          EnumerableCalc(expr#0..4=[{inputs}], expr#5=[true], $f01=[$t0], $f0=[$t5])
+          EnumerableCalc(expr#0..4=[{inputs}], expr#5=[true], deptno0=[$t0], $f0=[$t5])
             EnumerableJoin(condition=[=($0, $1)], joinType=[inner])
               EnumerableAggregate(group=[{0}])
-                EnumerableCalc(expr#0..4=[{inputs}], $f0=[$t1])
+                EnumerableCalc(expr#0..4=[{inputs}], deptno=[$t1])
                   EnumerableTableScan(table=[[hr, emps]])
               EnumerableTableScan(table=[[hr, depts]])
     EnumerableAggregate(group=[{0}], agg#0=[MIN($1)])
-      EnumerableCalc(expr#0..4=[{inputs}], expr#5=[true], expr#6=[90], expr#7=[+($t1, $t6)], expr#8=[CAST($t0):INTEGER NOT NULL], expr#9=[=($t7, $t8)], $f01=[$t0], $f0=[$t5], $condition=[$t9])
+      EnumerableCalc(expr#0..4=[{inputs}], expr#5=[true], expr#6=[90], expr#7=[+($t1, $t6)], expr#8=[CAST($t0):INTEGER NOT NULL], expr#9=[=($t7, $t8)], empid=[$t0], $f0=[$t5], $condition=[$t9])
         EnumerableJoin(condition=[true], joinType=[inner])
           EnumerableAggregate(group=[{0}])
-            EnumerableCalc(expr#0..4=[{inputs}], $f0=[$t0])
+            EnumerableCalc(expr#0..4=[{inputs}], empid=[$t0])
               EnumerableSemiJoin(condition=[=($1, $5)], joinType=[inner])
                 EnumerableTableScan(table=[[hr, emps]])
-                EnumerableCalc(expr#0..4=[{inputs}], expr#5=[true], $f01=[$t0], $f0=[$t5])
+                EnumerableCalc(expr#0..4=[{inputs}], expr#5=[true], deptno0=[$t0], $f0=[$t5])
                   EnumerableJoin(condition=[=($0, $1)], joinType=[inner])
                     EnumerableAggregate(group=[{0}])
-                      EnumerableCalc(expr#0..4=[{inputs}], $f0=[$t1])
+                      EnumerableCalc(expr#0..4=[{inputs}], deptno=[$t1])
                         EnumerableTableScan(table=[[hr, emps]])
                     EnumerableTableScan(table=[[hr, depts]])
           EnumerableTableScan(table=[[hr, depts]])
@@ -480,7 +480,7 @@ from "sales_fact_1997" as s
   join "product_class" as pc using ("product_class_id")
 where c."city" = 'San Francisco'
  and pc."product_department" = 'Snacks';
-EnumerableCalc(expr#0..56=[{inputs}], product_id=[$t20], time_id=[$t21], customer_id=[$t22], promotion_id=[$t23], store_id=[$t24], store_sales=[$t25], store_cost=[$t26], unit_sales=[$t27], customer_id0=[$t28], account_num=[$t29], lname=[$t30], fname=[$t31], mi=[$t32], address1=[$t33], address2=[$t34], address3=[$t35], address4=[$t36], city=[$t37], state_province=[$t38], postal_code=[$t39], country=[$t40], customer_region_id=[$t41], phone1=[$t42], phone2=[$t43], birthdate=[$t44], marital_status=[$t45], yearly_income=[$t46], gender=[$t47], total_children=[$t48], num_children_at_home=[$t49], education=[$t50], date_accnt_opened=[$t51], member_card=[$t52], occupation=[$t53], houseowner=[$t54], num_cars_owned=[$t55], fullname=[$t56], product_class_id=[$t5], product_id0=[$t6], brand_name=[$t7], product_name=[$t8], SKU=[$t9], SRP=[$t10], gross_weight=[$t11], net_weight=[$t12], recyclable_package=[$t13], low_fat=[$t14], units_per_case=[$t15], cases_per_pallet=[$t16], shelf_width=[$t17], shel
 f_height=[$t18], shelf_depth=[$t19], product_class_id0=[$t0], product_subcategory=[$t1], product_category=[$t2], product_department=[$t3], product_family=[$t4])
+EnumerableCalc(expr#0..56=[{inputs}], product_id0=[$t20], time_id=[$t21], customer_id=[$t22], promotion_id=[$t23], store_id=[$t24], store_sales=[$t25], store_cost=[$t26], unit_sales=[$t27], customer_id0=[$t28], account_num=[$t29], lname=[$t30], fname=[$t31], mi=[$t32], address1=[$t33], address2=[$t34], address3=[$t35], address4=[$t36], city=[$t37], state_province=[$t38], postal_code=[$t39], country=[$t40], customer_region_id=[$t41], phone1=[$t42], phone2=[$t43], birthdate=[$t44], marital_status=[$t45], yearly_income=[$t46], gender=[$t47], total_children=[$t48], num_children_at_home=[$t49], education=[$t50], date_accnt_opened=[$t51], member_card=[$t52], occupation=[$t53], houseowner=[$t54], num_cars_owned=[$t55], fullname=[$t56], product_class_id0=[$t5], product_id=[$t6], brand_name=[$t7], product_name=[$t8], SKU=[$t9], SRP=[$t10], gross_weight=[$t11], net_weight=[$t12], recyclable_package=[$t13], low_fat=[$t14], units_per_case=[$t15], cases_per_pallet=[$t16], shelf_width=[$t17], she
 lf_height=[$t18], shelf_depth=[$t19], product_class_id=[$t0], product_subcategory=[$t1], product_category=[$t2], product_department=[$t3], product_family=[$t4])
   EnumerableJoin(condition=[=($6, $20)], joinType=[inner])
     EnumerableJoin(condition=[=($0, $5)], joinType=[inner])
       EnumerableCalc(expr#0..4=[{inputs}], expr#5=['Snacks'], expr#6=[=($t3, $t5)], proj#0..4=[{exprs}], $condition=[$t6])


[4/9] incubator-calcite git commit: [CALCITE-88] Add collation as a trait and a kind of RelNode metadata

Posted by jh...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java b/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
index e108c78..2b129bb 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
@@ -36,6 +36,7 @@ import org.apache.calcite.rel.core.TableScan;
 import org.apache.calcite.rel.logical.LogicalTableFunctionScan;
 import org.apache.calcite.rel.logical.LogicalTableModify;
 import org.apache.calcite.rel.logical.LogicalValues;
+import org.apache.calcite.rel.metadata.RelMetadataQuery;
 import org.apache.calcite.rel.rules.ProjectRemoveRule;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeField;
@@ -157,9 +158,8 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
    * @param setOpFactory SetOp factory
    * @param useNamesInIdentityProjCalc
    *            Include field names in identity project determination
-   *
-   * @deprecated Remove before
-   * {@link org.apache.calcite.util.Bug#upgrade Calcite-1.1}. */
+   */
+  @Deprecated // to be removed before 1.1
   public RelFieldTrimmer(SqlValidator validator,
       RelFactories.ProjectFactory projectFactory,
       RelFactories.FilterFactory filterFactory,
@@ -231,6 +231,13 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
       // So, disable trimming.
       fieldsUsed = ImmutableBitSet.range(input.getRowType().getFieldCount());
     }
+    final ImmutableList<RelCollation> collations =
+        RelMetadataQuery.collations(rel);
+    for (RelCollation collation : collations) {
+      for (RelFieldCollation fieldCollation : collation.getFieldCollations()) {
+        fieldsUsed = fieldsUsed.set(fieldCollation.getFieldIndex());
+      }
+    }
     return dispatchTrimFields(input, fieldsUsed, extraFields);
   }
 
@@ -1014,7 +1021,8 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
         RelOptUtil.permute(values.getCluster().getTypeFactory(), rowType,
             mapping);
     final LogicalValues newValues =
-        new LogicalValues(values.getCluster(), newRowType, newTuples.build());
+        LogicalValues.create(values.getCluster(), newRowType,
+            newTuples.build());
     return new TrimResult(newValues, mapping);
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/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 aa8e548..8fa93a1 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/RelStructuredTypeFlattener.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/RelStructuredTypeFlattener.java
@@ -70,7 +70,6 @@ import org.apache.calcite.util.Util;
 import org.apache.calcite.util.mapping.Mappings;
 
 import com.google.common.base.Function;
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.SortedSetMultimap;
@@ -342,14 +341,9 @@ public class RelStructuredTypeFlattener implements ReflectiveVisitor {
 
   public void rewriteRel(LogicalTableModify rel) {
     LogicalTableModify newRel =
-        new LogicalTableModify(
-            rel.getCluster(),
-            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);
   }
 
@@ -398,8 +392,7 @@ public class RelStructuredTypeFlattener implements ReflectiveVisitor {
 
   public void rewriteRel(LogicalJoin rel) {
     LogicalJoin newRel =
-        new LogicalJoin(
-            rel.getCluster(),
+        LogicalJoin.create(
             getNewForOldRel(rel.getLeft()),
             getNewForOldRel(rel.getRight()),
             rel.getCondition().accept(new RewriteRexShuttle()),
@@ -420,9 +413,7 @@ public class RelStructuredTypeFlattener implements ReflectiveVisitor {
       newPos.set(getNewForOldInput(pos));
     }
     LogicalCorrelate newRel =
-        new LogicalCorrelate(
-            rel.getCluster(),
-            getNewForOldRel(rel.getLeft()),
+        LogicalCorrelate.create(getNewForOldRel(rel.getLeft()),
             getNewForOldRel(rel.getRight()),
             rel.getCorrelationId(),
             newPos.build(),
@@ -483,12 +474,12 @@ public class RelStructuredTypeFlattener implements ReflectiveVisitor {
 
   public void rewriteRel(LogicalCalc rel) {
     // Translate the child.
-    final RelNode newChild = getNewForOldRel(rel.getInput());
+    final RelNode newInput = getNewForOldRel(rel.getInput());
 
     final RelOptCluster cluster = rel.getCluster();
     RexProgramBuilder programBuilder =
         new RexProgramBuilder(
-            newChild.getRowType(),
+            newInput.getRowType(),
             cluster.getRexBuilder());
 
     // Convert the common expressions.
@@ -524,13 +515,7 @@ public class RelStructuredTypeFlattener implements ReflectiveVisitor {
     RexProgram newProgram = programBuilder.getProgram();
 
     // Create a new calc relational expression.
-    LogicalCalc newRel =
-        new LogicalCalc(
-            cluster,
-            rel.getTraitSet(),
-            newChild,
-            newProgram,
-            ImmutableList.<RelCollation>of());
+    LogicalCalc newRel = LogicalCalc.create(newInput, newProgram);
     setNewForOldRel(rel, newRel);
   }
 
@@ -640,10 +625,7 @@ public class RelStructuredTypeFlattener implements ReflectiveVisitor {
       RelDataType type,
       List<Pair<RexNode, String>> flattenedExps) {
     RelDataType flattenedType =
-        SqlTypeUtil.flattenRecordType(
-            rexBuilder.getTypeFactory(),
-            type,
-            null);
+        SqlTypeUtil.flattenRecordType(rexBuilder.getTypeFactory(), type, null);
     for (RelDataTypeField field : flattenedType.getFieldList()) {
       flattenedExps.add(
           Pair.of(

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/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 2eb7d2c..0ace1e9 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -27,7 +27,7 @@ import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.prepare.Prepare;
 import org.apache.calcite.prepare.RelOptTableImpl;
 import org.apache.calcite.rel.RelCollation;
-import org.apache.calcite.rel.RelCollationImpl;
+import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.RelFieldCollation;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelShuttle;
@@ -602,7 +602,7 @@ public class SqlToRelConverter {
         orderExprList,
         collationList);
     final RelCollation collation =
-        cluster.traitSetOf().canonize(RelCollationImpl.of(collationList));
+        cluster.traitSet().canonize(RelCollations.of(collationList));
 
     if (validator.isAggregate(select)) {
       convertAgg(
@@ -674,12 +674,8 @@ public class SqlToRelConverter {
         }
       }
       rel =
-          new LogicalProject(
-              cluster,
-              rel,
-              Pair.left(newProjects),
+          LogicalProject.create(rel, Pair.left(newProjects),
               Pair.right(newProjects));
-
       bb.root = rel;
       distinctify(bb, false);
       rel = bb.root;
@@ -698,12 +694,8 @@ public class SqlToRelConverter {
       }
 
       rel =
-          new LogicalProject(
-              cluster,
-              rel,
-              Pair.left(undoProjects),
+          LogicalProject.create(rel, Pair.left(undoProjects),
               Pair.right(undoProjects));
-
       bb.setRoot(
           rel,
           false);
@@ -780,7 +772,7 @@ public class SqlToRelConverter {
       bb.setRoot(
           new LogicalProject(
               cluster,
-              cluster.traitSetOf(RelCollationImpl.PRESERVE),
+              cluster.traitSetOf(RelCollations.PRESERVE),
               bb.root,
               exprs,
               cluster.getTypeFactory().createStructType(
@@ -1030,16 +1022,17 @@ public class SqlToRelConverter {
         final int keyCount = leftKeys.size();
         final List<Integer> args = ImmutableIntList.range(0, keyCount);
         LogicalAggregate aggregate =
-            new LogicalAggregate(cluster, seek, false, ImmutableBitSet.of(),
-                null,
+            LogicalAggregate.create(seek, false, ImmutableBitSet.of(), null,
                 ImmutableList.of(
                     new AggregateCall(SqlStdOperatorTable.COUNT, false,
                         ImmutableList.<Integer>of(), longType, null),
                     new AggregateCall(SqlStdOperatorTable.COUNT, false,
                         args, longType, null)));
         LogicalJoin join =
-            new LogicalJoin(cluster, bb.root, aggregate,
-                rexBuilder.makeLiteral(true), JoinRelType.INNER,
+            LogicalJoin.create(bb.root,
+                aggregate,
+                rexBuilder.makeLiteral(true),
+                JoinRelType.INNER,
                 ImmutableSet.<String>of());
         bb.setRoot(join, false);
       }
@@ -1487,10 +1480,7 @@ public class SqlToRelConverter {
       unionInputs.add(convertRowConstructor(bb, call));
     }
     LogicalValues values =
-        new LogicalValues(
-            cluster,
-            rowType,
-            tupleList.build());
+        LogicalValues.create(cluster, rowType, tupleList.build());
     RelNode resultRel;
     if (unionInputs.isEmpty()) {
       resultRel = values;
@@ -1498,12 +1488,7 @@ public class SqlToRelConverter {
       if (!values.getTuples().isEmpty()) {
         unionInputs.add(values);
       }
-      LogicalUnion union =
-          new LogicalUnion(
-              cluster,
-              unionInputs,
-              true);
-      resultRel = union;
+      resultRel = LogicalUnion.create(unionInputs, true);
     }
     leaves.add(resultRel);
     return resultRel;
@@ -1862,7 +1847,7 @@ public class SqlToRelConverter {
       if (shouldConvertTableAccess) {
         tableRel = toRel(table);
       } else {
-        tableRel = new LogicalTableScan(cluster, table);
+        tableRel = LogicalTableScan.create(cluster, table);
       }
       bb.setRoot(tableRel, true);
       if (usedDataset[0]) {
@@ -2004,8 +1989,7 @@ public class SqlToRelConverter {
     Set<RelColumnMapping> columnMappings =
         getColumnMappings(operator);
     LogicalTableFunctionScan callRel =
-        new LogicalTableFunctionScan(
-            cluster,
+        LogicalTableFunctionScan.create(cluster,
             inputs,
             rexCall,
             elementType,
@@ -2145,12 +2129,8 @@ public class SqlToRelConverter {
                   ImmutableSet.copyOf(Util.skip(correlNames)));
           rightRel = rightRel.accept(dedup);
         }
-        LogicalCorrelate corr = new LogicalCorrelate(
-            rightRel.getCluster(),
-            leftRel,
-            rightRel,
-            new CorrelationId(correlNames.get(0)),
-            requiredColumns.build(),
+        LogicalCorrelate corr = LogicalCorrelate.create(leftRel, rightRel,
+            new CorrelationId(correlNames.get(0)), requiredColumns.build(),
             SemiJoinType.of(joinType));
         if (!joinCond.isAlwaysTrue()) {
           return RelOptUtil.createFilter(corr, joinCond);
@@ -2753,12 +2733,7 @@ public class SqlToRelConverter {
   protected RelNode createAggregate(Blackboard bb, boolean indicator,
       ImmutableBitSet groupSet, ImmutableList<ImmutableBitSet> groupSets,
       List<AggregateCall> aggCalls) {
-    return new LogicalAggregate(
-        cluster,
-        bb.root,
-        indicator,
-        groupSet,
-        groupSets,
+    return LogicalAggregate.create(bb.root, indicator, groupSet, groupSets,
         aggCalls);
   }
 
@@ -2957,18 +2932,12 @@ public class SqlToRelConverter {
     }
     switch (call.getKind()) {
     case UNION:
-      return new LogicalUnion(
-          cluster,
-          ImmutableList.of(left, right),
-          all);
+      return LogicalUnion.create(ImmutableList.of(left, right), all);
 
     case INTERSECT:
       // TODO:  all
       if (!all) {
-        return new LogicalIntersect(
-            cluster,
-            ImmutableList.of(left, right),
-            all);
+        return LogicalIntersect.create(ImmutableList.of(left, right), all);
       } else {
         throw Util.newInternal(
             "set operator INTERSECT ALL not suported");
@@ -2977,10 +2946,7 @@ public class SqlToRelConverter {
     case EXCEPT:
       // TODO:  all
       if (!all) {
-        return new LogicalMinus(
-            cluster,
-            ImmutableList.of(left, right),
-            all);
+        return LogicalMinus.create(ImmutableList.of(left, right), all);
       } else {
         throw Util.newInternal(
             "set operator EXCEPT ALL not suported");
@@ -3016,14 +2982,8 @@ public class SqlToRelConverter {
           null,
           false);
     }
-    return new LogicalTableModify(
-        cluster,
-        targetTable,
-        catalogReader,
-        massagedRel,
-        LogicalTableModify.Operation.INSERT,
-        null,
-        false);
+    return LogicalTableModify.create(targetTable, catalogReader, massagedRel,
+        LogicalTableModify.Operation.INSERT, null, false);
   }
 
   private RelOptTable.ToRelContext createToRelContext() {
@@ -3164,14 +3124,8 @@ public class SqlToRelConverter {
   private RelNode convertDelete(SqlDelete call) {
     RelOptTable targetTable = getTargetTable(call);
     RelNode sourceRel = convertSelect(call.getSourceSelect());
-    return new LogicalTableModify(
-        cluster,
-        targetTable,
-        catalogReader,
-        sourceRel,
-        LogicalTableModify.Operation.DELETE,
-        null,
-        false);
+    return LogicalTableModify.create(targetTable, catalogReader, sourceRel,
+        LogicalTableModify.Operation.DELETE, null, false);
   }
 
   private RelNode convertUpdate(SqlUpdate call) {
@@ -3187,14 +3141,8 @@ public class SqlToRelConverter {
 
     RelNode sourceRel = convertSelect(call.getSourceSelect());
 
-    return new LogicalTableModify(
-        cluster,
-        targetTable,
-        catalogReader,
-        sourceRel,
-        LogicalTableModify.Operation.UPDATE,
-        targetColumnNameList,
-        false);
+    return LogicalTableModify.create(targetTable, catalogReader, sourceRel,
+        LogicalTableModify.Operation.UPDATE, targetColumnNameList, false);
   }
 
   private RelNode convertMerge(SqlMerge call) {
@@ -3270,14 +3218,8 @@ public class SqlToRelConverter {
     RelNode massagedRel =
         RelOptUtil.createProject(join, projects, null, true);
 
-    return new LogicalTableModify(
-        cluster,
-        targetTable,
-        catalogReader,
-        massagedRel,
-        LogicalTableModify.Operation.MERGE,
-        targetColumnNameList,
-        false);
+    return LogicalTableModify.create(targetTable, catalogReader, massagedRel,
+        LogicalTableModify.Operation.MERGE, targetColumnNameList, false);
   }
 
   /**
@@ -3507,12 +3449,7 @@ public class SqlToRelConverter {
       RexNode condition,
       JoinRelType joinType,
       Set<String> variablesStopped) {
-    return new LogicalJoin(
-        cluster,
-        left,
-        right,
-        condition,
-        joinType,
+    return LogicalJoin.create(left, right, condition, joinType,
         variablesStopped);
   }
 
@@ -3692,10 +3629,7 @@ public class SqlToRelConverter {
           true);
     } else {
       bb.setRoot(
-          new LogicalUnion(
-              cluster,
-              unionRels,
-              true),
+          LogicalUnion.create(unionRels, true),
           true);
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/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 115cbf1..154766f 100644
--- a/core/src/main/java/org/apache/calcite/tools/Programs.java
+++ b/core/src/main/java/org/apache/calcite/tools/Programs.java
@@ -101,6 +101,7 @@ public class Programs {
   public static final ImmutableSet<RelOptRule> RULE_SET =
       ImmutableSet.of(
           EnumerableRules.ENUMERABLE_JOIN_RULE,
+          EnumerableRules.ENUMERABLE_MERGE_JOIN_RULE,
           EnumerableRules.ENUMERABLE_SEMI_JOIN_RULE,
           EnumerableRules.ENUMERABLE_CORRELATE_RULE,
           EnumerableRules.ENUMERABLE_PROJECT_RULE,
@@ -261,7 +262,9 @@ public class Programs {
           public RelNode run(RelOptPlanner planner, RelNode rel,
               RelTraitSet requiredOutputTraits) {
             final RelNode rootRel2 =
-                planner.changeTraits(rel, requiredOutputTraits);
+                rel.getTraitSet().equals(requiredOutputTraits)
+                ? rel
+                : planner.changeTraits(rel, requiredOutputTraits);
             assert rootRel2 != null;
 
             planner.setRoot(rootRel2);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/util/Bug.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/Bug.java b/core/src/main/java/org/apache/calcite/util/Bug.java
index c91cde4..46189c2 100644
--- a/core/src/main/java/org/apache/calcite/util/Bug.java
+++ b/core/src/main/java/org/apache/calcite/util/Bug.java
@@ -182,6 +182,10 @@ public abstract class Bug {
   /**
    * Use this method to flag code that should be re-visited after upgrading
    * a component.
+   *
+   * <p>If the intended change is that a class or member be removed, flag
+   * instead using a {@link Deprecated} annotation followed by a comment such as
+   * "to be removed before 2.0".
    */
   public static boolean upgrade(String remark) {
     Util.discard(remark);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
index 779196a..fac2ef1 100644
--- a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
+++ b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
@@ -81,6 +81,7 @@ import java.util.Map;
 import java.util.TimeZone;
 import javax.sql.DataSource;
 
+import static org.apache.calcite.rel.metadata.BuiltInMetadata.Collation;
 import static org.apache.calcite.rel.metadata.BuiltInMetadata.ColumnOrigin;
 import static org.apache.calcite.rel.metadata.BuiltInMetadata.ColumnUniqueness;
 import static org.apache.calcite.rel.metadata.BuiltInMetadata.CumulativeCost;
@@ -124,6 +125,9 @@ public enum BuiltInMethod {
       String.class, Function1.class),
   JOIN(ExtendedEnumerable.class, "join", Enumerable.class, Function1.class,
       Function1.class, Function2.class),
+  MERGE_JOIN(Enumerables.class, "mergeJoin", Enumerable.class, Enumerable.class,
+      Function1.class, Function1.class, Function2.class, boolean.class,
+      boolean.class),
   SLICE0(Enumerables.class, "slice0", Enumerable.class),
   SEMI_JOIN(Enumerables.class, "semiJoin", Enumerable.class, Enumerable.class,
       Function1.class, Function1.class),
@@ -164,6 +168,7 @@ public enum BuiltInMethod {
   LIST_N(FlatLists.class, "of", Object[].class),
   LIST2(FlatLists.class, "of", Object.class, Object.class),
   LIST3(FlatLists.class, "of", Object.class, Object.class, Object.class),
+  COMPARABLE_EMPTY_LIST(FlatLists.class, "COMPARABLE_EMPTY_LIST", true),
   IDENTITY_COMPARER(Functions.class, "identityComparer"),
   IDENTITY_SELECTOR(Functions.class, "identitySelector"),
   AS_ENUMERABLE(Linq4j.class, "asEnumerable", Object[].class),
@@ -286,6 +291,7 @@ public enum BuiltInMethod {
   UNIQUE_KEYS(UniqueKeys.class, "getUniqueKeys", boolean.class),
   COLUMN_UNIQUENESS(ColumnUniqueness.class, "areColumnsUnique",
       ImmutableBitSet.class, boolean.class),
+  COLLATIONS(Collation.class, "collations"),
   ROW_COUNT(RowCount.class, "getRowCount"),
   DISTINCT_ROW_COUNT(DistinctRowCount.class, "getDistinctRowCount",
       ImmutableBitSet.class, RexNode.class),
@@ -323,22 +329,26 @@ public enum BuiltInMethod {
     MAP = builder.build();
   }
 
+  private BuiltInMethod(Method method, Constructor constructor, Field field) {
+    this.method = method;
+    this.constructor = constructor;
+    this.field = field;
+  }
+
+  /** Defines a method. */
   BuiltInMethod(Class clazz, String methodName, Class... argumentTypes) {
-    this.method = Types.lookupMethod(clazz, methodName, argumentTypes);
-    this.constructor = null;
-    this.field = null;
+    this(Types.lookupMethod(clazz, methodName, argumentTypes), null, null);
   }
 
+  /** Defines a constructor. */
   BuiltInMethod(Class clazz, Class... argumentTypes) {
-    this.method = null;
-    this.constructor = Types.lookupConstructor(clazz, argumentTypes);
-    this.field = null;
+    this(null, Types.lookupConstructor(clazz, argumentTypes), null);
   }
 
+  /** Defines a field. */
   BuiltInMethod(Class clazz, String fieldName, boolean dummy) {
-    this.method = null;
-    this.constructor = null;
-    this.field = Types.lookupField(clazz, fieldName);
+    this(null, null, Types.lookupField(clazz, fieldName));
+    assert dummy : "dummy value for method overloading must be true";
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/util/ImmutableBitSet.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/ImmutableBitSet.java b/core/src/main/java/org/apache/calcite/util/ImmutableBitSet.java
index 43c3d37..670b10e 100644
--- a/core/src/main/java/org/apache/calcite/util/ImmutableBitSet.java
+++ b/core/src/main/java/org/apache/calcite/util/ImmutableBitSet.java
@@ -735,6 +735,11 @@ public class ImmutableBitSet
     throw new IndexOutOfBoundsException("index out of range: " + n);
   }
 
+  /** Returns a bit set the same as this but with a given bit set. */
+  public ImmutableBitSet set(int i) {
+    return union(ImmutableBitSet.of(i));
+  }
+
   /** Returns a bit set the same as this but with a given bit cleared. */
   public ImmutableBitSet clear(int i) {
     return except(ImmutableBitSet.of(i));

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/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 ace0c95..e4d147d 100644
--- a/core/src/main/java/org/apache/calcite/util/ImmutableIntList.java
+++ b/core/src/main/java/org/apache/calcite/util/ImmutableIntList.java
@@ -131,7 +131,7 @@ public class ImmutableIntList extends FlatLists.AbstractFlatList<Integer> {
           : (T[]) Array.newInstance(
               a.getClass().getComponentType(), size);
     }
-    if (a.getClass() == Integer[].class) {
+    if ((Class) a.getClass() == Integer[].class) {
       final Integer[] integers = (Integer[]) a;
       for (int i = 0; i < integers.length; i++) {
         integers[i] = ints[i];

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/util/Util.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/Util.java b/core/src/main/java/org/apache/calcite/util/Util.java
index 4831a60..5aa8246 100644
--- a/core/src/main/java/org/apache/calcite/util/Util.java
+++ b/core/src/main/java/org/apache/calcite/util/Util.java
@@ -1153,6 +1153,11 @@ public class Util {
     return buf.toString();
   }
 
+  /** Converts a list of strings to a string separated by newlines. */
+  public static String lines(Iterable<String> strings) {
+    return toString(strings, "", "\n", "");
+  }
+
   /**
    * Converts a Java timezone to POSIX format, so that the boost C++ library
    * can instantiate timezone objects.
@@ -1978,9 +1983,19 @@ public class Util {
 
   /** Returns whether one list is a prefix of another. */
   public static <E> boolean startsWith(List<E> list0, List<E> list1) {
-    return list0.equals(list1)
-        || list0.size() > list1.size()
-        && list0.subList(0, list1.size()).equals(list1);
+    if (list0 == list1) {
+      return true;
+    }
+    final int size = list1.size();
+    if (list0.size() < size) {
+      return false;
+    }
+    for (int i = 0; i < size; i++) {
+      if (!Objects.equal(list0.get(i), list1.get(i))) {
+        return false;
+      }
+    }
+    return true;
   }
 
   /** Converts a number into human-readable form, with 3 digits and a "K", "M"

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/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 0410398..f5dd8a2 100644
--- a/core/src/test/java/org/apache/calcite/plan/RelWriterTest.java
+++ b/core/src/test/java/org/apache/calcite/plan/RelWriterTest.java
@@ -119,24 +119,24 @@ public class RelWriterTest {
                   RelOptSchema relOptSchema, SchemaPlus rootSchema) {
                 rootSchema.add("hr",
                     new ReflectiveSchema(new JdbcTest.HrSchema()));
-                LogicalTableScan table =
-                    new LogicalTableScan(cluster,
+                LogicalTableScan scan =
+                    LogicalTableScan.create(cluster,
                         relOptSchema.getTableForMember(
                             Arrays.asList("hr", "emps")));
                 final RexBuilder rexBuilder = cluster.getRexBuilder();
                 LogicalFilter filter =
-                    new LogicalFilter(cluster, table,
+                    LogicalFilter.create(scan,
                         rexBuilder.makeCall(
                             SqlStdOperatorTable.EQUALS,
                             rexBuilder.makeFieldAccess(
-                                rexBuilder.makeRangeReference(table),
+                                rexBuilder.makeRangeReference(scan),
                                 "deptno", true),
                             rexBuilder.makeExactLiteral(BigDecimal.TEN)));
                 final RelJsonWriter writer = new RelJsonWriter();
                 final RelDataType bigIntType =
                     cluster.getTypeFactory().createSqlType(SqlTypeName.BIGINT);
                 LogicalAggregate aggregate =
-                    new LogicalAggregate(cluster, filter, false,
+                    LogicalAggregate.create(filter, false,
                         ImmutableBitSet.of(0), null,
                         ImmutableList.of(
                             new AggregateCall(SqlStdOperatorTable.COUNT,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/test/java/org/apache/calcite/plan/volcano/VolcanoPlannerTraitTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/plan/volcano/VolcanoPlannerTraitTest.java b/core/src/test/java/org/apache/calcite/plan/volcano/VolcanoPlannerTraitTest.java
index aefed30..66654da 100644
--- a/core/src/test/java/org/apache/calcite/plan/volcano/VolcanoPlannerTraitTest.java
+++ b/core/src/test/java/org/apache/calcite/plan/volcano/VolcanoPlannerTraitTest.java
@@ -121,9 +121,9 @@ public class VolcanoPlannerTraitTest {
             new NoneSingleRel(cluster, noneLeafRel), ALT_TRAIT2);
 
     RelNode convertedRel =
-        planner.changeTraits(
-            noneRel,
-            cluster.traitSetOf(EnumerableConvention.INSTANCE, ALT_TRAIT2));
+        planner.changeTraits(noneRel,
+            cluster.traitSetOf(EnumerableConvention.INSTANCE)
+                .replace(ALT_TRAIT2));
 
     planner.setRoot(convertedRel);
     RelNode result = planner.chooseDelegate().findBestExp();
@@ -177,10 +177,9 @@ public class VolcanoPlannerTraitTest {
             new NoneSingleRel(cluster, noneLeafRel), ALT_TRAIT2);
 
     RelNode convertedRel =
-        planner.changeTraits(
-            noneRel,
-            cluster.traitSetOf(
-                EnumerableConvention.INSTANCE, ALT_TRAIT2));
+        planner.changeTraits(noneRel,
+            cluster.traitSetOf(EnumerableConvention.INSTANCE)
+                .replace(ALT_TRAIT2));
 
     planner.setRoot(convertedRel);
     RelNode result = planner.chooseDelegate().findBestExp();
@@ -251,7 +250,7 @@ public class VolcanoPlannerTraitTest {
       return ordinal;
     }
 
-    public boolean subsumes(RelTrait trait) {
+    public boolean satisfies(RelTrait trait) {
       return equals(trait);
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/test/java/org/apache/calcite/rel/RelCollationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/rel/RelCollationTest.java b/core/src/test/java/org/apache/calcite/rel/RelCollationTest.java
new file mode 100644
index 0000000..5486e42
--- /dev/null
+++ b/core/src/test/java/org/apache/calcite/rel/RelCollationTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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 com.google.common.collect.Lists;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Tests for {@link RelCollation} and {@link RelFieldCollation}.
+ */
+public class RelCollationTest {
+  /** Unit test for {@link RelCollations#contains}. */
+  @Test public void testCollationContains() {
+    final RelCollation collation =
+        RelCollations.of(
+            new RelFieldCollation(2, RelFieldCollation.Direction.ASCENDING),
+            new RelFieldCollation(1, RelFieldCollation.Direction.DESCENDING));
+    assertThat(RelCollations.contains(collation, Arrays.asList(2)), is(true));
+    assertThat(RelCollations.contains(collation, Arrays.asList(1)), is(false));
+    assertThat(RelCollations.contains(collation, Arrays.asList(0)), is(false));
+    assertThat(RelCollations.contains(collation, Arrays.asList(2, 1)),
+        is(true));
+    assertThat(RelCollations.contains(collation, Arrays.asList(2, 0)),
+        is(false));
+    assertThat(RelCollations.contains(collation, Arrays.asList(2, 1, 3)),
+        is(false));
+    assertThat(RelCollations.contains(collation, Arrays.<Integer>asList()),
+        is(true));
+  }
+
+  /** Unit test for
+   *  {@link org.apache.calcite.rel.RelCollationImpl#compareTo}. */
+  @Test public void testCollationCompare() {
+    assertThat(collation(1, 2).compareTo(collation(1, 2)), equalTo(0));
+    assertThat(collation(1, 2).compareTo(collation(1)), equalTo(1));
+    assertThat(collation(1).compareTo(collation(1, 2)), equalTo(-1));
+    assertThat(collation(1, 3).compareTo(collation(1, 2)), equalTo(1));
+    assertThat(collation(0, 3).compareTo(collation(1, 2)), equalTo(-1));
+    assertThat(collation().compareTo(collation(0)), equalTo(-1));
+    assertThat(collation(1).compareTo(collation()), equalTo(1));
+  }
+
+  private static RelCollation collation(int... ordinals) {
+    final List<RelFieldCollation> list = Lists.newArrayList();
+    for (int ordinal : ordinals) {
+      list.add(new RelFieldCollation(ordinal));
+    }
+    return RelCollations.of(list);
+  }
+}
+
+// End RelCollationTest.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java b/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
index bec93d8..48eb1d5 100644
--- a/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
@@ -1062,6 +1062,22 @@ public class SqlParserTest {
             + "ORDER BY 1, 2 DESC");
   }
 
+  @Test public void testOrderUnion() {
+    // ORDER BY inside UNION not allowed
+    sql("select a from t order by a\n"
+        + "^union^ all\n"
+        + "select b from t order by b")
+        .fails("(?s).*Encountered \"union\" at .*");
+  }
+
+  @Test public void testLimitUnion() {
+    // LIMIT inside UNION not allowed
+    sql("select a from t limit 10\n"
+        + "^union^ all\n"
+        + "select b from t order by b")
+        .fails("(?s).*Encountered \"union\" at .*");
+  }
+
   @Test public void testUnionOfNonQueryFails() {
     checkFails(
         "select 1 from emp union ^2^ + 5",

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/CalciteAssert.java b/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
index 25f249a..77faaf0 100644
--- a/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
+++ b/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
@@ -78,7 +78,6 @@ import javax.sql.DataSource;
 
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.CoreMatchers.equalTo;
-import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThat;
@@ -342,8 +341,10 @@ public class CalciteAssert {
           CalciteAssert.toStringList(resultSet, actualList);
           Collections.sort(actualList);
 
-          // Use assertArrayEquals since it implements fine-grained comparison.
-          assertArrayEquals(expectedList.toArray(), actualList.toArray());
+          if (!actualList.equals(expectedList)) {
+            assertThat(Util.lines(actualList),
+                equalTo(Util.lines(expectedList)));
+          }
           return null;
         } catch (SQLException e) {
           throw new RuntimeException(e);
@@ -358,9 +359,7 @@ public class CalciteAssert {
       public Void apply(ResultSet s) {
         try {
           final String actual = Util.toLinux(CalciteAssert.toString(s));
-          if (!actual.contains(expected)) {
-            assertEquals("contains", expected, actual);
-          }
+          assertThat(actual, containsString(expected));
           return null;
         } catch (SQLException e) {
           throw new RuntimeException(e);
@@ -377,9 +376,7 @@ public class CalciteAssert {
           final String actual = Util.toLinux(CalciteAssert.toString(s));
           final String maskedActual =
               actual.replaceAll(", id = [0-9]+", "");
-          if (!maskedActual.contains(expected)) {
-            assertEquals("contains", expected, maskedActual);
-          }
+          assertThat(maskedActual, containsString(expected));
           return null;
         } catch (SQLException e) {
           throw new RuntimeException(e);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/test/java/org/apache/calcite/test/CalciteSuite.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/CalciteSuite.java b/core/src/test/java/org/apache/calcite/test/CalciteSuite.java
index d36e3a5..d9ac400 100644
--- a/core/src/test/java/org/apache/calcite/test/CalciteSuite.java
+++ b/core/src/test/java/org/apache/calcite/test/CalciteSuite.java
@@ -22,6 +22,7 @@ import org.apache.calcite.plan.RelOptUtilTest;
 import org.apache.calcite.plan.RelWriterTest;
 import org.apache.calcite.plan.volcano.VolcanoPlannerTest;
 import org.apache.calcite.plan.volcano.VolcanoPlannerTraitTest;
+import org.apache.calcite.rel.RelCollationTest;
 import org.apache.calcite.rex.RexExecutorTest;
 import org.apache.calcite.runtime.BinarySearchTest;
 import org.apache.calcite.runtime.EnumerablesTest;
@@ -64,6 +65,7 @@ import org.junit.runners.Suite;
     DirectedGraphTest.class,
     ReflectVisitorTest.class,
     RelOptUtilTest.class,
+    RelCollationTest.class,
     UtilTest.class,
     MappingTest.class,
     CalciteResourceTest.class,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/test/java/org/apache/calcite/test/JdbcFrontJdbcBackLinqMiddleTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcFrontJdbcBackLinqMiddleTest.java b/core/src/test/java/org/apache/calcite/test/JdbcFrontJdbcBackLinqMiddleTest.java
index 540c6a8..3ef4dea 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcFrontJdbcBackLinqMiddleTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcFrontJdbcBackLinqMiddleTest.java
@@ -64,7 +64,7 @@ public class JdbcFrontJdbcBackLinqMiddleTest {
 
   @Test public void testCase() {
     that()
-        .with(CalciteAssert.Config.JDBC_FOODMART)
+        .with(CalciteAssert.Config.FOODMART_CLONE)
         .query("select \"day\",\n"
             + " \"week_day\",\n"
             + " case when \"day\" < 3 then upper(\"week_day\")\n"

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/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 c34becd..a6d23e0 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcFrontLinqBackTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcFrontLinqBackTest.java
@@ -68,9 +68,9 @@ public class JdbcFrontLinqBackTest {
             + "from \"foodmart\".\"sales_fact_1997\" as s\n"
             + "join \"hr\".\"emps\" as e\n"
             + "on e.\"empid\" = s.\"cust_id\"")
-        .returns(""
-            + "cust_id=100; prod_id=10; empid=100; deptno=10; name=Bill; salary=10000.0; commission=1000\n"
-            + "cust_id=150; prod_id=20; empid=150; deptno=10; name=Sebastian; salary=7000.0; commission=null\n");
+        .returnsUnordered(
+            "cust_id=100; prod_id=10; empid=100; deptno=10; name=Bill; salary=10000.0; commission=1000",
+            "cust_id=150; prod_id=20; empid=150; deptno=10; name=Sebastian; salary=7000.0; commission=null");
   }
 
   /**
@@ -93,6 +93,11 @@ 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"
+            + "  EnumerableSort(sort0=[$0], sort1=[$1], dir0=[ASC], dir1=[DESC])\n"
+            + "    EnumerableCalc(expr#0..4=[{inputs}], deptno=[$t1], name=[$t2])\n"
+            + "      EnumerableTableScan(table=[[hr, emps]])")
         .returns("UN=THEODORE; deptno=10\n"
             + "UN=SEBASTIAN; deptno=10\n"
             + "UN=BILL; deptno=10\n"

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/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 89c3b47..425cb6c 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -2542,6 +2542,26 @@ public class JdbcTest {
         .returns("EMPNO=1; DESC=SameName\n");
   }
 
+  /** Tests a merge-join. */
+  @Test public void testMergeJoin() {
+    CalciteAssert.that()
+        .with(CalciteAssert.Config.REGULAR)
+        .query("select \"emps\".\"empid\",\n"
+            + " \"depts\".\"deptno\", \"depts\".\"name\"\n"
+            + "from \"hr\".\"emps\"\n"
+            + " join \"hr\".\"depts\" using (\"deptno\")")
+        .explainContains(""
+            + "EnumerableCalc(expr#0..3=[{inputs}], empid=[$t2], deptno=[$t0], name=[$t1])\n"
+            + "  EnumerableJoin(condition=[=($0, $3)], joinType=[inner])\n"
+            + "    EnumerableCalc(expr#0..3=[{inputs}], proj#0..1=[{exprs}])\n"
+            + "      EnumerableTableScan(table=[[hr, depts]])\n"
+            + "    EnumerableCalc(expr#0..4=[{inputs}], proj#0..1=[{exprs}])\n"
+            + "      EnumerableTableScan(table=[[hr, emps]])")
+        .returns("empid=100; deptno=10; name=Sales\n"
+            + "empid=150; deptno=10; name=Sales\n"
+            + "empid=110; deptno=10; name=Sales\n");
+  }
+
   /** Tests a cartesian product aka cross join. */
   @Test public void testCartesianJoin() {
     CalciteAssert.hr()
@@ -2870,9 +2890,8 @@ public class JdbcTest {
             + "where \"store_id\" < 10\n"
             + "order by 1 fetch first 5 rows only")
         .explainContains("PLAN=EnumerableLimit(fetch=[5])\n"
-            + "  EnumerableSort(sort0=[$0], dir0=[ASC])\n"
-            + "    EnumerableCalc(expr#0..23=[{inputs}], expr#24=[10], expr#25=[<($t0, $t24)], store_id=[$t0], grocery_sqft=[$t16], $condition=[$t25])\n"
-            + "      EnumerableTableScan(table=[[foodmart2, store]])\n")
+            + "  EnumerableCalc(expr#0..23=[{inputs}], expr#24=[10], expr#25=[<($t0, $t24)], store_id=[$t0], grocery_sqft=[$t16], $condition=[$t25])\n"
+            + "    EnumerableTableScan(table=[[foodmart2, store]])\n")
         .returns("store_id=0; grocery_sqft=null\n"
             + "store_id=1; grocery_sqft=17475\n"
             + "store_id=2; grocery_sqft=22271\n"
@@ -3098,6 +3117,36 @@ public class JdbcTest {
         .returnsCount(10);
   }
 
+  /** ORDER BY on a sort-key does not require a sort. */
+  @Test public void testOrderOnSortedTable() throws IOException {
+    // The ArrayTable "store" is sorted by "store_id".
+    CalciteAssert.that()
+        .with(CalciteAssert.Config.FOODMART_CLONE)
+        .query("select \"day\"\n"
+            + "from \"days\"\n"
+            + "order by \"day\"")
+        .returns("day=1\n"
+            + "day=2\n"
+            + "day=3\n"
+            + "day=4\n"
+            + "day=5\n"
+            + "day=6\n"
+            + "day=7\n");
+  }
+
+  /** ORDER BY on a sort-key does not require a sort. */
+  @Test public void testOrderSorted() throws IOException {
+    // The ArrayTable "store" is sorted by "store_id".
+    CalciteAssert.that()
+        .with(CalciteAssert.Config.FOODMART_CLONE)
+        .query("select \"store_id\"\n"
+            + "from \"store\"\n"
+            + "order by \"store_id\" limit 3")
+        .returns("store_id=0\n"
+            + "store_id=1\n"
+            + "store_id=2\n");
+  }
+
   @Test public void testWhereNot() throws IOException {
     CalciteAssert.that()
         .with(CalciteAssert.Config.FOODMART_CLONE)
@@ -3187,8 +3236,8 @@ public class JdbcTest {
         .with(CalciteAssert.Config.FOODMART_CLONE)
         .query("select * from \"time_by_day\"\n"
             + "order by \"time_id\"")
-        .explainContains("PLAN=EnumerableSort(sort0=[$0], dir0=[ASC])\n"
-            + "  EnumerableTableScan(table=[[foodmart2, time_by_day]])\n\n");
+        .explainContains(
+            "PLAN=EnumerableTableScan(table=[[foodmart2, time_by_day]])\n");
   }
 
   /** Tests sorting by a column that is already sorted. */
@@ -4374,6 +4423,10 @@ public class JdbcTest {
     checkRun("sql/sequence.oq");
   }
 
+  @Test public void testRunSort() throws Exception {
+    checkRun("sql/sort.oq");
+  }
+
   @Test public void testRunSubquery() throws Exception {
     checkRun("sql/subquery.oq");
   }
@@ -6256,8 +6309,7 @@ public class JdbcTest {
         TableModify.Operation operation,
         List<String> updateColumnList,
         boolean flattened) {
-      return new LogicalTableModify(
-          cluster, table, catalogReader, child, operation,
+      return LogicalTableModify.create(table, catalogReader, child, operation,
           updateColumnList, flattened);
     }
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/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 86e8007..b51e51c 100644
--- a/core/src/test/java/org/apache/calcite/test/LatticeTest.java
+++ b/core/src/test/java/org/apache/calcite/test/LatticeTest.java
@@ -346,6 +346,32 @@ public class LatticeTest {
         .returnsCount(4);
   }
 
+  /** Tests a query that is created within {@link #testTileAlgorithm()}. */
+  @Test public void testJG() {
+    CalciteAssert.that().with(CalciteAssert.Config.JDBC_FOODMART)
+        .query(
+            "SELECT \"s\".\"unit_sales\", \"p\".\"recyclable_package\", \"t\".\"the_day\", \"t\".\"the_year\", \"t\".\"quarter\", \"pc\".\"product_family\", COUNT(*) AS \"m0\", SUM(\"s\".\"store_sales\") AS \"m1\", SUM(\"s\".\"unit_sales\") AS \"m2\"\n"
+                + "FROM \"foodmart\".\"sales_fact_1997\" AS \"s\"\n"
+                + "JOIN \"foodmart\".\"product\" AS \"p\" ON \"s\".\"product_id\" = \"p\".\"product_id\"\n"
+                + "JOIN \"foodmart\".\"time_by_day\" AS \"t\" ON \"s\".\"time_id\" = \"t\".\"time_id\"\n"
+                + "JOIN \"foodmart\".\"product_class\" AS \"pc\" ON \"p\".\"product_class_id\" = \"pc\".\"product_class_id\"\n"
+                + "GROUP BY \"s\".\"unit_sales\", \"p\".\"recyclable_package\", \"t\".\"the_day\", \"t\".\"the_year\", \"t\".\"quarter\", \"pc\".\"product_family\"")
+        .explainContains(
+            "EnumerableAggregate(group=[{0, 1, 2, 3, 4, 5}], m0=[COUNT()], m1=[SUM($6)], m2=[SUM($0)])\n"
+                + "  EnumerableCalc(expr#0..37=[{inputs}], unit_sales=[$t17], recyclable_package=[$t26], the_day=[$t2], the_year=[$t4], quarter=[$t8], product_family=[$t37], store_sales=[$t15])\n"
+                + "    EnumerableJoin(condition=[=($0, $11)], joinType=[inner])\n"
+                + "      JdbcToEnumerableConverter\n"
+                + "        JdbcTableScan(table=[[foodmart, time_by_day]])\n"
+                + "      EnumerableJoin(condition=[=($8, $23)], joinType=[inner])\n"
+                + "        EnumerableJoin(condition=[=($0, $9)], joinType=[inner])\n"
+                + "          JdbcToEnumerableConverter\n"
+                + "            JdbcTableScan(table=[[foodmart, sales_fact_1997]])\n"
+                + "          JdbcToEnumerableConverter\n"
+                + "            JdbcTableScan(table=[[foodmart, product]])\n"
+                + "        JdbcToEnumerableConverter\n"
+                + "          JdbcTableScan(table=[[foodmart, product_class]])");
+  }
+
   /** Tests a query that uses no columns from the fact table. */
   @Test public void testGroupByEmpty() {
     foodmartModel()

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java b/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java
index ed8e9a6..d5e94a9 100644
--- a/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java
+++ b/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java
@@ -22,7 +22,7 @@ import org.apache.calcite.plan.RelOptSchema;
 import org.apache.calcite.plan.RelOptTable;
 import org.apache.calcite.prepare.Prepare;
 import org.apache.calcite.rel.RelCollation;
-import org.apache.calcite.rel.RelCollationImpl;
+import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.RelFieldCollation;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.logical.LogicalTableScan;
@@ -369,10 +369,8 @@ public class MockCatalogReader implements Prepare.CatalogReader {
                 ? RelFieldCollation.Direction.DESCENDING
                 : RelFieldCollation.Direction.ASCENDING;
         collationList.add(
-            RelCollationImpl.of(
-                new RelFieldCollation(
-                    i,
-                    direction,
+            RelCollations.of(
+                new RelFieldCollation(i, direction,
                     RelFieldCollation.NullDirection.UNSPECIFIED)));
       }
     }
@@ -442,7 +440,7 @@ public class MockCatalogReader implements Prepare.CatalogReader {
     }
 
     public RelNode toRel(ToRelContext context) {
-      return new LogicalTableScan(context.getCluster(), this);
+      return LogicalTableScan.create(context.getCluster(), this);
     }
 
     public List<RelCollation> getCollationList() {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/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 3782957..0e60487 100644
--- a/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
@@ -16,22 +16,49 @@
  */
 package org.apache.calcite.test;
 
+import org.apache.calcite.adapter.enumerable.EnumerableMergeJoin;
+import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptPlanner;
+import org.apache.calcite.plan.RelOptSchema;
 import org.apache.calcite.plan.RelOptTable;
+import org.apache.calcite.rel.InvalidRelException;
+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;
 import org.apache.calcite.rel.core.Aggregate;
+import org.apache.calcite.rel.core.Join;
+import org.apache.calcite.rel.core.JoinRelType;
+import org.apache.calcite.rel.core.Project;
+import org.apache.calcite.rel.core.Sort;
 import org.apache.calcite.rel.logical.LogicalAggregate;
 import org.apache.calcite.rel.logical.LogicalFilter;
+import org.apache.calcite.rel.logical.LogicalProject;
+import org.apache.calcite.rel.logical.LogicalSort;
+import org.apache.calcite.rel.logical.LogicalTableScan;
+import org.apache.calcite.rel.logical.LogicalValues;
 import org.apache.calcite.rel.metadata.CachingRelMetadataProvider;
 import org.apache.calcite.rel.metadata.ChainedRelMetadataProvider;
 import org.apache.calcite.rel.metadata.DefaultRelMetadataProvider;
 import org.apache.calcite.rel.metadata.Metadata;
 import org.apache.calcite.rel.metadata.ReflectiveRelMetadataProvider;
 import org.apache.calcite.rel.metadata.RelColumnOrigin;
+import org.apache.calcite.rel.metadata.RelMdCollation;
 import org.apache.calcite.rel.metadata.RelMetadataProvider;
 import org.apache.calcite.rel.metadata.RelMetadataQuery;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rex.RexBuilder;
+import org.apache.calcite.rex.RexLiteral;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.schema.SchemaPlus;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.tools.Frameworks;
 import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.calcite.util.ImmutableIntList;
 
+import com.google.common.base.Throwables;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 
@@ -41,6 +68,7 @@ import org.junit.Ignore;
 import org.junit.Test;
 
 import java.lang.reflect.Method;
+import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
@@ -635,6 +663,136 @@ public class RelMetadataTest extends SqlToRelTestBase {
     assertThat(buf.size(), equalTo(7));
   }
 
+  /** Unit test for
+   * {@link org.apache.calcite.rel.metadata.RelMdCollation#project}
+   * and other helper functions for deducing collations. */
+  @Test public void testCollation() {
+    final Project rel = (Project) convertSql("select * from emp, dept");
+    final Join join = (Join) rel.getInput();
+    final RelOptTable empTable = join.getInput(0).getTable();
+    final RelOptTable deptTable = join.getInput(1).getTable();
+    Frameworks.withPlanner(
+        new Frameworks.PlannerAction<Void>() {
+          public Void apply(RelOptCluster cluster,
+              RelOptSchema relOptSchema,
+              SchemaPlus rootSchema) {
+            checkCollation(cluster, empTable, deptTable);
+            return null;
+          }
+        });
+  }
+
+  private void checkCollation(RelOptCluster cluster, RelOptTable empTable,
+      RelOptTable deptTable) {
+    final RexBuilder rexBuilder = cluster.getRexBuilder();
+    final LogicalTableScan empScan = LogicalTableScan.create(cluster, empTable);
+
+    List<RelCollation> collations =
+        RelMdCollation.table(empScan.getTable());
+    assertThat(collations.size(), equalTo(0));
+
+    // ORDER BY field#0 ASC, field#1 ASC
+    final RelCollation collation =
+        RelCollations.of(new RelFieldCollation(0), new RelFieldCollation(1));
+    collations = RelMdCollation.sort(collation);
+    assertThat(collations.size(), equalTo(1));
+    assertThat(collations.get(0).getFieldCollations().size(), equalTo(2));
+
+    final Sort empSort = LogicalSort.create(empScan, collation, null, null);
+
+    final List<RexNode> projects =
+        ImmutableList.of(rexBuilder.makeInputRef(empSort, 1),
+            rexBuilder.makeLiteral("foo"),
+            rexBuilder.makeInputRef(empSort, 0),
+            rexBuilder.makeCall(SqlStdOperatorTable.MINUS,
+                rexBuilder.makeInputRef(empSort, 0),
+                rexBuilder.makeInputRef(empSort, 3)));
+
+    collations = RelMdCollation.project(empSort, projects);
+    assertThat(collations.size(), equalTo(1));
+    assertThat(collations.get(0).getFieldCollations().size(), equalTo(2));
+    assertThat(collations.get(0).getFieldCollations().get(0).getFieldIndex(),
+        equalTo(2));
+    assertThat(collations.get(0).getFieldCollations().get(1).getFieldIndex(),
+        equalTo(0));
+
+    final LogicalProject project = LogicalProject.create(empSort, projects,
+        ImmutableList.of("a", "b", "c", "d"));
+
+    final LogicalTableScan deptScan =
+        LogicalTableScan.create(cluster, deptTable);
+
+    final RelCollation deptCollation =
+        RelCollations.of(new RelFieldCollation(0), new RelFieldCollation(1));
+    final Sort deptSort =
+        LogicalSort.create(deptScan, deptCollation, null, null);
+
+    final ImmutableIntList leftKeys = ImmutableIntList.of(2);
+    final ImmutableIntList rightKeys = ImmutableIntList.of(0);
+    final EnumerableMergeJoin join;
+    try {
+      join = EnumerableMergeJoin.create(project, deptSort,
+          rexBuilder.makeLiteral(true), leftKeys, rightKeys, JoinRelType.INNER);
+    } catch (InvalidRelException e) {
+      throw Throwables.propagate(e);
+    }
+    collations =
+        RelMdCollation.mergeJoin(project, deptSort, leftKeys, rightKeys);
+    assertThat(collations,
+        equalTo(join.getTraitSet().getTraits(RelCollationTraitDef.INSTANCE)));
+
+    // Values (empty)
+    collations = RelMdCollation.values(empTable.getRowType(),
+        ImmutableList.<ImmutableList<RexLiteral>>of());
+    assertThat(collations.toString(),
+        equalTo("[[0, 1, 2, 3, 4, 5, 6, 7, 8], "
+            + "[1, 2, 3, 4, 5, 6, 7, 8], "
+            + "[2, 3, 4, 5, 6, 7, 8], "
+            + "[3, 4, 5, 6, 7, 8], "
+            + "[4, 5, 6, 7, 8], "
+            + "[5, 6, 7, 8], "
+            + "[6, 7, 8], "
+            + "[7, 8], "
+            + "[8]]"));
+
+    final LogicalValues emptyValues =
+        LogicalValues.createEmpty(cluster, empTable.getRowType());
+    assertThat(RelMetadataQuery.collations(emptyValues), equalTo(collations));
+
+    // Values (non-empty)
+    final RelDataType rowType = cluster.getTypeFactory().builder()
+        .add("a", SqlTypeName.INTEGER)
+        .add("b", SqlTypeName.INTEGER)
+        .add("c", SqlTypeName.INTEGER)
+        .add("d", SqlTypeName.INTEGER)
+        .build();
+    final ImmutableList.Builder<ImmutableList<RexLiteral>> tuples =
+        ImmutableList.builder();
+    // sort keys are [a], [a, b], [a, b, c], [a, b, c, d], [a, c], [b], [b, a],
+    //   [b, d]
+    // algorithm deduces [a, b, c, d], [b, d] which is a useful sub-set
+    addRow(tuples, rexBuilder, 1, 1, 1, 1);
+    addRow(tuples, rexBuilder, 1, 2, 0, 3);
+    addRow(tuples, rexBuilder, 2, 3, 2, 2);
+    addRow(tuples, rexBuilder, 3, 3, 1, 4);
+    collations = RelMdCollation.values(rowType, tuples.build());
+    assertThat(collations.toString(),
+        equalTo("[[0, 1, 2, 3], [1, 3]]"));
+
+    final LogicalValues values =
+        LogicalValues.create(cluster, rowType, tuples.build());
+    assertThat(RelMetadataQuery.collations(values), equalTo(collations));
+  }
+
+  private void addRow(ImmutableList.Builder<ImmutableList<RexLiteral>> builder,
+      RexBuilder rexBuilder, Object... values) {
+    ImmutableList.Builder<RexLiteral> b = ImmutableList.builder();
+    for (Object value : values) {
+      b.add(rexBuilder.makeExactLiteral(BigDecimal.valueOf((Integer) value)));
+    }
+    builder.add(b.build());
+  }
+
   /** Custom metadata interface. */
   public interface ColType extends Metadata {
     String getColType(int column);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/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 1eb6b8c..4b51753 100644
--- a/core/src/test/java/org/apache/calcite/test/ScannableTableTest.java
+++ b/core/src/test/java/org/apache/calcite/test/ScannableTableTest.java
@@ -127,7 +127,7 @@ public class ScannableTableTest {
     resultSet.close();
     // Only 2 rows came out of the table. If the value is 4, it means that the
     // planner did not pass the filter down.
-    assertThat(buf.toString(), equalTo("returnCount=2"));
+    assertThat(buf.toString(), equalTo("returnCount=2, filter=4"));
     buf.setLength(0);
 
     // Now with an "uncooperative" filterable table that refuses to accept
@@ -161,7 +161,7 @@ public class ScannableTableTest {
     resultSet.close();
     // Only 2 rows came out of the table. If the value is 4, it means that the
     // planner did not pass the filter down.
-    assertThat(buf.toString(), equalTo("returnCount=2"));
+    assertThat(buf.toString(), equalTo("returnCount=2, filter=4"));
     buf.setLength(0);
 
     // Now with an "uncooperative" filterable table that refuses to accept
@@ -195,7 +195,8 @@ public class ScannableTableTest {
     assertThat(CalciteAssert.toString(resultSet),
         equalTo("k=1940; j=John\nk=1942; j=Paul\n"));
     resultSet.close();
-    assertThat(buf.toString(), equalTo("returnCount=2, projects=[2, 1]"));
+    assertThat(buf.toString(),
+        equalTo("returnCount=2, filter=4, projects=[2, 1]"));
     buf.setLength(0);
 
     // Filter on one of the projected columns.
@@ -467,6 +468,9 @@ public class ScannableTableTest {
       public void close() {
         current = null;
         buf.append("returnCount=").append(returnCount);
+        if (filter != null) {
+          buf.append(", filter=").append(filter);
+        }
         if (projects != null) {
           buf.append(", projects=").append(Arrays.toString(projects));
         }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/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 32e2dbe..180f877 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
@@ -24,7 +24,7 @@ import org.apache.calcite.plan.RelOptTable;
 import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.prepare.Prepare;
 import org.apache.calcite.rel.RelCollation;
-import org.apache.calcite.rel.RelCollationImpl;
+import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.RelFieldCollation;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.logical.LogicalTableScan;
@@ -248,10 +248,8 @@ public abstract class SqlToRelTestBase {
                   ? RelFieldCollation.Direction.DESCENDING
                   : RelFieldCollation.Direction.ASCENDING;
           collationList.add(
-              RelCollationImpl.of(
-                  new RelFieldCollation(
-                      i,
-                      direction,
+              RelCollations.of(
+                  new RelFieldCollation(i, direction,
                       RelFieldCollation.NullDirection.UNSPECIFIED)));
         }
       }
@@ -344,9 +342,8 @@ public abstract class SqlToRelTestBase {
         return MockRelOptSchema.this;
       }
 
-      public RelNode toRel(
-          ToRelContext context) {
-        return new LogicalTableScan(context.getCluster(), this);
+      public RelNode toRel(ToRelContext context) {
+        return LogicalTableScan.create(context.getCluster(), this);
       }
 
       public List<RelCollation> getCollationList() {
@@ -411,7 +408,7 @@ public abstract class SqlToRelTestBase {
     }
 
     public RelNode toRel(ToRelContext context) {
-      return new LogicalTableScan(context.getCluster(), this);
+      return LogicalTableScan.create(context.getCluster(), this);
     }
 
     public List<RelCollation> getCollationList() {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/test/java/org/apache/calcite/tools/FrameworksTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/tools/FrameworksTest.java b/core/src/test/java/org/apache/calcite/tools/FrameworksTest.java
index e882fc2..288adf3 100644
--- a/core/src/test/java/org/apache/calcite/tools/FrameworksTest.java
+++ b/core/src/test/java/org/apache/calcite/tools/FrameworksTest.java
@@ -93,13 +93,13 @@ public class FrameworksTest {
                         rexBuilder.makeRangeReference(tableRel), "i", true),
                     rexBuilder.makeExactLiteral(BigDecimal.ONE));
             final LogicalFilter filter =
-                new LogicalFilter(cluster, tableRel, condition);
+                LogicalFilter.create(tableRel, condition);
 
             // Specify that the result should be in Enumerable convention.
             final RelNode rootRel = filter;
             final RelOptPlanner planner = cluster.getPlanner();
-            RelTraitSet desiredTraits = rootRel.getTraitSet().replace(
-                EnumerableConvention.INSTANCE);
+            RelTraitSet desiredTraits =
+                cluster.traitSet().replace(EnumerableConvention.INSTANCE);
             final RelNode rootRel2 = planner.changeTraits(rootRel,
                 desiredTraits);
             planner.setRoot(rootRel2);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/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 54bee88..701d66a 100644
--- a/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
+++ b/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
@@ -352,7 +352,7 @@ public class PlannerTest {
 
   /** Unit test that parses, validates, converts and
    * plans for query using two duplicate order by.
-   * The duplicate order by should be removed by SortRemoveRule*/
+   * The duplicate order by should be removed by SortRemoveRule. */
   @Test public void testDuplicateSortPlan() throws Exception {
     RuleSet ruleSet =
         RuleSets.ofList(
@@ -370,6 +370,10 @@ public class PlannerTest {
     RelNode convert = planner.convert(validate);
     RelTraitSet traitSet = planner.getEmptyTraitSet()
         .replace(EnumerableConvention.INSTANCE);
+    if (traitSet.getTrait(RelCollationTraitDef.INSTANCE) == null) {
+      // SortRemoveRule can only work if collation trait is enabled.
+      return;
+    }
     RelNode transform = planner.transform(0, traitSet, convert);
     assertThat(toString(transform),
         equalTo("EnumerableProject(empid=[$0])\n"
@@ -721,6 +725,7 @@ public class PlannerTest {
             + "cross join \"department\"",
         "EnumerableProject(product_id=[$0], time_id=[$1], customer_id=[$2], promotion_id=[$3], store_id=[$4], store_sales=[$5], store_cost=[$6], unit_sales=[$7], customer_id0=[$8], account_num=[$9], lname=[$10], fname=[$11], mi=[$12], address1=[$13], address2=[$14], address3=[$15], address4=[$16], city=[$17], state_province=[$18], postal_code=[$19], country=[$20], customer_region_id=[$21], phone1=[$22], phone2=[$23], birthdate=[$24], marital_status=[$25], yearly_income=[$26], gender=[$27], total_children=[$28], num_children_at_home=[$29], education=[$30], date_accnt_opened=[$31], member_card=[$32], occupation=[$33], houseowner=[$34], num_cars_owned=[$35], fullname=[$36], department_id=[$37], department_description=[$38])\n"
             + "  EnumerableProject($f0=[$31], $f1=[$32], $f2=[$33], $f3=[$34], $f4=[$35], $f5=[$36], $f6=[$37], $f7=[$38], $f8=[$2], $f9=[$3], $f10=[$4], $f11=[$5], $f12=[$6], $f13=[$7], $f14=[$8], $f15=[$9], $f16=[$10], $f17=[$11], $f18=[$12], $f19=[$13], $f20=[$14], $f21=[$15], $f22=[$16], $f23=[$17], $f24=[$18], $f25=[$19], $f26=[$20], $f27=[$21], $f28=[$22], $f29=[$23], $f30=[$24], $f31=[$25], $f32=[$26], $f33=[$27], $f34=[$28], $f35=[$29], $f36=[$30], $f37=[$0], $f38=[$1])\n"
+            //+ "    EnumerableMergeJoin(condition=[true], joinType=[inner])\n"
             + "    EnumerableJoin(condition=[true], joinType=[inner])\n"
             + "      EnumerableTableScan(table=[[foodmart2, department]])\n"
             + "      EnumerableJoin(condition=[=($0, $31)], joinType=[inner])\n"
@@ -737,6 +742,7 @@ public class PlannerTest {
             + "join \"employee\" using (\"department_id\")",
         "EnumerableProject(product_id=[$0], time_id=[$1], customer_id=[$2], promotion_id=[$3], store_id=[$4], store_sales=[$5], store_cost=[$6], unit_sales=[$7], customer_id0=[$8], account_num=[$9], lname=[$10], fname=[$11], mi=[$12], address1=[$13], address2=[$14], address3=[$15], address4=[$16], city=[$17], state_province=[$18], postal_code=[$19], country=[$20], customer_region_id=[$21], phone1=[$22], phone2=[$23], birthdate=[$24], marital_status=[$25], yearly_income=[$26], gender=[$27], total_children=[$28], num_children_at_home=[$29], education=[$30], date_accnt_opened=[$31], member_card=[$32], occupation=[$33], houseowner=[$34], num_cars_owned=[$35], fullname=[$36], department_id=[$37], department_description=[$38], employee_id=[$39], full_name=[$40], first_name=[$41], last_name=[$42], position_id=[$43], position_title=[$44], store_id0=[$45], department_id0=[$46], birth_date=[$47], hire_date=[$48], end_date=[$49], salary=[$50], supervisor_id=[$51], education_level=[$52], marita
 l_status0=[$53], gender0=[$54], management_role=[$55])\n"
             + "  EnumerableProject($f0=[$48], $f1=[$49], $f2=[$50], $f3=[$51], $f4=[$52], $f5=[$53], $f6=[$54], $f7=[$55], $f8=[$19], $f9=[$20], $f10=[$21], $f11=[$22], $f12=[$23], $f13=[$24], $f14=[$25], $f15=[$26], $f16=[$27], $f17=[$28], $f18=[$29], $f19=[$30], $f20=[$31], $f21=[$32], $f22=[$33], $f23=[$34], $f24=[$35], $f25=[$36], $f26=[$37], $f27=[$38], $f28=[$39], $f29=[$40], $f30=[$41], $f31=[$42], $f32=[$43], $f33=[$44], $f34=[$45], $f35=[$46], $f36=[$47], $f37=[$0], $f38=[$1], $f39=[$2], $f40=[$3], $f41=[$4], $f42=[$5], $f43=[$6], $f44=[$7], $f45=[$8], $f46=[$9], $f47=[$10], $f48=[$11], $f49=[$12], $f50=[$13], $f51=[$14], $f52=[$15], $f53=[$16], $f54=[$17], $f55=[$18])\n"
+            // + "    EnumerableMergeJoin(condition=[true], joinType=[inner])\n"
             + "    EnumerableJoin(condition=[true], joinType=[inner])\n"
             + "      EnumerableJoin(condition=[=($0, $9)], joinType=[inner])\n"
             + "        EnumerableTableScan(table=[[foodmart2, department]])\n"

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/test/java/org/apache/calcite/util/ImmutableBitSetTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/util/ImmutableBitSetTest.java b/core/src/test/java/org/apache/calcite/util/ImmutableBitSetTest.java
index 7f2b984..605817c 100644
--- a/core/src/test/java/org/apache/calcite/util/ImmutableBitSetTest.java
+++ b/core/src/test/java/org/apache/calcite/util/ImmutableBitSetTest.java
@@ -425,6 +425,22 @@ public class ImmutableBitSetTest {
     assertThat(ImmutableBitSet.valueOf(LongBuffer.wrap(bitSet.toLongArray())),
         equalTo(bitSet));
   }
+
+  @Test public void testSet() {
+    final ImmutableBitSet bitSet = ImmutableBitSet.of(29, 4, 1969);
+    assertThat(bitSet.set(30),
+        equalTo(ImmutableBitSet.of(29, 4, 1969, 30)));
+    assertThat(bitSet.set(29),
+        equalTo(bitSet));
+  }
+
+  @Test public void testClear() {
+    final ImmutableBitSet bitSet = ImmutableBitSet.of(29, 4, 1969);
+    assertThat(bitSet.clear(29),
+        equalTo(ImmutableBitSet.of(4, 1969)));
+    assertThat(bitSet.clear(29).clear(4).clear(29).clear(1969),
+        equalTo(ImmutableBitSet.of()));
+  }
 }
 
 // End ImmutableBitSetTest.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/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
new file mode 100644
index 0000000..df6e385
--- /dev/null
+++ b/core/src/test/resources/sql/sort.oq
@@ -0,0 +1,71 @@
+# sort.oq - Sorting and collation
+#
+# 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.
+#
+!use foodmart
+!set outputformat mysql
+
+# The ArrayTable "days" is sorted by "day", so plan must not contain sort
+select * from "days" order by "day";
++-----+-----------+
+| day | week_day  |
++-----+-----------+
+|   1 | Sunday    |
+|   2 | Monday    |
+|   3 | Tuesday   |
+|   4 | Wednesday |
+|   5 | Thursday  |
+|   6 | Friday    |
+|   7 | Saturday  |
++-----+-----------+
+(7 rows)
+
+!ok
+EnumerableTableScan(table=[[foodmart2, days]])
+!plan
+
+# The ArrayTable "days" is sorted by "day", so the plan does not sort, only applies limit
+select * from "days" order by "day" limit 2;
++-----+----------+
+| day | week_day |
++-----+----------+
+|   1 | Sunday   |
+|   2 | Monday   |
++-----+----------+
+(2 rows)
+
+!ok
+EnumerableLimit(fetch=[2])
+  EnumerableTableScan(table=[[foodmart2, days]])
+!plan
+
+# The ArrayTable "days" is sorted by "day", so the plan must not contain Sort
+select * from "days" where "day" between 2 and 4 order by "day";
++-----+-----------+
+| day | week_day  |
++-----+-----------+
+|   2 | Monday    |
+|   3 | Tuesday   |
+|   4 | Wednesday |
++-----+-----------+
+(3 rows)
+
+!ok
+EnumerableCalc(expr#0..1=[{inputs}], expr#2=[2], expr#3=[>=($t0, $t2)], expr#4=[4], expr#5=[<=($t0, $t4)], expr#6=[AND($t3, $t5)], proj#0..1=[{exprs}], $condition=[$t6])
+  EnumerableTableScan(table=[[foodmart2, days]])
+!plan
+
+# End sort.oq

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/linq4j/src/main/java/org/apache/calcite/linq4j/Ord.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/Ord.java b/linq4j/src/main/java/org/apache/calcite/linq4j/Ord.java
index 18aa812..c7eedf5 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/Ord.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/Ord.java
@@ -17,10 +17,10 @@
 package org.apache.calcite.linq4j;
 
 import java.util.AbstractList;
-import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.RandomAccess;
 
 /**
  * Pair of an element and an ordinal.
@@ -49,7 +49,7 @@ public class Ord<E> implements Map.Entry<Integer, E> {
   /**
    * Creates an iterable of {@code Ord}s over an iterable.
    */
-  public static <E> Iterable<Ord<E>> zip(final Iterable<E> iterable) {
+  public static <E> Iterable<Ord<E>> zip(final Iterable<? extends E> iterable) {
     return new Iterable<Ord<E>>() {
       public Iterator<Ord<E>> iterator() {
         return zip(iterable.iterator());
@@ -60,7 +60,7 @@ public class Ord<E> implements Map.Entry<Integer, E> {
   /**
    * Creates an iterator of {@code Ord}s over an iterator.
    */
-  public static <E> Iterator<Ord<E>> zip(final Iterator<E> iterator) {
+  public static <E> Iterator<Ord<E>> zip(final Iterator<? extends E> iterator) {
     return new Iterator<Ord<E>>() {
       int n = 0;
 
@@ -82,22 +82,16 @@ public class Ord<E> implements Map.Entry<Integer, E> {
    * Returns a numbered list based on an array.
    */
   public static <E> List<Ord<E>> zip(final E[] elements) {
-    return zip(Arrays.asList(elements));
+    return new OrdArrayList<E>(elements);
   }
 
   /**
    * Returns a numbered list.
    */
-  public static <E> List<Ord<E>> zip(final List<E> elements) {
-    return new AbstractList<Ord<E>>() {
-      public Ord<E> get(int index) {
-        return of(index, elements.get(index));
-      }
-
-      public int size() {
-        return elements.size();
-      }
-    };
+  public static <E> List<Ord<E>> zip(final List<? extends E> elements) {
+    return elements instanceof RandomAccess
+        ? new OrdRandomAccessList<E>(elements)
+        : new OrdList<E>(elements);
   }
 
   public Integer getKey() {
@@ -111,6 +105,49 @@ public class Ord<E> implements Map.Entry<Integer, E> {
   public E setValue(E value) {
     throw new UnsupportedOperationException();
   }
+
+  /** List of {@link Ord} backed by a list of elements. */
+  private static class OrdList<E> extends AbstractList<Ord<E>> {
+    private final List<? extends E> elements;
+
+    public OrdList(List<? extends E> elements) {
+      this.elements = elements;
+    }
+
+    public Ord<E> get(int index) {
+      return of(index, elements.get(index));
+    }
+
+    public int size() {
+      return elements.size();
+    }
+  }
+
+  /** List of {@link Ord} backed by a random-access list of elements. */
+  private static class OrdRandomAccessList<E> extends OrdList<E>
+      implements RandomAccess {
+    public OrdRandomAccessList(List<? extends E> elements) {
+      super(elements);
+    }
+  }
+
+  /** List of {@link Ord} backed by an array of elements. */
+  private static class OrdArrayList<E> extends AbstractList<Ord<E>>
+      implements RandomAccess {
+    private final E[] elements;
+
+    public OrdArrayList(E[] elements) {
+      this.elements = elements;
+    }
+
+    @Override public Ord<E> get(int index) {
+      return Ord.of(index, elements[index]);
+    }
+
+    @Override public int size() {
+      return elements.length;
+    }
+  }
 }
 
 // End Ord.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoRules.java
----------------------------------------------------------------------
diff --git a/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoRules.java b/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoRules.java
index f67e0ee..0ccee35 100644
--- a/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoRules.java
+++ b/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoRules.java
@@ -24,7 +24,7 @@ import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelTrait;
 import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.InvalidRelException;
-import org.apache.calcite.rel.RelCollationImpl;
+import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.convert.ConverterRule;
 import org.apache.calcite.rel.core.Sort;
@@ -216,7 +216,7 @@ public class MongoRules {
           sort.getTraitSet().replace(out)
               .replace(sort.getCollation());
       return new MongoSort(rel.getCluster(), traitSet,
-          convert(sort.getInput(), traitSet.replace(RelCollationImpl.EMPTY)),
+          convert(sort.getInput(), traitSet.replace(RelCollations.EMPTY)),
           sort.getCollation(), sort.offset, sort.fetch);
     }
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/splunk/src/main/java/org/apache/calcite/adapter/splunk/SplunkPushDownRule.java
----------------------------------------------------------------------
diff --git a/splunk/src/main/java/org/apache/calcite/adapter/splunk/SplunkPushDownRule.java b/splunk/src/main/java/org/apache/calcite/adapter/splunk/SplunkPushDownRule.java
index 2976f87..d432466 100644
--- a/splunk/src/main/java/org/apache/calcite/adapter/splunk/SplunkPushDownRule.java
+++ b/splunk/src/main/java/org/apache/calcite/adapter/splunk/SplunkPushDownRule.java
@@ -20,7 +20,6 @@ import org.apache.calcite.adapter.splunk.util.StringUtils;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
 import org.apache.calcite.plan.RelOptRuleOperand;
-import org.apache.calcite.rel.RelCollationImpl;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.logical.LogicalFilter;
 import org.apache.calcite.rel.logical.LogicalProject;
@@ -279,13 +278,7 @@ public class SplunkPushDownRule
     if (proj == null) {
       return rel;
     }
-    return new LogicalProject(
-        proj.getCluster(),
-        proj.getCluster().traitSetOf(
-            proj.getCollationList().isEmpty()
-                ? RelCollationImpl.EMPTY
-                : proj.getCollationList().get(0)),
-        rel, proj.getProjects(), proj.getRowType());
+    return LogicalProject.create(rel, proj.getProjects(), proj.getRowType());
   }
 
   // TODO: use StringBuilder instead of String


[2/9] incubator-calcite git commit: [CALCITE-572] Remove Project.flags

Posted by jh...@apache.org.
[CALCITE-572] Remove Project.flags


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

Branch: refs/heads/master
Commit: 5a6d32a2a0dcc48c25dda51d350b76c9c8bf6d10
Parents: 44650d4
Author: Vladimir Sitnikov <si...@gmail.com>
Authored: Fri Jan 30 16:23:19 2015 -0800
Committer: julianhyde <jh...@apache.org>
Committed: Fri Feb 6 12:10:34 2015 -0800

----------------------------------------------------------------------
 .../adapter/enumerable/EnumerableProject.java   |  7 ++--
 .../enumerable/EnumerableProjectRule.java       |  4 +-
 .../adapter/enumerable/EnumerableRel.java       |  4 +-
 .../apache/calcite/adapter/jdbc/JdbcRules.java  | 25 ++++--------
 .../apache/calcite/interpreter/Bindables.java   | 12 +++---
 .../org/apache/calcite/plan/RelOptUtil.java     |  9 +---
 .../calcite/plan/SubstitutionVisitor.java       |  2 +-
 .../calcite/prepare/LixToRelTranslator.java     |  3 +-
 .../calcite/prepare/QueryableRelBuilder.java    |  4 +-
 .../org/apache/calcite/rel/core/Project.java    | 43 +-------------------
 .../calcite/rel/logical/LogicalProject.java     | 18 +++-----
 .../rel/rules/ReduceExpressionsRule.java        |  3 +-
 .../calcite/sql2rel/SqlToRelConverter.java      |  9 ++--
 .../org/apache/calcite/tools/PlannerTest.java   |  4 +-
 .../calcite/adapter/mongodb/MongoProject.java   |  6 +--
 .../calcite/adapter/mongodb/MongoRules.java     |  2 +-
 .../calcite/adapter/spark/SparkRules.java       | 20 ++-------
 .../adapter/splunk/SplunkPushDownRule.java      |  2 +-
 18 files changed, 42 insertions(+), 135 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a6d32a2/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 f145776..e12f953 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
@@ -33,16 +33,15 @@ public class EnumerableProject extends Project implements EnumerableRel {
       RelTraitSet traitSet,
       RelNode child,
       List<? extends RexNode> exps,
-      RelDataType rowType,
-      int flags) {
-    super(cluster, traitSet, child, exps, rowType, flags);
+      RelDataType rowType) {
+    super(cluster, traitSet, child, exps, rowType);
     assert getConvention() instanceof EnumerableConvention;
   }
 
   public EnumerableProject copy(RelTraitSet traitSet, RelNode input,
       List<RexNode> exps, RelDataType rowType) {
     return new EnumerableProject(getCluster(), traitSet, input,
-        exps, rowType, flags);
+        exps, rowType);
   }
 
   public Result implement(EnumerableRelImplementor implementor, Prefer pref) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a6d32a2/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 158365c..b7dcc69 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
@@ -20,7 +20,6 @@ import org.apache.calcite.plan.Convention;
 import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.convert.ConverterRule;
-import org.apache.calcite.rel.core.Project;
 import org.apache.calcite.rel.logical.LogicalProject;
 
 /**
@@ -41,8 +40,7 @@ class EnumerableProjectRule extends ConverterRule {
             project.getInput().getTraitSet()
                 .replace(EnumerableConvention.INSTANCE)),
         project.getProjects(),
-        project.getRowType(),
-        Project.Flags.BOXED);
+        project.getRowType());
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a6d32a2/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRel.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRel.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRel.java
index 247e4f7..c005faa 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRel.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRel.java
@@ -19,7 +19,6 @@ package org.apache.calcite.adapter.enumerable;
 import org.apache.calcite.linq4j.tree.BlockStatement;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.rel.RelNode;
-import org.apache.calcite.rel.core.Project;
 import org.apache.calcite.rel.core.RelFactories;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rex.RexNode;
@@ -54,8 +53,7 @@ public interface EnumerableRel
                       : SqlValidatorUtil.uniquify(fieldNames,
                           SqlValidatorUtil.F_SUGGESTER));
           return new EnumerableProject(cluster,
-              child.getTraitSet(), child, exprs, rowType,
-              Project.Flags.BOXED);
+              child.getTraitSet(), child, exprs, rowType);
         }
       };
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a6d32a2/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java
index 6bbf1c8..3716730 100644
--- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java
+++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java
@@ -354,7 +354,7 @@ public class JdbcRules {
 
       return new JdbcCalc(rel.getCluster(), rel.getTraitSet().replace(out),
           convert(calc.getInput(), calc.getTraitSet().replace(out)),
-          calc.getProgram(), Project.Flags.BOXED);
+          calc.getProgram());
     }
   }
 
@@ -364,19 +364,12 @@ public class JdbcRules {
   public static class JdbcCalc extends SingleRel implements JdbcRel {
     private final RexProgram program;
 
-    /**
-     * Values defined in {@link org.apache.calcite.rel.core.Project.Flags}.
-     */
-    protected final int flags;
-
     public JdbcCalc(RelOptCluster cluster,
         RelTraitSet traitSet,
         RelNode child,
-        RexProgram program,
-        int flags) {
+        RexProgram program) {
       super(cluster, traitSet, child);
       assert getConvention() instanceof JdbcConvention;
-      this.flags = flags;
       this.program = program;
       this.rowType = program.getOutputRowType();
     }
@@ -398,8 +391,7 @@ public class JdbcRules {
     }
 
     public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) {
-      return new JdbcCalc(getCluster(), traitSet, sole(inputs), program,
-          flags);
+      return new JdbcCalc(getCluster(), traitSet, sole(inputs), program);
     }
 
     public JdbcImplementor.Result implement(JdbcImplementor implementor) {
@@ -444,8 +436,7 @@ public class JdbcRules {
               project.getInput(),
               project.getInput().getTraitSet().replace(out)),
           project.getProjects(),
-          project.getRowType(),
-          Project.Flags.BOXED);
+          project.getRowType());
     }
   }
 
@@ -459,16 +450,14 @@ public class JdbcRules {
         RelTraitSet traitSet,
         RelNode child,
         List<RexNode> exps,
-        RelDataType rowType,
-        int flags) {
-      super(cluster, traitSet, child, exps, rowType, flags);
+        RelDataType rowType) {
+      super(cluster, traitSet, child, exps, rowType);
       assert getConvention() instanceof JdbcConvention;
     }
 
     @Override public JdbcProject copy(RelTraitSet traitSet, RelNode input,
         List<RexNode> exps, RelDataType rowType) {
-      return new JdbcProject(getCluster(), traitSet, input, exps, rowType,
-          flags);
+      return new JdbcProject(getCluster(), traitSet, input, exps, rowType);
     }
 
     @Override public RelOptCost computeSelfCost(RelOptPlanner planner) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a6d32a2/core/src/main/java/org/apache/calcite/interpreter/Bindables.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/Bindables.java b/core/src/main/java/org/apache/calcite/interpreter/Bindables.java
index cfe9b37..abb8082 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/Bindables.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/Bindables.java
@@ -220,8 +220,8 @@ public class Bindables {
               project.getInput().getTraitSet()
                   .replace(BindableConvention.INSTANCE)),
           project.getProjects(),
-          project.getRowType(),
-          Project.Flags.BOXED);
+          project.getRowType()
+      );
     }
   }
 
@@ -229,16 +229,14 @@ public class Bindables {
    * bindable calling convention. */
   public static class BindableProject extends Project implements BindableRel {
     public BindableProject(RelOptCluster cluster, RelTraitSet traitSet,
-        RelNode child, List<? extends RexNode> exps, RelDataType rowType,
-        int flags) {
-      super(cluster, traitSet, child, exps, rowType, flags);
+        RelNode child, List<? extends RexNode> exps, RelDataType rowType) {
+      super(cluster, traitSet, child, exps, rowType);
       assert getConvention() instanceof BindableConvention;
     }
 
     public BindableProject copy(RelTraitSet traitSet, RelNode input,
         List<RexNode> exps, RelDataType rowType) {
-      return new BindableProject(getCluster(), traitSet, input, exps, rowType,
-          flags);
+      return new BindableProject(getCluster(), traitSet, input, exps, rowType);
     }
 
     public Class<Object[]> getElementType() {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a6d32a2/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 72a57f2..88ad2ff 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
@@ -2295,10 +2295,6 @@ public abstract class RelOptUtil {
   public static boolean checkProjAndChildInputs(
       Project project,
       boolean checkNames) {
-    if (!project.isBoxed()) {
-      return false;
-    }
-
     int n = project.getProjects().size();
     RelDataType inputType = project.getInput().getRowType();
     if (inputType.getFieldList().size() != n) {
@@ -2501,7 +2497,7 @@ public abstract class RelOptUtil {
       names.add(field.getName());
     }
     return new LogicalProject(
-        child.getCluster(), child, nodes, names, LogicalProject.Flags.BOXED);
+        child.getCluster(), child, nodes, names);
   }
 
   /** Returns whether relational expression {@code target} occurs within a
@@ -2708,8 +2704,7 @@ public abstract class RelOptUtil {
             : collationList.get(0)),
         child,
         exprs,
-        rowType,
-        Project.Flags.BOXED);
+        rowType);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a6d32a2/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java b/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
index 54fe7b8..de9cb22 100644
--- a/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
+++ b/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
@@ -593,7 +593,7 @@ public class SubstitutionVisitor {
       return new LogicalProject(node.cluster,
           node.cluster.traitSetOf(RelCollationImpl.EMPTY),
           fromMutable(project.input),
-          project.projects, project.rowType, Project.Flags.BOXED);
+          project.projects, project.rowType);
     case FILTER:
       final MutableFilter filter = (MutableFilter) node;
       return new LogicalFilter(node.cluster, fromMutable(filter.input),

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a6d32a2/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 35b43cb..a4de2c0 100644
--- a/core/src/main/java/org/apache/calcite/prepare/LixToRelTranslator.java
+++ b/core/src/main/java/org/apache/calcite/prepare/LixToRelTranslator.java
@@ -92,8 +92,7 @@ class LixToRelTranslator implements RelOptTable.ToRelContext {
             toRex(
                 child,
                 (FunctionExpression) call.expressions.get(0)),
-            null,
-            LogicalProject.Flags.BOXED);
+            null);
 
       case WHERE:
         child = translate(call.targetExpression);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a6d32a2/core/src/main/java/org/apache/calcite/prepare/QueryableRelBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/QueryableRelBuilder.java b/core/src/main/java/org/apache/calcite/prepare/QueryableRelBuilder.java
index c2e4d14..57afc4d 100644
--- a/core/src/main/java/org/apache/calcite/prepare/QueryableRelBuilder.java
+++ b/core/src/main/java/org/apache/calcite/prepare/QueryableRelBuilder.java
@@ -40,7 +40,6 @@ import org.apache.calcite.linq4j.function.Predicate1;
 import org.apache.calcite.linq4j.function.Predicate2;
 import org.apache.calcite.linq4j.tree.FunctionExpression;
 import org.apache.calcite.rel.RelNode;
-import org.apache.calcite.rel.core.Project;
 import org.apache.calcite.rel.logical.LogicalFilter;
 import org.apache.calcite.rel.logical.LogicalProject;
 import org.apache.calcite.rel.logical.LogicalTableScan;
@@ -515,8 +514,7 @@ class QueryableRelBuilder<T> implements QueryableFactory<T> {
             translator.cluster,
             child,
             nodes,
-            null,
-            Project.Flags.BOXED));
+            null));
     return null;
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a6d32a2/core/src/main/java/org/apache/calcite/rel/core/Project.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Project.java b/core/src/main/java/org/apache/calcite/rel/core/Project.java
index ec3978b..ebd2544 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Project.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Project.java
@@ -67,11 +67,6 @@ public abstract class Project extends SingleRel {
 
   protected final ImmutableList<RexNode> exps;
 
-  /**
-   * Values defined in {@link Flags}.
-   */
-  protected int flags;
-
   protected final ImmutableList<RelCollation> collationList;
 
   //~ Constructors -----------------------------------------------------------
@@ -84,21 +79,17 @@ public abstract class Project extends SingleRel {
    * @param input   input relational expression
    * @param exps    List of expressions for the input columns
    * @param rowType output row type
-   * @param flags      Flags; values as in {@link Project.Flags},
-   *                   usually {@link Project.Flags#BOXED}
    */
   protected Project(
       RelOptCluster cluster,
       RelTraitSet traits,
       RelNode input,
       List<? extends RexNode> exps,
-      RelDataType rowType,
-      int flags) {
+      RelDataType rowType) {
     super(cluster, traits, input);
     assert rowType != null;
     this.exps = ImmutableList.copyOf(exps);
     this.rowType = rowType;
-    this.flags = flags;
     final RelCollation collation =
         traits.getTrait(RelCollationTraitDef.INSTANCE);
     this.collationList =
@@ -114,7 +105,7 @@ public abstract class Project extends SingleRel {
   protected Project(RelInput input) {
     this(input.getCluster(), input.getTraitSet(), input.getInput(),
         input.getExpressionList("exprs"),
-        input.getRowType("exprs", "fields"), Flags.BOXED);
+        input.getRowType("exprs", "fields"));
   }
 
   //~ Methods ----------------------------------------------------------------
@@ -144,10 +135,6 @@ public abstract class Project extends SingleRel {
     return collationList;
   }
 
-  public boolean isBoxed() {
-    return (flags & Flags.BOXED) == Flags.BOXED;
-  }
-
   @Override public List<RexNode> getChildExps() {
     return exps;
   }
@@ -179,10 +166,6 @@ public abstract class Project extends SingleRel {
     return Pair.zip(getProjects(), getRowType().getFieldNames());
   }
 
-  public int getFlags() {
-    return flags;
-  }
-
   public boolean isValid(boolean fail) {
     if (!super.isValid(fail)) {
       assert !fail;
@@ -205,12 +188,6 @@ public abstract class Project extends SingleRel {
       assert !fail;
       return false;
     }
-    if (!isBoxed()) {
-      if (exps.size() != 1) {
-        assert !fail;
-        return false;
-      }
-    }
     if (collationList == null) {
       assert !fail;
       return false;
@@ -357,22 +334,6 @@ public abstract class Project extends SingleRel {
 
   //~ Inner Classes ----------------------------------------------------------
 
-  /** A collection of integer constants that describe the kind of project. */
-  public static class Flags {
-    public static final int ANON_FIELDS = 2;
-
-    /**
-     * Whether the resulting row is to be a synthetic class whose fields are
-     * the aliases of the fields. <code>boxed</code> must be true unless
-     * there is only one field: <code>select {dept.deptno} from dept</code>
-     * is boxed, <code>select dept.deptno from dept</code> is not.
-     */
-    public static final int BOXED = 1;
-    public static final int NONE = 0;
-  }
-
-  //~ Inner Classes ----------------------------------------------------------
-
   /**
    * Visitor which walks over a program and checks validity.
    */

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a6d32a2/core/src/main/java/org/apache/calcite/rel/logical/LogicalProject.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalProject.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalProject.java
index 8cc81a5..d60324a 100644
--- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalProject.java
+++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalProject.java
@@ -44,15 +44,12 @@ public final class LogicalProject extends Project {
    * @param child      input relational expression
    * @param exps       set of expressions for the input columns
    * @param fieldNames aliases of the expressions
-   * @param flags      Flags; values as in {@link Project.Flags},
-   *                   usually {@link Project.Flags#BOXED}
    */
   public LogicalProject(
       RelOptCluster cluster,
       RelNode child,
       List<RexNode> exps,
-      List<String> fieldNames,
-      int flags) {
+      List<String> fieldNames) {
     this(
         cluster,
         cluster.traitSetOf(RelCollationImpl.EMPTY),
@@ -61,8 +58,7 @@ public final class LogicalProject extends Project {
         RexUtil.createStructType(
             cluster.getTypeFactory(),
             exps,
-            fieldNames),
-        flags);
+            fieldNames));
   }
 
   /**
@@ -73,17 +69,14 @@ public final class LogicalProject extends Project {
    * @param child    input relational expression
    * @param exps     List of expressions for the input columns
    * @param rowType  output row type
-   * @param flags      Flags; values as in {@link Project.Flags},
-   *                   usually {@link Project.Flags#BOXED}
    */
   public LogicalProject(
       RelOptCluster cluster,
       RelTraitSet traitSet,
       RelNode child,
       List<? extends RexNode> exps,
-      RelDataType rowType,
-      int flags) {
-    super(cluster, traitSet, child, exps, rowType, flags);
+      RelDataType rowType) {
+    super(cluster, traitSet, child, exps, rowType);
     assert traitSet.containsIfApplicable(Convention.NONE);
   }
 
@@ -98,8 +91,7 @@ public final class LogicalProject extends Project {
 
   @Override public LogicalProject copy(RelTraitSet traitSet, RelNode input,
       List<RexNode> exps, RelDataType rowType) {
-    return new LogicalProject(getCluster(), traitSet, input, exps, rowType,
-        flags);
+    return new LogicalProject(getCluster(), traitSet, input, exps, rowType);
   }
 
   @Override public RelNode accept(RelShuttle shuttle) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a6d32a2/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
index 16c5e82..d1bcaf2 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
@@ -200,8 +200,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
                     project.getTraitSet(),
                     project.getInput(),
                     expList,
-                    project.getRowType(),
-                    LogicalProject.Flags.BOXED));
+                    project.getRowType()));
 
             // New plan is absolutely better than old plan.
             call.getPlanner().setImportance(project, 0.0);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a6d32a2/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 7227d86..4723114 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -678,8 +678,7 @@ public class SqlToRelConverter {
               cluster,
               rel,
               Pair.left(newProjects),
-              Pair.right(newProjects),
-              LogicalProject.Flags.BOXED);
+              Pair.right(newProjects));
 
       bb.root = rel;
       distinctify(bb, false);
@@ -703,8 +702,7 @@ public class SqlToRelConverter {
               cluster,
               rel,
               Pair.left(undoProjects),
-              Pair.right(undoProjects),
-              LogicalProject.Flags.BOXED);
+              Pair.right(undoProjects));
 
       bb.setRoot(
           rel,
@@ -790,8 +788,7 @@ public class SqlToRelConverter {
               bb.root,
               exprs,
               cluster.getTypeFactory().createStructType(
-                  rowType.getFieldList().subList(0, fieldCount)),
-              Project.Flags.BOXED),
+                  rowType.getFieldList().subList(0, fieldCount))),
           false);
     }
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a6d32a2/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 23fe783..4342c19 100644
--- a/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
+++ b/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
@@ -38,7 +38,6 @@ import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.RelCollationTraitDef;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.convert.ConverterRule;
-import org.apache.calcite.rel.core.Project;
 import org.apache.calcite.rel.core.TableScan;
 import org.apache.calcite.rel.metadata.RelMetadataQuery;
 import org.apache.calcite.rel.rules.FilterMergeRule;
@@ -790,8 +789,7 @@ public class PlannerTest {
           convert(project.getInput(),
               project.getInput().getTraitSet().replace(getOutConvention())),
           project.getProjects(),
-          project.getRowType(),
-          Project.Flags.BOXED);
+          project.getRowType());
     }
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a6d32a2/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoProject.java
----------------------------------------------------------------------
diff --git a/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoProject.java b/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoProject.java
index 9bbf512..c2f5a52 100644
--- a/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoProject.java
+++ b/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoProject.java
@@ -37,8 +37,8 @@ import java.util.List;
  */
 public class MongoProject extends Project implements MongoRel {
   public MongoProject(RelOptCluster cluster, RelTraitSet traitSet,
-      RelNode child, List<RexNode> exps, RelDataType rowType, int flags) {
-    super(cluster, traitSet, child, exps, rowType, flags);
+      RelNode child, List<RexNode> exps, RelDataType rowType) {
+    super(cluster, traitSet, child, exps, rowType);
     assert getConvention() == MongoRel.CONVENTION;
     assert getConvention() == child.getConvention();
   }
@@ -46,7 +46,7 @@ public class MongoProject extends Project implements MongoRel {
   @Override public Project copy(RelTraitSet traitSet, RelNode input,
       List<RexNode> exps, RelDataType rowType) {
     return new MongoProject(getCluster(), traitSet, input, exps,
-        rowType, flags);
+        rowType);
   }
 
   @Override public RelOptCost computeSelfCost(RelOptPlanner planner) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a6d32a2/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoRules.java
----------------------------------------------------------------------
diff --git a/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoRules.java b/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoRules.java
index 2b2f250..f67e0ee 100644
--- a/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoRules.java
+++ b/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoRules.java
@@ -261,7 +261,7 @@ public class MongoRules {
       final RelTraitSet traitSet = project.getTraitSet().replace(out);
       return new MongoProject(project.getCluster(), traitSet,
           convert(project.getInput(), traitSet), project.getProjects(),
-          project.getRowType(), LogicalProject.Flags.BOXED);
+          project.getRowType());
     }
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a6d32a2/spark/src/main/java/org/apache/calcite/adapter/spark/SparkRules.java
----------------------------------------------------------------------
diff --git a/spark/src/main/java/org/apache/calcite/adapter/spark/SparkRules.java b/spark/src/main/java/org/apache/calcite/adapter/spark/SparkRules.java
index 24ebc99..6ba9b7e 100644
--- a/spark/src/main/java/org/apache/calcite/adapter/spark/SparkRules.java
+++ b/spark/src/main/java/org/apache/calcite/adapter/spark/SparkRules.java
@@ -41,7 +41,6 @@ import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelWriter;
 import org.apache.calcite.rel.SingleRel;
 import org.apache.calcite.rel.convert.ConverterRule;
-import org.apache.calcite.rel.core.Project;
 import org.apache.calcite.rel.core.Values;
 import org.apache.calcite.rel.logical.LogicalCalc;
 import org.apache.calcite.rel.logical.LogicalFilter;
@@ -240,8 +239,7 @@ public abstract class SparkRules {
           rel.getTraitSet().replace(SparkRel.CONVENTION),
           convert(calc.getInput(),
               calc.getInput().getTraitSet().replace(SparkRel.CONVENTION)),
-          program,
-          Project.Flags.BOXED);
+          program);
     }
   }
 
@@ -250,20 +248,13 @@ public abstract class SparkRules {
   public static class SparkCalc extends SingleRel implements SparkRel {
     private final RexProgram program;
 
-    /**
-     * Values defined in {@link org.apache.calcite.rel.core.Project.Flags}.
-     */
-    protected int flags;
-
     public SparkCalc(RelOptCluster cluster,
         RelTraitSet traitSet,
         RelNode child,
-        RexProgram program,
-        int flags) {
+        RexProgram program) {
       super(cluster, traitSet, child);
       assert getConvention() == SparkRel.CONVENTION;
       assert !program.containsAggs();
-      this.flags = flags;
       this.program = program;
       this.rowType = program.getOutputRowType();
     }
@@ -290,12 +281,7 @@ public abstract class SparkRules {
           getCluster(),
           traitSet,
           sole(inputs),
-          program,
-          getFlags());
-    }
-
-    public int getFlags() {
-      return flags;
+          program);
     }
 
     public Result implementSpark(Implementor implementor) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/5a6d32a2/splunk/src/main/java/org/apache/calcite/adapter/splunk/SplunkPushDownRule.java
----------------------------------------------------------------------
diff --git a/splunk/src/main/java/org/apache/calcite/adapter/splunk/SplunkPushDownRule.java b/splunk/src/main/java/org/apache/calcite/adapter/splunk/SplunkPushDownRule.java
index 49bb859..2976f87 100644
--- a/splunk/src/main/java/org/apache/calcite/adapter/splunk/SplunkPushDownRule.java
+++ b/splunk/src/main/java/org/apache/calcite/adapter/splunk/SplunkPushDownRule.java
@@ -285,7 +285,7 @@ public class SplunkPushDownRule
             proj.getCollationList().isEmpty()
                 ? RelCollationImpl.EMPTY
                 : proj.getCollationList().get(0)),
-        rel, proj.getProjects(), proj.getRowType(), proj.getFlags());
+        rel, proj.getProjects(), proj.getRowType());
   }
 
   // TODO: use StringBuilder instead of String


[5/9] incubator-calcite git commit: [CALCITE-88] Add collation as a trait and a kind of RelNode metadata

Posted by jh...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/logical/LogicalTableFunctionScan.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalTableFunctionScan.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalTableFunctionScan.java
index e4e02f6..c21720f 100644
--- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalTableFunctionScan.java
+++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalTableFunctionScan.java
@@ -52,20 +52,26 @@ public class LogicalTableFunctionScan extends TableFunctionScan {
    */
   public LogicalTableFunctionScan(
       RelOptCluster cluster,
+      RelTraitSet traitSet,
       List<RelNode> inputs,
       RexNode rexCall,
       Type elementType, RelDataType rowType,
       Set<RelColumnMapping> columnMappings) {
-    super(
-        cluster,
-        cluster.traitSetOf(Convention.NONE),
-        inputs,
-        rexCall,
-        elementType,
-        rowType,
+    super(cluster, traitSet, inputs, rexCall, elementType, rowType,
         columnMappings);
   }
 
+  @Deprecated // to be removed before 2.0
+  public LogicalTableFunctionScan(
+      RelOptCluster cluster,
+      List<RelNode> inputs,
+      RexNode rexCall,
+      Type elementType, RelDataType rowType,
+      Set<RelColumnMapping> columnMappings) {
+    this(cluster, cluster.traitSetOf(Convention.NONE), inputs, rexCall,
+        elementType, rowType, columnMappings);
+  }
+
   /**
    * Creates a LogicalTableFunctionScan by parsing serialized output.
    */
@@ -73,6 +79,18 @@ public class LogicalTableFunctionScan extends TableFunctionScan {
     super(input);
   }
 
+  /** Creates a LogicalTableFunctionScan. */
+  public static LogicalTableFunctionScan create(
+      RelOptCluster cluster,
+      List<RelNode> inputs,
+      RexNode rexCall,
+      Type elementType, RelDataType rowType,
+      Set<RelColumnMapping> columnMappings) {
+    final RelTraitSet traitSet = cluster.traitSetOf(Convention.NONE);
+    return new LogicalTableFunctionScan(cluster, traitSet, inputs, rexCall,
+        elementType, rowType, columnMappings);
+  }
+
   //~ Methods ----------------------------------------------------------------
 
   @Override public LogicalTableFunctionScan copy(

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/logical/LogicalTableModify.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalTableModify.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalTableModify.java
index c1835ff..f8c76ab 100644
--- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalTableModify.java
+++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalTableModify.java
@@ -33,38 +33,49 @@ import java.util.List;
 public final class LogicalTableModify extends TableModify {
   //~ Constructors -----------------------------------------------------------
 
-  public LogicalTableModify(
-      RelOptCluster cluster,
-      RelOptTable table,
-      Prepare.CatalogReader schema,
-      RelNode child,
-      Operation operation,
-      List<String> updateColumnList,
-      boolean flattened) {
-    super(
-        cluster,
+  /**
+   * Creates a LogicalTableModify.
+   *
+   * <p>Use {@link #create} unless you know what you're doing.
+   */
+  public LogicalTableModify(RelOptCluster cluster, RelTraitSet traitSet,
+      RelOptTable table, Prepare.CatalogReader schema, RelNode input,
+      Operation operation, List<String> updateColumnList, boolean flattened) {
+    super(cluster, traitSet, table, schema, input, operation, updateColumnList,
+        flattened);
+  }
+
+  @Deprecated // to be removed before 2.0
+  public LogicalTableModify(RelOptCluster cluster, RelOptTable table,
+      Prepare.CatalogReader schema, RelNode input, Operation operation,
+      List<String> updateColumnList, boolean flattened) {
+    this(cluster,
         cluster.traitSetOf(Convention.NONE),
         table,
         schema,
-        child,
+        input,
         operation,
         updateColumnList,
         flattened);
   }
 
+  /** Creates a LogicalTableModify. */
+  public static LogicalTableModify create(RelOptTable table,
+      Prepare.CatalogReader schema, RelNode input,
+      Operation operation, List<String> updateColumnList, boolean flattened) {
+    final RelOptCluster cluster = input.getCluster();
+    final RelTraitSet traitSet = cluster.traitSetOf(Convention.NONE);
+    return new LogicalTableModify(cluster, traitSet, table, schema, input,
+        operation, updateColumnList, flattened);
+  }
+
   //~ Methods ----------------------------------------------------------------
 
   @Override public LogicalTableModify copy(RelTraitSet traitSet,
       List<RelNode> inputs) {
     assert traitSet.containsIfApplicable(Convention.NONE);
-    return new LogicalTableModify(
-        getCluster(),
-        table,
-        catalogReader,
-        sole(inputs),
-        getOperation(),
-        getUpdateColumnList(),
-        isFlattened());
+    return new LogicalTableModify(getCluster(), traitSet, table, catalogReader,
+        sole(inputs), getOperation(), getUpdateColumnList(), isFlattened());
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/logical/LogicalTableScan.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalTableScan.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalTableScan.java
index 5340fd0..10b777c 100644
--- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalTableScan.java
+++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalTableScan.java
@@ -58,16 +58,16 @@ public final class LogicalTableScan extends TableScan {
   /**
    * Creates a LogicalTableScan.
    *
-   * @param cluster Cluster
-   * @param table   Table
+   * <p>Use {@link #create} unless you know what you're doing.
    */
-  public LogicalTableScan(
-      RelOptCluster cluster,
+  public LogicalTableScan(RelOptCluster cluster, RelTraitSet traitSet,
       RelOptTable table) {
-    super(
-        cluster,
-        cluster.traitSetOf(Convention.NONE),
-        table);
+    super(cluster, traitSet, table);
+  }
+
+  @Deprecated // to be removed before 2.0
+  public LogicalTableScan(RelOptCluster cluster, RelOptTable table) {
+    this(cluster, cluster.traitSetOf(Convention.NONE), table);
   }
 
   /**
@@ -82,6 +82,13 @@ public final class LogicalTableScan extends TableScan {
     assert inputs.isEmpty();
     return this;
   }
+
+  /** Creates a LogicalTableScan. */
+  public static LogicalTableScan create(RelOptCluster cluster,
+      RelOptTable table) {
+    final RelTraitSet traitSet = cluster.traitSetOf(Convention.NONE);
+    return new LogicalTableScan(cluster, traitSet, table);
+  }
 }
 
 // End LogicalTableScan.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/logical/LogicalUnion.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalUnion.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalUnion.java
index 49dde4d..ab7f3bf 100644
--- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalUnion.java
+++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalUnion.java
@@ -33,15 +33,22 @@ import java.util.List;
 public final class LogicalUnion extends Union {
   //~ Constructors -----------------------------------------------------------
 
-  public LogicalUnion(
-      RelOptCluster cluster,
+  /**
+   * Creates a LogicalUnion.
+   *
+   * <p>Use {@link #create} unless you know what you're doing.
+   */
+  public LogicalUnion(RelOptCluster cluster,
+      RelTraitSet traitSet,
       List<RelNode> inputs,
       boolean all) {
-    super(
-        cluster,
-        cluster.traitSetOf(Convention.NONE),
-        inputs,
-        all);
+    super(cluster, traitSet, inputs, all);
+  }
+
+  @Deprecated // to be removed before 2.0
+  public LogicalUnion(RelOptCluster cluster, List<RelNode> inputs,
+      boolean all) {
+    this(cluster, cluster.traitSetOf(Convention.NONE), inputs, all);
   }
 
   /**
@@ -51,15 +58,19 @@ public final class LogicalUnion extends Union {
     super(input);
   }
 
+  /** Creates a LogicalUnion. */
+  public static LogicalUnion create(List<RelNode> inputs, boolean all) {
+    final RelOptCluster cluster = inputs.get(0).getCluster();
+    final RelTraitSet traitSet = cluster.traitSetOf(Convention.NONE);
+    return new LogicalUnion(cluster, traitSet, inputs, all);
+  }
+
   //~ Methods ----------------------------------------------------------------
 
   public LogicalUnion copy(
       RelTraitSet traitSet, List<RelNode> inputs, boolean all) {
     assert traitSet.containsIfApplicable(Convention.NONE);
-    return new LogicalUnion(
-        getCluster(),
-        inputs,
-        all);
+    return new LogicalUnion(getCluster(), traitSet, inputs, all);
   }
 
   @Override public RelNode accept(RelShuttle shuttle) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/logical/LogicalValues.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalValues.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalValues.java
index 5d80851..02ca053 100644
--- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalValues.java
+++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalValues.java
@@ -19,14 +19,18 @@ package org.apache.calcite.rel.logical;
 import org.apache.calcite.plan.Convention;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelCollationTraitDef;
 import org.apache.calcite.rel.RelInput;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelShuttle;
 import org.apache.calcite.rel.core.Values;
+import org.apache.calcite.rel.metadata.RelMdCollation;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rex.RexLiteral;
 import org.apache.calcite.sql.type.SqlTypeName;
 
+import com.google.common.base.Supplier;
 import com.google.common.collect.ImmutableList;
 
 import java.math.BigDecimal;
@@ -40,11 +44,9 @@ public class LogicalValues extends Values {
   //~ Constructors -----------------------------------------------------------
 
   /**
-   * Creates a new LogicalValues.
+   * Creates a LogicalValues.
    *
-   * <p>Note that tuples passed in become owned by this
-   * rel (without a deep copy), so caller must not modify them after this
-   * call, otherwise bad things will happen.
+   * <p>Use {@link #create} unless you know what you're doing.
    *
    * @param cluster Cluster that this relational expression belongs to
    * @param rowType Row type for tuples produced by this rel
@@ -54,9 +56,18 @@ public class LogicalValues extends Values {
    */
   public LogicalValues(
       RelOptCluster cluster,
+      RelTraitSet traitSet,
       RelDataType rowType,
       ImmutableList<ImmutableList<RexLiteral>> tuples) {
-    super(cluster, rowType, tuples, cluster.traitSetOf(Convention.NONE));
+    super(cluster, rowType, tuples, traitSet);
+  }
+
+  @Deprecated // to be removed before 2.0
+  public LogicalValues(
+      RelOptCluster cluster,
+      RelDataType rowType,
+      ImmutableList<ImmutableList<RexLiteral>> tuples) {
+    this(cluster, cluster.traitSetOf(Convention.NONE), rowType, tuples);
   }
 
   /**
@@ -66,19 +77,30 @@ public class LogicalValues extends Values {
     super(input);
   }
 
+  /** Creates a LogicalValues. */
+  public static LogicalValues create(RelOptCluster cluster,
+      final RelDataType rowType,
+      final ImmutableList<ImmutableList<RexLiteral>> tuples) {
+    final RelTraitSet traitSet = cluster.traitSetOf(Convention.NONE)
+        .replaceIf(RelCollationTraitDef.INSTANCE,
+            new Supplier<List<RelCollation>>() {
+              public List<RelCollation> get() {
+                return RelMdCollation.values(rowType, tuples);
+              }
+            });
+    return new LogicalValues(cluster, traitSet, rowType, tuples);
+  }
+
   @Override public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) {
     assert traitSet.containsIfApplicable(Convention.NONE);
     assert inputs.isEmpty();
-    return new LogicalValues(
-        getCluster(),
-        rowType,
-        tuples);
+    return new LogicalValues(getCluster(), traitSet, rowType, tuples);
   }
 
   /** Creates a LogicalValues that outputs no rows of a given row type. */
   public static LogicalValues createEmpty(RelOptCluster cluster,
       RelDataType rowType) {
-    return new LogicalValues(cluster, rowType,
+    return create(cluster, rowType,
         ImmutableList.<ImmutableList<RexLiteral>>of());
   }
 
@@ -93,7 +115,7 @@ public class LogicalValues extends Values {
             ImmutableList.of(
                 cluster.getRexBuilder().makeExactLiteral(BigDecimal.ZERO,
                     rowType.getFieldList().get(0).getType())));
-    return new LogicalValues(cluster, rowType, tuples);
+    return create(cluster, rowType, tuples);
   }
 
   @Override public RelNode accept(RelShuttle shuttle) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/metadata/BuiltInMetadata.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/BuiltInMetadata.java b/core/src/main/java/org/apache/calcite/rel/metadata/BuiltInMetadata.java
index 5aa668f..1ab70e1 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/BuiltInMetadata.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/BuiltInMetadata.java
@@ -18,11 +18,14 @@ package org.apache.calcite.rel.metadata;
 
 import org.apache.calcite.plan.RelOptCost;
 import org.apache.calcite.plan.RelOptPredicateList;
+import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.sql.SqlExplainLevel;
 import org.apache.calcite.util.ImmutableBitSet;
 
+import com.google.common.collect.ImmutableList;
+
 import java.util.Set;
 
 /**
@@ -85,6 +88,12 @@ public abstract class BuiltInMetadata {
     Boolean areColumnsUnique(ImmutableBitSet columns, boolean ignoreNulls);
   }
 
+  /** Metadata about which columns are sorted. */
+  public interface Collation extends Metadata {
+    /** Determines which columns are sorted. */
+    ImmutableList<RelCollation> collations();
+  }
+
   /** Metadata about the number of rows returned by a relational expression. */
   public interface RowCount extends Metadata {
     /**

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/metadata/DefaultRelMetadataProvider.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/DefaultRelMetadataProvider.java b/core/src/main/java/org/apache/calcite/rel/metadata/DefaultRelMetadataProvider.java
index 33ad92f..8078af2 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/DefaultRelMetadataProvider.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/DefaultRelMetadataProvider.java
@@ -44,7 +44,8 @@ public class DefaultRelMetadataProvider extends ChainedRelMetadataProvider {
             RelMdDistinctRowCount.SOURCE,
             RelMdSelectivity.SOURCE,
             RelMdExplainVisibility.SOURCE,
-            RelMdPredicates.SOURCE));
+            RelMdPredicates.SOURCE,
+            RelMdCollation.SOURCE));
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
new file mode 100644
index 0000000..16168ca
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
@@ -0,0 +1,308 @@
+/*
+ * 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.metadata;
+
+import org.apache.calcite.adapter.enumerable.EnumerableMergeJoin;
+import org.apache.calcite.linq4j.Ord;
+import org.apache.calcite.plan.RelOptTable;
+import org.apache.calcite.plan.hep.HepRelVertex;
+import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelCollations;
+import org.apache.calcite.rel.RelFieldCollation;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.Filter;
+import org.apache.calcite.rel.core.Join;
+import org.apache.calcite.rel.core.Project;
+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.core.Window;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rex.RexInputRef;
+import org.apache.calcite.rex.RexLiteral;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexProgram;
+import org.apache.calcite.util.BuiltInMethod;
+import org.apache.calcite.util.ImmutableIntList;
+import org.apache.calcite.util.Pair;
+import org.apache.calcite.util.Util;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.LinkedListMultimap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Ordering;
+import com.google.common.collect.Sets;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.SortedSet;
+
+/**
+ * RelMdCollation supplies a default implementation of
+ * {@link org.apache.calcite.rel.metadata.RelMetadataQuery#collations}
+ * for the standard logical algebra.
+ */
+public class RelMdCollation {
+  public static final RelMetadataProvider SOURCE =
+      ReflectiveRelMetadataProvider.reflectiveSource(
+          BuiltInMethod.COLLATIONS.method, new RelMdCollation());
+
+  //~ Constructors -----------------------------------------------------------
+
+  private RelMdCollation() {}
+
+  //~ Methods ----------------------------------------------------------------
+
+  /** Fallback method to deduce collations for any relational expression not
+   * handled by a more specific method.
+   *
+   * <p>{@link org.apache.calcite.rel.core.Union},
+   * {@link org.apache.calcite.rel.core.Intersect},
+   * {@link org.apache.calcite.rel.core.Minus},
+   * {@link org.apache.calcite.rel.core.Join},
+   * {@link org.apache.calcite.rel.core.SemiJoin},
+   * {@link org.apache.calcite.rel.core.Correlate}
+   * do not in general return sorted results
+   * (but implementations using particular algorithms may).
+   *
+   * @param rel Relational expression
+   * @return Relational expression's collations
+   */
+  public ImmutableList<RelCollation> collations(RelNode rel) {
+    return ImmutableList.of();
+  }
+
+  public ImmutableList<RelCollation> collations(Window rel) {
+    return ImmutableList.copyOf(window(rel.getInput(), rel.groups));
+  }
+
+  public ImmutableList<RelCollation> collations(Filter rel) {
+    return RelMetadataQuery.collations(rel.getInput());
+  }
+
+  public ImmutableList<RelCollation> collations(TableScan scan) {
+    return ImmutableList.copyOf(table(scan.getTable()));
+  }
+
+  public ImmutableList<RelCollation> collations(EnumerableMergeJoin join) {
+    // In general a join is not sorted. But a merge join preserves the sort
+    // order of the left and right sides.
+    return ImmutableList.copyOf(
+        RelMdCollation.mergeJoin(join.getLeft(),
+            join.getRight(),
+            join.getLeftKeys(),
+            join.getRightKeys()));
+  }
+
+  public ImmutableList<RelCollation> collations(Sort sort) {
+    return ImmutableList.copyOf(
+        RelMdCollation.sort(sort.getCollation()));
+  }
+
+  public ImmutableList<RelCollation> collations(Project project) {
+    return ImmutableList.copyOf(
+        project(project.getInput(), project.getProjects()));
+  }
+
+  public ImmutableList<RelCollation> collations(Values values) {
+    return ImmutableList.copyOf(
+        values(values.getRowType(), values.getTuples()));
+  }
+
+  public ImmutableList<RelCollation> collations(HepRelVertex rel) {
+    return RelMetadataQuery.collations(rel.getCurrentRel());
+  }
+
+  // Helper methods
+
+  /** Helper method to determine a
+   * {@link org.apache.calcite.rel.core.TableScan}'s collation. */
+  public static List<RelCollation> table(RelOptTable table) {
+    return table.getCollationList();
+  }
+
+  /** Helper method to determine a
+   * {@link org.apache.calcite.rel.core.Sort}'s collation. */
+  public static List<RelCollation> sort(RelCollation collation) {
+    return ImmutableList.of(collation);
+  }
+
+  /** Helper method to determine a
+   * {@link org.apache.calcite.rel.core.Filter}'s collation. */
+  public static List<RelCollation> filter(RelNode input) {
+    return RelMetadataQuery.collations(input);
+  }
+
+  /** Helper method to determine a
+   * {@link org.apache.calcite.rel.core.Calc}'s collation. */
+  public static List<RelCollation> calc(RelNode input,
+      RexProgram program) {
+    return program.getCollations(RelMetadataQuery.collations(input));
+  }
+
+  /** Helper method to determine a {@link Project}'s collation. */
+  public static List<RelCollation> project(RelNode input,
+      List<? extends RexNode> projects) {
+    // TODO: also monotonic expressions
+    final SortedSet<RelCollation> collations = Sets.newTreeSet();
+    final List<RelCollation> inputCollations =
+        RelMetadataQuery.collations(input);
+    if (inputCollations == null || inputCollations.isEmpty()) {
+      return ImmutableList.of();
+    }
+    final Multimap<Integer, Integer> targets = LinkedListMultimap.create();
+    for (Ord<RexNode> project : Ord.zip(projects)) {
+      if (project.e instanceof RexInputRef) {
+        targets.put(((RexInputRef) project.e).getIndex(), project.i);
+      }
+    }
+    final List<RelFieldCollation> fieldCollations = Lists.newArrayList();
+  loop:
+    for (RelCollation ic : inputCollations) {
+      if (ic.getFieldCollations().isEmpty()) {
+        continue;
+      }
+      fieldCollations.clear();
+      for (RelFieldCollation ifc : ic.getFieldCollations()) {
+        final Collection<Integer> integers = targets.get(ifc.getFieldIndex());
+        if (integers.isEmpty()) {
+          continue loop; // cannot do this collation
+        }
+        fieldCollations.add(ifc.copy(integers.iterator().next()));
+      }
+      assert !fieldCollations.isEmpty();
+      collations.add(RelCollations.of(fieldCollations));
+    }
+    return ImmutableList.copyOf(collations);
+  }
+
+  /** Helper method to determine a
+   * {@link org.apache.calcite.rel.core.Window}'s collation.
+   *
+   * <p>A Window projects the fields of its input first, followed by the output
+   * from each of its windows. Assuming (quite reasonably) that the
+   * implementation does not re-order its input rows, then any collations of its
+   * input are preserved. */
+  public static List<RelCollation> window(RelNode input,
+      ImmutableList<Window.Group> groups) {
+    return RelMetadataQuery.collations(input);
+  }
+
+  /** Helper method to determine a
+   * {@link org.apache.calcite.rel.core.Values}'s collation.
+   *
+   * <p>We actually under-report the collations. A Values with 0 or 1 rows - an
+   * edge case, but legitimate and very common - is ordered by every permutation
+   * of every subset of the columns.
+   *
+   * <p>So, our algorithm aims to:<ul>
+   *   <li>produce at most N collations (where N is the number of columns);
+   *   <li>make each collation as long as possible;
+   *   <li>do not repeat combinations already emitted -
+   *       if we've emitted {@code (a, b)} do not later emit {@code (b, a)};
+   *   <li>probe the actual values and make sure that each collation is
+   *      consistent with the data
+   * </ul>
+   *
+   * <p>So, for an empty Values with 4 columns, we would emit
+   * {@code (a, b, c, d), (b, c, d), (c, d), (d)}. */
+  public static List<RelCollation> values(RelDataType rowType,
+      ImmutableList<ImmutableList<RexLiteral>> tuples) {
+    final List<RelCollation> list = Lists.newArrayList();
+    final int n = rowType.getFieldCount();
+    final List<Pair<RelFieldCollation, Ordering<List<RexLiteral>>>> pairs =
+        Lists.newArrayList();
+  outer:
+    for (int i = 0; i < n; i++) {
+      pairs.clear();
+      for (int j = i; j < n; j++) {
+        final RelFieldCollation fieldCollation = new RelFieldCollation(j);
+        Ordering<List<RexLiteral>> comparator = comparator(fieldCollation);
+        Ordering<List<RexLiteral>> ordering;
+        if (pairs.isEmpty()) {
+          ordering = comparator;
+        } else {
+          ordering = Util.last(pairs).right.compound(comparator);
+        }
+        pairs.add(Pair.of(fieldCollation, ordering));
+        if (!ordering.isOrdered(tuples)) {
+          if (j == i) {
+            continue outer;
+          }
+          pairs.remove(pairs.size() - 1);
+        }
+      }
+      if (!pairs.isEmpty()) {
+        list.add(RelCollations.of(Pair.left(pairs)));
+      }
+    }
+    return list;
+  }
+
+  private static Ordering<List<RexLiteral>> comparator(
+      RelFieldCollation fieldCollation) {
+    final int nullComparison = fieldCollation.nullDirection.nullComparison;
+    final int x = fieldCollation.getFieldIndex();
+    switch (fieldCollation.direction) {
+    case ASCENDING:
+      return new Ordering<List<RexLiteral>>() {
+        public int compare(List<RexLiteral> o1, List<RexLiteral> o2) {
+          final Comparable c1 = o1.get(x).getValue();
+          final Comparable c2 = o2.get(x).getValue();
+          return RelFieldCollation.compare(c1, c2, nullComparison);
+        }
+      };
+    default:
+      return new Ordering<List<RexLiteral>>() {
+        public int compare(List<RexLiteral> o1, List<RexLiteral> o2) {
+          final Comparable c1 = o1.get(x).getValue();
+          final Comparable c2 = o2.get(x).getValue();
+          return RelFieldCollation.compare(c2, c1, -nullComparison);
+        }
+      };
+    }
+  }
+
+  /** Helper method to determine a {@link Join}'s collation assuming that it
+   * uses a merge-join algorithm.
+   *
+   * <p>If the inputs are sorted on other keys <em>in addition to</em> the join
+   * key, the result preserves those collations too. */
+  public static List<RelCollation> mergeJoin(RelNode left, RelNode right,
+      ImmutableIntList leftKeys, ImmutableIntList rightKeys) {
+    final ImmutableList.Builder<RelCollation> builder = ImmutableList.builder();
+
+    final ImmutableList<RelCollation> leftCollations =
+        RelMetadataQuery.collations(left);
+    assert RelCollations.contains(leftCollations, leftKeys)
+        : "cannot merge join: left input is not sorted on left keys";
+    builder.addAll(leftCollations);
+
+    final ImmutableList<RelCollation> rightCollations =
+        RelMetadataQuery.collations(right);
+    assert RelCollations.contains(rightCollations, rightKeys)
+        : "cannot merge join: right input is not sorted on right keys";
+    final int leftFieldCount = left.getRowType().getFieldCount();
+    for (RelCollation collation : rightCollations) {
+      builder.add(RelCollations.shift(collation, leftFieldCount));
+    }
+    return builder.build();
+  }
+}
+
+// End RelMdCollation.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataQuery.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataQuery.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataQuery.java
index c537ef1..b17864d 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataQuery.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataQuery.java
@@ -19,11 +19,13 @@ package org.apache.calcite.rel.metadata;
 import org.apache.calcite.plan.RelOptCost;
 import org.apache.calcite.plan.RelOptPredicateList;
 import org.apache.calcite.plan.RelOptTable;
+import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.sql.SqlExplainLevel;
 import org.apache.calcite.util.ImmutableBitSet;
 
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 
 import java.util.Set;
@@ -277,6 +279,21 @@ public abstract class RelMetadataQuery {
 
   /**
    * Returns the
+   * {@link org.apache.calcite.rel.metadata.BuiltInMetadata.Collation#collations()}
+   * statistic.
+   *
+   * @param rel         the relational expression
+   * @return List of sorted column combinations, or
+   * null if not enough information is available to make that determination
+   */
+  public static ImmutableList<RelCollation> collations(RelNode rel) {
+    final BuiltInMetadata.Collation metadata =
+        rel.metadata(BuiltInMetadata.Collation.class);
+    return metadata.collations();
+  }
+
+  /**
+   * Returns the
    * {@link BuiltInMetadata.PopulationSize#getPopulationSize(org.apache.calcite.util.ImmutableBitSet)}
    * statistic.
    *
@@ -285,6 +302,7 @@ public abstract class RelMetadataQuery {
    *                 the row count will be determined
    * @return distinct row count for the given groupKey, or null if no reliable
    * estimate can be determined
+   *
    */
   public static Double getPopulationSize(RelNode rel,
       ImmutableBitSet groupKey) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/rules/AggregateExpandDistinctAggregatesRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateExpandDistinctAggregatesRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateExpandDistinctAggregatesRule.java
index d661727..3afe7cc 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateExpandDistinctAggregatesRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateExpandDistinctAggregatesRule.java
@@ -154,9 +154,8 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
       rel = null;
     } else {
       rel =
-          new LogicalAggregate(aggregate.getCluster(), aggregate.getInput(),
-              aggregate.indicator, groupSet, aggregate.getGroupSets(),
-              newAggCallList);
+          LogicalAggregate.create(aggregate.getInput(), aggregate.indicator,
+              groupSet, aggregate.getGroupSets(), newAggCallList);
     }
 
     // For each set of operands, find and rewrite all calls which have that

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectPullUpConstantsRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectPullUpConstantsRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectPullUpConstantsRule.java
index 9ad2f2f..c7667a6 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectPullUpConstantsRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectPullUpConstantsRule.java
@@ -82,7 +82,7 @@ public class AggregateProjectPullUpConstantsRule extends RelOptRule {
   // implement RelOptRule
   public void onMatch(RelOptRuleCall call) {
     LogicalAggregate aggregate = call.rel(0);
-    LogicalProject child = call.rel(1);
+    LogicalProject input = call.rel(1);
 
     final int groupCount = aggregate.getGroupCount();
     if (groupCount == 1) {
@@ -92,11 +92,13 @@ public class AggregateProjectPullUpConstantsRule extends RelOptRule {
     }
 
     final RexProgram program =
-      RexProgram.create(child.getInput().getRowType(),
-        child.getProjects(), null, child.getRowType(),
-        child.getCluster().getRexBuilder());
+      RexProgram.create(input.getInput().getRowType(),
+          input.getProjects(),
+          null,
+          input.getRowType(),
+          input.getCluster().getRexBuilder());
 
-    final RelDataType childRowType = child.getRowType();
+    final RelDataType childRowType = input.getRowType();
     IntList constantList = new IntList();
     Map<Integer, RexNode> constants = new HashMap<Integer, RexNode>();
     for (int i : aggregate.getGroupSet()) {
@@ -134,11 +136,11 @@ public class AggregateProjectPullUpConstantsRule extends RelOptRule {
           new ArrayList<AggregateCall>();
       for (AggregateCall aggCall : aggregate.getAggCallList()) {
         newAggCalls.add(
-            aggCall.adaptTo(child, aggCall.getArgList(), groupCount,
+            aggCall.adaptTo(input, aggCall.getArgList(), groupCount,
                 newGroupCount));
       }
       newAggregate =
-          new LogicalAggregate(aggregate.getCluster(), child, false,
+          LogicalAggregate.create(input, false,
               ImmutableBitSet.range(newGroupCount), null, newAggCalls);
     } else {
       // Create the mapping from old field positions to new field
@@ -162,7 +164,7 @@ public class AggregateProjectPullUpConstantsRule extends RelOptRule {
       }
 
       // Create a projection to permute fields into these positions.
-      final RelNode project = createProjection(mapping, child);
+      final RelNode project = createProjection(mapping, input);
 
       // Adjust aggregate calls for new field positions.
       final List<AggregateCall> newAggCalls =
@@ -180,7 +182,7 @@ public class AggregateProjectPullUpConstantsRule extends RelOptRule {
 
       // Aggregate on projection.
       newAggregate =
-          new LogicalAggregate(aggregate.getCluster(), project, false,
+          LogicalAggregate.create(project, false,
               ImmutableBitSet.range(newGroupCount), null, newAggCalls);
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
index 6af92cc..ead7cd5 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
@@ -543,17 +543,17 @@ public class AggregateReduceFunctionsRule extends RelOptRule {
    * into Aggregate and subclasses - but it's only needed for some
    * subclasses.
    *
-   * @param oldAggRel LogicalAggregate to clone.
-   * @param inputRel  Input relational expression
+   * @param oldAggregate LogicalAggregate to clone.
+   * @param input  Input relational expression
    * @param newCalls  New list of AggregateCalls
    * @return shallow clone with new list of AggregateCalls.
    */
   protected Aggregate newAggregateRel(
-      Aggregate oldAggRel,
-      RelNode inputRel,
+      Aggregate oldAggregate,
+      RelNode input,
       List<AggregateCall> newCalls) {
-    return new LogicalAggregate(oldAggRel.getCluster(), inputRel,
-        oldAggRel.indicator, oldAggRel.getGroupSet(), oldAggRel.getGroupSets(),
+    return LogicalAggregate.create(input, oldAggregate.indicator,
+        oldAggregate.getGroupSet(), oldAggregate.getGroupSets(),
         newCalls);
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionAggregateRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionAggregateRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionAggregateRule.java
index 1005f8a..c1b5a28 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionAggregateRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionAggregateRule.java
@@ -95,14 +95,10 @@ public class AggregateUnionAggregateRule extends RelOptRule {
       return;
     }
 
-    LogicalUnion newUnion =
-        new LogicalUnion(
-            union.getCluster(),
-            unionInputs,
-            true);
+    LogicalUnion newUnion = LogicalUnion.create(unionInputs, true);
 
     LogicalAggregate newAggRel =
-        new LogicalAggregate(topAggRel.getCluster(), newUnion, false,
+        LogicalAggregate.create(newUnion, false,
             topAggRel.getGroupSet(), null, topAggRel.getAggCallList());
 
     call.transformTo(newAggRel);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/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 dfb0932..eb72876 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
@@ -116,23 +116,23 @@ public class AggregateUnionTransposeRule extends RelOptRule {
       } else {
         anyTransformed = true;
         newUnionInputs.add(
-            new LogicalAggregate(cluster, input, false, aggRel.getGroupSet(),
+            LogicalAggregate.create(input, false, aggRel.getGroupSet(),
                 null, aggRel.getAggCallList()));
       }
     }
 
     if (!anyTransformed) {
-      // none of the children could benefit from the pushdown,
+      // none of the children could benefit from the push-down,
       // so bail out (preventing the infinite loop to which most
       // planners would succumb)
       return;
     }
 
-    // create a new union whose children are the aggs created above
-    LogicalUnion newUnion = new LogicalUnion(cluster, newUnionInputs, true);
+    // create a new union whose children are the aggregates created above
+    LogicalUnion newUnion = LogicalUnion.create(newUnionInputs, true);
 
     LogicalAggregate newTopAggRel =
-        new LogicalAggregate(cluster, newUnion, aggRel.indicator,
+        LogicalAggregate.create(newUnion, aggRel.indicator,
             aggRel.getGroupSet(), aggRel.getGroupSets(), transformedAggCalls);
 
     call.transformTo(newTopAggRel);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/rules/CalcRelSplitter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/CalcRelSplitter.java b/core/src/main/java/org/apache/calcite/rel/rules/CalcRelSplitter.java
index 989e1fc..a8810d8 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/CalcRelSplitter.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/CalcRelSplitter.java
@@ -19,7 +19,6 @@ package org.apache.calcite.rel.rules;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptPlanner;
 import org.apache.calcite.plan.RelTraitSet;
-import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Calc;
 import org.apache.calcite.rel.logical.LogicalCalc;
@@ -774,12 +773,7 @@ public abstract class CalcRelSplitter {
         RelTraitSet traits,
         RelNode child,
         RexProgram program) {
-      return new LogicalCalc(
-          cluster,
-          traits,
-          child,
-          program,
-          Collections.<RelCollation>emptyList());
+      return LogicalCalc.create(child, program);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/rules/FilterCalcMergeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/FilterCalcMergeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/FilterCalcMergeRule.java
index fdc8415..7f5191b 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/FilterCalcMergeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/FilterCalcMergeRule.java
@@ -18,7 +18,6 @@ package org.apache.calcite.rel.rules;
 
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.core.Filter;
 import org.apache.calcite.rel.logical.LogicalCalc;
 import org.apache.calcite.rel.logical.LogicalFilter;
@@ -26,8 +25,6 @@ import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexProgram;
 import org.apache.calcite.rex.RexProgramBuilder;
 
-import java.util.Collections;
-
 /**
  * Planner rule that merges a
  * {@link org.apache.calcite.rel.logical.LogicalFilter} and a
@@ -83,12 +80,7 @@ public class FilterCalcMergeRule extends RelOptRule {
             bottomProgram,
             rexBuilder);
     final LogicalCalc newCalc =
-        new LogicalCalc(
-            calc.getCluster(),
-            calc.getTraitSet(),
-            calc.getInput(),
-            mergedProgram,
-            Collections.<RelCollation>emptyList());
+        LogicalCalc.create(calc.getInput(), mergedProgram);
     call.transformTo(newCalc);
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java b/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java
index bb0b8cc..fdfb359 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java
@@ -16,7 +16,6 @@
  */
 package org.apache.calcite.rel.rules;
 
-import org.apache.calcite.plan.Convention;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
 import org.apache.calcite.plan.RelOptRuleOperand;
@@ -228,7 +227,7 @@ public abstract class FilterJoinRule extends RelOptRule {
 
     RelNode newJoinRel =
         join.copy(
-            join.getCluster().traitSetOf(Convention.NONE),
+            join.getTraitSet(),
             joinFilter,
             leftRel,
             rightRel,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/rules/FilterTableFunctionTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/FilterTableFunctionTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/FilterTableFunctionTransposeRule.java
index 24f6a04..3f517ab 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/FilterTableFunctionTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/FilterTableFunctionTransposeRule.java
@@ -104,16 +104,13 @@ public class FilterTableFunctionTransposeRule extends RelOptRule {
                   funcInput.getRowType().getFieldList(),
                   adjustments));
       newFuncInputs.add(
-          new LogicalFilter(cluster, funcInput, newCondition));
+          LogicalFilter.create(funcInput, newCondition));
     }
 
     // create a new UDX whose children are the filters created above
     LogicalTableFunctionScan newFuncRel =
-        new LogicalTableFunctionScan(
-            cluster,
-            newFuncInputs,
-            funcRel.getCall(),
-            funcRel.getElementType(), funcRel.getRowType(),
+        LogicalTableFunctionScan.create(cluster, newFuncInputs,
+            funcRel.getCall(), funcRel.getElementType(), funcRel.getRowType(),
             columnMappings);
     call.transformTo(newFuncRel);
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/rules/FilterToCalcRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/FilterToCalcRule.java b/core/src/main/java/org/apache/calcite/rel/rules/FilterToCalcRule.java
index 68044bf..2e7feaf 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/FilterToCalcRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/FilterToCalcRule.java
@@ -18,7 +18,6 @@ package org.apache.calcite.rel.rules;
 
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.logical.LogicalCalc;
 import org.apache.calcite.rel.logical.LogicalFilter;
@@ -27,10 +26,8 @@ import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexProgram;
 import org.apache.calcite.rex.RexProgramBuilder;
 
-import com.google.common.collect.ImmutableList;
-
 /**
- * Planner rule which converts a
+ * Planner rule that converts a
  * {@link org.apache.calcite.rel.logical.LogicalFilter} to a
  * {@link org.apache.calcite.rel.logical.LogicalCalc}.
  *
@@ -69,13 +66,7 @@ public class FilterToCalcRule extends RelOptRule {
     programBuilder.addCondition(filter.getCondition());
     final RexProgram program = programBuilder.getProgram();
 
-    final LogicalCalc calc =
-        new LogicalCalc(
-            filter.getCluster(),
-            filter.getTraitSet(),
-            rel,
-            program,
-            ImmutableList.<RelCollation>of());
+    final LogicalCalc calc = LogicalCalc.create(rel, program);
     call.transformTo(calc);
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/rules/JoinToCorrelateRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/JoinToCorrelateRule.java b/core/src/main/java/org/apache/calcite/rel/rules/JoinToCorrelateRule.java
index e520f9d..5e71048 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/JoinToCorrelateRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/JoinToCorrelateRule.java
@@ -123,9 +123,7 @@ public class JoinToCorrelateRule extends RelOptRule {
     final RelNode filteredRight =
         RelOptUtil.createFilter(right, joinCondition, filterFactory);
     RelNode newRel =
-        new LogicalCorrelate(
-            join.getCluster(),
-            left,
+        LogicalCorrelate.create(left,
             filteredRight,
             correlationId,
             requiredColumns.build(),

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/rules/ProjectCalcMergeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ProjectCalcMergeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ProjectCalcMergeRule.java
index f2c832a..9ecd044 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ProjectCalcMergeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ProjectCalcMergeRule.java
@@ -19,7 +19,6 @@ package org.apache.calcite.rel.rules;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.logical.LogicalCalc;
 import org.apache.calcite.rel.logical.LogicalProject;
 import org.apache.calcite.rex.RexBuilder;
@@ -29,8 +28,6 @@ import org.apache.calcite.rex.RexProgram;
 import org.apache.calcite.rex.RexProgramBuilder;
 import org.apache.calcite.util.Pair;
 
-import java.util.Collections;
-
 /**
  * Planner rule which merges a
  * {@link org.apache.calcite.rel.logical.LogicalProject} and a
@@ -78,13 +75,7 @@ public class ProjectCalcMergeRule extends RelOptRule {
             project.getRowType(),
             cluster.getRexBuilder());
     if (RexOver.containsOver(program)) {
-      LogicalCalc projectAsCalc =
-          new LogicalCalc(
-              cluster,
-              project.getTraitSet(),
-              calc,
-              program,
-              Collections.<RelCollation>emptyList());
+      LogicalCalc projectAsCalc = LogicalCalc.create(calc, program);
       call.transformTo(projectAsCalc);
       return;
     }
@@ -108,12 +99,7 @@ public class ProjectCalcMergeRule extends RelOptRule {
             bottomProgram,
             rexBuilder);
     final LogicalCalc newCalc =
-        new LogicalCalc(
-            cluster,
-            project.getTraitSet(),
-            calc.getInput(),
-            mergedProgram,
-            Collections.<RelCollation>emptyList());
+        LogicalCalc.create(calc.getInput(), mergedProgram);
     call.transformTo(newCalc);
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/rules/ProjectRemoveRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ProjectRemoveRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ProjectRemoveRule.java
index 2bc5d59..3631c31 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ProjectRemoveRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ProjectRemoveRule.java
@@ -59,8 +59,7 @@ public class ProjectRemoveRule extends RelOptRule {
 
   public static final ProjectRemoveRule INSTANCE = new ProjectRemoveRule(false);
 
-  /** @deprecated Remove before
-   * {@link org.apache.calcite.util.Bug#upgrade Calcite-1.1}. */
+  @Deprecated // to be removed before 1.1
   public static final ProjectRemoveRule NAME_CALC_INSTANCE =
       new ProjectRemoveRule(true);
 
@@ -110,10 +109,8 @@ public class ProjectRemoveRule extends RelOptRule {
   /**
    * Returns the child of a project if the project is trivial
    * otherwise the project itself. If useNamesInIdentityProjCalc is true
-   * then trivial comparison uses both names and types.
-   *
-   * @deprecated Remove before
-   * {@link org.apache.calcite.util.Bug#upgrade Calcite-1.1}. */
+   * then trivial comparison uses both names and types. */
+  @Deprecated // to be removed before 1.1
   public static RelNode strip(Project project,
       boolean useNamesInIdentityProjCalc) {
     return isTrivial(project, useNamesInIdentityProjCalc)
@@ -124,8 +121,7 @@ public class ProjectRemoveRule extends RelOptRule {
     return isTrivial(project, false);
   }
 
-  /** @deprecated Remove before
-   * {@link org.apache.calcite.util.Bug#upgrade Calcite-1.1}. */
+  @Deprecated // to be removed before 1.1
   public static boolean isTrivial(Project project,
     boolean useNamesInIdentityProjCalc) {
     RelNode child = project.getInput();
@@ -144,8 +140,7 @@ public class ProjectRemoveRule extends RelOptRule {
         && RexUtil.containIdentity(exps, childRowType, false);
   }
 
-  /** @deprecated Remove before
-   * {@link org.apache.calcite.util.Bug#upgrade Calcite-1.1}. */
+  @Deprecated // to be removed before 1.1
   public static boolean isIdentity(List<? extends RexNode> exps,
       RelDataType rowType, RelDataType childRowType) {
     return childRowType.getFieldCount() == exps.size()

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/rules/ProjectToCalcRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ProjectToCalcRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ProjectToCalcRule.java
index 6233fc1..b6f05c9 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ProjectToCalcRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ProjectToCalcRule.java
@@ -18,14 +18,11 @@ package org.apache.calcite.rel.rules;
 
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.logical.LogicalCalc;
 import org.apache.calcite.rel.logical.LogicalProject;
 import org.apache.calcite.rex.RexProgram;
 
-import com.google.common.collect.ImmutableList;
-
 /**
  * Rule to convert a
  * {@link org.apache.calcite.rel.logical.LogicalProject} to a
@@ -55,21 +52,15 @@ public class ProjectToCalcRule extends RelOptRule {
 
   public void onMatch(RelOptRuleCall call) {
     final LogicalProject project = call.rel(0);
-    final RelNode child = project.getInput();
+    final RelNode input = project.getInput();
     final RexProgram program =
         RexProgram.create(
-            child.getRowType(),
+            input.getRowType(),
             project.getProjects(),
             null,
             project.getRowType(),
             project.getCluster().getRexBuilder());
-    final LogicalCalc calc =
-        new LogicalCalc(
-            project.getCluster(),
-            project.getTraitSet(),
-            child,
-            program,
-            ImmutableList.<RelCollation>of());
+    final LogicalCalc calc = LogicalCalc.create(input, program);
     call.transformTo(calc);
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/rules/ProjectToWindowRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ProjectToWindowRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ProjectToWindowRule.java
index 685b925..3719253 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ProjectToWindowRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ProjectToWindowRule.java
@@ -22,7 +22,6 @@ import org.apache.calcite.plan.RelOptRuleCall;
 import org.apache.calcite.plan.RelOptRuleOperand;
 import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.plan.RelTraitSet;
-import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Calc;
 import org.apache.calcite.rel.core.Project;
@@ -42,7 +41,6 @@ import org.apache.calcite.util.Util;
 
 import com.google.common.base.Function;
 import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 
 import java.util.Collections;
@@ -112,22 +110,16 @@ public abstract class ProjectToWindowRule extends RelOptRule {
         @Override public void onMatch(RelOptRuleCall call) {
           Project project = call.rel(0);
           assert RexOver.containsOver(project.getProjects(), null);
-          final RelNode child = project.getInput();
+          final RelNode input = project.getInput();
           final RexProgram program =
               RexProgram.create(
-                  child.getRowType(),
+                  input.getRowType(),
                   project.getProjects(),
                   null,
                   project.getRowType(),
                   project.getCluster().getRexBuilder());
           // temporary LogicalCalc, never registered
-          final LogicalCalc calc =
-              new LogicalCalc(
-                  project.getCluster(),
-                  project.getTraitSet(),
-                  child,
-                  program,
-                  ImmutableList.<RelCollation>of());
+          final LogicalCalc calc = LogicalCalc.create(input, program);
           CalcRelSplitter transform = new WindowedAggRelSplitter(calc) {
             @Override protected RelNode handle(RelNode rel) {
               if (rel instanceof LogicalCalc) {
@@ -135,9 +127,7 @@ public abstract class ProjectToWindowRule extends RelOptRule {
                 final RexProgram program = calc.getProgram();
                 rel = calc.getInput();
                 if (program.getCondition() != null) {
-                  rel = new LogicalFilter(
-                      calc.getCluster(),
-                      rel,
+                  rel = LogicalFilter.create(rel,
                       program.expandLocalRef(
                           program.getCondition()));
                 }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/rules/PruneEmptyRules.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/PruneEmptyRules.java b/core/src/main/java/org/apache/calcite/rel/rules/PruneEmptyRules.java
index 008f9aa..2f4cada 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/PruneEmptyRules.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/PruneEmptyRules.java
@@ -93,11 +93,7 @@ public abstract class PruneEmptyRules {
                     true);
             break;
           default:
-            newRel =
-                new LogicalUnion(
-                    union.getCluster(),
-                    newChildRels,
-                    union.all);
+            newRel = LogicalUnion.create(newChildRels, union.all);
             break;
           }
           call.transformTo(newRel);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/rules/ReduceDecimalsRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ReduceDecimalsRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ReduceDecimalsRule.java
index a3ecf19..143620d 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ReduceDecimalsRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ReduceDecimalsRule.java
@@ -20,7 +20,6 @@ import org.apache.calcite.linq4j.Ord;
 import org.apache.calcite.plan.Convention;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.logical.LogicalCalc;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeSystem;
@@ -44,7 +43,6 @@ import com.google.common.collect.ImmutableList;
 
 import java.math.BigDecimal;
 import java.math.BigInteger;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -110,13 +108,7 @@ public class ReduceDecimalsRule extends RelOptRule {
             true);
 
     final RexProgram newProgram = programBuilder.getProgram();
-    LogicalCalc newCalc =
-        new LogicalCalc(
-            calc.getCluster(),
-            calc.getTraitSet(),
-            calc.getInput(),
-            newProgram,
-            Collections.<RelCollation>emptyList());
+    LogicalCalc newCalc = LogicalCalc.create(calc.getInput(), newProgram);
     call.transformTo(newCalc);
   }
 
@@ -1218,10 +1210,9 @@ public class ReduceDecimalsRule extends RelOptRule {
     public abstract RelDataType getArgType(RexCall call, int ordinal);
 
     public RexNode expand(RexCall call) {
-      List<RexNode> operands = call.operands;
       ImmutableList.Builder<RexNode> opBuilder = ImmutableList.builder();
 
-      for (Ord<RexNode> operand : Ord.zip(operands)) {
+      for (Ord<RexNode> operand : Ord.zip(call.operands)) {
         RelDataType targetType = getArgType(call, operand.i);
         if (SqlTypeUtil.isDecimal(operand.e.getType())) {
           opBuilder.add(ensureType(targetType, operand.e, true));

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
index d1bcaf2..7e54253 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
@@ -195,11 +195,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
               Lists.newArrayList(project.getProjects());
           if (reduceExpressions(project, expList, predicates)) {
             call.transformTo(
-                new LogicalProject(
-                    project.getCluster(),
-                    project.getTraitSet(),
-                    project.getInput(),
-                    expList,
+                LogicalProject.create(project.getInput(), expList,
                     project.getRowType()));
 
             // New plan is absolutely better than old plan.
@@ -303,12 +299,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
                   program.getOutputRowType().getFieldNames().get(k++));
             }
             call.transformTo(
-                new LogicalCalc(
-                    calc.getCluster(),
-                    calc.getTraitSet(),
-                    calc.getInput(),
-                    builder.getProgram(),
-                    calc.getCollationList()));
+                LogicalCalc.create(calc.getInput(), builder.getProgram()));
 
             // New plan is absolutely better than old plan.
             call.getPlanner().setImportance(calc, 0.0);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/rules/SortProjectTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/SortProjectTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/SortProjectTransposeRule.java
index 60cfc53..2240c38 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/SortProjectTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/SortProjectTransposeRule.java
@@ -21,6 +21,7 @@ import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
 import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelCollationTraitDef;
 import org.apache.calcite.rel.RelFieldCollation;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Sort;
@@ -79,7 +80,7 @@ public class SortProjectTransposeRule extends RelOptRule {
       }
     }
     final RelCollation newCollation =
-        cluster.traitSetOf().canonize(
+        cluster.traitSet().canonize(
             RexUtil.apply(map, sort.getCollation()));
     final Sort newSort =
         sort.copy(
@@ -95,10 +96,15 @@ public class SortProjectTransposeRule extends RelOptRule {
     // Not only is newProject equivalent to sort;
     // newSort is equivalent to project's input
     // (but only if the sort is not also applying an offset/limit).
-    Map<RelNode, RelNode> equiv =
-        sort.offset == null && sort.fetch == null
-            ? ImmutableMap.<RelNode, RelNode>of(newSort, project.getInput())
-            : ImmutableMap.<RelNode, RelNode>of();
+    Map<RelNode, RelNode> equiv;
+    if (sort.offset == null
+        && sort.fetch == null
+        && cluster.getPlanner().getRelTraitDefs()
+            .contains(RelCollationTraitDef.INSTANCE)) {
+      equiv = ImmutableMap.of((RelNode) newSort, project.getInput());
+    } else {
+      equiv = ImmutableMap.of();
+    }
     call.transformTo(newProject, equiv);
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/rules/UnionMergeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/UnionMergeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/UnionMergeRule.java
index f772777..bda281c 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/UnionMergeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/UnionMergeRule.java
@@ -87,12 +87,7 @@ public class UnionMergeRule extends RelOptRule {
         == bottomUnion.getInputs().size()
         + topUnion.getInputs().size()
         - 1;
-    LogicalUnion newUnion =
-        new LogicalUnion(
-            topUnion.getCluster(),
-            unionInputs,
-            true);
-
+    LogicalUnion newUnion = LogicalUnion.create(unionInputs, true);
     call.transformTo(newUnion);
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/rules/UnionToDistinctRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/UnionToDistinctRule.java b/core/src/main/java/org/apache/calcite/rel/rules/UnionToDistinctRule.java
index 39a6d92..c688170 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/UnionToDistinctRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/UnionToDistinctRule.java
@@ -49,11 +49,7 @@ public class UnionToDistinctRule extends RelOptRule {
     if (union.all) {
       return; // nothing to do
     }
-    LogicalUnion unionAll =
-        new LogicalUnion(
-            union.getCluster(),
-            union.getInputs(),
-            true);
+    LogicalUnion unionAll = LogicalUnion.create(union.getInputs(), true);
     call.transformTo(RelOptUtil.createDistinctRel(unionAll));
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rel/rules/ValuesReduceRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ValuesReduceRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ValuesReduceRule.java
index 18e0f92..d1f205d 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ValuesReduceRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ValuesReduceRule.java
@@ -221,7 +221,7 @@ public abstract class ValuesReduceRule extends RelOptRule {
         rowType = values.getRowType();
       }
       final RelNode newRel =
-          new LogicalValues(values.getCluster(), rowType,
+          LogicalValues.create(values.getCluster(), rowType,
               tuplesBuilder.build());
       call.transformTo(newRel);
     } else {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rex/RexNode.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexNode.java b/core/src/main/java/org/apache/calcite/rex/RexNode.java
index 897c06c..0922116 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexNode.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexNode.java
@@ -86,7 +86,7 @@ public abstract class RexNode {
    * Accepts a visitor, dispatching to the right overloaded
    * {@link RexVisitor#visitInputRef visitXxx} method.
    *
-   * <p>Also see {@link RexProgram#apply(RexVisitor, java.util.List, RexNode)},
+   * <p>Also see {@link RexUtil#apply(RexVisitor, java.util.List, RexNode)},
    * which applies a visitor to several expressions simultaneously.
    */
   public abstract <R> R accept(RexVisitor<R> visitor);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rex/RexOver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexOver.java b/core/src/main/java/org/apache/calcite/rex/RexOver.java
index babfacc..3b45f36 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexOver.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexOver.java
@@ -107,7 +107,7 @@ public class RexOver extends RexCall {
    */
   public static boolean containsOver(RexProgram program) {
     try {
-      RexProgram.apply(FINDER, program.getExprList(), null);
+      RexUtil.apply(FINDER, program.getExprList(), null);
       return false;
     } catch (OverFound e) {
       Util.swallow(e, null);
@@ -120,7 +120,7 @@ public class RexOver extends RexCall {
    */
   public static boolean containsOver(List<RexNode> exprs, RexNode condition) {
     try {
-      RexProgram.apply(FINDER, exprs, condition);
+      RexUtil.apply(FINDER, exprs, condition);
       return false;
     } catch (OverFound e) {
       Util.swallow(e, null);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/rex/RexProgram.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexProgram.java b/core/src/main/java/org/apache/calcite/rex/RexProgram.java
index 03f7540..caef1de 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexProgram.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexProgram.java
@@ -18,7 +18,7 @@ package org.apache.calcite.rex;
 
 import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.rel.RelCollation;
-import org.apache.calcite.rel.RelCollationImpl;
+import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.RelFieldCollation;
 import org.apache.calcite.rel.RelWriter;
 import org.apache.calcite.rel.externalize.RelWriterImpl;
@@ -596,7 +596,7 @@ public class RexProgram {
 
       // Success -- all of the source fields of this key are mapped
       // to the output.
-      outputCollations.add(RelCollationImpl.of(fieldCollations));
+      outputCollations.add(RelCollations.of(fieldCollations));
     }
   }
 
@@ -670,7 +670,7 @@ public class RexProgram {
     }
     refCounts = new int[exprs.size()];
     ReferenceCounter refCounter = new ReferenceCounter();
-    apply(refCounter, exprs, null);
+    RexUtil.apply(refCounter, exprs, null);
     if (condition != null) {
       refCounter.visitLocalRef(condition);
     }
@@ -681,26 +681,6 @@ public class RexProgram {
   }
 
   /**
-   * Applies a visitor to an array of expressions and, if specified, a single
-   * expression.
-   *
-   * @param visitor Visitor
-   * @param exprs   Array of expressions
-   * @param expr    Single expression, may be null
-   */
-  public static void apply(
-      RexVisitor<Void> visitor,
-      List<RexNode> exprs,
-      RexNode expr) {
-    for (RexNode expr0 : exprs) {
-      expr0.accept(visitor);
-    }
-    if (expr != null) {
-      expr.accept(visitor);
-    }
-  }
-
-  /**
    * Returns whether an expression is constant.
    */
   public boolean isConstant(RexNode ref) {
@@ -777,7 +757,7 @@ public class RexProgram {
    */
   public HashSet<String> getCorrelVariableNames() {
     final HashSet<String> paramIdSet = new HashSet<String>();
-    apply(
+    RexUtil.apply(
         new RexVisitorImpl<Void>(true) {
           public Void visitCorrelVariable(
               RexCorrelVariable correlVariable) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/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 f7712e1..c02861d 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexUtil.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
@@ -19,7 +19,7 @@ package org.apache.calcite.rex;
 import org.apache.calcite.linq4j.function.Predicate1;
 import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.rel.RelCollation;
-import org.apache.calcite.rel.RelCollationImpl;
+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;
@@ -616,10 +616,8 @@ public class RexUtil {
   /**
    * Returns whether the leading edge of a given array of expressions is
    * wholly {@link RexInputRef} objects with types and names corresponding
-   * to the underlying row type.
-   *
-   * @deprecated Remove before
-   * {@link org.apache.calcite.util.Bug#upgrade Calcite-1.1}. */
+   * to the underlying row type. */
+  @Deprecated // to be removed before 1.1
   public static boolean containIdentity(List<? extends RexNode> exps,
       RelDataType rowType, RelDataType childRowType) {
     List<RelDataTypeField> fields = rowType.getFieldList();
@@ -767,7 +765,7 @@ public class RexUtil {
     final List<RelCollation> newCollationList =
         new ArrayList<RelCollation>();
     for (RelCollation collation : collationList) {
-      if (collation == RelCollationImpl.PRESERVE) {
+      if (collation == RelCollations.PRESERVE) {
         newCollationList.add(collation);
         continue;
       }
@@ -789,7 +787,7 @@ public class RexUtil {
       // and duplicate collations. Ignore these.
       if (!newFieldCollationList.isEmpty()) {
         final RelCollation newCollation =
-            RelCollationImpl.of(newFieldCollationList);
+            RelCollations.of(newFieldCollationList);
         if (!newCollationList.contains(newCollation)) {
           newCollationList.add(newCollation);
         }
@@ -817,7 +815,7 @@ public class RexUtil {
         applyFields(mapping, collation.getFieldCollations());
     return fieldCollations.equals(collation.getFieldCollations())
         ? collation
-        : RelCollationImpl.of(fieldCollations);
+        : RelCollations.of(fieldCollations);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/schema/Statistic.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/schema/Statistic.java b/core/src/main/java/org/apache/calcite/schema/Statistic.java
index b725d4b..4a4bce9 100644
--- a/core/src/main/java/org/apache/calcite/schema/Statistic.java
+++ b/core/src/main/java/org/apache/calcite/schema/Statistic.java
@@ -16,8 +16,11 @@
  */
 package org.apache.calcite.schema;
 
+import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.util.ImmutableBitSet;
 
+import java.util.List;
+
 /**
  * Statistics about a {@link Table}.
  *
@@ -33,6 +36,9 @@ public interface Statistic {
    * of a unique key, of the table.
    */
   boolean isKey(ImmutableBitSet columns);
+
+  /** Returns the collections of columns on which this table is sorted. */
+  List<RelCollation> getCollations();
 }
 
 // End Statistic.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/schema/Statistics.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/schema/Statistics.java b/core/src/main/java/org/apache/calcite/schema/Statistics.java
index 4b2611a..8e58c4d 100644
--- a/core/src/main/java/org/apache/calcite/schema/Statistics.java
+++ b/core/src/main/java/org/apache/calcite/schema/Statistics.java
@@ -16,8 +16,11 @@
  */
 package org.apache.calcite.schema;
 
+import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.util.ImmutableBitSet;
 
+import com.google.common.collect.ImmutableList;
+
 import java.util.List;
 
 /**
@@ -37,11 +40,21 @@ public class Statistics {
         public boolean isKey(ImmutableBitSet columns) {
           return false;
         }
+
+        public List<RelCollation> getCollations() {
+          return ImmutableList.of();
+        }
       };
 
   /** Returns a statistic with a given row count and set of unique keys. */
   public static Statistic of(final double rowCount,
       final List<ImmutableBitSet> keys) {
+    return of(rowCount, keys, ImmutableList.<RelCollation>of());
+  }
+
+  /** Returns a statistic with a given row count and set of unique keys. */
+  public static Statistic of(final double rowCount,
+      final List<ImmutableBitSet> keys, final List<RelCollation> collations) {
     return new Statistic() {
       public Double getRowCount() {
         return rowCount;
@@ -55,6 +68,10 @@ public class Statistics {
         }
         return false;
       }
+
+      public List<RelCollation> getCollations() {
+        return collations;
+      }
     };
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/sql/SqlWindow.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlWindow.java b/core/src/main/java/org/apache/calcite/sql/SqlWindow.java
index be9d9fc..afc6b45 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlWindow.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlWindow.java
@@ -836,8 +836,7 @@ public class SqlWindow extends SqlCall {
         boolean onlyExpressions,
         SqlBasicVisitor.ArgHandler<R> argHandler) {
       if (onlyExpressions) {
-        final List<SqlNode> operandList = call.getOperandList();
-        for (Ord<SqlNode> operand : Ord.zip(operandList)) {
+        for (Ord<SqlNode> operand : Ord.zip(call.getOperandList())) {
           // if the second param is an Identifier then it's supposed to
           // be a name from a window clause and isn't part of the
           // group by check

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/sql/advise/SqlAdvisor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/advise/SqlAdvisor.java b/core/src/main/java/org/apache/calcite/sql/advise/SqlAdvisor.java
index 06d10c0..e6690a5 100644
--- a/core/src/main/java/org/apache/calcite/sql/advise/SqlAdvisor.java
+++ b/core/src/main/java/org/apache/calcite/sql/advise/SqlAdvisor.java
@@ -422,7 +422,7 @@ public class SqlAdvisor {
    * <p>To use a different parser (recognizing a different dialect of SQL),
    * derived class should override.
    *
-   * @return a {@link SqlAbstractParserImpl.Metadata} instance.
+   * @return metadata
    */
   protected SqlAbstractParserImpl.Metadata getParserMetadata() {
     SqlParser parser = SqlParser.create("");

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/sql/fun/SqlLiteralChainOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlLiteralChainOperator.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlLiteralChainOperator.java
index a3d6f24..c0e891c 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlLiteralChainOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlLiteralChainOperator.java
@@ -159,8 +159,7 @@ public class SqlLiteralChainOperator extends SqlSpecialOperator {
       int rightPrec) {
     final SqlWriter.Frame frame = writer.startList("", "");
     SqlCollation collation = null;
-    final List<SqlNode> rands = call.getOperandList();
-    for (Ord<SqlNode> operand : Ord.zip(rands)) {
+    for (Ord<SqlNode> operand : Ord.zip(call.getOperandList())) {
       SqlLiteral rand = (SqlLiteral) operand.e;
       if (operand.i > 0) {
         // SQL:2003 says there must be a newline between string

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/sql/util/SqlShuttle.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/util/SqlShuttle.java b/core/src/main/java/org/apache/calcite/sql/util/SqlShuttle.java
index c530c5c..c4e6f67 100644
--- a/core/src/main/java/org/apache/calcite/sql/util/SqlShuttle.java
+++ b/core/src/main/java/org/apache/calcite/sql/util/SqlShuttle.java
@@ -94,8 +94,9 @@ public class SqlShuttle extends SqlBasicVisitor<SqlNode> {
   //~ Inner Classes ----------------------------------------------------------
 
   /**
-   * Implementation of {@link ArgHandler} which deep-copies {@link SqlCall}s
-   * and their operands.
+   * Implementation of
+   * {@link org.apache.calcite.sql.util.SqlBasicVisitor.ArgHandler}
+   * that deep-copies {@link SqlCall}s and their operands.
    */
   protected class CallCopyingArgHandler implements ArgHandler<SqlNode> {
     boolean update;

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2709896e/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java b/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
index 8521ce2..7313f5e 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
@@ -575,8 +575,11 @@ public class RelDecorrelator implements ReflectiveVisitor {
     }
 
     LogicalAggregate newAggregate =
-        new LogicalAggregate(rel.getCluster(), newProjectRel, false,
-            ImmutableBitSet.range(newGroupKeyCount), null, newAggCalls);
+        LogicalAggregate.create(newProjectRel,
+            false,
+            ImmutableBitSet.range(newGroupKeyCount),
+            null,
+            newAggCalls);
 
     mapOldToNewRel.put(rel, newAggregate);
 
@@ -767,13 +770,9 @@ public class RelDecorrelator implements ReflectiveVisitor {
           resultRel = distinctRel;
         } else {
           resultRel =
-              new LogicalJoin(
-                  cluster,
-                  resultRel,
-                  distinctRel,
+              LogicalJoin.create(resultRel, distinctRel,
                   cluster.getRexBuilder().makeLiteral(true),
-                  JoinRelType.INNER,
-                  Collections.<String>emptySet());
+                  JoinRelType.INNER, ImmutableSet.<String>of());
         }
       }
     }
@@ -848,13 +847,8 @@ public class RelDecorrelator implements ReflectiveVisitor {
 
     final Set<String> variablesStopped = Collections.emptySet();
     RelNode joinRel =
-        new LogicalJoin(
-            rel.getCluster(),
-            newLeftChildRel,
-            valueGenRel,
-            rexBuilder.makeLiteral(true),
-            JoinRelType.INNER,
-            variablesStopped);
+        LogicalJoin.create(newLeftChildRel, valueGenRel,
+            rexBuilder.makeLiteral(true), JoinRelType.INNER, variablesStopped);
 
     mapOldToNewRel.put(oldChildRel, joinRel);
     mapNewRelToMapCorVarToOutputPos.put(joinRel, mapCorVarToOutputPos);
@@ -1063,13 +1057,8 @@ public class RelDecorrelator implements ReflectiveVisitor {
 
     final Set<String> variablesStopped = Collections.emptySet();
     RelNode newRel =
-        new LogicalJoin(
-            rel.getCluster(),
-            newLeftRel,
-            newRightRel,
-            condition,
-            rel.getJoinType().toJoinType(),
-            variablesStopped);
+        LogicalJoin.create(newLeftRel, newRightRel, condition,
+            rel.getJoinType().toJoinType(), variablesStopped);
 
     mapOldToNewRel.put(rel, newRel);
     mapNewRelToMapOldToNewOutputPos.put(newRel, mapOldToNewOutputPos);
@@ -1115,12 +1104,8 @@ public class RelDecorrelator implements ReflectiveVisitor {
 
     final Set<String> variablesStopped = Collections.emptySet();
     RelNode newRel =
-        new LogicalJoin(
-            rel.getCluster(),
-            newLeftRel,
-            newRightRel,
-            decorrelateExpr(rel.getCondition()),
-            rel.getJoinType(),
+        LogicalJoin.create(newLeftRel, newRightRel,
+            decorrelateExpr(rel.getCondition()), rel.getJoinType(),
             variablesStopped);
 
     // Create the mapping between the output of the old correlation rel
@@ -1981,12 +1966,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
 
       // make the new join rel
       LogicalJoin join =
-          new LogicalJoin(
-              corRel.getCluster(),
-              leftInputRel,
-              rightInputRel,
-              joinCond,
-              joinType,
+          LogicalJoin.create(leftInputRel, rightInputRel, joinCond, joinType,
               ImmutableSet.<String>of());
 
       RelNode newProjRel =
@@ -2266,12 +2246,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
                       "nullIndicator")));
 
       LogicalJoin join =
-          new LogicalJoin(
-              cluster,
-              leftInputRel,
-              rightInputRel,
-              joinCond,
-              joinType,
+          LogicalJoin.create(leftInputRel, rightInputRel, joinCond, joinType,
               ImmutableSet.<String>of());
 
       // To the consumer of joinOutputProjRel, nullIndicator is located
@@ -2345,8 +2320,11 @@ public class RelDecorrelator implements ReflectiveVisitor {
       ImmutableBitSet groupSet =
           ImmutableBitSet.range(groupCount);
       LogicalAggregate newAggRel =
-          new LogicalAggregate(cluster, joinOutputProjRel, false, groupSet,
-              null, newAggCalls);
+          LogicalAggregate.create(joinOutputProjRel,
+              false,
+              groupSet,
+              null,
+              newAggCalls);
 
       List<RexNode> newAggOutputProjExprList = Lists.newArrayList();
       for (int i : groupSet) {
@@ -2493,12 +2471,8 @@ public class RelDecorrelator implements ReflectiveVisitor {
       //     LogicalAggregate (groupby (0), agg0(), agg1()...)
       //
       LogicalCorrelate newCorRel =
-          new LogicalCorrelate(
-              cluster,
-              leftInputRel,
-              aggRel,
-              corRel.getCorrelationId(),
-              corRel.getRequiredColumns(),
+          LogicalCorrelate.create(leftInputRel, aggRel,
+              corRel.getCorrelationId(), corRel.getRequiredColumns(),
               corRel.getJoinType());
 
       // remember this rel so we don't fire rule on it again