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/06/10 00:08:05 UTC

[1/7] incubator-calcite git commit: [CALCITE-749] Add MaterializationService.TableFactory (Rajat Venkatesh)

Repository: incubator-calcite
Updated Branches:
  refs/heads/master ec9d96604 -> dbdb091dc


[CALCITE-749] Add MaterializationService.TableFactory (Rajat Venkatesh)

Return TableEntry for getTable family of functions (breaking change).

Close apache/incubator-calcite#90


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

Branch: refs/heads/master
Commit: 8b53dc49f49113daf12a355c5db18ccc248f4924
Parents: ec9d966
Author: Rajat Venkatesh <rv...@qubole.com>
Authored: Mon Jun 1 22:33:58 2015 +0530
Committer: Julian Hyde <jh...@apache.org>
Committed: Fri Jun 5 10:06:57 2015 -0700

----------------------------------------------------------------------
 .../apache/calcite/jdbc/CalciteMetaImpl.java    |   2 +-
 .../org/apache/calcite/jdbc/CalciteSchema.java  |  29 ++--
 .../materialize/MaterializationService.java     | 156 ++++++++++++-------
 .../calcite/prepare/CalciteCatalogReader.java   |  13 +-
 4 files changed, 125 insertions(+), 75 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/8b53dc49/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java
index 332ed40..d087f9b 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java
@@ -400,7 +400,7 @@ public class CalciteMetaImpl extends MetaImpl {
             new Function1<String, MetaTable>() {
               public MetaTable apply(String name) {
                 final Table table =
-                    schema.calciteSchema.getTable(name, true).getValue();
+                    schema.calciteSchema.getTable(name, true).getTable();
                 return new CalciteMetaTable(table,
                     schema.tableCatalog,
                     schema.tableSchem,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/8b53dc49/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java
index 346b721..081ed85 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java
@@ -26,7 +26,6 @@ import org.apache.calcite.schema.TableMacro;
 import org.apache.calcite.schema.impl.MaterializedViewTable;
 import org.apache.calcite.schema.impl.StarTable;
 import org.apache.calcite.util.Compatible;
-import org.apache.calcite.util.Pair;
 
 import com.google.common.base.Preconditions;
 import com.google.common.cache.CacheBuilder;
@@ -251,30 +250,30 @@ public class CalciteSchema {
   }
 
   /** Returns a table that materializes the given SQL statement. */
-  public final Pair<String, Table> getTableBySql(String sql) {
+  public final TableEntry getTableBySql(String sql) {
     for (TableEntry tableEntry : tableMap.values()) {
       if (tableEntry.sqls.contains(sql)) {
-        return Pair.of(tableEntry.name, tableEntry.getTable());
+        return tableEntry;
       }
     }
     return null;
   }
 
   /** Returns a table with the given name. Does not look for views. */
-  public final Pair<String, Table> getTable(String tableName,
+  public final TableEntry getTable(String tableName,
       boolean caseSensitive) {
     if (caseSensitive) {
       // Check explicit tables, case-sensitive.
       final TableEntry entry = tableMap.get(tableName);
       if (entry != null) {
-        return Pair.of(tableName, entry.getTable());
+        return entry;
       }
       // Check implicit tables, case-sensitive.
       final long now = System.currentTimeMillis();
       if (implicitTableCache.get(now).contains(tableName)) {
         final Table table = schema.getTable(tableName);
         if (table != null) {
-          return Pair.of(tableName, table);
+          return new TableEntryImpl(this, tableName, table, ImmutableList.<String>of());
         }
       }
       return null;
@@ -283,7 +282,7 @@ public class CalciteSchema {
       //noinspection LoopStatementThatDoesntLoop
       for (Map.Entry<String, TableEntry> entry
           : find(tableMap, tableName).entrySet()) {
-        return Pair.of(entry.getKey(), entry.getValue().getTable());
+        return entry.getValue();
       }
       // Check implicit tables, case-insensitive.
       final long now = System.currentTimeMillis();
@@ -293,7 +292,7 @@ public class CalciteSchema {
       if (tableName2 != null) {
         final Table table = schema.getTable(tableName2);
         if (table != null) {
-          return Pair.of(tableName2, table);
+          return new TableEntryImpl(this, tableName2, table, ImmutableList.<String>of());
         }
       }
       return null;
@@ -446,7 +445,7 @@ public class CalciteSchema {
 
   /** Returns a tables derived from explicit and implicit functions
    * that take zero parameters. */
-  public Pair<String, Table> getTableBasedOnNullaryFunction(String tableName,
+  public TableEntry getTableBasedOnNullaryFunction(String tableName,
       boolean caseSensitive) {
     if (caseSensitive) {
       final FunctionEntry functionEntry = nullaryFunctionMap.get(tableName);
@@ -455,14 +454,14 @@ public class CalciteSchema {
         if (function instanceof TableMacro) {
           assert function.getParameters().isEmpty();
           final Table table = ((TableMacro) function).apply(ImmutableList.of());
-          return Pair.of(tableName, table);
+          return new TableEntryImpl(this, tableName, table, ImmutableList.<String>of());
         }
       }
       for (Function function : schema.getFunctions(tableName)) {
         if (function instanceof TableMacro
             && function.getParameters().isEmpty()) {
           final Table table = ((TableMacro) function).apply(ImmutableList.of());
-          return Pair.of(tableName, table);
+          return new TableEntryImpl(this, tableName, table, ImmutableList.<String>of());
         }
       }
     } else {
@@ -472,7 +471,7 @@ public class CalciteSchema {
         if (function instanceof TableMacro) {
           assert function.getParameters().isEmpty();
           final Table table = ((TableMacro) function).apply(ImmutableList.of());
-          return Pair.of(entry.getKey(), table);
+          return new TableEntryImpl(this, tableName, table, ImmutableList.<String>of());
         }
       }
       final NavigableSet<String> set =
@@ -483,7 +482,7 @@ public class CalciteSchema {
               && function.getParameters().isEmpty()) {
             final Table table =
                 ((TableMacro) function).apply(ImmutableList.of());
-            return Pair.of(s, table);
+            return new TableEntryImpl(this, tableName, table, ImmutableList.<String>of());
           }
         }
       }
@@ -604,8 +603,8 @@ public class CalciteSchema {
     }
 
     public Table getTable(String name) {
-      final Pair<String, Table> pair = CalciteSchema.this.getTable(name, true);
-      return pair == null ? null : pair.getValue();
+      final TableEntry entry = CalciteSchema.this.getTable(name, true);
+      return entry == null ? null : entry.getTable();
     }
 
     public NavigableSet<String> getTableNames() {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/8b53dc49/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java b/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java
index 3d98567..8776271 100644
--- a/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java
+++ b/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java
@@ -18,7 +18,6 @@ package org.apache.calcite.materialize;
 
 import org.apache.calcite.DataContext;
 import org.apache.calcite.adapter.clone.CloneSchema;
-import org.apache.calcite.adapter.java.JavaTypeFactory;
 import org.apache.calcite.avatica.ColumnMetaData;
 import org.apache.calcite.config.CalciteConnectionProperty;
 import org.apache.calcite.jdbc.CalciteConnection;
@@ -94,8 +93,18 @@ public class MaterializationService {
 
   /** Defines a new materialization. Returns its key. */
   public MaterializationKey defineMaterialization(final CalciteSchema schema,
+                                                  TileKey tileKey, String viewSql,
+                                                  List<String> viewSchemaPath,
+                                                  final String suggestedTableName, boolean create) {
+    TableFactory tableFactory =
+        new MaterializationService.DefaultTableFactory(suggestedTableName);
+    return defineMaterialization(schema, tileKey, viewSql, viewSchemaPath, tableFactory, create);
+  }
+
+  /** Defines a new materialization. Returns its key. */
+  public MaterializationKey defineMaterialization(final CalciteSchema schema,
       TileKey tileKey, String viewSql, List<String> viewSchemaPath,
-      final String suggestedTableName, boolean create) {
+      final TableFactory tableFactory, boolean create) {
     final MaterializationActor.QueryKey queryKey =
         new MaterializationActor.QueryKey(viewSql, schema, viewSchemaPath);
     final MaterializationKey existingKey = actor.keyBySql.get(queryKey);
@@ -108,57 +117,13 @@ public class MaterializationService {
 
     final CalciteConnection connection =
         CalciteMetaImpl.connect(schema.root(), null);
-    final Pair<String, Table> pair = schema.getTableBySql(viewSql);
-    Table materializedTable = pair == null ? null : pair.right;
+    CalciteSchema.TableEntry tableEntry = schema.getTableBySql(viewSql);
     RelDataType rowType = null;
-    if (materializedTable == null) {
-      final ImmutableMap<CalciteConnectionProperty, String> map =
-          ImmutableMap.of(CalciteConnectionProperty.CREATE_MATERIALIZATIONS,
-              "false");
-      final CalcitePrepare.CalciteSignature<Object> calciteSignature =
-          Schemas.prepare(connection, schema, viewSchemaPath, viewSql, map);
-      rowType = calciteSignature.rowType;
-      final JavaTypeFactory typeFactory = connection.getTypeFactory();
-      materializedTable =
-          CloneSchema.createCloneTable(typeFactory,
-              RelDataTypeImpl.proto(calciteSignature.rowType),
-              Lists.transform(calciteSignature.columns,
-                  new Function<ColumnMetaData, ColumnMetaData.Rep>() {
-                    public ColumnMetaData.Rep apply(ColumnMetaData column) {
-                      return column.type.rep;
-                    }
-                  }),
-              new AbstractQueryable<Object>() {
-                public Enumerator<Object> enumerator() {
-                  final DataContext dataContext =
-                      Schemas.createDataContext(connection);
-                  return calciteSignature.enumerable(dataContext).enumerator();
-                }
-
-                public Type getElementType() {
-                  return Object.class;
-                }
-
-                public Expression getExpression() {
-                  throw new UnsupportedOperationException();
-                }
-
-                public QueryProvider getProvider() {
-                  return connection;
-                }
-
-                public Iterator<Object> iterator() {
-                  final DataContext dataContext =
-                      Schemas.createDataContext(connection);
-                  return calciteSignature.enumerable(dataContext).iterator();
-                }
-              });
+    if (tableEntry == null) {
+      tableEntry = tableFactory.createTable(schema, viewSql, viewSchemaPath);
+      rowType = tableEntry.getTable().getRowType(connection.getTypeFactory());
     }
-    final String tableName =
-        Schemas.uniqueTableName(schema, Util.first(suggestedTableName, "m"));
-    final CalciteSchema.TableEntry tableEntry =
-        schema.add(tableName, materializedTable, ImmutableList.of(viewSql));
-    Hook.CREATE_MATERIALIZATION.run(tableName);
+
     if (rowType == null) {
       // If we didn't validate the SQL by populating a table, validate it now.
       final CalcitePrepare.ParseResult parse =
@@ -199,6 +164,13 @@ public class MaterializationService {
   public Pair<CalciteSchema.TableEntry, TileKey> defineTile(Lattice lattice,
       ImmutableBitSet groupSet, List<Lattice.Measure> measureList,
       CalciteSchema schema, boolean create, boolean exact) {
+    TableFactory defaultTableFactory = new DefaultTableFactory("m" + groupSet);
+    return defineTile(lattice, groupSet, measureList, schema, create, exact, defaultTableFactory);
+  }
+
+  public Pair<CalciteSchema.TableEntry, TileKey> defineTile(Lattice lattice,
+        ImmutableBitSet groupSet, List<Lattice.Measure> measureList,
+        CalciteSchema schema, boolean create, boolean exact, TableFactory tableFactory) {
     MaterializationKey materializationKey;
     final TileKey tileKey =
         new TileKey(lattice, groupSet, ImmutableList.copyOf(measureList));
@@ -287,9 +259,11 @@ public class MaterializationService {
         new TileKey(lattice, groupSet, ImmutableList.copyOf(measureSet));
 
     final String sql = lattice.sql(groupSet, newTileKey.measures);
+
+    System.out.println(sql);
     materializationKey =
         defineMaterialization(schema, newTileKey, sql, schema.path(null),
-            "m" + groupSet, true);
+            tableFactory, true);
     if (materializationKey != null) {
       final CalciteSchema.TableEntry tableEntry =
           checkValid(materializationKey);
@@ -360,6 +334,84 @@ public class MaterializationService {
     return INSTANCE;
   }
 
+  /**
+   * TableFactory Interface defines functions required by
+   * MaterializationService to create tables that represent
+   * a materialized view.
+   */
+  public interface TableFactory {
+    CalciteSchema.TableEntry createTable(final CalciteSchema schema,
+                                         final String viewSql,
+                                         final List<String> viewSchemaPath);
+    String getTableName(CalciteSchema schema);
+  }
+
+  /**
+   * Default implementation of TableFactory.
+   * Creates a table using CloneSchema.
+   */
+  public static class DefaultTableFactory implements TableFactory {
+    final String tableName;
+
+    public DefaultTableFactory(final String tableName) {
+      this.tableName = tableName;
+    }
+
+    public CalciteSchema.TableEntry createTable(final CalciteSchema schema,
+                                                final String viewSql,
+                                                final List<String> viewSchemaPath) {
+      final CalciteConnection connection =
+          CalciteMetaImpl.connect(schema.root(), null);
+      final ImmutableMap<CalciteConnectionProperty, String> map =
+          ImmutableMap.of(CalciteConnectionProperty.CREATE_MATERIALIZATIONS,
+              "false");
+      final CalcitePrepare.CalciteSignature<Object> calciteSignature =
+          Schemas.prepare(connection, schema, viewSchemaPath, viewSql, map);
+      Table table = CloneSchema.createCloneTable(connection.getTypeFactory(),
+          RelDataTypeImpl.proto(calciteSignature.rowType),
+          Lists.transform(calciteSignature.columns,
+              new Function<ColumnMetaData, ColumnMetaData.Rep>() {
+                public ColumnMetaData.Rep apply(ColumnMetaData column) {
+                  return column.type.rep;
+                }
+              }),
+          new AbstractQueryable<Object>() {
+            public Enumerator<Object> enumerator() {
+              final DataContext dataContext =
+                  Schemas.createDataContext(connection);
+              return calciteSignature.enumerable(dataContext).enumerator();
+            }
+
+            public Type getElementType() {
+              return Object.class;
+            }
+
+            public Expression getExpression() {
+              throw new UnsupportedOperationException();
+            }
+
+            public QueryProvider getProvider() {
+              return connection;
+            }
+
+            public Iterator<Object> iterator() {
+              final DataContext dataContext =
+                  Schemas.createDataContext(connection);
+              return calciteSignature.enumerable(dataContext).iterator();
+            }
+          });
+
+      final String tableName = this.getTableName(schema);
+      CalciteSchema.TableEntry tableEntry = schema.add(tableName, table,
+          ImmutableList.of(viewSql));
+      Hook.CREATE_MATERIALIZATION.run(tableName);
+      return tableEntry;
+    }
+
+    public String getTableName(CalciteSchema schema) {
+      return Schemas.uniqueTableName(schema, Util.first(tableName, "m"));
+    }
+  }
 }
 
 // End MaterializationService.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/8b53dc49/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java b/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java
index ada3442..8412305 100644
--- a/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java
+++ b/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java
@@ -49,7 +49,6 @@ import org.apache.calcite.sql.validate.SqlUserDefinedFunction;
 import org.apache.calcite.sql.validate.SqlUserDefinedTableFunction;
 import org.apache.calcite.sql.validate.SqlUserDefinedTableMacro;
 import org.apache.calcite.sql.validate.SqlValidatorUtil;
-import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Util;
 
 import com.google.common.collect.Collections2;
@@ -114,13 +113,13 @@ public class CalciteCatalogReader implements Prepare.CatalogReader,
       return null;
     }
     final String name = Util.last(names);
-    Pair<String, Table> pair = schema.getTable(name, caseSensitive);
-    if (pair == null) {
-      pair = schema.getTableBasedOnNullaryFunction(name, caseSensitive);
+    CalciteSchema.TableEntry entry = schema.getTable(name, caseSensitive);
+    if (entry == null) {
+      entry = schema.getTableBasedOnNullaryFunction(name, caseSensitive);
     }
-    if (pair != null) {
-      final Table table = pair.getValue();
-      final String name2 = pair.getKey();
+    if (entry != null) {
+      final Table table = entry.getTable();
+      final String name2 = entry.name;
       return RelOptTableImpl.create(this, table.getRowType(typeFactory),
           schema.add(name2, table), null);
     }


[4/7] incubator-calcite git commit: Add license notice for web site

Posted by jh...@apache.org.
Add license notice for web site


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

Branch: refs/heads/master
Commit: b181851c525e130abfe6862751aacca81e814f31
Parents: 530e398
Author: Julian Hyde <jh...@apache.org>
Authored: Fri Jun 5 16:05:12 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Fri Jun 5 16:06:12 2015 -0700

----------------------------------------------------------------------
 LICENSE | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b181851c/LICENSE
----------------------------------------------------------------------
diff --git a/LICENSE b/LICENSE
index d645695..5d678e8 100644
--- a/LICENSE
+++ b/LICENSE
@@ -200,3 +200,39 @@
    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.
+
+
+
+
+
+
+APACHE CALCITE SUBCOMPONENTS:
+
+The Apache Calcite project contains subcomponents with separate copyright
+notices and license terms. Your use of the source code for the these
+subcomponents is subject to the terms and conditions of the following
+licenses.
+
+For parts of the site:
+
+The MIT License (MIT)
+
+Copyright (c) 2008-2015 Tom Preston-Werner
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file


[2/7] incubator-calcite git commit: Separate TableFactory from suggested table name, so one TableFactory can be used for several tables

Posted by jh...@apache.org.
Separate TableFactory from suggested table name, so one TableFactory can be used for several tables

Make TableFactory.createTable return Table, not TableEntry; the client now needs to choose a name and register it in a schema.


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

Branch: refs/heads/master
Commit: 3aec3f8208828eca530685b4e1eef16db6146f9d
Parents: 8b53dc4
Author: Julian Hyde <jh...@apache.org>
Authored: Thu Jun 4 21:27:25 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Fri Jun 5 10:10:33 2015 -0700

----------------------------------------------------------------------
 .../org/apache/calcite/jdbc/CalciteSchema.java  | 17 +++--
 .../materialize/MaterializationService.java     | 71 +++++++-------------
 2 files changed, 37 insertions(+), 51 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/3aec3f82/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java
index 081ed85..3ce35b0 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java
@@ -138,6 +138,11 @@ public class CalciteSchema {
     return rootSchema;
   }
 
+  /** Creates a TableEntryImpl with no SQLs. */
+  private TableEntryImpl tableEntry(String name, Table table) {
+    return new TableEntryImpl(this, name, table, ImmutableList.<String>of());
+  }
+
   /** Defines a table within this schema. */
   public TableEntry add(String tableName, Table table) {
     return add(tableName, table, ImmutableList.<String>of());
@@ -273,7 +278,7 @@ public class CalciteSchema {
       if (implicitTableCache.get(now).contains(tableName)) {
         final Table table = schema.getTable(tableName);
         if (table != null) {
-          return new TableEntryImpl(this, tableName, table, ImmutableList.<String>of());
+          return tableEntry(tableName, table);
         }
       }
       return null;
@@ -292,7 +297,7 @@ public class CalciteSchema {
       if (tableName2 != null) {
         final Table table = schema.getTable(tableName2);
         if (table != null) {
-          return new TableEntryImpl(this, tableName2, table, ImmutableList.<String>of());
+          return tableEntry(tableName2, table);
         }
       }
       return null;
@@ -454,14 +459,14 @@ public class CalciteSchema {
         if (function instanceof TableMacro) {
           assert function.getParameters().isEmpty();
           final Table table = ((TableMacro) function).apply(ImmutableList.of());
-          return new TableEntryImpl(this, tableName, table, ImmutableList.<String>of());
+          return tableEntry(tableName, table);
         }
       }
       for (Function function : schema.getFunctions(tableName)) {
         if (function instanceof TableMacro
             && function.getParameters().isEmpty()) {
           final Table table = ((TableMacro) function).apply(ImmutableList.of());
-          return new TableEntryImpl(this, tableName, table, ImmutableList.<String>of());
+          return tableEntry(tableName, table);
         }
       }
     } else {
@@ -471,7 +476,7 @@ public class CalciteSchema {
         if (function instanceof TableMacro) {
           assert function.getParameters().isEmpty();
           final Table table = ((TableMacro) function).apply(ImmutableList.of());
-          return new TableEntryImpl(this, tableName, table, ImmutableList.<String>of());
+          return tableEntry(tableName, table);
         }
       }
       final NavigableSet<String> set =
@@ -482,7 +487,7 @@ public class CalciteSchema {
               && function.getParameters().isEmpty()) {
             final Table table =
                 ((TableMacro) function).apply(ImmutableList.of());
-            return new TableEntryImpl(this, tableName, table, ImmutableList.<String>of());
+            return tableEntry(tableName, table);
           }
         }
       }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/3aec3f82/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java b/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java
index 8776271..b594cca 100644
--- a/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java
+++ b/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java
@@ -87,24 +87,23 @@ public class MaterializationService {
       };
 
   private final MaterializationActor actor = new MaterializationActor();
+  private final DefaultTableFactory tableFactory = new DefaultTableFactory();
 
   private MaterializationService() {
   }
 
   /** Defines a new materialization. Returns its key. */
   public MaterializationKey defineMaterialization(final CalciteSchema schema,
-                                                  TileKey tileKey, String viewSql,
-                                                  List<String> viewSchemaPath,
-                                                  final String suggestedTableName, boolean create) {
-    TableFactory tableFactory =
-        new MaterializationService.DefaultTableFactory(suggestedTableName);
-    return defineMaterialization(schema, tileKey, viewSql, viewSchemaPath, tableFactory, create);
+      TileKey tileKey, String viewSql, List<String> viewSchemaPath,
+      final String suggestedTableName, boolean create) {
+    return defineMaterialization(schema, tileKey, viewSql, viewSchemaPath,
+        suggestedTableName, tableFactory, create);
   }
 
   /** Defines a new materialization. Returns its key. */
   public MaterializationKey defineMaterialization(final CalciteSchema schema,
       TileKey tileKey, String viewSql, List<String> viewSchemaPath,
-      final TableFactory tableFactory, boolean create) {
+      String suggestedTableName, TableFactory tableFactory, boolean create) {
     final MaterializationActor.QueryKey queryKey =
         new MaterializationActor.QueryKey(viewSql, schema, viewSchemaPath);
     final MaterializationKey existingKey = actor.keyBySql.get(queryKey);
@@ -120,8 +119,12 @@ public class MaterializationService {
     CalciteSchema.TableEntry tableEntry = schema.getTableBySql(viewSql);
     RelDataType rowType = null;
     if (tableEntry == null) {
-      tableEntry = tableFactory.createTable(schema, viewSql, viewSchemaPath);
-      rowType = tableEntry.getTable().getRowType(connection.getTypeFactory());
+      Table table = tableFactory.createTable(schema, viewSql, viewSchemaPath);
+      final String tableName = Schemas.uniqueTableName(schema,
+          Util.first(suggestedTableName, "m"));
+      tableEntry = schema.add(tableName, table, ImmutableList.of(viewSql));
+      Hook.CREATE_MATERIALIZATION.run(tableName);
+      rowType = table.getRowType(connection.getTypeFactory());
     }
 
     if (rowType == null) {
@@ -164,13 +167,14 @@ public class MaterializationService {
   public Pair<CalciteSchema.TableEntry, TileKey> defineTile(Lattice lattice,
       ImmutableBitSet groupSet, List<Lattice.Measure> measureList,
       CalciteSchema schema, boolean create, boolean exact) {
-    TableFactory defaultTableFactory = new DefaultTableFactory("m" + groupSet);
-    return defineTile(lattice, groupSet, measureList, schema, create, exact, defaultTableFactory);
+    return defineTile(lattice, groupSet, measureList, schema, create, exact,
+        "m" + groupSet, tableFactory);
   }
 
   public Pair<CalciteSchema.TableEntry, TileKey> defineTile(Lattice lattice,
-        ImmutableBitSet groupSet, List<Lattice.Measure> measureList,
-        CalciteSchema schema, boolean create, boolean exact, TableFactory tableFactory) {
+      ImmutableBitSet groupSet, List<Lattice.Measure> measureList,
+      CalciteSchema schema, boolean create, boolean exact,
+      String suggestedTableName, TableFactory tableFactory) {
     MaterializationKey materializationKey;
     final TileKey tileKey =
         new TileKey(lattice, groupSet, ImmutableList.copyOf(measureList));
@@ -259,11 +263,9 @@ public class MaterializationService {
         new TileKey(lattice, groupSet, ImmutableList.copyOf(measureSet));
 
     final String sql = lattice.sql(groupSet, newTileKey.measures);
-
-    System.out.println(sql);
     materializationKey =
         defineMaterialization(schema, newTileKey, sql, schema.path(null),
-            tableFactory, true);
+            suggestedTableName, tableFactory, true);
     if (materializationKey != null) {
       final CalciteSchema.TableEntry tableEntry =
           checkValid(materializationKey);
@@ -335,31 +337,20 @@ public class MaterializationService {
   }
 
   /**
-   * TableFactory Interface defines functions required by
-   * MaterializationService to create tables that represent
-   * a materialized view.
+   * Creates tables that represent a materialized view.
    */
   public interface TableFactory {
-    CalciteSchema.TableEntry createTable(final CalciteSchema schema,
-                                         final String viewSql,
-                                         final List<String> viewSchemaPath);
-    String getTableName(CalciteSchema schema);
+    Table createTable(CalciteSchema schema, String viewSql,
+        List<String> viewSchemaPath);
   }
 
   /**
-   * Default implementation of TableFactory.
-   * Creates a table using CloneSchema.
+   * Default implementation of {@link TableFactory}.
+   * Creates a table using {@link CloneSchema}.
    */
   public static class DefaultTableFactory implements TableFactory {
-    final String tableName;
-
-    public DefaultTableFactory(final String tableName) {
-      this.tableName = tableName;
-    }
-
-    public CalciteSchema.TableEntry createTable(final CalciteSchema schema,
-                                                final String viewSql,
-                                                final List<String> viewSchemaPath) {
+    public Table createTable(CalciteSchema schema, String viewSql,
+        List<String> viewSchemaPath) {
       final CalciteConnection connection =
           CalciteMetaImpl.connect(schema.root(), null);
       final ImmutableMap<CalciteConnectionProperty, String> map =
@@ -367,7 +358,7 @@ public class MaterializationService {
               "false");
       final CalcitePrepare.CalciteSignature<Object> calciteSignature =
           Schemas.prepare(connection, schema, viewSchemaPath, viewSql, map);
-      Table table = CloneSchema.createCloneTable(connection.getTypeFactory(),
+      return CloneSchema.createCloneTable(connection.getTypeFactory(),
           RelDataTypeImpl.proto(calciteSignature.rowType),
           Lists.transform(calciteSignature.columns,
               new Function<ColumnMetaData, ColumnMetaData.Rep>() {
@@ -400,16 +391,6 @@ public class MaterializationService {
               return calciteSignature.enumerable(dataContext).iterator();
             }
           });
-
-      final String tableName = this.getTableName(schema);
-      CalciteSchema.TableEntry tableEntry = schema.add(tableName, table,
-          ImmutableList.of(viewSql));
-      Hook.CREATE_MATERIALIZATION.run(tableName);
-      return tableEntry;
-    }
-
-    public String getTableName(CalciteSchema schema) {
-      return Schemas.uniqueTableName(schema, Util.first(tableName, "m"));
     }
   }
 }


[7/7] incubator-calcite git commit: [CALCITE-665] ClassCastException in MongoDB adapter

Posted by jh...@apache.org.
[CALCITE-665] ClassCastException in MongoDB adapter


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

Branch: refs/heads/master
Commit: dbdb091dc6fa5d2322d87df65bde142276930129
Parents: 6609cb1
Author: Julian Hyde <jh...@apache.org>
Authored: Mon Jun 8 10:25:55 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Jun 8 10:25:55 2015 -0700

----------------------------------------------------------------------
 .../adapter/mongodb/MongoEnumerator.java        | 21 ++++++++++---
 .../org/apache/calcite/test/MongoAdapterIT.java | 32 +++++++++++++++++---
 2 files changed, 44 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/dbdb091d/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoEnumerator.java
----------------------------------------------------------------------
diff --git a/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoEnumerator.java b/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoEnumerator.java
index 94efffb..0821f32 100644
--- a/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoEnumerator.java
+++ b/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoEnumerator.java
@@ -19,6 +19,7 @@ package org.apache.calcite.adapter.mongodb;
 import org.apache.calcite.avatica.util.DateTimeUtils;
 import org.apache.calcite.linq4j.Enumerator;
 import org.apache.calcite.linq4j.function.Function1;
+import org.apache.calcite.linq4j.tree.Primitive;
 
 import com.mongodb.DBCursor;
 import com.mongodb.DBObject;
@@ -122,13 +123,23 @@ class MongoEnumerator implements Enumerator<Object> {
   }
 
   private static Object convert(Object o, Class clazz) {
-    if (o == null || clazz.isInstance(o)) {
+    if (o == null) {
+      return null;
+    }
+    Primitive primitive = Primitive.of(clazz);
+    if (primitive != null) {
+      clazz = primitive.boxClass;
+    } else {
+      primitive = Primitive.ofBox(clazz);
+    }
+    if (clazz.isInstance(o)) {
       return o;
     }
-    if (clazz == int.class || clazz == Integer.class) {
-      if (o instanceof Date) {
-        return (int) (((Date) o).getTime() / DateTimeUtils.MILLIS_PER_DAY);
-      }
+    if (o instanceof Date && primitive != null) {
+      o = ((Date) o).getTime() / DateTimeUtils.MILLIS_PER_DAY;
+    }
+    if (o instanceof Number && primitive != null) {
+      return primitive.number((Number) o);
     }
     return o;
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/dbdb091d/mongodb/src/test/java/org/apache/calcite/test/MongoAdapterIT.java
----------------------------------------------------------------------
diff --git a/mongodb/src/test/java/org/apache/calcite/test/MongoAdapterIT.java b/mongodb/src/test/java/org/apache/calcite/test/MongoAdapterIT.java
index d3b37e1..f994142 100644
--- a/mongodb/src/test/java/org/apache/calcite/test/MongoAdapterIT.java
+++ b/mongodb/src/test/java/org/apache/calcite/test/MongoAdapterIT.java
@@ -22,9 +22,11 @@ import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Util;
 
 import com.google.common.base.Function;
+import com.google.common.base.Throwables;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
 
+import org.hamcrest.CoreMatchers;
 import org.junit.Ignore;
 import org.junit.Test;
 
@@ -496,8 +498,8 @@ public class MongoAdapterIT {
         .query(
             "select state, avg(pop) as a from zips group by state order by state")
         .limit(2)
-        .returns("STATE=AK; A=2793.3230769230768\n"
-            + "STATE=AL; A=7126.255731922399\n")
+        .returns("STATE=AK; A=2793\n"
+            + "STATE=AL; A=7126\n")
         .queryContains(
             mongoChecker(
                 "{$project: {POP: '$pop', STATE: '$state'}}",
@@ -513,8 +515,8 @@ public class MongoAdapterIT {
         .query(
             "select state, avg(pop) as a, sum(pop) as s, count(pop) as c from zips group by state order by state")
         .limit(2)
-        .returns("STATE=AK; A=2793.3230769230768; S=544698; C=195\n"
-            + "STATE=AL; A=7126.255731922399; S=4040587; C=567\n")
+        .returns("STATE=AK; A=2793; S=544698; C=195\n"
+            + "STATE=AL; A=7126; S=4040587; C=567\n")
         .queryContains(
             mongoChecker(
                 "{$project: {POP: '$pop', STATE: '$state'}}",
@@ -774,6 +776,28 @@ public class MongoAdapterIT {
         .query("select cast(_MAP['date'] as DATE) from \"datatypes\"")
         .returnsUnordered("EXPR$0=2012-09-05");
   }
+
+  /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-665">[CALCITE-665]
+   * ClassCastException in MongoDB adapter</a>. */
+  @Test public void testCountViaInt() {
+    CalciteAssert.that()
+        .enable(enabled())
+        .with(ZIPS)
+        .query("select count(*) from zips")
+        .returns(
+            new Function<ResultSet, Void>() {
+              public Void apply(ResultSet input) {
+                try {
+                  assertThat(input.next(), CoreMatchers.is(true));
+                  assertThat(input.getInt(1), CoreMatchers.is(29353));
+                  return null;
+                } catch (SQLException e) {
+                  throw Throwables.propagate(e);
+                }
+              }
+            });
+  }
 }
 
 // End MongoAdapterIT.java


[5/7] incubator-calcite git commit: [CALCITE-748] Add RelBuilder, builder for expressions in relational algebra

Posted by jh...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/6609cb1a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
new file mode 100644
index 0000000..ed351d5
--- /dev/null
+++ b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
@@ -0,0 +1,624 @@
+/*
+ * 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.test;
+
+import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.plan.RelTraitDef;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.AggregateCall;
+import org.apache.calcite.rel.core.Correlate;
+import org.apache.calcite.rel.core.Exchange;
+import org.apache.calcite.rel.core.JoinRelType;
+import org.apache.calcite.rel.core.TableFunctionScan;
+import org.apache.calcite.rel.core.TableModify;
+import org.apache.calcite.rel.core.Window;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rex.RexInputRef;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.schema.SchemaPlus;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.sql.parser.SqlParser;
+import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.tools.Frameworks;
+import org.apache.calcite.tools.Programs;
+import org.apache.calcite.tools.RelBuilder;
+
+import org.junit.Test;
+
+import java.util.List;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+
+/**
+ * Unit test for {@link RelBuilder}.
+ *
+ * <p>Tasks:</p>
+ * <ol>
+ *   <li>Add RelBuilder.scan(List&lt;String&gt;)</li>
+ *   <li>Add RelBuilder.scan(Table)</li>
+ *   <li>Test that {@link RelBuilder#filter} does not create a filter if the
+ *   predicates optimize to true</li>
+ *   <li>Test that {@link RelBuilder#filter} DOES create a filter if the
+ *   predicates optimize to false. (Creating an empty Values seems too
+ *   devious.)</li>
+ *   <li>Test that {@link RelBuilder#scan} throws good error if table not
+ *   found</li>
+ *   <li>Test that {@link RelBuilder#scan} obeys case-sensitivity</li>
+ *   <li>Test that {@link RelBuilder#join(JoinRelType, String...)} obeys
+ *   case-sensitivity</li>
+ *   <li>Test RelBuilder with alternative factories</li>
+ *   <li>Test that {@link RelBuilder#field(String)} obeys case-sensitivity</li>
+ *   <li>Test case-insensitive unique field names</li>
+ *   <li>Test that an alias created using
+ *      {@link RelBuilder#alias(RexNode, String)} is removed if not a top-level
+ *      project</li>
+ *   <li>{@link RelBuilder#aggregate} with grouping sets</li>
+ *   <li>{@link RelBuilder#aggregateCall} with filter</li>
+ *   <li>Add call to create {@link TableFunctionScan}</li>
+ *   <li>Add call to create {@link Window}</li>
+ *   <li>Add call to create {@link TableModify}</li>
+ *   <li>Add call to create {@link Exchange}</li>
+ *   <li>Add call to create {@link Correlate}</li>
+ *   <li>Add call to create {@link AggregateCall} with filter</li>
+ * </ol>
+ */
+public class RelBuilderTest {
+  /** Creates a config based on the "scott" schema. */
+  public static Frameworks.ConfigBuilder config() {
+    final SchemaPlus rootSchema = Frameworks.createRootSchema(true);
+    return Frameworks.newConfigBuilder()
+        .parserConfig(SqlParser.Config.DEFAULT)
+        .defaultSchema(
+            CalciteAssert.addSchema(rootSchema, CalciteAssert.SchemaSpec.SCOTT))
+        .traitDefs((List<RelTraitDef>) null)
+        .programs(Programs.heuristicJoinOrder(Programs.RULE_SET, true, 2));
+  }
+
+  @Test public void testScan() {
+    // Equivalent SQL:
+    //   SELECT *
+    //   FROM emp
+    final RelNode root =
+        RelBuilder.create(config().build())
+            .scan("EMP")
+            .build();
+    assertThat(RelOptUtil.toString(root),
+        is("LogicalTableScan(table=[[scott, EMP]])\n"));
+  }
+
+  @Test public void testScanFilterTrue() {
+    // Equivalent SQL:
+    //   SELECT *
+    //   FROM emp
+    //   WHERE TRUE
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode root =
+        builder.scan("EMP")
+            .filter(builder.literal(true))
+            .build();
+    assertThat(RelOptUtil.toString(root),
+        is("LogicalTableScan(table=[[scott, EMP]])\n"));
+  }
+
+  @Test public void testScanFilterEquals() {
+    // Equivalent SQL:
+    //   SELECT *
+    //   FROM emp
+    //   WHERE deptno = 20
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode root =
+        builder.scan("EMP")
+            .filter(
+                builder.equals(builder.field("DEPTNO"), builder.literal(20)))
+            .build();
+    assertThat(RelOptUtil.toString(root),
+        is("LogicalFilter(condition=[=($7, 20)])\n"
+            + "  LogicalTableScan(table=[[scott, EMP]])\n"));
+  }
+
+  @Test public void testScanFilterOr() {
+    // Equivalent SQL:
+    //   SELECT *
+    //   FROM emp
+    //   WHERE (deptno = 20 OR comm IS NULL) AND mgr IS NOT NULL
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode root =
+        builder.scan("EMP")
+            .filter(
+                builder.call(SqlStdOperatorTable.OR,
+                    builder.call(SqlStdOperatorTable.EQUALS,
+                        builder.field("DEPTNO"),
+                        builder.literal(20)),
+                    builder.isNull(builder.field(6))),
+                builder.isNotNull(builder.field(3)))
+            .build();
+    assertThat(RelOptUtil.toString(root),
+        is("LogicalFilter(condition=[AND(OR(=($7, 20), IS NULL($6)), IS NOT NULL($3))])\n"
+            + "  LogicalTableScan(table=[[scott, EMP]])\n"));
+  }
+
+  @Test public void testBadFieldName() {
+    final RelBuilder builder = RelBuilder.create(config().build());
+    try {
+      RexInputRef ref = builder.scan("EMP").field("deptno");
+      fail("expected error, got " + ref);
+    } catch (IllegalArgumentException e) {
+      assertThat(e.getMessage(),
+          is("field [deptno] not found; input fields are: [EMPNO, ENAME, JOB, "
+              + "MGR, HIREDATE, SAL, COMM, DEPTNO]"));
+    }
+  }
+
+  @Test public void testBadFieldOrdinal() {
+    final RelBuilder builder = RelBuilder.create(config().build());
+    try {
+      RexInputRef ref = builder.scan("DEPT").field(20);
+      fail("expected error, got " + ref);
+    } catch (IllegalArgumentException e) {
+      assertThat(e.getMessage(),
+          is("field ordinal [20] out of range; "
+                  + "input fields are: [DEPTNO, DNAME, LOC]"));
+    }
+  }
+
+  @Test public void testBadType() {
+    final RelBuilder builder = RelBuilder.create(config().build());
+    try {
+      builder.scan("EMP");
+      RexNode call = builder.call(SqlStdOperatorTable.PLUS, builder.field(1),
+          builder.field(3));
+      fail("expected error, got " + call);
+    } catch (IllegalArgumentException e) {
+      assertThat(e.getMessage(),
+          is("cannot derive type: +; "
+              + "operands: [$1: VARCHAR(10), $3: SMALLINT]"));
+    }
+  }
+
+  @Test public void testProject() {
+    // Equivalent SQL:
+    //   SELECT deptno, CAST(comm AS SMALLINT) AS comm, 20 AS $f2,
+    //     comm AS comm3, comm AS c
+    //   FROM emp
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode root =
+        builder.scan("EMP")
+            .project(builder.field("DEPTNO"),
+                builder.cast(builder.field(6), SqlTypeName.SMALLINT),
+                builder.literal(20),
+                builder.field(6),
+                builder.alias(builder.field(6), "C"))
+            .build();
+    // Note: CAST(COMM) gets the COMM alias because it occurs first
+    // Note: AS(COMM, C) becomes just $6
+    assertThat(RelOptUtil.toString(root),
+        is(
+            "LogicalProject(DEPTNO=[$7], COMM=[CAST($6):SMALLINT NOT NULL], $f2=[20], COMM3=[$6], C=[$6])\n"
+            + "  LogicalTableScan(table=[[scott, EMP]])\n"));
+  }
+
+  /** Tests each method that creates a scalar expression. */
+  @Test public void testProject2() {
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode root =
+        builder.scan("EMP")
+            .project(builder.field("DEPTNO"),
+                builder.cast(builder.field(6), SqlTypeName.SMALLINT),
+                builder.or(
+                    builder.equals(builder.field("DEPTNO"),
+                        builder.literal(20)),
+                    builder.and(builder.literal(false),
+                        builder.equals(builder.field("DEPTNO"),
+                            builder.literal(10)),
+                        builder.and(builder.isNull(builder.field(6)),
+                            builder.not(builder.isNotNull(builder.field(7))))),
+                    builder.equals(builder.field("DEPTNO"),
+                        builder.literal(20)),
+                    builder.equals(builder.field("DEPTNO"),
+                        builder.literal(30))),
+                builder.alias(builder.isNull(builder.field(2)), "n2"),
+                builder.alias(builder.isNotNull(builder.field(3)), "nn2"),
+                builder.literal(20),
+                builder.field(6),
+                builder.alias(builder.field(6), "C"))
+            .build();
+    assertThat(RelOptUtil.toString(root),
+        is("LogicalProject(DEPTNO=[$7], COMM=[CAST($6):SMALLINT NOT NULL],"
+                + " $f2=[OR(=($7, 20), AND(false, =($7, 10), IS NULL($6),"
+                + " NOT(IS NOT NULL($7))), =($7, 30))], n2=[IS NULL($2)],"
+                + " nn2=[IS NOT NULL($3)], $f5=[20], COMM6=[$6], C=[$6])\n"
+                + "  LogicalTableScan(table=[[scott, EMP]])\n"));
+  }
+
+  @Test public void testAggregate() {
+    // Equivalent SQL:
+    //   SELECT COUNT(DISTINCT deptno) AS c
+    //   FROM emp
+    //   GROUP BY ()
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode root =
+        builder.scan("EMP")
+            .aggregate(
+                builder.groupKey(), builder.aggregateCall(
+                    SqlStdOperatorTable.COUNT,
+                    true,
+                    "C",
+                    builder.field("DEPTNO")))
+            .build();
+    assertThat(RelOptUtil.toString(root),
+        is("LogicalAggregate(group=[{}], C=[COUNT(DISTINCT $7)])\n"
+            + "  LogicalTableScan(table=[[scott, EMP]])\n"));
+  }
+
+  @Test public void testAggregate2() {
+    // Equivalent SQL:
+    //   SELECT COUNT(*) AS c, SUM(mgr + 1) AS s
+    //   FROM emp
+    //   GROUP BY ename, hiredate + mgr
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode root =
+        builder.scan("EMP")
+            .aggregate(
+                builder.groupKey(builder.field(1),
+                    builder.call(SqlStdOperatorTable.PLUS, builder.field(4),
+                        builder.field(3)),
+                    builder.field(1)),
+                builder.aggregateCall(SqlStdOperatorTable.COUNT, false, "C"),
+                builder.aggregateCall(SqlStdOperatorTable.SUM, false, "S",
+                    builder.call(
+                        SqlStdOperatorTable.PLUS,
+                        builder.field(3),
+                        builder.literal(1))))
+            .build();
+    assertThat(RelOptUtil.toString(root),
+        is(""
+            + "LogicalAggregate(group=[{1, 8}], C=[COUNT()], S=[SUM($9)])\n"
+            + "  LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], $f8=[+($4, $3)], $f9=[+($3, 1)])\n"
+            + "    LogicalTableScan(table=[[scott, EMP]])\n"));
+  }
+
+  @Test public void testDistinct() {
+    // Equivalent SQL:
+    //   SELECT DISTINCT *
+    //   FROM emp
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode root =
+        builder.scan("EMP")
+            .distinct()
+            .build();
+    assertThat(RelOptUtil.toString(root),
+        is("LogicalAggregate(group=[{}])\n"
+                + "  LogicalTableScan(table=[[scott, EMP]])\n"));
+  }
+
+  @Test public void testUnion() {
+    // Equivalent SQL:
+    //   SELECT deptno FROM emp
+    //   UNION ALL
+    //   SELECT deptno FROM dept
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode root =
+        builder.scan("EMP")
+            .filter(
+                builder.call(SqlStdOperatorTable.EQUALS,
+                    builder.field("DEPTNO"),
+                    builder.literal(20)))
+            .project(builder.field("EMPNO"))
+            .scan("DEPT")
+            .project(builder.field("DEPTNO"))
+            .union(true)
+            .build();
+    assertThat(RelOptUtil.toString(root),
+        is("LogicalUnion(all=[true])\n"
+            + "  LogicalProject(DEPTNO=[$0])\n"
+            + "    LogicalTableScan(table=[[scott, DEPT]])\n"
+            + "  LogicalProject(EMPNO=[$0])\n"
+            + "    LogicalFilter(condition=[=($7, 20)])\n"
+            + "      LogicalTableScan(table=[[scott, EMP]])\n"));
+  }
+
+  @Test public void testIntersect() {
+    // Equivalent SQL:
+    //   SELECT empno FROM emp
+    //   WHERE deptno = 20
+    //   INTERSECT
+    //   SELECT deptno FROM dept
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode root =
+        builder.scan("EMP")
+            .filter(
+                builder.call(SqlStdOperatorTable.EQUALS,
+                    builder.field("DEPTNO"),
+                    builder.literal(20)))
+            .project(builder.field("EMPNO"))
+            .scan("DEPT")
+            .project(builder.field("DEPTNO"))
+            .intersect(false)
+            .build();
+    assertThat(RelOptUtil.toString(root),
+        is("LogicalIntersect(all=[false])\n"
+            + "  LogicalProject(DEPTNO=[$0])\n"
+            + "    LogicalTableScan(table=[[scott, DEPT]])\n"
+            + "  LogicalProject(EMPNO=[$0])\n"
+            + "    LogicalFilter(condition=[=($7, 20)])\n"
+            + "      LogicalTableScan(table=[[scott, EMP]])\n"));
+  }
+
+  @Test public void testExcept() {
+    // Equivalent SQL:
+    //   SELECT empno FROM emp
+    //   WHERE deptno = 20
+    //   MINUS
+    //   SELECT deptno FROM dept
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode root =
+        builder.scan("EMP")
+            .filter(
+                builder.call(SqlStdOperatorTable.EQUALS,
+                    builder.field("DEPTNO"),
+                    builder.literal(20)))
+            .project(builder.field("EMPNO"))
+            .scan("DEPT")
+            .project(builder.field("DEPTNO"))
+            .minus(false)
+            .build();
+    assertThat(RelOptUtil.toString(root),
+        is("LogicalMinus(all=[false])\n"
+            + "  LogicalProject(DEPTNO=[$0])\n"
+            + "    LogicalTableScan(table=[[scott, DEPT]])\n"
+            + "  LogicalProject(EMPNO=[$0])\n"
+            + "    LogicalFilter(condition=[=($7, 20)])\n"
+            + "      LogicalTableScan(table=[[scott, EMP]])\n"));
+  }
+
+  @Test public void testJoin() {
+    // Equivalent SQL:
+    //   SELECT *
+    //   FROM (SELECT * FROM emp WHERE comm IS NULL)
+    //   JOIN dept ON emp.deptno = dept.deptno
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode root =
+        builder.scan("EMP")
+            .filter(
+                builder.call(SqlStdOperatorTable.IS_NULL,
+                    builder.field("COMM")))
+            .scan("DEPT")
+            .join(JoinRelType.INNER,
+                builder.call(SqlStdOperatorTable.EQUALS,
+                    builder.field(2, 0, "DEPTNO"),
+                    builder.field(2, 1, "DEPTNO")))
+            .build();
+    final String expected =
+        "LogicalJoin(condition=[=($7, $0)], joinType=[inner])\n"
+            + "  LogicalTableScan(table=[[scott, DEPT]])\n"
+            + "  LogicalFilter(condition=[IS NULL($6)])\n"
+            + "    LogicalTableScan(table=[[scott, EMP]])\n";
+    assertThat(RelOptUtil.toString(root), is(expected));
+
+    // Using USING method
+    final RelNode root2 =
+        builder.scan("EMP")
+            .filter(
+                builder.call(SqlStdOperatorTable.IS_NULL,
+                    builder.field("COMM")))
+            .scan("DEPT")
+            .join(JoinRelType.INNER, "DEPTNO")
+            .build();
+    assertThat(RelOptUtil.toString(root2), is(expected));
+  }
+
+  @Test public void testJoinCartesian() {
+    // Equivalent SQL:
+    //   SELECT * emp CROSS JOIN dept
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode root =
+        builder.scan("EMP")
+            .scan("DEPT")
+            .join(JoinRelType.INNER)
+            .build();
+    final String expected =
+        "LogicalJoin(condition=[true], joinType=[inner])\n"
+            + "  LogicalTableScan(table=[[scott, DEPT]])\n"
+            + "  LogicalTableScan(table=[[scott, EMP]])\n";
+    assertThat(RelOptUtil.toString(root), is(expected));
+  }
+
+  @Test public void testValues() {
+    // Equivalent SQL:
+    //   VALUES (true, 1), (false, -50) AS t(a, b)
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode root =
+        builder.values(new String[]{"a", "b"}, true, 1, false, -50)
+            .build();
+    final String expected =
+        "LogicalValues(tuples=[[{ true, 1 }, { false, -50 }]])\n";
+    assertThat(RelOptUtil.toString(root), is(expected));
+    final String expectedType =
+        "RecordType(BOOLEAN NOT NULL a, INTEGER NOT NULL b) NOT NULL";
+    assertThat(root.getRowType().getFullTypeString(), is(expectedType));
+  }
+
+  /** Tests creating Values with some field names and some values null. */
+  @Test public void testValuesNullable() {
+    // Equivalent SQL:
+    //   VALUES (null, 1, 'abc'), (false, null, 'longer string')
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode root =
+        builder.values(new String[]{"a", null, "c"},
+            null, 1, "abc",
+            false, null, "longer string").build();
+    final String expected =
+        "LogicalValues(tuples=[[{ null, 1, 'abc' }, { false, null, 'longer string' }]])\n";
+    assertThat(RelOptUtil.toString(root), is(expected));
+    final String expectedType =
+        "RecordType(BOOLEAN a, INTEGER expr$1, CHAR(13) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\" NOT NULL c) NOT NULL";
+    assertThat(root.getRowType().getFullTypeString(), is(expectedType));
+  }
+
+  @Test public void testValuesBadNullFieldNames() {
+    try {
+      final RelBuilder builder = RelBuilder.create(config().build());
+      RelBuilder root = builder.values((String[]) null, "a", "b");
+      fail("expected error, got " + root);
+    } catch (IllegalArgumentException e) {
+      assertThat(e.getMessage(),
+          is("Value count must be a positive multiple of field count"));
+    }
+  }
+
+  @Test public void testValuesBadNoFields() {
+    try {
+      final RelBuilder builder = RelBuilder.create(config().build());
+      RelBuilder root = builder.values(new String[0], 1, 2, 3);
+      fail("expected error, got " + root);
+    } catch (IllegalArgumentException e) {
+      assertThat(e.getMessage(),
+          is("Value count must be a positive multiple of field count"));
+    }
+  }
+
+  @Test public void testValuesBadNoValues() {
+    try {
+      final RelBuilder builder = RelBuilder.create(config().build());
+      RelBuilder root = builder.values(new String[]{"a", "b"});
+      fail("expected error, got " + root);
+    } catch (IllegalArgumentException e) {
+      assertThat(e.getMessage(),
+          is("Value count must be a positive multiple of field count"));
+    }
+  }
+
+  @Test public void testValuesBadOddMultiple() {
+    try {
+      final RelBuilder builder = RelBuilder.create(config().build());
+      RelBuilder root = builder.values(new String[] {"a", "b"}, 1, 2, 3, 4, 5);
+      fail("expected error, got " + root);
+    } catch (IllegalArgumentException e) {
+      assertThat(e.getMessage(),
+          is("Value count must be a positive multiple of field count"));
+    }
+  }
+
+  @Test public void testValuesBadAllNull() {
+    try {
+      final RelBuilder builder = RelBuilder.create(config().build());
+      RelBuilder root =
+          builder.values(new String[] {"a", "b"}, null, null, 1, null);
+      fail("expected error, got " + root);
+    } catch (IllegalArgumentException e) {
+      assertThat(e.getMessage(),
+          is("All values of field 'b' are null; cannot deduce type"));
+    }
+  }
+
+  @Test public void testValuesAllNull() {
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelDataType rowType =
+        builder.getTypeFactory().builder()
+            .add("a", SqlTypeName.BIGINT)
+            .add("a", SqlTypeName.VARCHAR, 10)
+            .build();
+    RelNode root =
+        builder.values(rowType, null, null, 1, null).build();
+    final String expected =
+        "LogicalValues(tuples=[[{ null, null }, { 1, null }]])\n";
+    assertThat(RelOptUtil.toString(root), is(expected));
+    final String expectedType =
+        "RecordType(BIGINT NOT NULL a, VARCHAR(10) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\" NOT NULL a) NOT NULL";
+    assertThat(root.getRowType().getFullTypeString(), is(expectedType));
+  }
+
+  @Test public void testSort() {
+    // Equivalent SQL:
+    //   SELECT *
+    //   FROM emp
+    //   ORDER BY 3. 1 DESC
+    final RelBuilder builder = RelBuilder.create(config().build());
+    final RelNode root =
+        builder.scan("EMP")
+            .sort(builder.field(2), builder.desc(builder.field(0)))
+            .build();
+    final String expected =
+        "LogicalSort(sort0=[$2], sort1=[$0], dir0=[ASC], dir1=[DESC])\n"
+            + "  LogicalTableScan(table=[[scott, EMP]])\n";
+    assertThat(RelOptUtil.toString(root), is(expected));
+
+    // same result using ordinals
+    final RelNode root2 =
+        builder.scan("EMP")
+            .sort(2, -1)
+            .build();
+    assertThat(RelOptUtil.toString(root2), is(expected));
+  }
+
+  @Test public void testSortByExpression() {
+    // Equivalent SQL:
+    //   SELECT *
+    //   FROM emp
+    //   ORDER BY ename ASC NULLS LAST, hiredate + mgr DESC NULLS FIRST
+    final RelBuilder builder = RelBuilder.create(config().build());
+    final RelNode root =
+        builder.scan("EMP")
+            .sort(builder.nullsLast(builder.desc(builder.field(1))),
+                builder.nullsFirst(
+                    builder.call(SqlStdOperatorTable.PLUS, builder.field(4),
+                        builder.field(3))))
+            .build();
+    final String expected =
+        "LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7])\n"
+            + "  LogicalSort(sort0=[$1], sort1=[$8], dir0=[DESC-nulls-last], dir1=[ASC-nulls-first])\n"
+            + "    LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], $f8=[+($4, $3)])\n"
+            + "      LogicalTableScan(table=[[scott, EMP]])\n";
+    assertThat(RelOptUtil.toString(root), is(expected));
+  }
+
+  @Test public void testLimit() {
+    // Equivalent SQL:
+    //   SELECT *
+    //   FROM emp
+    //   OFFSET 2 FETCH 10
+    final RelBuilder builder = RelBuilder.create(config().build());
+    final RelNode root =
+        builder.scan("EMP")
+            .limit(2, 10)
+            .build();
+    final String expected =
+        "LogicalSort(offset=[2], fetch=[10])\n"
+            + "  LogicalTableScan(table=[[scott, EMP]])\n";
+    assertThat(RelOptUtil.toString(root), is(expected));
+  }
+
+  @Test public void testSortLimit() {
+    // Equivalent SQL:
+    //   SELECT *
+    //   FROM emp
+    //   ORDER BY deptno DESC FETCH 10
+    final RelBuilder builder = RelBuilder.create(config().build());
+    final RelNode root =
+        builder.scan("EMP")
+            .sortLimit(-1, 10, builder.desc(builder.field("DEPTNO")))
+            .build();
+    final String expected =
+        "LogicalSort(sort0=[$7], dir0=[DESC], fetch=[10])\n"
+            + "  LogicalTableScan(table=[[scott, EMP]])\n";
+    assertThat(RelOptUtil.toString(root), is(expected));
+  }
+}
+
+// End RelBuilderTest.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/6609cb1a/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 9a4756b..3d33234 100644
--- a/core/src/test/java/org/apache/calcite/tools/FrameworksTest.java
+++ b/core/src/test/java/org/apache/calcite/tools/FrameworksTest.java
@@ -33,7 +33,9 @@ import org.apache.calcite.rel.type.RelDataTypeSystemImpl;
 import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexLiteral;
 import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.schema.Path;
 import org.apache.calcite.schema.SchemaPlus;
+import org.apache.calcite.schema.Schemas;
 import org.apache.calcite.schema.Table;
 import org.apache.calcite.schema.impl.AbstractTable;
 import org.apache.calcite.server.CalciteServerStatement;
@@ -50,8 +52,10 @@ import org.junit.Test;
 import java.math.BigDecimal;
 
 import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
 
 /**
  * Unit tests for methods in {@link Frameworks}.
@@ -188,6 +192,36 @@ public class FrameworksTest {
     assertThat(Util.toLinux(valStr), equalTo(expandedStr));
   }
 
+  /** Test for {@link Path}. */
+  @Test public void testSchemaPath() {
+    final SchemaPlus rootSchema = Frameworks.createRootSchema(true);
+    final FrameworkConfig config = Frameworks.newConfigBuilder()
+        .defaultSchema(
+            CalciteAssert.addSchema(rootSchema, CalciteAssert.SchemaSpec.HR))
+        .build();
+    final Path path = Schemas.path(config.getDefaultSchema());
+    assertThat(path.size(), is(2));
+    assertThat(path.get(0).left, is(""));
+    assertThat(path.get(1).left, is("hr"));
+    assertThat(path.names().size(), is(1));
+    assertThat(path.names().get(0), is("hr"));
+    assertThat(path.schemas().size(), is(2));
+
+    final Path parent = path.parent();
+    assertThat(parent.size(), is(1));
+    assertThat(parent.names().size(), is(0));
+
+    final Path grandparent = parent.parent();
+    assertThat(grandparent.size(), is(0));
+
+    try {
+      Object o = grandparent.parent();
+      fail("expected exception, got " + o);
+    } catch (IllegalArgumentException e) {
+      // ok
+    }
+  }
+
   /** Dummy type system, similar to Hive's, accessed via an INSTANCE member. */
   public static class HiveLikeTypeSystem extends RelDataTypeSystemImpl {
     public static final RelDataTypeSystem INSTANCE = new HiveLikeTypeSystem();

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/6609cb1a/core/src/test/java/org/apache/calcite/util/UtilTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/util/UtilTest.java b/core/src/test/java/org/apache/calcite/util/UtilTest.java
index 8aca657..2d731a7 100644
--- a/core/src/test/java/org/apache/calcite/util/UtilTest.java
+++ b/core/src/test/java/org/apache/calcite/util/UtilTest.java
@@ -18,6 +18,7 @@ package org.apache.calcite.util;
 
 import org.apache.calcite.avatica.AvaticaUtils;
 import org.apache.calcite.avatica.util.Spaces;
+import org.apache.calcite.examples.RelBuilderExample;
 import org.apache.calcite.linq4j.function.Function1;
 import org.apache.calcite.runtime.FlatLists;
 import org.apache.calcite.runtime.Resources;
@@ -1376,6 +1377,10 @@ public class UtilTest {
     assertThat(map.get("X"), is((String) null));
     assertThat(map.get("Y"), equalTo("y"));
   }
+
+  @Test public void testRelBuilderExample() {
+    new RelBuilderExample(false).runAllExamples();
+  }
 }
 
 // End UtilTest.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/6609cb1a/site/_docs/algebra.md
----------------------------------------------------------------------
diff --git a/site/_docs/algebra.md b/site/_docs/algebra.md
index 1116362..ef93f97 100644
--- a/site/_docs/algebra.md
+++ b/site/_docs/algebra.md
@@ -22,6 +22,9 @@ limitations under the License.
 {% endcomment %}
 -->
 
+{% assign sourceRoot = "http://github.com/apache/incubator-calcite/blob/master" %}
+{% assign apiRoot = "http://calcite.hydromatic.net/apidocs" %}
+
 Relational algebra is at the heart of Calcite. Every query is
 represented as a tree of relational operators. You can translate from
 SQL to relational algebra, or you can build the tree directly.
@@ -38,3 +41,317 @@ semantics as the original but a lower cost.
 
 The planning process is extensible. You can add your own relational
 operators, planner rules, cost model, and statistics.
+
+## Algebra builder
+
+The simplest way to build a relational expression is to use the algebra builder,
+[RelBuilder]({{ apiRoot }}/org/apache/calcite/tools/RelBuilder.html).
+Here is an example:
+
+### TableScan
+
+{% highlight java %}
+final FrameworkConfig config;
+final RelBuilder builder = RelBuilder.create(config);
+final RelNode node = builder
+  .scan("EMP")
+  .build();
+System.out.println(RelOptUtil.toString(node));
+{% endhighlight %}
+
+(You can find the full code for this and other examples in
+[RelBuilderExample.java]({{ sourceRoot }}/core/src/test/java/org/apache/calcite/examples/RelBuilderExample.java).)
+
+The code prints
+
+{% highlight text %}
+LogicalTableScan(table=[[scott, EMP]])
+{% endhighlight %}
+
+It has created a scan of the `EMP` table; equivalent to the SQL
+
+{% highlight sql %}
+SELECT *
+FROM scott.EMP;
+{% endhighlight %}
+
+### Adding a Project
+
+Now, let's add a Project, the equivalent of
+
+{% highlight sql %}
+SELECT ename, deptno
+FROM scott.EMP;
+{% endhighlight %}
+
+We just add a call to the `project` method before calling
+`build`:
+
+{% highlight java %}
+final RelNode node = builder
+  .scan("EMP")
+  .project(builder.field("DEPTNO"), builder.field("ENAME"))
+  .build();
+System.out.println(RelOptUtil.toString(node));
+{% endhighlight %}
+
+and the output is
+
+{% highlight text %}
+LogicalProject(DEPTNO=[$7], ENAME=[$1])
+  LogicalTableScan(table=[[scott, EMP]])
+{% endhighlight %}
+
+The two calls to `builder.field` create simple expressions
+that return the fields from the input relational expression,
+namely the TableScan created by the `scan` call.
+
+Calcite has converted them to field references by ordinal,
+`$7` and `$1`.
+
+### Adding a Filter and Aggregate
+
+A query with an Aggregate, and a Filter:
+
+{% highlight java %}
+final RelNode node = builder
+  .scan("EMP")
+  .aggregate(builder.groupKey("DEPTNO"),
+      builder.count(false, "C"),
+      builder.sum(false, "S", builder.field("SAL")))
+  .filter(
+      builder.call(SqlStdOperatorTable.GREATER_THAN,
+          builder.field("C"),
+          builder.literal(10)))
+  .build();
+System.out.println(RelOptUtil.toString(node));
+{% endhighlight %}
+
+is equivalent to SQL
+
+{% highlight sql %}
+SELECT deptno, count(*) AS c, sum(sal) AS s
+FROM emp
+GROUP BY deptno
+HAVING count(*) > 10
+{% endhighlight %}
+
+and produces 
+
+{% highlight text %}
+LogicalFilter(condition=[>($1, 10)])
+  LogicalAggregate(group=[{7}], C=[COUNT()], S=[SUM($5)])
+    LogicalTableScan(table=[[scott, EMP]])
+{% endhighlight %}
+
+### Push and pop
+
+The builder uses a stack to store the relational expression produced by
+one step and pass it as an input to the next step. This allows the
+methods that produce relational expressions to produce a builder.
+
+Most of the time, the only stack method you will use is `build()`, to get the
+last relational expression, namely the root of the tree.
+
+Sometimes the stack becomes so deeply nested it gets confusing. To keep things
+straight, you can remove expressions from the stack. For example, here we are
+building a bushy join:
+
+{% highlight text %}
+.
+               join
+             /      \
+        join          join 
+      /      \      /      \
+CUSTOMERS ORDERS LINE_ITEMS PRODUCTS
+{% endhighlight %}
+
+We build it in three stages. Store the intermediate results in variables
+`left` and `right`, and use `push()` to put them back on the stack when it is
+time to create the final `Join`:
+
+{% highlight java %}
+final RelNode left = builder
+  .scan("CUSTOMERS")
+  .scan("ORDERS")
+  .join(JoinRelType.INNER, "ORDER_ID")
+  .build();
+
+final RelNode right = builder
+  .scan("LINE_ITEMS")
+  .scan("PRODUCTS")
+  .join(JoinRelType.INNER, "PRODUCT_ID")
+  .build();
+
+final RelNode result = builder
+  .push(left)
+  .push(right)
+  .join(JoinRelType.INNER, "ORDER_ID")
+  .build();
+{% endhighlight %}
+
+### Field names and ordinals
+
+You can reference a field by name or ordinal.
+
+Ordinals are zero-based. Each operator guarantees the order in which its output
+fields occur. For example, `Project` returns the fields in the generated by
+each of the scalar expressions.
+
+The field names of an operator are guaranteed to be unique, but sometimes that
+means that the names are not exactly what you expect. For example, when you
+join EMP to DEPT, one of the output fields will be called DEPTNO and another
+will be called something like DEPTNO_1.
+
+Some relational expression methods give you more control over field names:
+
+* `project` lets you wrap expressions using `alias(expr, fieldName)`. It
+  removes the wrapper but keeps the suggested name (as long as it is unique).
+* `values(String[] fieldNames, Object... values)` accepts an array of field
+  names. If any element of the array is null, the builder will generate a unique
+  name.
+
+If an expression projects an input field, or a cast of an input field, it will
+use the name of that input field.
+
+Once the unique field names have been assigned, the names are immutable.
+If you have a particular `RelNode` instance, you can rely on the field names not
+changing. In fact, the whole relational expression is immutable.
+
+But if a relational expression has passed through several rewrite rules (see
+([RelOptRule]({{ apiRoot }}/org/apache/calcite/plan/RelOptRule.html)), the field
+names of the resulting expression might not look much like the originals.
+At that point it is better to reference fields by ordinal.
+
+When you are building a relational expression that accepts multiple inputs,
+you need to build field references that take that into account. This occurs
+most often when building join conditions.
+
+Suppose you are building a join on EMP,
+which has 8 fields [EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO]
+and DEPT,
+which has 3 fields [DEPTNO, DNAME, LOC].
+Internally, Calcite represents those fields as offsets into
+a combined input row with 11 fields: the first field of the left input is
+field #0 (0-based, remember), and the first field of the right input is
+field #8.
+
+But through the builder API, you specify which field of which input.
+To reference "SAL", internal field #5,
+write `builder.field(2, 0, "SAL")`
+or `builder.field(2, 0, 5)`.
+This means "the field #5 of input #0 of two inputs".
+(Why does it need to know that there are two inputs? Because they are stored on
+the stack; input #1 is at the top of the stack, and input #0 is below it.
+If we did not tell the builder that were two inputs, it would not know how deep
+to go for input #0.)
+
+Similarly, to reference "DNAME", internal field #9 (8 + 1),
+write `builder.field(2, 1, "DNAME")`
+or `builder.field(2, 1, 1)`.
+
+### API summary
+
+#### Relational operators
+
+The following methods create a relational expression
+([RelNode]({{ apiRoot }}/org/apache/calcite/rel/RelNode.html)),
+push it onto the stack, and
+return the `RelBuilder`.
+
+| Method              | Description
+|:------------------- |:-----------
+| `scan(tableName)` | Creates a [TableScan]({{ apiRoot }}/org/apache/calcite/rel/core/TableScan.html).
+| `values(fieldNames, value...)`<br/>`values(rowType, tupleList)` | Creates a [Values]({{ apiRoot }}/org/apache/calcite/rel/core/Values.html).
+| `filter(expr...)`<br/>`filter(exprList)` | Creates a [Filter]({{ apiRoot }}/org/apache/calcite/rel/core/Filter.html) over the AND of the given predicates.
+| `project(expr...)`<br/>`project(exprList)` | Creates a [Project]({{ apiRoot }}/org/apache/calcite/rel/core/Project.html). To override the default name, wrap expressions using `alias`.
+| `aggregate(groupKey, aggCall...)`<br/>`aggregate(groupKey, aggCallList)` | Creates an [Aggregate]({{ apiRoot }}/org/apache/calcite/rel/core/Aggregate.html).
+| `distinct()` | Creates an [Aggregate]({{ apiRoot }}/org/apache/calcite/rel/core/Aggregate.html) that eliminates duplicate records.
+| `sort(fieldOrdinal...)`<br/>`sort(expr...)`<br/>`sort(exprList)` | Creates a [Sort]({{ apiRoot }}/org/apache/calcite/rel/core/Sort.html).<br/><br/>In the first form, field ordinals are 0-based, and a negative ordinal indicates descending; for example, -2 means field 1 descending.<br/><br/>In the other forms, you can wrap expressions in `as`, `nullsFirst` or `nullsLast`.
+| `sortLimit(offset, fetch, expr...)`<br/>`sortLimit(offset, fetch, exprList)` | Creates a [Sort]({{ apiRoot }}/org/apache/calcite/rel/core/Sort.html) with offset and limit.
+| `limit(offset, fetch)` | Creates a [Sort]({{ apiRoot }}/org/apache/calcite/rel/core/Sort.html) that does not sort, only applies with offset and limit.
+| `join(joinType, expr)`<br/>`join(joinType, fieldName...)` | Creates a [Join]({{ apiRoot }}/org/apache/calcite/rel/core/Join.html) of the two most recent relational expressions.<br/><br/>The first form joins on an boolean expression.<br/><br/>The second form joins on named fields; each side must have a field of each name.
+| `union(all)` | Creates a [Union]({{ apiRoot }}/org/apache/calcite/rel/core/Union.html) of the two most recent relational expressions.
+| `intersect(all)` | Creates an [Intersect]({{ apiRoot }}/org/apache/calcite/rel/core/Intersect.html) of the two most recent relational expressions.
+| `minus(all)` | Creates a [Minus]({{ apiRoot }}/org/apache/calcite/rel/core/Minus.html) of the two most recent relational expressions.
+
+Argument types:
+
+* `expr`  [RexNode]({{ apiRoot }}/org/apache/calcite/rex/RexNode.html)
+* `expr...` Array of [RexNode]({{ apiRoot }}/org/apache/calcite/rex/RexNode.html)
+* `exprList` Iterable of [RexNode]({{ apiRoot }}/org/apache/calcite/rex/RexNode.html)
+* `fieldOrdinal` Ordinal of a field within its row (starting from 0)
+* `fieldName` Name of a field, unique within its row
+* `fieldName...` Array of String
+* `fieldNames` Iterable of String
+* `rowType` [RelDataType]({{ apiRoot }}/org/apache/calcite/rel/type/RelDataType.html)
+* `groupKey` [RelBuilder.GroupKey]({{ apiRoot }}/org/apache/calcite/tools/RelBuilder/GroupKey.html)
+* `aggCall...` Array of [RelBuilder.AggCall]({{ apiRoot }}/org/apache/calcite/tools/RelBuilder/AggCall.html)
+* `aggCallList` Iterable of [RelBuilder.AggCall]({{ apiRoot }}/org/apache/calcite/tools/RelBuilder/AggCall.html)
+* `value...` Array of Object
+* `value` Object
+* `tupleList` Iterable of List of [RexLiteral]({{ apiRoot }}/org/apache/calcite/rex/RexLiteral.html)
+* `all` boolean
+* `distinct` boolean
+* `alias` String
+
+### Stack methods
+
+
+| Method              | Description
+|:------------------- |:-----------
+| `build()`           | Pops the most recently created relational expression off the stack
+| `push(rel)`         | Pushes a relational expression onto the stack. Relational methods such as `scan`, above, call this method, but user code generally does not
+| `peek()`            | Returns the relational expression most recently put onto the stack, but does not remove it
+
+#### Scalar expression methods
+
+The following methods return a scalar expression
+([RexNode]({{ apiRoot }}/org/apache/calcite/rex/RexNode.html)).
+
+Many of them use the contents of the stack. For example, `field("DEPTNO")`
+returns a reference to the "DEPTNO" field of the relational expression just
+added to the stack.
+
+| Method              | Description
+|:------------------- |:-----------
+| `literal(value)` | Constant
+| `field(fieldName)` | Reference, by name, to a field of the top-most relational expression
+| `field(fieldOrdinal)` | Reference, by ordinal, to a field of the top-most relational expression
+| `field(inputCount, inputOrdinal, fieldName)` | Reference, by name, to a field of the (`inputCount` - `inputOrdinal`)th relational expression
+| `field(inputCount, inputOrdinal, fieldOrdinal)` | Reference, by ordinal, to a field of the (`inputCount` - `inputOrdinal`)th relational expression
+| `call(op, expr...)`<br/>`call(op, exprList)` | Call to a function or operator
+| `and(expr...)`<br/>`and(exprList)` | Logical AND. Flattens nested ANDs, and optimizes cases involving TRUE and FALSE. 
+| `or(expr...)`<br/>`or(exprList)` | Logical OR. Flattens nested ORs, and optimizes cases involving TRUE and FALSE.
+| `not(expr)` | Logical NOT
+| `equals(expr, expr)` | Equals
+| `isNull(expr)` | Checks whether an expression is null
+| `isNotNull(expr)` | Checks whether an expression is not null
+| `alias(expr, fieldName)` | Renames an expression (only valid as an argument to `project`)
+| `cast(expr, typeName)`<br/>`cast(expr, typeName, precision)`<br/>`cast(expr, typeName, precision, scale)`<br/> | Converts an expression to a given type
+| `desc(expr)` | Changes sort direction to descending (only valid as an argument to `sort` or `sortLimit`)
+| `nullsFirst(expr)` | Changes sort order to nulls first (only valid as an argument to `sort` or `sortLimit`)
+| `nullsLast(expr)` | Changes sort order to nulls last (only valid as an argument to `sort` or `sortLimit`)
+
+### Group key methods
+
+The following methods return a
+[RelBuilder.GroupKey]({{ apiRoot }}/org/apache/calcite/tools/RelBuilder/GroupKey.html).
+
+| Method              | Description
+|:------------------- |:-----------
+| `groupKey(fieldName...)`<br/>`groupKey(fieldOrdinal...)`<br/>`groupKey(expr...)`<br/>`groupKey(exprList)` | Creates a group key of the given expressions
+
+### Aggregate call methods
+
+The following methods return an
+[RelBuilder.AggCall]({{ apiRoot }}/org/apache/calcite/tools/RelBuilder/AggCall.html).
+
+| Method              | Description
+|:------------------- |:-----------
+| `aggregateCall(op, distinct, alias, expr...)`<br/>`aggregateCall(op, distinct, alias, exprList)` | Creates a call to a given aggregate function
+| `count(distinct, alias, expr...)` | Creates a call to the COUNT aggregate function
+| `countStar(alias)` | Creates a call to the COUNT(*) aggregate function
+| `sum(distinct, alias, expr)` | Creates a call to the SUM aggregate function
+| `min(alias, expr)` | Creates a call to the MIN aggregate function
+| `max(alias, expr)` | Creates a call to the MAX aggregate function

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/6609cb1a/site/_docs/reference.md
----------------------------------------------------------------------
diff --git a/site/_docs/reference.md b/site/_docs/reference.md
index dc7efb5..3dc4ca2 100644
--- a/site/_docs/reference.md
+++ b/site/_docs/reference.md
@@ -29,7 +29,7 @@ The page describes the SQL dialect recognized by Calcite's default SQL parser.
 SQL grammar in [BNF](http://en.wikipedia.org/wiki/Backus%E2%80%93Naur_Form)-like
 form.
 
-{% highlight SQL %}
+{% highlight sql %}
 statement:
       setStatement
   |   explain
@@ -228,7 +228,7 @@ name will have been converted to upper case also.
 
 Where:
 
-{% highlight SQL %}
+{% highlight sql %}
 timeUnit:
   YEAR | MONTH | DAY | HOUR | MINUTE | SECOND
 {% endhighlight %}
@@ -514,7 +514,7 @@ Not implemented:
 
 Syntax:
 
-{% highlight SQL %}
+{% highlight sql %}
 aggregateCall:
         agg( [ DISTINCT ] value [, value]* ) [ FILTER ( WHERE condition ) ]
     |   agg(*) [ FILTER ( WHERE condition ) ]

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/6609cb1a/site/_posts/2015-06-05-algebra-builder.md
----------------------------------------------------------------------
diff --git a/site/_posts/2015-06-05-algebra-builder.md b/site/_posts/2015-06-05-algebra-builder.md
new file mode 100644
index 0000000..fb25ce1
--- /dev/null
+++ b/site/_posts/2015-06-05-algebra-builder.md
@@ -0,0 +1,89 @@
+---
+layout: news_item
+title: "Algebra builder"
+date: "2015-06-05 19:29:07 -0800"
+author: jhyde
+categories: ["new features"]
+---
+<!--
+{% comment %}
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to you under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+{% endcomment %}
+-->
+
+{% assign apiRoot = "http://calcite.hydromatic.net/apidocs" %}
+
+Calcite's foundation is a comprehensive implementation of relational
+algebra (together with transformation rules, cost model, and metadata)
+but to create algebra expressions you had to master a complex API.
+
+We're solving this problem by introducing an
+[algebra builder]({{ apiRoot }}/org/apache/calcite/tools/RelBuilder.html),
+a single class with all the methods you need to build any relational
+expression.
+
+For example,
+
+{% highlight java %}
+final FrameworkConfig config;
+final RelBuilder builder = RelBuilder.create(config);
+final RelNode node = builder
+  .scan("EMP")
+  .aggregate(builder.groupKey("DEPTNO"),
+      builder.count(false, "C"),
+      builder.sum(false, "S", builder.field("SAL")))
+  .filter(
+      builder.call(SqlStdOperatorTable.GREATER_THAN,
+          builder.field("C"),
+          builder.literal(10)))
+  .build();
+System.out.println(RelOptUtil.toString(node));
+{% endhighlight %}
+
+creates the algebra
+
+{% highlight text %}
+LogicalFilter(condition=[>($1, 10)])
+  LogicalAggregate(group=[{7}], C=[COUNT()], S=[SUM($5)])
+    LogicalTableScan(table=[[scott, EMP]])
+{% endhighlight %}
+
+which is equivalent to the SQL
+
+{% highlight sql %}
+SELECT deptno, count(*) AS c, sum(sal) AS s
+FROM emp
+GROUP BY deptno
+HAVING count(*) > 10
+{% endhighlight %}
+
+The [algebra builder documentation](/docs/algebra.html) describes the
+full API and has lots of examples.
+
+We're still working on the algebra builder, but plan to release it
+with Calcite 1.4 (see
+[[CALCITE-748](https://issues.apache.org/jira/browse/CALCITE-748)]).
+
+The algebra builder will make some existing tasks easier (such as
+writing planner rules), but will also enable new things, such as
+writing applications directly on top of Calcite, or implementing
+non-SQL query languages. These applications and languages will be able
+to take advantage of Calcite's existing back-ends (including
+Hive-on-Tez, Drill, MongoDB, Splunk, Spark, JDBC data sources) and
+extensive set of query-optimization rules.
+
+If you have questions or comments, please post to the
+[mailing list](/develop).
\ No newline at end of file



[6/7] incubator-calcite git commit: [CALCITE-748] Add RelBuilder, builder for expressions in relational algebra

Posted by jh...@apache.org.
[CALCITE-748] Add RelBuilder, builder for expressions in relational algebra

Deprecate RelTraitSet argument to SortFactory.createSort.

Add RelProtoBuilder and use it in one planner rule, FilterAggregateTransposeRule.


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

Branch: refs/heads/master
Commit: 6609cb1a30bf36b1223078e8ebaf7cc9f7289b7c
Parents: b181851
Author: Julian Hyde <jh...@apache.org>
Authored: Mon Jun 1 21:00:59 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Fri Jun 5 16:06:13 2015 -0700

----------------------------------------------------------------------
 .../java/org/apache/calcite/plan/Contexts.java  |  21 +-
 .../org/apache/calcite/plan/RelOptRuleCall.java |  12 +-
 .../calcite/prepare/CalcitePrepareImpl.java     |   8 +-
 .../apache/calcite/rel/core/RelFactories.java   | 108 ++-
 .../rel/rules/FilterAggregateTransposeRule.java |  30 +-
 .../java/org/apache/calcite/schema/Path.java    |   7 +
 .../java/org/apache/calcite/schema/Schemas.java |  27 +-
 .../apache/calcite/sql2rel/RelFieldTrimmer.java |  24 +-
 .../org/apache/calcite/tools/Frameworks.java    |   6 +-
 .../org/apache/calcite/tools/RelBuilder.java    | 958 +++++++++++++++++++
 .../java/org/apache/calcite/util/Stacks.java    |  17 +
 .../calcite/examples/RelBuilderExample.java     | 171 ++++
 .../org/apache/calcite/test/CalciteSuite.java   |   1 +
 .../org/apache/calcite/test/RelBuilderTest.java | 624 ++++++++++++
 .../apache/calcite/tools/FrameworksTest.java    |  34 +
 .../java/org/apache/calcite/util/UtilTest.java  |   5 +
 site/_docs/algebra.md                           | 317 ++++++
 site/_docs/reference.md                         |   6 +-
 site/_posts/2015-06-05-algebra-builder.md       |  89 ++
 19 files changed, 2419 insertions(+), 46 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/6609cb1a/core/src/main/java/org/apache/calcite/plan/Contexts.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/Contexts.java b/core/src/main/java/org/apache/calcite/plan/Contexts.java
index 5a4eb74..7612999 100644
--- a/core/src/main/java/org/apache/calcite/plan/Contexts.java
+++ b/core/src/main/java/org/apache/calcite/plan/Contexts.java
@@ -22,6 +22,7 @@ import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -56,7 +57,16 @@ public class Contexts {
     return new WrapContext(o);
   }
 
-  /** Returns a context that wraps an object.
+  /** Returns a context that wraps an array of objects. */
+  public static Context of(Object... os) {
+    final List<Context> contexts = new ArrayList<>();
+    for (Object o : os) {
+      contexts.add(of(o));
+    }
+    return chain(contexts);
+  }
+
+  /** Returns a context that wraps a list of contexts.
    *
    * <p>A call to {@code unwrap(C)} will return the first object that is an
    * instance of {@code C}.
@@ -65,6 +75,10 @@ public class Contexts {
    * object. Thus this method can be used to chain contexts.
    */
   public static Context chain(Context... contexts) {
+    return chain(ImmutableList.copyOf(contexts));
+  }
+
+  private static Context chain(Iterable<? extends Context> contexts) {
     // Flatten any chain contexts in the list, and remove duplicates
     final List<Context> list = Lists.newArrayList();
     for (Context context : contexts) {
@@ -82,12 +96,15 @@ public class Contexts {
 
   /** Recursively populates a list of contexts. */
   private static void build(List<Context> list, Context context) {
+    if (context == EMPTY_CONTEXT || list.contains(context)) {
+      return;
+    }
     if (context instanceof ChainContext) {
       ChainContext chainContext = (ChainContext) context;
       for (Context child : chainContext.contexts) {
         build(list, child);
       }
-    } else if (!list.contains(context)) {
+    } else {
       list.add(context);
     }
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/6609cb1a/core/src/main/java/org/apache/calcite/plan/RelOptRuleCall.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptRuleCall.java b/core/src/main/java/org/apache/calcite/plan/RelOptRuleCall.java
index 7b36cb9..9a1fb0d 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptRuleCall.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptRuleCall.java
@@ -17,6 +17,8 @@
 package org.apache.calcite.plan;
 
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.Filter;
+import org.apache.calcite.tools.RelBuilder;
 import org.apache.calcite.util.trace.CalciteTrace;
 
 import com.google.common.collect.ImmutableList;
@@ -116,6 +118,7 @@ public abstract class RelOptRuleCall {
    * @return matched relational expressions
    * @deprecated Use {@link #getRelList()} or {@link #rel(int)}
    */
+  @Deprecated // to be removed before 2.0
   public RelNode[] getRels() {
     return rels;
   }
@@ -151,7 +154,7 @@ public abstract class RelOptRuleCall {
    * {@link org.apache.calcite.plan.RelOptRuleOperandChildPolicy#ANY},
    * the children will have their
    * own operands and therefore be easily available in the array returned by
-   * the {@link #getRels} method, so this method returns null.
+   * the {@link #getRelList()} method, so this method returns null.
    *
    * <p>This method is for
    * {@link org.apache.calcite.plan.RelOptRuleOperandChildPolicy#ANY},
@@ -209,6 +212,13 @@ public abstract class RelOptRuleCall {
   public final void transformTo(RelNode rel) {
     transformTo(rel, ImmutableMap.<RelNode, RelNode>of());
   }
+
+  /** Creates a {@link org.apache.calcite.tools.RelBuilder} to be used by
+   * code within the call. The {@code protoBuilder} argument contains policies
+   * such as what implementation of {@link Filter} to create. */
+  public RelBuilder builder(RelBuilder.ProtoRelBuilder protoBuilder) {
+    return protoBuilder.create(rel(0).getCluster(), null);
+  }
 }
 
 // End RelOptRuleCall.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/6609cb1a/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 9ebfe8a..d78f160 100644
--- a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
@@ -862,10 +862,14 @@ public class CalcitePrepareImpl implements CalcitePrepare {
     final CalcitePrepare.Context prepareContext =
         statement.createPrepareContext();
     final JavaTypeFactory typeFactory = prepareContext.getTypeFactory();
+    final CalciteSchema schema =
+        action.getConfig().getDefaultSchema() != null
+            ? CalciteSchema.from(action.getConfig().getDefaultSchema())
+            : prepareContext.getRootSchema();
     CalciteCatalogReader catalogReader =
-        new CalciteCatalogReader(prepareContext.getRootSchema(),
+        new CalciteCatalogReader(schema.root(),
             prepareContext.config().caseSensitive(),
-            prepareContext.getDefaultSchemaPath(),
+            schema.path(null),
             typeFactory);
     final RexBuilder rexBuilder = new RexBuilder(typeFactory);
     final RelOptPlanner planner =

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/6609cb1a/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 2e2225a..787ab1f 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,6 +17,9 @@
 
 package org.apache.calcite.rel.core;
 
+import org.apache.calcite.plan.Contexts;
+import org.apache.calcite.plan.RelOptCluster;
+import org.apache.calcite.plan.RelOptTable;
 import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.RelCollation;
@@ -27,10 +30,15 @@ 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.LogicalTableScan;
 import org.apache.calcite.rel.logical.LogicalUnion;
+import org.apache.calcite.rel.logical.LogicalValues;
+import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.rex.RexLiteral;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.tools.RelBuilder;
 import org.apache.calcite.util.ImmutableBitSet;
 
 import com.google.common.collect.ImmutableList;
@@ -63,6 +71,27 @@ public class RelFactories {
   public static final SetOpFactory DEFAULT_SET_OP_FACTORY =
       new SetOpFactoryImpl();
 
+  public static final ValuesFactory DEFAULT_VALUES_FACTORY =
+      new ValuesFactoryImpl();
+
+  public static final TableScanFactory DEFAULT_TABLE_SCAN_FACTORY =
+      new TableScanFactoryImpl();
+
+  /** Creates a {@link RelBuilder} that will create logical relational
+   * expressions for everything.
+   */
+  public static final RelBuilder.ProtoRelBuilder DEFAULT_PROTO =
+      RelBuilder.proto(
+          Contexts.of(DEFAULT_PROJECT_FACTORY,
+              DEFAULT_FILTER_FACTORY,
+              DEFAULT_JOIN_FACTORY,
+              DEFAULT_SEMI_JOIN_FACTORY,
+              DEFAULT_SORT_FACTORY,
+              DEFAULT_AGGREGATE_FACTORY,
+              DEFAULT_SET_OP_FACTORY,
+              DEFAULT_VALUES_FACTORY,
+              DEFAULT_TABLE_SCAN_FACTORY));
+
   private RelFactories() {
   }
 
@@ -73,7 +102,7 @@ public class RelFactories {
    */
   public interface ProjectFactory {
     /** Creates a project. */
-    RelNode createProject(RelNode child, List<? extends RexNode> childExprs,
+    RelNode createProject(RelNode input, List<? extends RexNode> childExprs,
         List<String> fieldNames);
   }
 
@@ -82,9 +111,9 @@ public class RelFactories {
    * {@link org.apache.calcite.rel.logical.LogicalProject}.
    */
   private static class ProjectFactoryImpl implements ProjectFactory {
-    public RelNode createProject(RelNode child,
+    public RelNode createProject(RelNode input,
         List<? extends RexNode> childExprs, List<String> fieldNames) {
-      return RelOptUtil.createProject(child, childExprs, fieldNames);
+      return RelOptUtil.createProject(input, childExprs, fieldNames);
     }
   }
 
@@ -94,7 +123,11 @@ public class RelFactories {
    */
   public interface SortFactory {
     /** Creates a sort. */
-    RelNode createSort(RelTraitSet traits, RelNode child,
+    RelNode createSort(RelNode input, RelCollation collation, RexNode offset,
+        RexNode fetch);
+
+    @Deprecated // to be removed before 2.0
+    RelNode createSort(RelTraitSet traits, RelNode input,
         RelCollation collation, RexNode offset, RexNode fetch);
   }
 
@@ -103,9 +136,15 @@ public class RelFactories {
    * returns a vanilla {@link Sort}.
    */
   private static class SortFactoryImpl implements SortFactory {
-    public RelNode createSort(RelTraitSet traits, RelNode child,
+    public RelNode createSort(RelNode input, RelCollation collation,
+        RexNode offset, RexNode fetch) {
+      return LogicalSort.create(input, collation, offset, fetch);
+    }
+
+    @Deprecated // to be removed before 2.0
+    public RelNode createSort(RelTraitSet traits, RelNode input,
         RelCollation collation, RexNode offset, RexNode fetch) {
-      return LogicalSort.create(child, collation, offset, fetch);
+      return createSort(input, collation, offset, fetch);
     }
   }
 
@@ -146,7 +185,7 @@ public class RelFactories {
    */
   public interface AggregateFactory {
     /** Creates an aggregate. */
-    RelNode createAggregate(RelNode child, boolean indicator,
+    RelNode createAggregate(RelNode input, boolean indicator,
         ImmutableBitSet groupSet, ImmutableList<ImmutableBitSet> groupSets,
         List<AggregateCall> aggCalls);
   }
@@ -156,10 +195,10 @@ public class RelFactories {
    * that returns a vanilla {@link LogicalAggregate}.
    */
   private static class AggregateFactoryImpl implements AggregateFactory {
-    public RelNode createAggregate(RelNode child, boolean indicator,
+    public RelNode createAggregate(RelNode input, boolean indicator,
         ImmutableBitSet groupSet, ImmutableList<ImmutableBitSet> groupSets,
         List<AggregateCall> aggCalls) {
-      return LogicalAggregate.create(child, indicator,
+      return LogicalAggregate.create(input, indicator,
           groupSet, groupSets, aggCalls);
     }
   }
@@ -170,7 +209,7 @@ public class RelFactories {
    */
   public interface FilterFactory {
     /** Creates a filter. */
-    RelNode createFilter(RelNode child, RexNode condition);
+    RelNode createFilter(RelNode input, RexNode condition);
   }
 
   /**
@@ -178,8 +217,8 @@ public class RelFactories {
    * returns a vanilla {@link LogicalFilter}.
    */
   private static class FilterFactoryImpl implements FilterFactory {
-    public RelNode createFilter(RelNode child, RexNode condition) {
-      return LogicalFilter.create(child, condition);
+    public RelNode createFilter(RelNode input, RexNode condition) {
+      return LogicalFilter.create(input, condition);
     }
   }
 
@@ -247,6 +286,51 @@ public class RelFactories {
         condition, joinInfo.leftKeys, joinInfo.rightKeys);
     }
   }
+
+  /**
+   * Can create a {@link Values} of the appropriate type for a rule's calling
+   * convention.
+   */
+  public interface ValuesFactory {
+    /**
+     * Creates a Values.
+     */
+    RelNode createValues(RelOptCluster cluster, RelDataType rowType,
+        List<ImmutableList<RexLiteral>> tuples);
+  }
+
+  /**
+   * Implementation of {@link ValuesFactory} that returns a
+   * {@link LogicalValues}.
+   */
+  private static class ValuesFactoryImpl implements ValuesFactory {
+    public RelNode createValues(RelOptCluster cluster, RelDataType rowType,
+        List<ImmutableList<RexLiteral>> tuples) {
+      return LogicalValues.create(cluster, rowType,
+          ImmutableList.copyOf(tuples));
+    }
+  }
+
+  /**
+   * Can create a {@link TableScan} of the appropriate type for a rule's calling
+   * convention.
+   */
+  public interface TableScanFactory {
+    /**
+     * Creates a {@link TableScan}.
+     */
+    RelNode createScan(RelOptCluster cluster, RelOptTable table);
+  }
+
+  /**
+   * Implementation of {@link TableScanFactory} that returns a
+   * {@link LogicalTableScan}.
+   */
+  private static class TableScanFactoryImpl implements TableScanFactory {
+    public RelNode createScan(RelOptCluster cluster, RelOptTable table) {
+      return LogicalTableScan.create(cluster, table);
+    }
+  }
 }
 
 // End RelFactories.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/6609cb1a/core/src/main/java/org/apache/calcite/rel/rules/FilterAggregateTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/FilterAggregateTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/FilterAggregateTransposeRule.java
index 3701a1a..d3de47f 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/FilterAggregateTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/FilterAggregateTransposeRule.java
@@ -16,6 +16,7 @@
  */
 package org.apache.calcite.rel.rules;
 
+import org.apache.calcite.plan.Contexts;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
 import org.apache.calcite.plan.RelOptUtil;
@@ -26,6 +27,7 @@ import org.apache.calcite.rel.core.RelFactories;
 import org.apache.calcite.rel.type.RelDataTypeField;
 import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.tools.RelBuilder;
 import org.apache.calcite.util.ImmutableBitSet;
 
 import com.google.common.collect.ImmutableList;
@@ -46,33 +48,40 @@ public class FilterAggregateTransposeRule extends RelOptRule {
    *
    * <p>It matches any kind of agg. or filter */
   public static final FilterAggregateTransposeRule INSTANCE =
-      new FilterAggregateTransposeRule(Filter.class,
-          RelFactories.DEFAULT_FILTER_FACTORY,
+      new FilterAggregateTransposeRule(Filter.class, RelFactories.DEFAULT_PROTO,
           Aggregate.class);
 
-  private final RelFactories.FilterFactory filterFactory;
+  private final RelBuilder.ProtoRelBuilder protoBuilder;
 
   //~ Constructors -----------------------------------------------------------
 
   /**
-   * Creates a PushFilterPastAggRule.
+   * Creates a FilterAggregateTransposeRule.
    *
    * <p>If {@code filterFactory} is null, creates the same kind of filter as
    * matched in the rule. Similarly {@code aggregateFactory}.</p>
    */
   public FilterAggregateTransposeRule(
       Class<? extends Filter> filterClass,
-      RelFactories.FilterFactory filterFactory,
+      RelBuilder.ProtoRelBuilder protoBuilder,
       Class<? extends Aggregate> aggregateClass) {
     super(
         operand(filterClass,
             operand(aggregateClass, any())));
-    this.filterFactory = filterFactory;
+    this.protoBuilder = protoBuilder;
+  }
+
+  @Deprecated // to be removed before 2.0
+  public FilterAggregateTransposeRule(
+      Class<? extends Filter> filterClass,
+      RelFactories.FilterFactory filterFactory,
+      Class<? extends Aggregate> aggregateClass) {
+    this(filterClass, RelBuilder.proto(Contexts.of(filterFactory)),
+        aggregateClass);
   }
 
   //~ Methods ----------------------------------------------------------------
 
-  // implement RelOptRule
   public void onMatch(RelOptRuleCall call) {
     final Filter filterRel = call.rel(0);
     final Aggregate aggRel = call.rel(1);
@@ -112,13 +121,14 @@ public class FilterAggregateTransposeRule extends RelOptRule {
       }
     }
 
-    RelNode rel = RelOptUtil.createFilter(aggRel.getInput(), pushedConditions,
-        filterFactory);
+    final RelBuilder builder = call.builder(protoBuilder);
+    RelNode rel =
+        builder.push(aggRel.getInput()).filter(pushedConditions).build();
     if (rel == aggRel.getInput(0)) {
       return;
     }
     rel = aggRel.copy(aggRel.getTraitSet(), ImmutableList.of(rel));
-    rel = RelOptUtil.createFilter(rel, remainingConditions, filterFactory);
+    rel = builder.push(rel).filter(remainingConditions).build();
     call.transformTo(rel);
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/6609cb1a/core/src/main/java/org/apache/calcite/schema/Path.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/schema/Path.java b/core/src/main/java/org/apache/calcite/schema/Path.java
index 7c363a0..1575f58 100644
--- a/core/src/main/java/org/apache/calcite/schema/Path.java
+++ b/core/src/main/java/org/apache/calcite/schema/Path.java
@@ -32,7 +32,14 @@ import java.util.RandomAccess;
  * </ul>
  */
 public interface Path extends List<Pair<String, Schema>>, RandomAccess {
+  /** Returns the parent path, or null if the path is empty. */
   Path parent();
+
+  /** Returns the names of this path, not including the name of the root. */
+  List<String> names();
+
+  /** Returns the schemas of this path. */
+  List<Schema> schemas();
 }
 
 // End Path.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/6609cb1a/core/src/main/java/org/apache/calcite/schema/Schemas.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/schema/Schemas.java b/core/src/main/java/org/apache/calcite/schema/Schemas.java
index b634233..7c09ffb 100644
--- a/core/src/main/java/org/apache/calcite/schema/Schemas.java
+++ b/core/src/main/java/org/apache/calcite/schema/Schemas.java
@@ -514,6 +514,15 @@ public final class Schemas {
     return new PathImpl(build);
   }
 
+  /** Returns the path to get to a schema from its root. */
+  public static Path path(SchemaPlus schema) {
+    List<Pair<String, Schema>> list = new ArrayList<>();
+    for (SchemaPlus s = schema; s != null; s = s.getParentSchema()) {
+      list.add(Pair.<String, Schema>of(s.getName(), s));
+    }
+    return new PathImpl(ImmutableList.copyOf(Lists.reverse(list)));
+  }
+
   /** Dummy data context that has no variables. */
   private static class DummyDataContext implements DataContext {
     private final CalciteConnection connection;
@@ -572,12 +581,28 @@ public final class Schemas {
       return pairs.size();
     }
 
-    @Override public Path parent() {
+    public Path parent() {
       if (pairs.isEmpty()) {
         throw new IllegalArgumentException("at root");
       }
       return new PathImpl(pairs.subList(0, pairs.size() - 1));
     }
+
+    public List<String> names() {
+      return new AbstractList<String>() {
+        public String get(int index) {
+          return pairs.get(index + 1).left;
+        }
+
+        public int size() {
+          return pairs.size() - 1;
+        }
+      };
+    }
+
+    public List<Schema> schemas() {
+      return Pair.right(pairs);
+    }
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/6609cb1a/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 99975b3..5e9e333 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
@@ -19,7 +19,6 @@ package org.apache.calcite.sql2rel;
 import org.apache.calcite.linq4j.Ord;
 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.RelFieldCollation;
 import org.apache.calcite.rel.RelNode;
@@ -234,7 +233,7 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
     }
     final RelDataType rowType = input.getRowType();
     List<RelDataTypeField> fieldList = rowType.getFieldList();
-    final List<RexNode> exprList = new ArrayList<RexNode>();
+    final List<RexNode> exprList = new ArrayList<>();
     final List<String> nameList = rowType.getFieldNames();
     RexBuilder rexBuilder = rel.getCluster().getRexBuilder();
     assert trimResult.right.getSourceCount() == fieldList.size();
@@ -331,7 +330,7 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
 
     // Which fields are required from the input?
     final Set<RelDataTypeField> inputExtraFields =
-        new LinkedHashSet<RelDataTypeField>(extraFields);
+        new LinkedHashSet<>(extraFields);
     RelOptUtil.InputFinder inputFinder =
         new RelOptUtil.InputFinder(inputExtraFields);
     for (Ord<RexNode> ord : Ord.zip(project.getProjects())) {
@@ -436,7 +435,7 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
     // We use the fields used by the consumer, plus any fields used in the
     // filter.
     final Set<RelDataTypeField> inputExtraFields =
-        new LinkedHashSet<RelDataTypeField>(extraFields);
+        new LinkedHashSet<>(extraFields);
     RelOptUtil.InputFinder inputFinder =
         new RelOptUtil.InputFinder(inputExtraFields);
     inputFinder.inputBitSet.addAll(fieldsUsed);
@@ -513,9 +512,8 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
 
     final RelCollation newCollation =
         sort.getTraitSet().canonize(RexUtil.apply(inputMapping, collation));
-    final RelTraitSet newTraitSet = sort.getTraitSet().replace(newCollation);
-    final RelNode newSort = sortFactory.createSort(
-        newTraitSet, newInput, newCollation, sort.offset, sort.fetch);
+    final RelNode newSort =
+        sortFactory.createSort(newInput, newCollation, sort.offset, sort.fetch);
 
     // The result has the same mapping as the input gave us. Sometimes we
     // return fields that the consumer didn't ask for, because the filter
@@ -539,7 +537,7 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
 
     // Add in fields used in the condition.
     final Set<RelDataTypeField> combinedInputExtraFields =
-        new LinkedHashSet<RelDataTypeField>(extraFields);
+        new LinkedHashSet<>(extraFields);
     RelOptUtil.InputFinder inputFinder =
         new RelOptUtil.InputFinder(combinedInputExtraFields);
     inputFinder.inputBitSet.addAll(fieldsUsed);
@@ -563,9 +561,9 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
     int offset = systemFieldCount;
     int changeCount = 0;
     int newFieldCount = newSystemFieldCount;
-    List<RelNode> newInputs = new ArrayList<RelNode>(2);
-    List<Mapping> inputMappings = new ArrayList<Mapping>();
-    List<Integer> inputExtraFieldCounts = new ArrayList<Integer>();
+    final List<RelNode> newInputs = new ArrayList<>(2);
+    final List<Mapping> inputMappings = new ArrayList<>();
+    final List<Integer> inputExtraFieldCounts = new ArrayList<>();
     for (RelNode input : join.getInputs()) {
       final RelDataType inputRowType = input.getRowType();
       final int inputFieldCount = inputRowType.getFieldCount();
@@ -688,7 +686,7 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
     final Mapping mapping = createMapping(fieldsUsed, fieldCount);
 
     // Create input with trimmed columns.
-    final List<RelNode> newInputs = new ArrayList<RelNode>();
+    final List<RelNode> newInputs = new ArrayList<>();
     for (RelNode input : setOp.getInputs()) {
       TrimResult trimResult =
           trimChild(setOp, input, fieldsUsed, extraFields);
@@ -914,7 +912,7 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
       Set<RelDataTypeField> extraFields) {
     final RelDataType rowType = tabFun.getRowType();
     final int fieldCount = rowType.getFieldCount();
-    List<RelNode> newInputs = new ArrayList<RelNode>();
+    final List<RelNode> newInputs = new ArrayList<>();
 
     for (RelNode input : tabFun.getInputs()) {
       final int inputFieldCount = input.getRowType().getFieldCount();

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/6609cb1a/core/src/main/java/org/apache/calcite/tools/Frameworks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/tools/Frameworks.java b/core/src/main/java/org/apache/calcite/tools/Frameworks.java
index a9efcc0..c73a1e2 100644
--- a/core/src/main/java/org/apache/calcite/tools/Frameworks.java
+++ b/core/src/main/java/org/apache/calcite/tools/Frameworks.java
@@ -101,12 +101,14 @@ public class Frameworks {
    * @return Return value from action
    */
   public static <R> R withPlanner(final PlannerAction<R> action, //
-      FrameworkConfig config) {
+      final FrameworkConfig config) {
     return withPrepare(
         new Frameworks.PrepareAction<R>(config) {
           public R apply(RelOptCluster cluster, RelOptSchema relOptSchema,
               SchemaPlus rootSchema, CalciteServerStatement statement) {
-            return action.apply(cluster, relOptSchema, rootSchema);
+            final CalciteSchema schema =
+                CalciteSchema.from(config.getDefaultSchema());
+            return action.apply(cluster, relOptSchema, schema.root().plus());
           }
         });
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/6609cb1a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
new file mode 100644
index 0000000..ce185d8
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
@@ -0,0 +1,958 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.tools;
+
+import org.apache.calcite.linq4j.Ord;
+import org.apache.calcite.plan.Context;
+import org.apache.calcite.plan.Contexts;
+import org.apache.calcite.plan.RelOptCluster;
+import org.apache.calcite.plan.RelOptRule;
+import org.apache.calcite.plan.RelOptSchema;
+import org.apache.calcite.plan.RelOptTable;
+import org.apache.calcite.rel.RelCollations;
+import org.apache.calcite.rel.RelFieldCollation;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.AggregateCall;
+import org.apache.calcite.rel.core.JoinRelType;
+import org.apache.calcite.rel.core.RelFactories;
+import org.apache.calcite.rel.core.Sort;
+import org.apache.calcite.rel.core.Values;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.rex.RexBuilder;
+import org.apache.calcite.rex.RexCall;
+import org.apache.calcite.rex.RexInputRef;
+import org.apache.calcite.rex.RexLiteral;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexUtil;
+import org.apache.calcite.schema.SchemaPlus;
+import org.apache.calcite.server.CalciteServerStatement;
+import org.apache.calcite.sql.SqlAggFunction;
+import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlOperator;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.calcite.util.NlsString;
+import org.apache.calcite.util.Stacks;
+import org.apache.calcite.util.Util;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+
+import java.math.BigDecimal;
+import java.util.AbstractList;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Builder for relational expressions.
+ *
+ * <p>{@code RelBuilder} does not make possible anything that you could not
+ * also accomplish by calling the factory methods of the particular relational
+ * expression. But it makes common tasks more straightforward and concise.
+ *
+ * <p>{@code RelBuilder} uses factories to create relational expressions.
+ * By default, it uses the default factories, which create logical relational
+ * expressions ({@link org.apache.calcite.rel.logical.LogicalFilter},
+ * {@link org.apache.calcite.rel.logical.LogicalProject} and so forth).
+ * But you could override those factories so that, say, {@code filter} creates
+ * instead a {@code HiveFilter}.
+ *
+ * <p>It is not thread-safe.
+ */
+public class RelBuilder {
+  private static final Function<RexNode, String> FN_TYPE =
+      new Function<RexNode, String>() {
+        public String apply(RexNode input) {
+          return input + ": " + input.getType();
+        }
+      };
+
+  private final RelOptCluster cluster;
+  private final RelOptSchema relOptSchema;
+  private final RelFactories.FilterFactory filterFactory;
+  private final RelFactories.ProjectFactory projectFactory;
+  private final RelFactories.AggregateFactory aggregateFactory;
+  private final RelFactories.SortFactory sortFactory;
+  private final RelFactories.SetOpFactory setOpFactory;
+  private final RelFactories.JoinFactory joinFactory;
+  private final RelFactories.ValuesFactory valuesFactory;
+  private final RelFactories.TableScanFactory scanFactory;
+  private final List<RelNode> stack = new ArrayList<>();
+
+  private RelBuilder(Context context, RelOptCluster cluster,
+      RelOptSchema relOptSchema) {
+    this.cluster = cluster;
+    this.relOptSchema = relOptSchema;
+    if (context == null) {
+      context = Contexts.EMPTY_CONTEXT;
+    }
+    this.aggregateFactory =
+        Util.first(context.unwrap(RelFactories.AggregateFactory.class),
+            RelFactories.DEFAULT_AGGREGATE_FACTORY);
+    this.filterFactory =
+        Util.first(context.unwrap(RelFactories.FilterFactory.class),
+            RelFactories.DEFAULT_FILTER_FACTORY);
+    this.projectFactory =
+        Util.first(context.unwrap(RelFactories.ProjectFactory.class),
+            RelFactories.DEFAULT_PROJECT_FACTORY);
+    this.sortFactory =
+        Util.first(context.unwrap(RelFactories.SortFactory.class),
+            RelFactories.DEFAULT_SORT_FACTORY);
+    this.setOpFactory =
+        Util.first(context.unwrap(RelFactories.SetOpFactory.class),
+            RelFactories.DEFAULT_SET_OP_FACTORY);
+    this.joinFactory =
+        Util.first(context.unwrap(RelFactories.JoinFactory.class),
+            RelFactories.DEFAULT_JOIN_FACTORY);
+    this.valuesFactory =
+        Util.first(context.unwrap(RelFactories.ValuesFactory.class),
+            RelFactories.DEFAULT_VALUES_FACTORY);
+    this.scanFactory =
+        Util.first(context.unwrap(RelFactories.TableScanFactory.class),
+            RelFactories.DEFAULT_TABLE_SCAN_FACTORY);
+  }
+
+  /** Creates a RelBuilder. */
+  public static RelBuilder create(FrameworkConfig config) {
+    final RelOptCluster[] clusters = {null};
+    final RelOptSchema[] relOptSchemas = {null};
+    Frameworks.withPrepare(
+        new Frameworks.PrepareAction<Void>(config) {
+          public Void apply(RelOptCluster cluster, RelOptSchema relOptSchema,
+              SchemaPlus rootSchema, CalciteServerStatement statement) {
+            clusters[0] = cluster;
+            relOptSchemas[0] = relOptSchema;
+            return null;
+          }
+        });
+    return new RelBuilder(config.getContext(), clusters[0], relOptSchemas[0]);
+  }
+
+  /** Returns the type factory. */
+  public RelDataTypeFactory getTypeFactory() {
+    return cluster.getTypeFactory();
+  }
+
+  /** Creates a {@link ProtoRelBuilder}, a partially-created RelBuilder.
+   * Just add a {@link RelOptCluster} and a {@link RelOptSchema} */
+  public static ProtoRelBuilder proto(final Context context) {
+    return new ProtoRelBuilder() {
+      public RelBuilder create(RelOptCluster cluster, RelOptSchema schema) {
+        return new RelBuilder(context, cluster, schema);
+      }
+    };
+  }
+
+  // Methods for manipulating the stack
+
+  /** Adds a relational expression to be the input to the next relational
+   * expression constructed.
+   *
+   * <p>This method is usual when you want to weave in relational expressions
+   * that are not supported by the builder. If, while creating such expressions,
+   * you need to use previously built expressions as inputs, call
+   * {@link #build()} to pop those inputs. */
+  public RelBuilder push(RelNode node) {
+    Stacks.push(stack, node);
+    return this;
+  }
+
+  /** Returns the final relational expression.
+   *
+   * <p>Throws if the stack is empty.
+   */
+  public RelNode build() {
+    if (stack.size() < 1) {
+      throw new IllegalArgumentException("expected stack size 1, but was "
+          + stack.size() + ": " + stack);
+    }
+    return Stacks.pop(stack);
+  }
+
+  /** Returns the relational expression at the top of the stack, but does not
+   * remove it. */
+  public RelNode peek() {
+    return Stacks.peek(stack);
+  }
+
+  /** Returns the relational expression {@code n} positions from the top of the
+   * stack, but does not remove it. */
+  public RelNode peek(int n) {
+    return Stacks.peek(n, stack);
+  }
+
+  // Methods that return scalar expressions
+
+  /** Creates a literal (constant expression). */
+  public RexNode literal(Object value) {
+    final RexBuilder rexBuilder = cluster.getRexBuilder();
+    if (value == null) {
+      return rexBuilder.constantNull();
+    } else if (value instanceof Boolean) {
+      return rexBuilder.makeLiteral((Boolean) value);
+    } else if (value instanceof BigDecimal) {
+      return rexBuilder.makeExactLiteral((BigDecimal) value);
+    } else if (value instanceof Float || value instanceof Double) {
+      return rexBuilder.makeApproxLiteral(
+          BigDecimal.valueOf(((Number) value).doubleValue()));
+    } else if (value instanceof Number) {
+      return rexBuilder.makeExactLiteral(
+          BigDecimal.valueOf(((Number) value).longValue()));
+    } else if (value instanceof String) {
+      return rexBuilder.makeLiteral((String) value);
+    } else {
+      throw new IllegalArgumentException("cannot convert " + value
+          + " (" + value.getClass() + ") to a constant");
+    }
+  }
+
+  /** Creates a reference to a field by name.
+   *
+   * <p>Equivalent to {@code field(1, 0, fieldName)}.
+   *
+   * @param fieldName Field name
+   */
+  public RexInputRef field(String fieldName) {
+    return field(1, 0, fieldName);
+  }
+
+  /** Creates a reference to a field of given input relational expression
+   * by name.
+   *
+   * @param inputCount Number of inputs
+   * @param inputOrdinal Input ordinal
+   * @param fieldName Field name
+   */
+  public RexInputRef field(int inputCount, int inputOrdinal, String fieldName) {
+    final RelNode input = peek(inputCount - 1 - inputOrdinal);
+    final RelDataType rowType = input.getRowType();
+    final int ordinal = rowType.getFieldNames().indexOf(fieldName);
+    if (ordinal < 0) {
+      throw new IllegalArgumentException("field [" + fieldName
+          + "] not found; input fields are: " + rowType.getFieldNames());
+    }
+    return field(inputCount, inputOrdinal, ordinal);
+  }
+
+  /** Creates a reference to an input field by ordinal.
+   *
+   * <p>Equivalent to {@code field(1, 0, ordinal)}.
+   *
+   * @param fieldOrdinal Field ordinal
+   */
+  public RexInputRef field(int fieldOrdinal) {
+    return field(1, 0, fieldOrdinal);
+  }
+
+  /** Creates a reference to a field of a given input relational expression
+   * by ordinal.
+   *
+   * @param inputCount Number of inputs
+   * @param inputOrdinal Input ordinal
+   * @param fieldOrdinal Field ordinal within input
+   */
+  public RexInputRef field(int inputCount, int inputOrdinal, int fieldOrdinal) {
+    final RelNode input = peek(inputCount - 1 - inputOrdinal);
+    final RelDataType rowType = input.getRowType();
+    if (fieldOrdinal < 0 || fieldOrdinal > rowType.getFieldCount()) {
+      throw new IllegalArgumentException("field ordinal [" + fieldOrdinal
+          + "] out of range; input fields are: " + rowType.getFieldNames());
+    }
+    return cluster.getRexBuilder().makeInputRef(input, fieldOrdinal);
+  }
+
+  /** Creates a call to a scalar operator. */
+  public RexNode call(SqlOperator operator, RexNode... operands) {
+    final RexBuilder builder = cluster.getRexBuilder();
+    final List<RexNode> operandList = ImmutableList.copyOf(operands);
+    final RelDataType type = builder.deriveReturnType(operator, operandList);
+    if (type == null) {
+      throw new IllegalArgumentException("cannot derive type: " + operator
+          + "; operands: " + Lists.transform(operandList, FN_TYPE));
+    }
+    return builder.makeCall(type, operator, operandList);
+  }
+
+  /** Creates a call to a scalar operator. */
+  public RexNode call(SqlOperator operator,
+      Iterable<? extends RexNode> operands) {
+    return cluster.getRexBuilder().makeCall(operator,
+        ImmutableList.copyOf(operands));
+  }
+
+  /** Creates an AND. */
+  public RexNode and(RexNode... operands) {
+    return and(ImmutableList.copyOf(operands));
+  }
+
+  /** Creates an AND. */
+  public RexNode and(Iterable<? extends RexNode> operands) {
+    return RexUtil.composeConjunction(cluster.getRexBuilder(), operands, false);
+  }
+
+  /** Creates an OR. */
+  public RexNode or(RexNode... operands) {
+    return or(ImmutableList.copyOf(operands));
+  }
+
+  /** Creates an OR. */
+  public RexNode or(Iterable<? extends RexNode> operands) {
+    return RexUtil.composeDisjunction(cluster.getRexBuilder(), operands, false);
+  }
+
+  /** Creates a NOT. */
+  public RexNode not(RexNode operand) {
+    return call(SqlStdOperatorTable.NOT, operand);
+  }
+
+  /** Creates an =. */
+  public RexNode equals(RexNode operand0, RexNode operand1) {
+    return call(SqlStdOperatorTable.EQUALS, operand0, operand1);
+  }
+
+  /** Creates a IS NULL. */
+  public RexNode isNull(RexNode operand) {
+    return call(SqlStdOperatorTable.IS_NULL, operand);
+  }
+
+  /** Creates a IS NOT NULL. */
+  public RexNode isNotNull(RexNode operand) {
+    return call(SqlStdOperatorTable.IS_NOT_NULL, operand);
+  }
+
+  /** Creates an expression that casts an expression to a given type. */
+  public RexNode cast(RexNode expr, SqlTypeName typeName) {
+    final RelDataType type = cluster.getTypeFactory().createSqlType(typeName);
+    return cluster.getRexBuilder().makeCast(type, expr);
+  }
+
+  /** Creates an expression that casts an expression to a type with a given name
+   * and precision or length. */
+  public RexNode cast(RexNode expr, SqlTypeName typeName, int precision) {
+    final RelDataType type =
+        cluster.getTypeFactory().createSqlType(typeName, precision);
+    return cluster.getRexBuilder().makeCast(type, expr);
+  }
+
+  /** Creates an expression that casts an expression to a type with a given
+   * name, precision and scale. */
+  public RexNode cast(RexNode expr, SqlTypeName typeName, int precision,
+      int scale) {
+    final RelDataType type =
+        cluster.getTypeFactory().createSqlType(typeName, precision, scale);
+    return cluster.getRexBuilder().makeCast(type, expr);
+  }
+
+  /**
+   * Returns an expression wrapped in an alias.
+   *
+   * @see #project
+   */
+  public RexNode alias(RexNode expr, String alias) {
+    return call(SqlStdOperatorTable.AS, expr, literal(alias));
+  }
+
+  /** Converts a sort expression to descending. */
+  public RexNode desc(RexNode node) {
+    return call(SqlStdOperatorTable.DESC, node);
+  }
+
+  /** Converts a sort expression to nulls last. */
+  public RexNode nullsLast(RexNode node) {
+    return call(SqlStdOperatorTable.NULLS_LAST, node);
+  }
+
+  /** Converts a sort expression to nulls first. */
+  public RexNode nullsFirst(RexNode node) {
+    return call(SqlStdOperatorTable.NULLS_FIRST, node);
+  }
+
+  // Methods that create group keys and aggregate calls
+
+  /** Creates an empty group key. */
+  public GroupKey groupKey() {
+    return groupKey(ImmutableList.<RexNode>of());
+  }
+
+  /** Creates a group key. */
+  public GroupKey groupKey(RexNode... nodes) {
+    return groupKey(ImmutableList.copyOf(nodes));
+  }
+
+  /** Creates a group key. */
+  public GroupKey groupKey(Iterable<? extends RexNode> nodes) {
+    return new GroupKeyImpl(ImmutableList.copyOf(nodes));
+  }
+
+  /** Creates a group key of fields identified by ordinal. */
+  public GroupKey groupKey(int... fieldOrdinals) {
+    final ImmutableList.Builder<RexNode> builder = ImmutableList.builder();
+    for (int fieldOrdinal : fieldOrdinals) {
+      builder.add(field(fieldOrdinal));
+    }
+    return groupKey(builder.build());
+  }
+
+  /** Creates a group key of fields identified by name. */
+  public GroupKey groupKey(String... fieldNames) {
+    final ImmutableList.Builder<RexNode> builder = ImmutableList.builder();
+    for (String fieldName : fieldNames) {
+      builder.add(field(fieldName));
+    }
+    return groupKey(builder.build());
+  }
+
+  /** Creates a call to an aggregate function. */
+  public AggCall aggregateCall(SqlAggFunction aggFunction,
+      boolean distinct, String alias, RexNode... operands) {
+    return new AggCallImpl(aggFunction, distinct, alias,
+        ImmutableList.copyOf(operands));
+  }
+
+  /** Creates a call to the COUNT aggregate function. */
+  public AggCall count(boolean distinct, String alias, RexNode... operands) {
+    return aggregateCall(SqlStdOperatorTable.COUNT, distinct, alias, operands);
+  }
+
+  /** Creates a call to the COUNT(*) aggregate function. */
+  public AggCall countStar(String alias) {
+    return aggregateCall(SqlStdOperatorTable.COUNT, false, alias);
+  }
+
+  /** Creates a call to the SUM aggregate function. */
+  public AggCall sum(boolean distinct, String alias, RexNode operand) {
+    return aggregateCall(SqlStdOperatorTable.SUM, distinct, alias, operand);
+  }
+
+  /** Creates a call to the MIN aggregate function. */
+  public AggCall min(String alias, RexNode operand) {
+    return aggregateCall(SqlStdOperatorTable.MIN, false, alias, operand);
+  }
+
+  /** Creates a call to the MAX aggregate function. */
+  public AggCall max(String alias, RexNode operand) {
+    return aggregateCall(SqlStdOperatorTable.MAX, false, alias, operand);
+  }
+
+  // Methods that create relational expressions
+
+  /** Creates a {@link org.apache.calcite.rel.core.TableScan} of the table
+   * with a given name.
+   *
+   * <p>Throws if the table does not exist within the current schema.
+   *
+   * <p>Returns this builder.
+   *
+   * @param tableName Name of table
+   */
+  public RelBuilder scan(String tableName) {
+    final RelOptTable relOptTable =
+        relOptSchema.getTableForMember(ImmutableList.of(tableName));
+    final RelNode scan = scanFactory.createScan(cluster, relOptTable);
+    push(scan);
+    return this;
+  }
+
+  /** Creates a {@link org.apache.calcite.rel.core.Filter} of an array of
+   * predicates.
+   *
+   * <p>The predicates are combined using AND,
+   * and optimized in a similar way to the {@link #and} method.
+   * If the result is TRUE no filter is created. */
+  public RelBuilder filter(RexNode... predicates) {
+    return filter(ImmutableList.copyOf(predicates));
+  }
+
+  /** Creates a {@link org.apache.calcite.rel.core.Filter} of a list of
+   * predicates.
+   *
+   * <p>The predicates are combined using AND,
+   * and optimized in a similar way to the {@link #and} method.
+   * If the result is TRUE no filter is created. */
+  public RelBuilder filter(Iterable<? extends RexNode> predicates) {
+    final RexNode x = RexUtil.composeConjunction(cluster.getRexBuilder(),
+        predicates, true);
+    if (x != null) {
+      final RelNode filter = filterFactory.createFilter(build(), x);
+      push(filter);
+    }
+    return this;
+  }
+
+  /** Creates a {@link org.apache.calcite.rel.core.Project} of the given list
+   * of expressions.
+   *
+   * <p>Infers all field names.
+   * If an expression projects an input field,
+   * or is a cast an input field,
+   * uses the input field name.
+   * If an expression is a call to
+   * {@link org.apache.calcite.sql.fun.SqlStdOperatorTable#AS}
+   * (see {@link #alias}), removes the
+   * call but uses the intended alias.
+   * After the field names have been inferred, makes the
+   * field names unique by appending numeric suffixes. */
+  public RelBuilder project(List<RexNode> nodes) {
+    final List<String> names = new ArrayList<>();
+    final List<RexNode> exprList = Lists.newArrayList(nodes);
+    for (RexNode node : nodes) {
+      names.add(inferAlias(exprList, node));
+    }
+    final RelNode project =
+        projectFactory.createProject(build(), ImmutableList.copyOf(exprList),
+            names);
+    push(project);
+    return this;
+  }
+
+  /** Creates a {@link org.apache.calcite.rel.core.Project} of the given
+   * expressions. */
+  public RelBuilder project(RexNode... nodes) {
+    return project(ImmutableList.copyOf(nodes));
+  }
+
+  /** Infers the alias of an expression.
+   *
+   * <p>If the expression was created by {@link #alias}, replaces the expression
+   * in the project list.
+   */
+  private String inferAlias(List<RexNode> exprList, RexNode expr) {
+    switch (expr.getKind()) {
+    case INPUT_REF:
+      final RexInputRef ref = (RexInputRef) expr;
+      return peek(0).getRowType().getFieldNames().get(ref.getIndex());
+    case CAST:
+      return inferAlias(exprList, ((RexCall) expr).getOperands().get(0));
+    case AS:
+      final RexCall call = (RexCall) expr;
+      for (;;) {
+        final int i = exprList.indexOf(expr);
+        if (i < 0) {
+          break;
+        }
+        exprList.set(i, call.getOperands().get(0));
+      }
+      return ((NlsString) ((RexLiteral) call.getOperands().get(1)).getValue())
+          .getValue();
+    default:
+      return null;
+    }
+  }
+
+  /** Creates an {@link org.apache.calcite.rel.core.Aggregate} that makes the
+   * relational expression distinct on all fields. */
+  public RelBuilder distinct() {
+    return aggregate(groupKey());
+  }
+
+  /** Creates an {@link org.apache.calcite.rel.core.Aggregate} with an array of
+   * calls. */
+  public RelBuilder aggregate(GroupKey groupKey, AggCall... aggCalls) {
+    return aggregate(groupKey, ImmutableList.copyOf(aggCalls));
+  }
+
+  /** Creates an {@link org.apache.calcite.rel.core.Aggregate} with a list of
+   * calls. */
+  public RelBuilder aggregate(GroupKey groupKey, Iterable<AggCall> aggCalls) {
+    final ImmutableBitSet.Builder builder = ImmutableBitSet.builder();
+    final RelDataType inputRowType = peek().getRowType();
+    final List<RexNode> extraNodes = projects(inputRowType);
+    for (RexNode node : ((GroupKeyImpl) groupKey).nodes) {
+      builder.set(registerExpression(extraNodes, node));
+    }
+    final ImmutableBitSet groupSet = builder.build();
+    for (AggCall aggCall : aggCalls) {
+      final AggCallImpl aggCall1 = (AggCallImpl) aggCall;
+      for (RexNode operand : aggCall1.operands) {
+        registerExpression(extraNodes, operand);
+      }
+    }
+    if (extraNodes.size() > inputRowType.getFieldCount()) {
+      project(extraNodes);
+    }
+    final RelNode r = build();
+    final List<AggregateCall> aggregateCalls = new ArrayList<>();
+    for (AggCall aggCall : aggCalls) {
+      final List<Integer> args = new ArrayList<>();
+      final AggCallImpl aggCall1 = (AggCallImpl) aggCall;
+      for (RexNode operand : aggCall1.operands) {
+        args.add(registerExpression(extraNodes, operand));
+      }
+      aggregateCalls.add(
+          AggregateCall.create(aggCall1.aggFunction, aggCall1.distinct,
+              args, -1, groupSet.cardinality(), r, null, aggCall1.alias));
+    }
+
+    RelNode aggregate = aggregateFactory.createAggregate(r, false, groupSet,
+        ImmutableList.of(groupSet), aggregateCalls);
+    push(aggregate);
+    return this;
+  }
+
+  private List<RexNode> projects(RelDataType inputRowType) {
+    final List<RexNode> exprList = new ArrayList<>();
+    for (RelDataTypeField field : inputRowType.getFieldList()) {
+      final RexBuilder rexBuilder = cluster.getRexBuilder();
+      exprList.add(rexBuilder.makeInputRef(field.getType(), field.getIndex()));
+    }
+    return exprList;
+  }
+
+  private static int registerExpression(List<RexNode> exprList, RexNode node) {
+    int i = exprList.indexOf(node);
+    if (i < 0) {
+      i = exprList.size();
+      exprList.add(node);
+    }
+    return i;
+  }
+
+  /** Creates a {@link org.apache.calcite.rel.core.Union} of the two most recent
+   * relational expressions on the stack.
+   *
+   * @param all Whether to create UNION ALL
+   */
+  public RelBuilder union(boolean all) {
+    final RelNode left = build();
+    final RelNode right = build();
+    final RelNode union = setOpFactory.createSetOp(SqlKind.UNION,
+        ImmutableList.of(left, right), all);
+    push(union);
+    return this;
+  }
+
+  /** Creates an {@link org.apache.calcite.rel.core.Intersect} of the two most
+   * recent relational expressions on the stack.
+   *
+   * @param all Whether to create INTERSECT ALL
+   */
+  public RelBuilder intersect(boolean all) {
+    final RelNode left = build();
+    final RelNode right = build();
+    final RelNode intersect = setOpFactory.createSetOp(SqlKind.INTERSECT,
+        ImmutableList.of(left, right), all);
+    push(intersect);
+    return this;
+  }
+
+  /** Creates a {@link org.apache.calcite.rel.core.Minus} of the two most recent
+   * relational expressions on the stack.
+   *
+   * @param all Whether to create EXCEPT ALL
+   */
+  public RelBuilder minus(boolean all) {
+    final RelNode left = build();
+    final RelNode right = build();
+    final RelNode except = setOpFactory.createSetOp(SqlKind.EXCEPT,
+        ImmutableList.of(left, right), all);
+    push(except);
+    return this;
+  }
+
+  /** Creates a {@link org.apache.calcite.rel.core.Join}. */
+  public RelBuilder join(JoinRelType joinType, RexNode condition) {
+    final RelNode left = build();
+    final RelNode right = build();
+    final RelNode join = joinFactory.createJoin(left, right, condition,
+        joinType, ImmutableSet.<String>of(), false);
+    push(join);
+    return this;
+  }
+
+  /** Creates a {@link org.apache.calcite.rel.core.Join} using USING syntax.
+   *
+   * <p>For each of the field names, both left and right inputs must have a
+   * field of that name. Constructs a join condition that the left and right
+   * fields are equal.
+   *
+   * @param joinType Join type
+   * @param fieldNames Field names
+   */
+  public RelBuilder join(JoinRelType joinType, String... fieldNames) {
+    final List<RexNode> conditions = new ArrayList<>();
+    for (String fieldName : fieldNames) {
+      conditions.add(
+          call(SqlStdOperatorTable.EQUALS,
+              field(2, 0, fieldName),
+              field(2, 1, fieldName)));
+    }
+    final RexNode condition =
+        RexUtil.composeConjunction(cluster.getRexBuilder(), conditions, false);
+    return join(joinType, condition);
+  }
+
+  /** Creates a {@link Values}.
+   *
+   * <p>The {@code values} array must have the same number of entries as
+   * {@code fieldNames}, or an integer multiple if you wish to create multiple
+   * rows.
+   *
+   * <p>If there are zero rows, or if all values of a any column are
+   * null, this method cannot deduce the type of columns. For these cases,
+   * call {@link #values(RelDataType, Iterable)}.
+   *
+   * @param fieldNames Field names
+   * @param values Values
+   */
+  public RelBuilder values(String[] fieldNames, Object... values) {
+    if (fieldNames == null
+        || fieldNames.length == 0
+        || values.length % fieldNames.length != 0
+        || values.length < fieldNames.length) {
+      throw new IllegalArgumentException(
+          "Value count must be a positive multiple of field count");
+    }
+    final int rowCount = values.length / fieldNames.length;
+    for (Ord<String> fieldName : Ord.zip(fieldNames)) {
+      if (allNull(values, fieldName.i, fieldNames.length)) {
+        throw new IllegalArgumentException("All values of field '" + fieldName.e
+            + "' are null; cannot deduce type");
+      }
+    }
+    final ImmutableList<ImmutableList<RexLiteral>> tupleList =
+        tupleList(fieldNames.length, values);
+    final RelDataTypeFactory.FieldInfoBuilder rowTypeBuilder =
+        cluster.getTypeFactory().builder();
+    for (final Ord<String> fieldName : Ord.zip(fieldNames)) {
+      final String name =
+          fieldName.e != null ? fieldName.e : "expr$" + fieldName.i;
+      final RelDataType type = cluster.getTypeFactory().leastRestrictive(
+          new AbstractList<RelDataType>() {
+            public RelDataType get(int index) {
+              return tupleList.get(index).get(fieldName.i).getType();
+            }
+
+            public int size() {
+              return rowCount;
+            }
+          });
+      rowTypeBuilder.add(name, type);
+    }
+    final RelDataType rowType = rowTypeBuilder.build();
+    return values(rowType, tupleList);
+  }
+
+  private ImmutableList<ImmutableList<RexLiteral>> tupleList(int columnCount,
+      Object[] values) {
+    final ImmutableList.Builder<ImmutableList<RexLiteral>> listBuilder =
+        ImmutableList.builder();
+    final List<RexLiteral> valueList = new ArrayList<>();
+    for (int i = 0; i < values.length; i++) {
+      Object value = values[i];
+      valueList.add((RexLiteral) literal(value));
+      if ((i + 1) % columnCount == 0) {
+        listBuilder.add(ImmutableList.copyOf(valueList));
+        valueList.clear();
+      }
+    }
+    return listBuilder.build();
+  }
+
+  /** Returns whether all values for a given column are null. */
+  private boolean allNull(Object[] values, int column, int columnCount) {
+    for (int i = column; i < values.length; i += columnCount) {
+      if (values[i] != null) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /** Creates a {@link Values} with a specified row type.
+   *
+   * <p>This method can handle cases that {@link #values(String[], Object...)}
+   * cannot, such as all values of a column being null, or there being zero
+   * rows.
+   *
+   * @param rowType Row type
+   * @param columnValues Values
+   */
+  public RelBuilder values(RelDataType rowType, Object... columnValues) {
+    final ImmutableList<ImmutableList<RexLiteral>> tupleList =
+        tupleList(rowType.getFieldCount(), columnValues);
+    RelNode values = valuesFactory.createValues(cluster, rowType,
+        ImmutableList.copyOf(tupleList));
+    push(values);
+    return this;
+  }
+
+  /** Creates a {@link Values} with a specified row type.
+   *
+   * <p>This method can handle cases that {@link #values(String[], Object...)}
+   * cannot, such as all values of a column being null, or there being zero
+   * rows.
+   *
+   * @param rowType Row type
+   * @param tupleList Tuple list
+   */
+  protected RelBuilder values(RelDataType rowType,
+      Iterable<ImmutableList<RexLiteral>> tupleList) {
+    RelNode values = valuesFactory.createValues(cluster, rowType,
+        ImmutableList.copyOf(tupleList));
+    push(values);
+    return this;
+  }
+
+  /** Creates a limit without a sort. */
+  public RelBuilder limit(int offset, int fetch) {
+    return sortLimit(offset, fetch, ImmutableList.<RexNode>of());
+  }
+
+  /** Creates a {@link Sort} by field ordinals.
+   *
+   * <p>Negative fields mean descending: -1 means field(0) descending,
+   * -2 means field(1) descending, etc.
+   */
+  public RelBuilder sort(int... fields) {
+    final ImmutableList.Builder<RexNode> builder = ImmutableList.builder();
+    for (int field : fields) {
+      builder.add(field < 0 ? desc(field(-field - 1)) : field(field));
+    }
+    return sortLimit(-1, -1, builder.build());
+  }
+
+  /** Creates a {@link Sort} by expressions. */
+  public RelBuilder sort(RexNode... nodes) {
+    return sortLimit(-1, -1, ImmutableList.copyOf(nodes));
+  }
+
+  /** Creates a {@link Sort} by expressions. */
+  public RelBuilder sort(Iterable<? extends RexNode> nodes) {
+    return sortLimit(-1, -1, nodes);
+  }
+
+  /** Creates a {@link Sort} by expressions, with limit and offset. */
+  public RelBuilder sortLimit(int offset, int fetch, RexNode... nodes) {
+    return sortLimit(offset, fetch, ImmutableList.copyOf(nodes));
+  }
+
+  /** Creates a {@link Sort} by a list of expressions, with limit and offset.
+   *
+   * @param offset Number of rows to skip; non-positive means don't skip any
+   * @param fetch Maximum number of rows to fetch; negative means no limit
+   * @param nodes Sort expressions
+   */
+  public RelBuilder sortLimit(int offset, int fetch,
+      Iterable<? extends RexNode> nodes) {
+    final List<RelFieldCollation> fieldCollations = new ArrayList<>();
+    final RelDataType inputRowType = peek().getRowType();
+    final List<RexNode> extraNodes = projects(inputRowType);
+    final List<RexNode> originalExtraNodes = ImmutableList.copyOf(extraNodes);
+    for (RexNode node : nodes) {
+      fieldCollations.add(
+          collation(node, RelFieldCollation.Direction.ASCENDING,
+              RelFieldCollation.NullDirection.UNSPECIFIED, extraNodes));
+    }
+    final RexNode offsetNode = offset <= 0 ? null : literal(offset);
+    final RexNode fetchNode = fetch < 0 ? null : literal(fetch);
+    if (extraNodes.size() > inputRowType.getFieldCount()) {
+      project(extraNodes);
+    }
+    final RelNode sort =
+        sortFactory.createSort(build(), RelCollations.of(fieldCollations),
+            offsetNode, fetchNode);
+    push(sort);
+    if (extraNodes.size() > inputRowType.getFieldCount()) {
+      project(originalExtraNodes);
+    }
+    return this;
+  }
+
+  private static RelFieldCollation collation(RexNode node,
+      RelFieldCollation.Direction direction,
+      RelFieldCollation.NullDirection nullDirection, List<RexNode> extraNodes) {
+    switch (node.getKind()) {
+    case INPUT_REF:
+      return new RelFieldCollation(((RexInputRef) node).getIndex(),
+          direction, nullDirection);
+    case DESCENDING:
+      return collation(((RexCall) node).getOperands().get(0),
+          RelFieldCollation.Direction.DESCENDING,
+          nullDirection, extraNodes);
+    case NULLS_FIRST:
+      return collation(((RexCall) node).getOperands().get(0), direction,
+          RelFieldCollation.NullDirection.FIRST, extraNodes);
+    case NULLS_LAST:
+      return collation(((RexCall) node).getOperands().get(0), direction,
+          RelFieldCollation.NullDirection.LAST, extraNodes);
+    default:
+      final int fieldIndex = extraNodes.size();
+      extraNodes.add(node);
+      return new RelFieldCollation(fieldIndex, direction, nullDirection);
+    }
+  }
+
+  /** Information necessary to create a call to an aggregate function.
+   *
+   * @see RelBuilder#aggregateCall */
+  public interface AggCall {
+  }
+
+  /** Information necessary to create the GROUP BY clause of an Aggregate.
+   *
+   * @see RelBuilder#groupKey */
+  public interface GroupKey {
+  }
+
+  /** Implementation of {@link RelBuilder.GroupKey}. */
+  private static class GroupKeyImpl implements GroupKey {
+    private final ImmutableList<RexNode> nodes;
+
+    GroupKeyImpl(ImmutableList<RexNode> nodes) {
+      this.nodes = nodes;
+    }
+  }
+
+  /** Implementation of {@link RelBuilder.AggCall}. */
+  private static class AggCallImpl implements AggCall {
+    private final SqlAggFunction aggFunction;
+    private final boolean distinct;
+    private final String alias;
+    private final ImmutableList<RexNode> operands;
+
+    public AggCallImpl(SqlAggFunction aggFunction, boolean distinct,
+        String alias, ImmutableList<RexNode> operands) {
+      this.aggFunction = aggFunction;
+      this.distinct = distinct;
+      this.alias = alias;
+      this.operands = operands;
+    }
+  }
+
+  /** A partially-created RelBuilder.
+   *
+   * <p>Add a cluster, and optionally a schema,
+   * when you want to create a builder.
+   *
+   * <p>A {@code ProtoRelBuilder} can be shared among queries, and thus can
+   * be inside a {@link RelOptRule}. It is a nice way to encapsulate the policy
+   * that this particular rule instance should create {@code DrillFilter}
+   * and {@code DrillProject} versus {@code HiveFilter} and {@code HiveProject}.
+   *
+   * @see RelFactories#DEFAULT_PROTO
+   */
+  public interface ProtoRelBuilder {
+    RelBuilder create(RelOptCluster cluster, RelOptSchema schema);
+  }
+}
+
+// End RelBuilder.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/6609cb1a/core/src/main/java/org/apache/calcite/util/Stacks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/Stacks.java b/core/src/main/java/org/apache/calcite/util/Stacks.java
index 70ef045..2a41368 100644
--- a/core/src/main/java/org/apache/calcite/util/Stacks.java
+++ b/core/src/main/java/org/apache/calcite/util/Stacks.java
@@ -34,6 +34,14 @@ public class Stacks {
   }
 
   /**
+   * Returns the {@code n}th most recently added element in the stack.
+   * Throws if the stack is empty.
+   */
+  public static <T> T peek(int n, List<T> stack) {
+    return stack.get(stack.size() - n - 1);
+  }
+
+  /**
    * Adds an element to the stack.
    */
   public static <T> void push(List<T> stack, T element) {
@@ -48,6 +56,15 @@ public class Stacks {
     assert stack.get(stack.size() - 1) == element;
     stack.remove(stack.size() - 1);
   }
+
+  /**
+   * Removes an element from the stack and returns it.
+   *
+   * <p>Throws if the stack is empty.
+   */
+  public static <T> T pop(List<T> stack) {
+    return stack.remove(stack.size() - 1);
+  }
 }
 
 // End Stacks.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/6609cb1a/core/src/test/java/org/apache/calcite/examples/RelBuilderExample.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/examples/RelBuilderExample.java b/core/src/test/java/org/apache/calcite/examples/RelBuilderExample.java
new file mode 100644
index 0000000..12801e8
--- /dev/null
+++ b/core/src/test/java/org/apache/calcite/examples/RelBuilderExample.java
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.examples;
+
+import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.JoinRelType;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.test.RelBuilderTest;
+import org.apache.calcite.tools.FrameworkConfig;
+import org.apache.calcite.tools.RelBuilder;
+
+/**
+ * Example that uses {@link org.apache.calcite.tools.RelBuilder}
+ * to create various relational expressions.
+ */
+public class RelBuilderExample {
+  private final boolean verbose;
+
+  public RelBuilderExample(boolean verbose) {
+    this.verbose = verbose;
+  }
+
+  public static void main(String[] args) {
+    new RelBuilderExample(true).runAllExamples();
+  }
+
+  public void runAllExamples() {
+    // Create a builder. The config contains a schema mapped
+    // to the SCOTT database, with tables EMP and DEPT.
+    final FrameworkConfig config = RelBuilderTest.config().build();
+    final RelBuilder builder = RelBuilder.create(config);
+    for (int i = 0; i < 4; i++) {
+      doExample(builder, i);
+      final RelNode node = builder.build();
+      if (verbose) {
+        System.out.println(RelOptUtil.toString(node));
+      }
+    }
+  }
+
+  private RelBuilder doExample(RelBuilder builder, int i) {
+    switch (i) {
+    case 0:
+      return example0(builder);
+    case 1:
+      return example1(builder);
+    case 2:
+      return example2(builder);
+    case 3:
+      return example3(builder);
+    case 4:
+      return example4(builder);
+    default:
+      throw new AssertionError("unknown example " + i);
+    }
+  }
+
+  /**
+   * Creates a relational expression for a table scan.
+   * It is equivalent to
+   *
+   * <pre>
+   * SELECT *
+   * FROM emp</pre>
+   */
+  private RelBuilder example0(RelBuilder builder) {
+    return builder
+        .values(new String[] {"a", "b"}, 1, true, null, false);
+  }
+
+  /**
+   * Creates a relational expression for a table scan.
+   * It is equivalent to
+   *
+   * <pre>
+   * SELECT *
+   * FROM emp</pre>
+   */
+  private RelBuilder example1(RelBuilder builder) {
+    return builder
+        .scan("EMP");
+  }
+
+  /**
+   * Creates a relational expression for a table scan and project.
+   * It is equivalent to
+   *
+   * <pre>
+   * SELECT deptno, ename
+   * FROM emp</pre>
+   */
+  private RelBuilder example2(RelBuilder builder) {
+    return builder
+        .scan("EMP")
+        .project(builder.field("DEPTNO"), builder.field("ENAME"));
+  }
+
+  /**
+   * Creates a relational expression for a table scan, aggregate, filter.
+   * It is equivalent to
+   *
+   * <pre>
+   * SELECT deptno, count(*) AS c, sum(sal) AS s
+   * FROM emp
+   * GROUP BY deptno
+   * HAVING count(*) > 10</pre>
+   */
+  private RelBuilder example3(RelBuilder builder) {
+    return builder
+        .scan("EMP")
+        .aggregate(builder.groupKey("DEPTNO"),
+            builder.count(false, "C"),
+            builder.sum(false, "S", builder.field("SAL")))
+        .filter(
+            builder.call(SqlStdOperatorTable.GREATER_THAN, builder.field("C"),
+                builder.literal(10)));
+  }
+
+  /**
+   * Sometimes the stack becomes so deeply nested it gets confusing. To keep
+   * things straight, you can remove expressions from the stack. For example,
+   * here we are building a bushy join:
+   *
+   * <pre>
+   *                join
+   *              /      \
+   *         join          join
+   *       /      \      /      \
+   * CUSTOMERS ORDERS LINE_ITEMS PRODUCTS
+   * </pre>
+   *
+   * <p>We build it in three stages. Store the intermediate results in variables
+   * `left` and `right`, and use `push()` to put them back on the stack when it
+   * is time to create the final `Join`.
+   */
+  private RelBuilder example4(RelBuilder builder) {
+    final RelNode left = builder
+        .scan("CUSTOMERS")
+        .scan("ORDERS")
+        .join(JoinRelType.INNER, "ORDER_ID")
+        .build();
+
+    final RelNode right = builder
+        .scan("LINE_ITEMS")
+        .scan("PRODUCTS")
+        .join(JoinRelType.INNER, "PRODUCT_ID")
+        .build();
+
+    return builder
+        .push(left)
+        .push(right)
+        .join(JoinRelType.INNER, "ORDER_ID");
+  }
+}
+
+// End RelBuilderExample.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/6609cb1a/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 cad237e..5a87733 100644
--- a/core/src/test/java/org/apache/calcite/test/CalciteSuite.java
+++ b/core/src/test/java/org/apache/calcite/test/CalciteSuite.java
@@ -113,6 +113,7 @@ import org.junit.runners.Suite;
 
     // slow tests (above 1s)
     PlannerTest.class,
+    RelBuilderTest.class,
     MaterializationTest.class,
     JdbcAdapterTest.class,
     LinqFrontJdbcBackTest.class,


[3/7] incubator-calcite git commit: Wrap file header in HTML comments

Posted by jh...@apache.org.
Wrap file header in HTML comments


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

Branch: refs/heads/master
Commit: 530e398b729e3c768f190236792000ef80d3fc5f
Parents: 3aec3f8
Author: Julian Hyde <jh...@apache.org>
Authored: Fri Jun 5 10:17:49 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Fri Jun 5 10:23:53 2015 -0700

----------------------------------------------------------------------
 README.md                                          | 2 ++
 site/README.md                                     | 2 ++
 site/_docs/adapter.md                              | 2 ++
 site/_docs/algebra.md                              | 2 ++
 site/_docs/api.md                                  | 2 ++
 site/_docs/avatica.md                              | 3 +++
 site/_docs/contributing.md                         | 2 ++
 site/_docs/downloads.md                            | 2 ++
 site/_docs/history.md                              | 2 ++
 site/_docs/howto.md                                | 2 ++
 site/_docs/index.md                                | 2 ++
 site/_docs/lattice.md                              | 3 +++
 site/_docs/model.md                                | 3 +++
 site/_docs/reference.md                            | 3 +++
 site/_docs/stream.md                               | 2 ++
 site/_docs/tutorial.md                             | 2 ++
 site/_posts/2014-06-27-release-0.8.0-incubating.md | 2 ++
 site/_posts/2014-08-19-release-0.9.0-incubating.md | 2 ++
 site/_posts/2014-10-02-release-0.9.1-incubating.md | 2 ++
 site/_posts/2014-11-05-release-0.9.2-incubating.md | 2 ++
 site/_posts/2015-01-31-release-1.0.0-incubating.md | 2 ++
 site/_posts/2015-03-13-release-1.1.0-incubating.md | 2 ++
 site/_posts/2015-04-07-release-1.2.0-incubating.md | 2 ++
 site/_posts/2015-04-24-new-committers.md           | 2 ++
 site/_posts/2015-05-30-release-1.3.0-incubating.md | 2 ++
 site/develop/index.md                              | 2 ++
 site/help/index.md                                 | 2 ++
 site/talks/index.md                                | 2 ++
 28 files changed, 60 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/530e398b/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
index 7a154a8..fcdbc75 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,4 @@
+<!--
 {% comment %}
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
@@ -14,6 +15,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 {% endcomment %}
+-->
 [![Build Status](https://travis-ci.org/julianhyde/incubator-calcite.svg?branch=master)](https://travis-ci.org/julianhyde/incubator-calcite)
 
 # Apache Calcite

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/530e398b/site/README.md
----------------------------------------------------------------------
diff --git a/site/README.md b/site/README.md
index ae957c3..e48b853 100644
--- a/site/README.md
+++ b/site/README.md
@@ -1,3 +1,4 @@
+<!--
 {% comment %}
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
@@ -14,6 +15,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 {% endcomment %}
+-->
 
 # Apache Calcite docs site
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/530e398b/site/_docs/adapter.md
----------------------------------------------------------------------
diff --git a/site/_docs/adapter.md b/site/_docs/adapter.md
index 271b91a..39f039e 100644
--- a/site/_docs/adapter.md
+++ b/site/_docs/adapter.md
@@ -3,6 +3,7 @@ layout: docs
 title: Adapters
 permalink: /docs/adapter.html
 ---
+<!--
 {% comment %}
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
@@ -19,6 +20,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 {% endcomment %}
+-->
 
 * <a href="https://github.com/apache/incubator-drill">Apache Drill adapter</a>
 * Cascading adapter (<a href="https://github.com/Cascading/lingual">Lingual</a>)

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/530e398b/site/_docs/algebra.md
----------------------------------------------------------------------
diff --git a/site/_docs/algebra.md b/site/_docs/algebra.md
index a69ca7b..1116362 100644
--- a/site/_docs/algebra.md
+++ b/site/_docs/algebra.md
@@ -3,6 +3,7 @@ layout: docs
 title: Algebra
 permalink: /docs/algebra.html
 ---
+<!--
 {% comment %}
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
@@ -19,6 +20,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 {% endcomment %}
+-->
 
 Relational algebra is at the heart of Calcite. Every query is
 represented as a tree of relational operators. You can translate from

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/530e398b/site/_docs/api.md
----------------------------------------------------------------------
diff --git a/site/_docs/api.md b/site/_docs/api.md
index 5ab031a..db961ea 100644
--- a/site/_docs/api.md
+++ b/site/_docs/api.md
@@ -5,6 +5,7 @@ external_url: /apidocs
 ---
 
 <!--
+{% comment %}
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
 this work for additional information regarding copyright ownership.
@@ -19,4 +20,5 @@ distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
+{% endcomment %}
 -->

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/530e398b/site/_docs/avatica.md
----------------------------------------------------------------------
diff --git a/site/_docs/avatica.md b/site/_docs/avatica.md
index 0458ece..2382a86 100644
--- a/site/_docs/avatica.md
+++ b/site/_docs/avatica.md
@@ -5,6 +5,7 @@ permalink: /docs/avatica.html
 ---
 
 <!--
+{% comment %}
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
 this work for additional information regarding copyright ownership.
@@ -19,7 +20,9 @@ distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
+{% endcomment %}
 -->
+
 Avatica is a framework for building JDBC and ODBC drivers for databases,
 and an RPC wire protocol.
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/530e398b/site/_docs/contributing.md
----------------------------------------------------------------------
diff --git a/site/_docs/contributing.md b/site/_docs/contributing.md
index 8fbdd6d..aa8b686 100644
--- a/site/_docs/contributing.md
+++ b/site/_docs/contributing.md
@@ -5,6 +5,7 @@ permalink: /docs/contributing.html
 ---
 
 <!--
+{% comment %}
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
 this work for additional information regarding copyright ownership.
@@ -19,6 +20,7 @@ distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
+{% endcomment %}
 -->
 
 We welcome contributions.

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/530e398b/site/_docs/downloads.md
----------------------------------------------------------------------
diff --git a/site/_docs/downloads.md b/site/_docs/downloads.md
index 74d1acd..1da41b2 100644
--- a/site/_docs/downloads.md
+++ b/site/_docs/downloads.md
@@ -5,6 +5,7 @@ permalink: /docs/downloads.html
 ---
 
 <!--
+{% comment %}
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
 this work for additional information regarding copyright ownership.
@@ -19,6 +20,7 @@ distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
+{% endcomment %}
 -->
 
 Calcite is released as a source artifact, and also through Maven.

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/530e398b/site/_docs/history.md
----------------------------------------------------------------------
diff --git a/site/_docs/history.md b/site/_docs/history.md
index 4488546..b809b19 100644
--- a/site/_docs/history.md
+++ b/site/_docs/history.md
@@ -5,6 +5,7 @@ permalink: "/docs/history.html"
 ---
 
 <!--
+{% comment %}
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
 this work for additional information regarding copyright ownership.
@@ -19,6 +20,7 @@ distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
+{% endcomment %}
 -->
 
 For a full list of releases, see

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/530e398b/site/_docs/howto.md
----------------------------------------------------------------------
diff --git a/site/_docs/howto.md b/site/_docs/howto.md
index 7443262..cd5011a 100644
--- a/site/_docs/howto.md
+++ b/site/_docs/howto.md
@@ -5,6 +5,7 @@ permalink: /docs/howto.html
 ---
 
 <!--
+{% comment %}
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
 this work for additional information regarding copyright ownership.
@@ -19,6 +20,7 @@ distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
+{% endcomment %}
 -->
 {% assign sourceRoot = "http://github.com/apache/incubator-calcite/blob/master" %}
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/530e398b/site/_docs/index.md
----------------------------------------------------------------------
diff --git a/site/_docs/index.md b/site/_docs/index.md
index 60f439d..2edddb6 100644
--- a/site/_docs/index.md
+++ b/site/_docs/index.md
@@ -3,6 +3,7 @@ layout: docs
 title: Background
 permalink: /docs/index.html
 ---
+<!--
 {% comment %}
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
@@ -19,6 +20,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 {% endcomment %}
+-->
 
 Apache Calcite is a dynamic data management framework.
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/530e398b/site/_docs/lattice.md
----------------------------------------------------------------------
diff --git a/site/_docs/lattice.md b/site/_docs/lattice.md
index 7c38f1c..8bd51ff 100644
--- a/site/_docs/lattice.md
+++ b/site/_docs/lattice.md
@@ -4,6 +4,7 @@ title: Lattices
 permalink: /docs/lattice.html
 ---
 <!--
+{% comment %}
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
 this work for additional information regarding copyright ownership.
@@ -18,7 +19,9 @@ distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
+{% endcomment %}
 -->
+
 A lattice is a framework for creating and populating materialized views,
 and for recognizing that a materialized view can be used to solve a
 particular query.

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/530e398b/site/_docs/model.md
----------------------------------------------------------------------
diff --git a/site/_docs/model.md b/site/_docs/model.md
index b08b2ab..78061b0 100644
--- a/site/_docs/model.md
+++ b/site/_docs/model.md
@@ -4,6 +4,7 @@ title: JSON models
 permalink: /docs/model.html
 ---
 <!--
+{% comment %}
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
 this work for additional information regarding copyright ownership.
@@ -18,7 +19,9 @@ distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
+{% endcomment %}
 -->
+
 Calcite models can be represented as JSON files.
 This page describes the structure of those files.
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/530e398b/site/_docs/reference.md
----------------------------------------------------------------------
diff --git a/site/_docs/reference.md b/site/_docs/reference.md
index 02b4674..dc7efb5 100644
--- a/site/_docs/reference.md
+++ b/site/_docs/reference.md
@@ -4,6 +4,7 @@ title: SQL language
 permalink: /docs/reference.html
 ---
 <!--
+{% comment %}
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
 this work for additional information regarding copyright ownership.
@@ -18,7 +19,9 @@ distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
+{% endcomment %}
 -->
+
 The page describes the SQL dialect recognized by Calcite's default SQL parser.
 
 ## Grammar

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/530e398b/site/_docs/stream.md
----------------------------------------------------------------------
diff --git a/site/_docs/stream.md b/site/_docs/stream.md
index 7418208..395447b 100644
--- a/site/_docs/stream.md
+++ b/site/_docs/stream.md
@@ -4,6 +4,7 @@ title: Streaming
 permalink: /docs/stream.html
 ---
 <!--
+{% comment %}
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
 this work for additional information regarding copyright ownership.
@@ -18,6 +19,7 @@ distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
+{% endcomment %}
 -->
 
 Calcite has extended SQL and relational algebra in order to support

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/530e398b/site/_docs/tutorial.md
----------------------------------------------------------------------
diff --git a/site/_docs/tutorial.md b/site/_docs/tutorial.md
index 51ec187..3440b3d 100644
--- a/site/_docs/tutorial.md
+++ b/site/_docs/tutorial.md
@@ -4,6 +4,7 @@ title: Tutorial
 permalink: /docs/tutorial.html
 ---
 <!--
+{% comment %}
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
 this work for additional information regarding copyright ownership.
@@ -18,6 +19,7 @@ distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
+{% endcomment %}
 -->
 
 {% assign sourceRoot = "http://github.com/apache/incubator-calcite/blob/master" %}

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/530e398b/site/_posts/2014-06-27-release-0.8.0-incubating.md
----------------------------------------------------------------------
diff --git a/site/_posts/2014-06-27-release-0.8.0-incubating.md b/site/_posts/2014-06-27-release-0.8.0-incubating.md
index 49fbbe7..588edaf 100644
--- a/site/_posts/2014-06-27-release-0.8.0-incubating.md
+++ b/site/_posts/2014-06-27-release-0.8.0-incubating.md
@@ -7,6 +7,7 @@ tag: v0-8
 sha: 3da850a1
 categories: [release]
 ---
+<!--
 {% comment %}
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
@@ -23,5 +24,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 {% endcomment %}
+-->
 
 This is the first release under the Apache incubator process.

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/530e398b/site/_posts/2014-08-19-release-0.9.0-incubating.md
----------------------------------------------------------------------
diff --git a/site/_posts/2014-08-19-release-0.9.0-incubating.md b/site/_posts/2014-08-19-release-0.9.0-incubating.md
index 5855529..7ca65ac 100644
--- a/site/_posts/2014-08-19-release-0.9.0-incubating.md
+++ b/site/_posts/2014-08-19-release-0.9.0-incubating.md
@@ -8,6 +8,7 @@ tag: v0-9-0
 sha: 45e5269b
 categories: [release]
 ---
+<!--
 {% comment %}
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
@@ -24,5 +25,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 {% endcomment %}
+-->
 
 This is the first release under the Apache incubator process.

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/530e398b/site/_posts/2014-10-02-release-0.9.1-incubating.md
----------------------------------------------------------------------
diff --git a/site/_posts/2014-10-02-release-0.9.1-incubating.md b/site/_posts/2014-10-02-release-0.9.1-incubating.md
index 7c35516..bca9113 100644
--- a/site/_posts/2014-10-02-release-0.9.1-incubating.md
+++ b/site/_posts/2014-10-02-release-0.9.1-incubating.md
@@ -7,6 +7,7 @@ tag: v0-9-1
 sha: 68012573
 categories: [release]
 ---
+<!--
 {% comment %}
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
@@ -23,5 +24,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 {% endcomment %}
+-->
 
 This is the first release as Calcite. (The project was previously called Optiq.)

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/530e398b/site/_posts/2014-11-05-release-0.9.2-incubating.md
----------------------------------------------------------------------
diff --git a/site/_posts/2014-11-05-release-0.9.2-incubating.md b/site/_posts/2014-11-05-release-0.9.2-incubating.md
index 1658145..47741c0 100644
--- a/site/_posts/2014-11-05-release-0.9.2-incubating.md
+++ b/site/_posts/2014-11-05-release-0.9.2-incubating.md
@@ -7,6 +7,7 @@ tag: v0-9-2
 sha: 0404fd23
 categories: [release]
 ---
+<!--
 {% comment %}
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
@@ -23,6 +24,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 {% endcomment %}
+-->
 
 A fairly minor release, and last release before we rename all of the
 packages and lots of classes, in what we expect to call 1.0. If you

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/530e398b/site/_posts/2015-01-31-release-1.0.0-incubating.md
----------------------------------------------------------------------
diff --git a/site/_posts/2015-01-31-release-1.0.0-incubating.md b/site/_posts/2015-01-31-release-1.0.0-incubating.md
index ff219c9..ad60205 100644
--- a/site/_posts/2015-01-31-release-1.0.0-incubating.md
+++ b/site/_posts/2015-01-31-release-1.0.0-incubating.md
@@ -7,6 +7,7 @@ tag: v1-0-0
 sha: 2dd83f2
 categories: [release]
 ---
+<!--
 {% comment %}
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
@@ -23,6 +24,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 {% endcomment %}
+-->
 
 Calcite's first major release.
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/530e398b/site/_posts/2015-03-13-release-1.1.0-incubating.md
----------------------------------------------------------------------
diff --git a/site/_posts/2015-03-13-release-1.1.0-incubating.md b/site/_posts/2015-03-13-release-1.1.0-incubating.md
index 6661894..327b023 100644
--- a/site/_posts/2015-03-13-release-1.1.0-incubating.md
+++ b/site/_posts/2015-03-13-release-1.1.0-incubating.md
@@ -7,6 +7,7 @@ tag: v1-1-0
 sha: f10ea367
 categories: [release]
 ---
+<!--
 {% comment %}
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
@@ -23,6 +24,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 {% endcomment %}
+-->
 
 This Calcite release makes it possible to exploit physical properties
 of relational expressions to produce more efficient plans, introducing

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/530e398b/site/_posts/2015-04-07-release-1.2.0-incubating.md
----------------------------------------------------------------------
diff --git a/site/_posts/2015-04-07-release-1.2.0-incubating.md b/site/_posts/2015-04-07-release-1.2.0-incubating.md
index c89b74f..8332063 100644
--- a/site/_posts/2015-04-07-release-1.2.0-incubating.md
+++ b/site/_posts/2015-04-07-release-1.2.0-incubating.md
@@ -7,6 +7,7 @@ tag: v1-2-0
 sha: d60f2aa
 categories: [release]
 ---
+<!--
 {% comment %}
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
@@ -23,6 +24,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 {% endcomment %}
+-->
 
 A short release, less than a month after 1.1.
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/530e398b/site/_posts/2015-04-24-new-committers.md
----------------------------------------------------------------------
diff --git a/site/_posts/2015-04-24-new-committers.md b/site/_posts/2015-04-24-new-committers.md
index 305209b..92a2466 100644
--- a/site/_posts/2015-04-24-new-committers.md
+++ b/site/_posts/2015-04-24-new-committers.md
@@ -5,6 +5,7 @@ date: "2015-04-24 19:03:07 -0800"
 author: jhyde
 categories: [team]
 ---
+<!--
 {% comment %}
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
@@ -21,6 +22,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 {% endcomment %}
+-->
 
 The Calcite project management committee today added five new
 committers for their work on Calcite. Welcome all!

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/530e398b/site/_posts/2015-05-30-release-1.3.0-incubating.md
----------------------------------------------------------------------
diff --git a/site/_posts/2015-05-30-release-1.3.0-incubating.md b/site/_posts/2015-05-30-release-1.3.0-incubating.md
index 254f661..b72765f 100644
--- a/site/_posts/2015-05-30-release-1.3.0-incubating.md
+++ b/site/_posts/2015-05-30-release-1.3.0-incubating.md
@@ -7,6 +7,7 @@ categories: [release]
 tag: v1-3-0
 sha: 495f1859
 ---
+<!--
 {% comment %}
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
@@ -23,6 +24,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 {% endcomment %}
+-->
 
 Mainly bug-fixes, but this release adds support for
 <a href="https://issues.apache.org/jira/browse/CALCITE-505">modifiable views</a>

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/530e398b/site/develop/index.md
----------------------------------------------------------------------
diff --git a/site/develop/index.md b/site/develop/index.md
index 1a93bcd..5082ce0 100644
--- a/site/develop/index.md
+++ b/site/develop/index.md
@@ -2,6 +2,7 @@
 layout: page
 title: Developing
 ---
+<!--
 {% comment %}
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
@@ -18,6 +19,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 {% endcomment %}
+-->
 
 Want to help add a feature or fix a bug?
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/530e398b/site/help/index.md
----------------------------------------------------------------------
diff --git a/site/help/index.md b/site/help/index.md
index 8157c12..65921b4 100644
--- a/site/help/index.md
+++ b/site/help/index.md
@@ -2,6 +2,7 @@
 layout: page
 title: Getting Help
 ---
+<!--
 {% comment %}
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
@@ -18,6 +19,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 {% endcomment %}
+-->
 
 Need help with Calcite? Try these resources.
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/530e398b/site/talks/index.md
----------------------------------------------------------------------
diff --git a/site/talks/index.md b/site/talks/index.md
index 2d24014..65efb1c 100644
--- a/site/talks/index.md
+++ b/site/talks/index.md
@@ -2,6 +2,7 @@
 layout: page
 title: Calcite Talks
 ---
+<!--
 {% comment %}
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
@@ -18,6 +19,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 {% endcomment %}
+-->
 
 Want to learn more about Calcite?