calcite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jh...@apache.org
Subject [4/5] calcite git commit: [CALCITE-707] Add "server" module, with built-in support for simple DDL statements
Date Mon, 27 Nov 2017 19:04:09 GMT
[CALCITE-707] Add "server" module, with built-in support for simple DDL statements

The default parser in core does not contain DDL. We do not want to
impose our DDL dialect on sub-projects.

In server module's parser, add CREATE [FOREIGN] SCHEMA, DROP SCHEMA,
CREATE TABLE, CREATE TABLE AS ..., DROP TABLE, CREATE VIEW,
CREATE MATERIALIZED VIEW, DROP VIEW.

CREATE TABLE supports STORED and VIRTUAL generated
columns, default column values, and constraints.

Add Quidem test in server module; QuidemTest is now abstract, and has
sub-class CoreQuidemTest in core module.

Add class ColumnStrategy, which describes how a column is populated.

All CREATE commands have IF NOT EXISTS (except CREATE VIEW, which has
OR REPLACE), and all DROP commands have IF EXISTS.

Add SqlDdl as base class for SqlCreate and SqlDrop. Add SqlOperator as
first argument to SqlCreate and SqlDrop constructors, and deprecate
previous constructors.

Ensure that collations deduced for Calc are sorted.

Add Static.cons as short-hand for ConsList.of.


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

Branch: refs/heads/master
Commit: 238b3225a2309a1a72bd1383b57982feaa2068e8
Parents: 0ea976e
Author: Julian Hyde <jhyde@apache.org>
Authored: Thu Sep 14 17:33:17 2017 -0700
Committer: Julian Hyde <jhyde@apache.org>
Committed: Sun Nov 26 19:39:28 2017 -0800

----------------------------------------------------------------------
 core/src/main/codegen/templates/Parser.jj       |  80 ++++-
 .../calcite/jdbc/CachingCalciteSchema.java      |  18 +
 .../calcite/jdbc/CalciteConnectionImpl.java     |  21 +-
 .../apache/calcite/jdbc/CalciteMetaImpl.java    |  16 +-
 .../org/apache/calcite/jdbc/CalcitePrepare.java |  21 +-
 .../apache/calcite/jdbc/CalciteResultSet.java   |   3 +-
 .../org/apache/calcite/jdbc/CalciteSchema.java  |  21 ++
 .../materialize/MaterializationService.java     |   4 +
 .../calcite/plan/RelOptAbstractTable.java       |   7 +
 .../calcite/plan/RelOptMaterializations.java    |   2 +-
 .../org/apache/calcite/plan/RelOptTable.java    |   5 +
 .../calcite/prepare/CalcitePrepareImpl.java     |   9 +-
 .../org/apache/calcite/prepare/Prepare.java     |   7 +
 .../apache/calcite/prepare/RelOptTableImpl.java |  87 +++++
 .../apache/calcite/rel/type/RelDataType.java    |   2 +-
 .../java/org/apache/calcite/rex/RexProgram.java |   8 +-
 .../apache/calcite/runtime/CalciteResource.java |  34 +-
 .../org/apache/calcite/runtime/ConsList.java    |   5 +-
 .../apache/calcite/schema/ColumnStrategy.java   |  42 +++
 .../java/org/apache/calcite/schema/Schemas.java |   9 +
 .../calcite/schema/impl/AbstractTable.java      |  15 +-
 .../schema/impl/ModifiableViewTable.java        |  33 +-
 .../java/org/apache/calcite/sql/SqlCreate.java  |  17 +-
 .../java/org/apache/calcite/sql/SqlDdl.java     |  42 +++
 .../java/org/apache/calcite/sql/SqlDrop.java    |  14 +-
 .../calcite/sql/SqlExecutableStatement.java     |   2 +
 .../java/org/apache/calcite/sql/SqlKind.java    |  36 ++
 .../calcite/sql/validate/SqlNameMatcher.java    |   2 +-
 .../calcite/sql/validate/SqlValidatorImpl.java  |  67 +++-
 .../calcite/sql/validate/SqlValidatorTable.java |   8 +-
 .../calcite/sql2rel/InitializerContext.java     |   4 +
 .../sql2rel/InitializerExpressionFactory.java   |  21 ++
 .../NullInitializerExpressionFactory.java       |  19 +-
 .../calcite/sql2rel/SqlToRelConverter.java      | 157 +++++++--
 .../sql2rel/StandardConvertletTable.java        |   4 +
 .../java/org/apache/calcite/util/NameMap.java   |   7 +
 .../org/apache/calcite/util/NameMultimap.java   |  14 +
 .../java/org/apache/calcite/util/Static.java    |   8 +
 .../main/java/org/apache/calcite/util/Util.java |   6 +-
 .../org/apache/calcite/util/graph/Graphs.java   |   5 +-
 .../calcite/runtime/CalciteResource.properties  |  11 +-
 .../calcite/sql/parser/SqlParserTest.java       |  90 ++++-
 .../parserextensiontesting/SqlCreateTable.java  |   8 +-
 .../org/apache/calcite/test/CalciteAssert.java  |  20 ++
 .../org/apache/calcite/test/CalciteSuite.java   |   2 +-
 .../org/apache/calcite/test/CoreQuidemTest.java |  90 +++++
 .../java/org/apache/calcite/test/JdbcTest.java  |   2 +-
 .../apache/calcite/test/MockCatalogReader.java  | 169 ++++++----
 .../org/apache/calcite/test/QuidemTest.java     |  68 +---
 .../apache/calcite/test/RelOptRulesTest.java    |   2 -
 .../apache/calcite/test/SqlToRelTestBase.java   |   9 +
 .../apache/calcite/test/SqlValidatorTest.java   |  17 +-
 core/src/test/resources/sql/blank.iq            |   6 +-
 .../calcite/adapter/mongodb/MongoTable.java     |   5 +-
 pom.xml                                         |   7 +-
 server/pom.xml                                  | 245 ++++++++++++++
 server/src/main/codegen/config.fmpp             |  99 ++++++
 .../src/main/codegen/includes/parserImpls.ftl   | 293 ++++++++++++++++
 .../calcite/sql/ddl/SqlCheckConstraint.java     |  75 ++++
 .../calcite/sql/ddl/SqlColumnDeclaration.java   | 102 ++++++
 .../calcite/sql/ddl/SqlCreateForeignSchema.java | 191 +++++++++++
 .../sql/ddl/SqlCreateMaterializedView.java      | 157 +++++++++
 .../apache/calcite/sql/ddl/SqlCreateSchema.java |  92 +++++
 .../apache/calcite/sql/ddl/SqlCreateTable.java  | 338 +++++++++++++++++++
 .../apache/calcite/sql/ddl/SqlCreateView.java   | 120 +++++++
 .../org/apache/calcite/sql/ddl/SqlDdlNodes.java | 221 ++++++++++++
 .../sql/ddl/SqlDropMaterializedView.java        |  65 ++++
 .../apache/calcite/sql/ddl/SqlDropObject.java   |  93 +++++
 .../apache/calcite/sql/ddl/SqlDropSchema.java   |  89 +++++
 .../apache/calcite/sql/ddl/SqlDropTable.java    |  38 +++
 .../org/apache/calcite/sql/ddl/SqlDropView.java |  38 +++
 .../calcite/sql/ddl/SqlKeyConstraint.java       |  89 +++++
 .../apache/calcite/sql/ddl/package-info.java    |  35 ++
 .../apache/calcite/test/ServerParserTest.java   | 245 ++++++++++++++
 .../apache/calcite/test/ServerQuidemTest.java   |  82 +++++
 .../org/apache/calcite/test/ServerTest.java     | 274 +++++++++++++++
 .../src/test/resources/sql/materialized_view.iq | 272 +++++++++++++++
 server/src/test/resources/sql/schema.iq         | 168 +++++++++
 server/src/test/resources/sql/table.iq          | 154 +++++++++
 server/src/test/resources/sql/table_as.iq       | 251 ++++++++++++++
 server/src/test/resources/sql/view.iq           | 183 ++++++++++
 site/_docs/adapter.md                           |  76 +++++
 site/_docs/reference.md                         |  97 +++++-
 sqlline                                         |   2 +-
 sqlline.bat                                     |   2 +-
 85 files changed, 5314 insertions(+), 260 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/codegen/templates/Parser.jj
----------------------------------------------------------------------
diff --git a/core/src/main/codegen/templates/Parser.jj b/core/src/main/codegen/templates/Parser.jj
index f71abce..fd81f7b 100644
--- a/core/src/main/codegen/templates/Parser.jj
+++ b/core/src/main/codegen/templates/Parser.jj
@@ -704,7 +704,7 @@ SqlNode ParenthesizedExpression(ExprContext exprContext) :
  * <p>which should be illegal.  The above is interpreted as equivalent to
  *
  * <blockquote><pre>
- * <code>WHERE x IN ((select count(*) from t where c=d),5)</pre>
+ * WHERE x IN ((select count(*) from t where c=d),5)</pre>
  * </blockquote>
  *
  * <p>which is a legal use of a sub-query.  The only way to fix the hole is to
@@ -759,6 +759,61 @@ SqlNodeList ParenthesizedQueryOrCommaList(
     }
 }
 
+/** As ParenthesizedQueryOrCommaList, but allows DEFAULT
+ * in place of any of the expressions. For example,
+ * {@code (x, DEFAULT, null, DEFAULT)}. */
+SqlNodeList ParenthesizedQueryOrCommaListWithDefault(
+    ExprContext exprContext) :
+{
+    SqlNode e;
+    List<SqlNode> list;
+    ExprContext firstExprContext = exprContext;
+    final Span s;
+}
+{
+    <LPAREN>
+    {
+        // we've now seen left paren, so a query by itself should
+        // be interpreted as a sub-query
+        s = span();
+        switch (exprContext) {
+        case ACCEPT_SUB_QUERY:
+            firstExprContext = ExprContext.ACCEPT_NONCURSOR;
+            break;
+        case ACCEPT_CURSOR:
+            firstExprContext = ExprContext.ACCEPT_ALL;
+            break;
+        }
+    }
+    (
+        e = OrderedQueryOrExpr(firstExprContext)
+    |
+        e = Default()
+    )
+    {
+        list = startList(e);
+    }
+    (
+        <COMMA>
+        {
+            // a comma-list can't appear where only a query is expected
+            checkNonQueryExpression(exprContext);
+        }
+        (
+            e = Expression(exprContext)
+        |
+            e = Default()
+        )
+        {
+            list.add(e);
+        }
+    )*
+    <RPAREN>
+    {
+        return new SqlNodeList(list, s.end(this));
+    }
+}
+
 /**
  * Parses function parameter lists including DISTINCT keyword recognition,
  * DEFAULT, and named argument assignment.
@@ -823,9 +878,7 @@ void Arg0(List list, ExprContext exprContext) :
         name = SimpleIdentifier() <NAMED_ARGUMENT_ASSIGNMENT>
     ]
     (
-        <DEFAULT_> {
-            e = SqlStdOperatorTable.DEFAULT.createCall(getPos());
-        }
+        e = Default()
     |
         e = OrderedQueryOrExpr(firstExprContext)
     )
@@ -850,9 +903,7 @@ void Arg(List list, ExprContext exprContext) :
         name = SimpleIdentifier() <NAMED_ARGUMENT_ASSIGNMENT>
     ]
     (
-        <DEFAULT_> {
-            e = SqlStdOperatorTable.DEFAULT.createCall(getPos());
-        }
+        e = Default()
     |
         e = Expression(exprContext)
     )
@@ -867,6 +918,13 @@ void Arg(List list, ExprContext exprContext) :
     }
 }
 
+SqlNode Default() : {}
+{
+    <DEFAULT_> {
+        return SqlStdOperatorTable.DEFAULT.createCall(getPos());
+    }
+}
+
 /**
  * Parses a query (SELECT, UNION, INTERSECT, EXCEPT, VALUES, TABLE) followed by
  * the end-of-file symbol.
@@ -903,6 +961,10 @@ SqlNode SqlStmt() :
         stmt = SqlCreate()
     |
 </#if>
+<#if parser.dropStatementParserMethods?size != 0>
+        stmt = SqlDrop()
+    |
+</#if>
         stmt = OrderedQueryOrExpr(ExprContext.ACCEPT_QUERY)
     |
         stmt = SqlExplain()
@@ -2087,7 +2149,7 @@ SqlNode RowConstructor() :
         LOOKAHEAD(3)
         <LPAREN> { s = span(); }
         <ROW>
-        valueList = ParenthesizedQueryOrCommaList(ExprContext.ACCEPT_NONCURSOR)
+        valueList = ParenthesizedQueryOrCommaListWithDefault(ExprContext.ACCEPT_NONCURSOR)
         <RPAREN> { s.add(this); }
     |
         LOOKAHEAD(3)
@@ -2096,7 +2158,7 @@ SqlNode RowConstructor() :
         |
             { s = Span.of(); }
         )
-        valueList = ParenthesizedQueryOrCommaList(ExprContext.ACCEPT_NONCURSOR)
+        valueList = ParenthesizedQueryOrCommaListWithDefault(ExprContext.ACCEPT_NONCURSOR)
     |
         value = Expression(ExprContext.ACCEPT_NONCURSOR)
         {

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/jdbc/CachingCalciteSchema.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CachingCalciteSchema.java b/core/src/main/java/org/apache/calcite/jdbc/CachingCalciteSchema.java
index 4c61a21..96476f1 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CachingCalciteSchema.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CachingCalciteSchema.java
@@ -226,6 +226,24 @@ class CachingCalciteSchema extends CalciteSchema {
     return snapshot;
   }
 
+  @Override public boolean removeTable(String name) {
+    if (cache) {
+      final long now = System.nanoTime();
+      implicitTableCache.enable(now, false);
+      implicitTableCache.enable(now, true);
+    }
+    return super.removeTable(name);
+  }
+
+  @Override public boolean removeFunction(String name) {
+    if (cache) {
+      final long now = System.nanoTime();
+      implicitFunctionCache.enable(now, false);
+      implicitFunctionCache.enable(now, true);
+    }
+    return super.removeFunction(name);
+  }
+
   /** Strategy for caching the value of an object and re-creating it if its
    * value is out of date as of a given timestamp.
    *

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java
index 85dfc65..ff6fb9f 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java
@@ -465,13 +465,15 @@ abstract class CalciteConnectionImpl
   /** Implementation of Context. */
   static class ContextImpl implements CalcitePrepare.Context {
     private final CalciteConnectionImpl connection;
+    private final CalciteSchema mutableRootSchema;
     private final CalciteSchema rootSchema;
 
     ContextImpl(CalciteConnectionImpl connection) {
       this.connection = Preconditions.checkNotNull(connection);
       long now = System.currentTimeMillis();
       SchemaVersion schemaVersion = new LongSchemaVersion(now);
-      this.rootSchema = connection.rootSchema.createSnapshot(schemaVersion);
+      this.mutableRootSchema = connection.rootSchema;
+      this.rootSchema = mutableRootSchema.createSnapshot(schemaVersion);
     }
 
     public JavaTypeFactory getTypeFactory() {
@@ -482,6 +484,10 @@ abstract class CalciteConnectionImpl
       return rootSchema;
     }
 
+    public CalciteSchema getMutableRootSchema() {
+      return mutableRootSchema;
+    }
+
     public List<String> getDefaultSchemaPath() {
       final String schemaName = connection.getSchema();
       return schemaName == null
@@ -502,6 +508,19 @@ abstract class CalciteConnectionImpl
           rootSchema);
     }
 
+    public RelRunner getRelRunner() {
+      final RelRunner runner;
+      try {
+        runner = connection.unwrap(RelRunner.class);
+      } catch (SQLException e) {
+        throw new RuntimeException(e);
+      }
+      if (runner == null) {
+        throw new UnsupportedOperationException();
+      }
+      return runner;
+    }
+
     public CalcitePrepare.SparkHandler spark() {
       final boolean enable = config().spark();
       return CalcitePrepare.Dummy.getSparkHandler(enable);

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/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 c17b6bf..12d6296 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java
@@ -596,13 +596,25 @@ public class CalciteMetaImpl extends MetaImpl {
       synchronized (callback.getMonitor()) {
         callback.clear();
         final CalciteConnectionImpl calciteConnection = getConnection();
-        CalciteServerStatement statement =
+        final CalciteServerStatement statement =
             calciteConnection.server.getStatement(h);
         final Context context = statement.createPrepareContext();
         final CalcitePrepare.Query<Object> query = toQuery(context, sql);
         signature = calciteConnection.parseQuery(query, context, maxRowCount);
         statement.setSignature(signature);
-        callback.assign(signature, null, -1);
+        final int updateCount;
+        switch (signature.statementType) {
+        case CREATE:
+        case DROP:
+        case ALTER:
+        case OTHER_DDL:
+          updateCount = 0; // DDL produces no result set
+          break;
+        default:
+          updateCount = -1; // SELECT and DML produces result set
+          break;
+        }
+        callback.assign(signature, null, updateCount);
       }
       callback.execute();
       final MetaResultSet metaResultSet =

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java b/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
index 56c5385..e0be075 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
@@ -43,6 +43,7 @@ import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.validate.CyclicDefinitionException;
 import org.apache.calcite.sql.validate.SqlValidator;
+import org.apache.calcite.tools.RelRunner;
 import org.apache.calcite.util.ImmutableIntList;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
@@ -109,8 +110,15 @@ public interface CalcitePrepare {
   interface Context {
     JavaTypeFactory getTypeFactory();
 
+    /** Returns the root schema for statements that need a read-consistent
+     * snapshot. */
     CalciteSchema getRootSchema();
 
+    /** Returns the root schema for statements that need to be able to modify
+     * schemas and have the results available to other statements. Viz, DDL
+     * statements. */
+    CalciteSchema getMutableRootSchema();
+
     List<String> getDefaultSchemaPath();
 
     CalciteConnectionConfig config();
@@ -126,6 +134,9 @@ public interface CalcitePrepare {
      * being analyzed further up the stack, the view definition can be deduced
      * to be cyclic. */
     List<String> getObjectPath();
+
+    /** Gets a runner; it can execute a relational expression. */
+    RelRunner getRelRunner();
   }
 
   /** Callback to register Spark as the main engine. */
@@ -319,17 +330,15 @@ public interface CalcitePrepare {
     private final long maxRowCount;
     private final Bindable<T> bindable;
 
+    @Deprecated // to be removed before 2.0
     public CalciteSignature(String sql, List<AvaticaParameter> parameterList,
         Map<String, Object> internalParameters, RelDataType rowType,
         List<ColumnMetaData> columns, Meta.CursorFactory cursorFactory,
         CalciteSchema rootSchema, List<RelCollation> collationList,
         long maxRowCount, Bindable<T> bindable) {
-      super(columns, sql, parameterList, internalParameters, cursorFactory, null);
-      this.rowType = rowType;
-      this.rootSchema = rootSchema;
-      this.collationList = collationList;
-      this.maxRowCount = maxRowCount;
-      this.bindable = bindable;
+      this(sql, parameterList, internalParameters, rowType, columns,
+          cursorFactory, rootSchema, collationList, maxRowCount, bindable,
+          null);
     }
 
     public CalciteSignature(String sql,

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/jdbc/CalciteResultSet.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteResultSet.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteResultSet.java
index 6bc59c7..bf7957f 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalciteResultSet.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteResultSet.java
@@ -83,7 +83,8 @@ public class CalciteResultSet extends AvaticaResultSet {
         new CalcitePrepare.CalciteSignature<>(signature.sql,
             signature.parameters, signature.internalParameters,
             signature.rowType, columnMetaDataList, Meta.CursorFactory.ARRAY,
-            signature.rootSchema, ImmutableList.<RelCollation>of(), -1, null);
+            signature.rootSchema, ImmutableList.<RelCollation>of(), -1, null,
+            statement.getStatementType());
     ResultSetMetaData subResultSetMetaData =
         new AvaticaResultSetMetaData(statement, null, newSignature);
     final CalciteResultSet resultSet =

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/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 f120ec7..b189e1b 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java
@@ -16,6 +16,7 @@
  */
 package org.apache.calcite.jdbc;
 
+import org.apache.calcite.linq4j.function.Experimental;
 import org.apache.calcite.linq4j.tree.Expression;
 import org.apache.calcite.materialize.Lattice;
 import org.apache.calcite.schema.Function;
@@ -460,6 +461,26 @@ public abstract class CalciteSchema {
     return rootSchema;
   }
 
+  @Experimental
+  public boolean removeSubSchema(String name) {
+    return subSchemaMap.remove(name) != null;
+  }
+
+  @Experimental
+  public boolean removeTable(String name) {
+    return tableMap.remove(name) != null;
+  }
+
+  @Experimental
+  public boolean removeFunction(String name) {
+    final FunctionEntry remove = nullaryFunctionMap.remove(name);
+    if (remove == null) {
+      return false;
+    }
+    functionMap.remove(name, remove);
+    return true;
+  }
+
   /**
    * Entry in a schema, such as a table or sub-schema.
    *

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/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 3625a02..39a077f 100644
--- a/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java
+++ b/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java
@@ -351,6 +351,10 @@ public class MaterializationService {
     return INSTANCE;
   }
 
+  public void removeMaterialization(MaterializationKey key) {
+    actor.keyMap.remove(key);
+  }
+
   /**
    * Creates tables that represent a materialized view.
    */

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/plan/RelOptAbstractTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptAbstractTable.java b/core/src/main/java/org/apache/calcite/plan/RelOptAbstractTable.java
index d640aa8..854e42f 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptAbstractTable.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptAbstractTable.java
@@ -17,6 +17,7 @@
 package org.apache.calcite.plan;
 
 import org.apache.calcite.linq4j.tree.Expression;
+import org.apache.calcite.prepare.RelOptTableImpl;
 import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelDistribution;
 import org.apache.calcite.rel.RelDistributions;
@@ -25,6 +26,7 @@ import org.apache.calcite.rel.RelReferentialConstraint;
 import org.apache.calcite.rel.logical.LogicalTableScan;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.schema.ColumnStrategy;
 import org.apache.calcite.util.ImmutableBitSet;
 
 import com.google.common.collect.ImmutableList;
@@ -111,6 +113,11 @@ public abstract class RelOptAbstractTable implements RelOptTable {
   public RelOptTable extend(List<RelDataTypeField> extendedFields) {
     throw new UnsupportedOperationException();
   }
+
+  public List<ColumnStrategy> getColumnStrategies() {
+    return RelOptTableImpl.columnStrategies(this);
+  }
+
 }
 
 // End RelOptAbstractTable.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/plan/RelOptMaterializations.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptMaterializations.java b/core/src/main/java/org/apache/calcite/plan/RelOptMaterializations.java
index ce0c033..3c0362c 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptMaterializations.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptMaterializations.java
@@ -46,7 +46,7 @@ import java.util.Map;
 import java.util.Set;
 
 /**
- * <code>MaterializationOptUtil</code> defines static utility methods for using
+ * Utility methods for using
  * materialized views and lattices for queries.
  */
 public abstract class RelOptMaterializations {

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/plan/RelOptTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptTable.java b/core/src/main/java/org/apache/calcite/plan/RelOptTable.java
index 668dc1c..1e351ac 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptTable.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptTable.java
@@ -25,6 +25,7 @@ import org.apache.calcite.rel.RelRoot;
 import org.apache.calcite.rel.metadata.RelMetadataQuery;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.schema.ColumnStrategy;
 import org.apache.calcite.schema.Wrapper;
 import org.apache.calcite.util.ImmutableBitSet;
 
@@ -119,6 +120,10 @@ public interface RelOptTable extends Wrapper {
    */
   RelOptTable extend(List<RelDataTypeField> extendedFields);
 
+  /** Returns a list describing how each column is populated. The list has the
+   *  same number of entries as there are fields, and is immutable. */
+  List<ColumnStrategy> getColumnStrategies();
+
   /** Can expand a view into relational expressions. */
   interface ViewExpander {
     /**

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/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 74b62d5..a7de759 100644
--- a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
@@ -765,17 +765,12 @@ public class CalcitePrepareImpl implements CalcitePrepare {
       if (sqlNode.getKind().belongsTo(SqlKind.DDL)) {
         executeDdl(context, sqlNode);
 
-        // Return a dummy signature that contains no rows
-        final Bindable<T> bindable = new Bindable<T>() {
-          public Enumerable<T> bind(DataContext dataContext) {
-            return Linq4j.emptyEnumerable();
-          }
-        };
         return new CalciteSignature<>(query.sql,
             ImmutableList.<AvaticaParameter>of(),
             ImmutableMap.<String, Object>of(), null,
             ImmutableList.<ColumnMetaData>of(), Meta.CursorFactory.OBJECT,
-            null, ImmutableList.<RelCollation>of(), -1, bindable);
+            null, ImmutableList.<RelCollation>of(), -1, null,
+            Meta.StatementType.OTHER_DDL);
       }
 
       final SqlValidator validator =

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/prepare/Prepare.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/Prepare.java b/core/src/main/java/org/apache/calcite/prepare/Prepare.java
index 42d8cdf..95758e5 100644
--- a/core/src/main/java/org/apache/calcite/prepare/Prepare.java
+++ b/core/src/main/java/org/apache/calcite/prepare/Prepare.java
@@ -43,6 +43,7 @@ import org.apache.calcite.rex.RexExecutorImpl;
 import org.apache.calcite.runtime.Bindable;
 import org.apache.calcite.runtime.Hook;
 import org.apache.calcite.runtime.Typed;
+import org.apache.calcite.schema.ColumnStrategy;
 import org.apache.calcite.schema.ExtensibleTable;
 import org.apache.calcite.schema.Table;
 import org.apache.calcite.schema.Wrapper;
@@ -429,8 +430,10 @@ public abstract class Prepare {
    * for {@link #columnHasDefaultValue}. */
   public abstract static class AbstractPreparingTable
       implements PreparingTable {
+    @SuppressWarnings("deprecation")
     public boolean columnHasDefaultValue(RelDataType rowType, int ordinal,
         InitializerContext initializerContext) {
+      // This method is no longer used
       final Table table = this.unwrap(Table.class);
       if (table != null && table instanceof Wrapper) {
         final InitializerExpressionFactory initializerExpressionFactory =
@@ -476,6 +479,10 @@ public abstract class Prepare {
     /** Implementation-specific code to instantiate a new {@link RelOptTable}
      * based on a {@link Table} that has been extended. */
     protected abstract RelOptTable extend(Table extendedTable);
+
+    public List<ColumnStrategy> getColumnStrategies() {
+      return RelOptTableImpl.columnStrategies(AbstractPreparingTable.this);
+    }
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java b/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java
index d7a8526..8ed16aa 100644
--- a/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java
@@ -31,8 +31,11 @@ import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelReferentialConstraint;
 import org.apache.calcite.rel.logical.LogicalTableScan;
 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.rel.type.RelRecordType;
 import org.apache.calcite.runtime.Hook;
+import org.apache.calcite.schema.ColumnStrategy;
 import org.apache.calcite.schema.FilterableTable;
 import org.apache.calcite.schema.ModifiableTable;
 import org.apache.calcite.schema.Path;
@@ -46,9 +49,12 @@ import org.apache.calcite.schema.Schemas;
 import org.apache.calcite.schema.StreamableTable;
 import org.apache.calcite.schema.Table;
 import org.apache.calcite.schema.TranslatableTable;
+import org.apache.calcite.schema.Wrapper;
 import org.apache.calcite.sql.SqlAccessType;
 import org.apache.calcite.sql.validate.SqlModality;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
+import org.apache.calcite.sql2rel.InitializerExpressionFactory;
+import org.apache.calcite.sql2rel.NullInitializerExpressionFactory;
 import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Util;
@@ -58,6 +64,7 @@ import com.google.common.base.Functions;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 
+import java.util.AbstractList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Set;
@@ -185,6 +192,12 @@ public class RelOptTableImpl extends Prepare.AbstractPreparingTable {
     if (clazz.isInstance(table)) {
       return clazz.cast(table);
     }
+    if (table instanceof Wrapper) {
+      final T t = ((Wrapper) table).unwrap(clazz);
+      if (t != null) {
+        return t;
+      }
+    }
     if (clazz == CalciteSchema.class) {
       return clazz.cast(
           Schemas.subSchema(((CalciteCatalogReader) schema).rootSchema,
@@ -243,6 +256,30 @@ public class RelOptTableImpl extends Prepare.AbstractPreparingTable {
       return relOptTable.toRel(context);
     }
 
+    // If there are any virtual columns, create a copy of this table without
+    // those virtual columns.
+    final List<ColumnStrategy> strategies = getColumnStrategies();
+    if (strategies.contains(ColumnStrategy.VIRTUAL)) {
+      final RelDataTypeFactory.Builder b =
+          context.getCluster().getTypeFactory().builder();
+      for (RelDataTypeField field : rowType.getFieldList()) {
+        if (strategies.get(field.getIndex()) != ColumnStrategy.VIRTUAL) {
+          b.add(field.getName(), field.getType());
+        }
+      }
+      final RelOptTable relOptTable =
+          new RelOptTableImpl(this.schema, b.build(), this.names, this.table,
+              this.expressionFunction, this.rowCount) {
+            @Override public <T> T unwrap(Class<T> clazz) {
+              if (clazz.isAssignableFrom(InitializerExpressionFactory.class)) {
+                return clazz.cast(NullInitializerExpressionFactory.INSTANCE);
+              }
+              return super.unwrap(clazz);
+            }
+          };
+      return relOptTable.toRel(context);
+    }
+
     if (table instanceof TranslatableTable) {
       return ((TranslatableTable) table).toRel(context, this);
     }
@@ -328,6 +365,56 @@ public class RelOptTableImpl extends Prepare.AbstractPreparingTable {
     return SqlAccessType.ALL;
   }
 
+  /** Helper for {@link #getColumnStrategies()}. */
+  public static List<ColumnStrategy> columnStrategies(final RelOptTable table) {
+    final int fieldCount = table.getRowType().getFieldCount();
+    final InitializerExpressionFactory ief =
+        Util.first(table.unwrap(InitializerExpressionFactory.class),
+            NullInitializerExpressionFactory.INSTANCE);
+    return new AbstractList<ColumnStrategy>() {
+      public int size() {
+        return fieldCount;
+      }
+
+      public ColumnStrategy get(int index) {
+        return ief.generationStrategy(table, index);
+      }
+    };
+  }
+
+  /** Converts the ordinal of a field into the ordinal of a stored field.
+   * That is, it subtracts the number of virtual fields that come before it. */
+  public static int realOrdinal(final RelOptTable table, int i) {
+    List<ColumnStrategy> strategies = table.getColumnStrategies();
+    int n = 0;
+    for (int j = 0; j < i; j++) {
+      switch (strategies.get(j)) {
+      case VIRTUAL:
+        ++n;
+      }
+    }
+    return i - n;
+  }
+
+  /** Returns the row type of a table after any {@link ColumnStrategy#VIRTUAL}
+   * columns have been removed. This is the type of the records that are
+   * actually stored. */
+  public static RelDataType realRowType(RelOptTable table) {
+    final RelDataType rowType = table.getRowType();
+    final List<ColumnStrategy> strategies = columnStrategies(table);
+    if (!strategies.contains(ColumnStrategy.VIRTUAL)) {
+      return rowType;
+    }
+    final RelDataTypeFactory.Builder builder =
+        table.getRelOptSchema().getTypeFactory().builder();
+    for (RelDataTypeField field : rowType.getFieldList()) {
+      if (strategies.get(field.getIndex()) != ColumnStrategy.VIRTUAL) {
+        builder.add(field);
+      }
+    }
+    return builder.build();
+  }
+
   /** Implementation of {@link SchemaPlus} that wraps a regular schema and knows
    * its name and parent.
    *

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/rel/type/RelDataType.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/type/RelDataType.java b/core/src/main/java/org/apache/calcite/rel/type/RelDataType.java
index aa8d495..8299d00 100644
--- a/core/src/main/java/org/apache/calcite/rel/type/RelDataType.java
+++ b/core/src/main/java/org/apache/calcite/rel/type/RelDataType.java
@@ -32,7 +32,7 @@ import java.util.List;
  * different type classes into one. Inelegant, but since our type system was
  * defined before the advent of Java generics, it avoids a lot of typecasting.
  */
-public interface RelDataType /*extends Type*/ {
+public interface RelDataType {
   int SCALE_NOT_SPECIFIED = Integer.MIN_VALUE;
   int PRECISION_NOT_SPECIFIED = -1;
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/rex/RexProgram.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexProgram.java b/core/src/main/java/org/apache/calcite/rex/RexProgram.java
index c91c0f0..152bf35 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexProgram.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexProgram.java
@@ -35,6 +35,7 @@ import org.apache.calcite.util.Permutation;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
+import com.google.common.collect.Ordering;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
@@ -527,10 +528,10 @@ public class RexProgram {
   /**
    * Given a list of collations which hold for the input to this program,
    * returns a list of collations which hold for its output. The result is
-   * mutable.
+   * mutable and sorted.
    */
   public List<RelCollation> getCollations(List<RelCollation> inputCollations) {
-    List<RelCollation> outputCollations = new ArrayList<>(1);
+    final List<RelCollation> outputCollations = new ArrayList<>();
     deduceCollations(
         outputCollations,
         inputRowType.getFieldCount(), projects,
@@ -540,7 +541,7 @@ public class RexProgram {
 
   /**
    * Given a list of expressions and a description of which are ordered,
-   * computes a list of collations. The result is mutable.
+   * populates a list of collations, sorted in natural order.
    */
   public static void deduceCollations(
       List<RelCollation> outputCollations,
@@ -573,6 +574,7 @@ public class RexProgram {
       // to the output.
       outputCollations.add(RelCollations.of(fieldCollations));
     }
+    Collections.sort(outputCollations, Ordering.natural());
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
index 1f34ec7..f122076 100644
--- a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
+++ b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
@@ -445,6 +445,9 @@ public interface CalciteResource {
   @BaseMessage("DEFAULT is only allowed for optional parameters")
   ExInst<SqlValidatorException> defaultForOptionalParameter();
 
+  @BaseMessage("DEFAULT not allowed here")
+  ExInst<SqlValidatorException> defaultNotAllowed();
+
   @BaseMessage("Not allowed to perform {0} on {1}")
   ExInst<SqlValidatorException> accessNotAllowed(String a0, String a1);
 
@@ -521,8 +524,8 @@ public interface CalciteResource {
   @BaseMessage("''{0}'' is not a valid datetime format")
   ExInst<CalciteException> invalidDatetimeFormat(String a0);
 
-  @BaseMessage("Cannot explicitly insert value into IDENTITY column ''{0}'' which is ALWAYS GENERATED")
-  ExInst<CalciteException> insertIntoAlwaysGenerated(String a0);
+  @BaseMessage("Cannot INSERT into generated column ''{0}''")
+  ExInst<SqlValidatorException> insertIntoAlwaysGenerated(String a0);
 
   @BaseMessage("Argument to function ''{0}'' must have a scale of 0")
   ExInst<CalciteException> argumentMustHaveScaleZero(String a0);
@@ -721,6 +724,33 @@ public interface CalciteResource {
 
   @BaseMessage("Rolled up column ''{0}'' is not allowed in {1}")
   ExInst<SqlValidatorException> rolledUpNotAllowed(String column, String context);
+
+  @BaseMessage("Schema ''{0}'' already exists")
+  ExInst<SqlValidatorException> schemaExists(String name);
+
+  @BaseMessage("Invalid schema type ''{0}''; valid values: {1}")
+  ExInst<SqlValidatorException> schemaInvalidType(String type, String values);
+
+  @BaseMessage("Table ''{0}'' already exists")
+  ExInst<SqlValidatorException> tableExists(String name);
+
+  // If CREATE TABLE does not have "AS query", there must be a column list
+  @BaseMessage("Missing column list")
+  ExInst<SqlValidatorException> createTableRequiresColumnList();
+
+  // If CREATE TABLE does not have "AS query", a type must be specified for each
+  // column
+  @BaseMessage("Type required for column ''{0}'' in CREATE TABLE without AS")
+  ExInst<SqlValidatorException> createTableRequiresColumnTypes(String columnName);
+
+  @BaseMessage("View ''{0}'' already exists and REPLACE not specified")
+  ExInst<SqlValidatorException> viewExists(String name);
+
+  @BaseMessage("Schema ''{0}'' not found")
+  ExInst<SqlValidatorException> schemaNotFound(String name);
+
+  @BaseMessage("View ''{0}'' not found")
+  ExInst<SqlValidatorException> viewNotFound(String name);
 }
 
 // End CalciteResource.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/runtime/ConsList.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/runtime/ConsList.java b/core/src/main/java/org/apache/calcite/runtime/ConsList.java
index a30af84..fe53901 100644
--- a/core/src/main/java/org/apache/calcite/runtime/ConsList.java
+++ b/core/src/main/java/org/apache/calcite/runtime/ConsList.java
@@ -37,11 +37,12 @@ public class ConsList<E> extends AbstractImmutableList<E> {
   /** Creates a ConsList.
    * It consists of an element pre-pended to another list.
    * If the other list is mutable, creates an immutable copy. */
-  public static <E> List<E> of(E first, List<E> rest) {
+  public static <E> List<E> of(E first, List<? extends E> rest) {
     if (rest instanceof ConsList
         || rest instanceof ImmutableList
         && !rest.isEmpty()) {
-      return new ConsList<>(first, rest);
+      //noinspection unchecked
+      return new ConsList<>(first, (List<E>) rest);
     } else {
       return ImmutableList.<E>builder().add(first).addAll(rest).build();
     }

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/schema/ColumnStrategy.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/schema/ColumnStrategy.java b/core/src/main/java/org/apache/calcite/schema/ColumnStrategy.java
new file mode 100644
index 0000000..f51175d
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/schema/ColumnStrategy.java
@@ -0,0 +1,42 @@
+/*
+ * 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.schema;
+
+import org.apache.calcite.plan.RelOptTable;
+
+/** Describes how a column gets populated.
+ *
+ * @see org.apache.calcite.sql2rel.InitializerExpressionFactory#generationStrategy
+ * @see RelOptTable#getColumnStrategies()
+ */
+public enum ColumnStrategy {
+  /** Column does not have a default value, but does allow null values.
+   * If you don't specify it in an INSERT, it will get a NULL value. */
+  NULLABLE,
+  /** Column does not have a default value, and does not allow nulls.
+   * You must specify it in an INSERT. */
+  NOT_NULLABLE,
+  /** Column has a default value.
+   * If you don't specify it in an INSERT, it will get a NULL value. */
+  DEFAULT,
+  /** Column is computed and stored. You cannot insert into it. */
+  STORED,
+  /** Column is computed and not stored. You cannot insert into it. */
+  VIRTUAL
+}
+
+// End ColumnStrategy.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/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 6466d31..a13df14 100644
--- a/core/src/main/java/org/apache/calcite/schema/Schemas.java
+++ b/core/src/main/java/org/apache/calcite/schema/Schemas.java
@@ -37,6 +37,7 @@ import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rel.type.RelProtoDataType;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.sql.type.SqlTypeUtil;
+import org.apache.calcite.tools.RelRunner;
 import org.apache.calcite.util.BuiltInMethod;
 import org.apache.calcite.util.Pair;
 
@@ -407,6 +408,10 @@ public final class Schemas {
         return schema.root();
       }
 
+      public CalciteSchema getMutableRootSchema() {
+        return getRootSchema();
+      }
+
       public List<String> getDefaultSchemaPath() {
         // schemaPath is usually null. If specified, it overrides schema
         // as the context within which the SQL is validated.
@@ -428,6 +433,10 @@ public final class Schemas {
         return dataContext;
       }
 
+      public RelRunner getRelRunner() {
+        throw new UnsupportedOperationException();
+      }
+
       public CalcitePrepare.SparkHandler spark() {
         final boolean enable = config().spark();
         return CalcitePrepare.Dummy.getSparkHandler(enable);

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/schema/impl/AbstractTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/schema/impl/AbstractTable.java b/core/src/main/java/org/apache/calcite/schema/impl/AbstractTable.java
index 2f2b6bf..d2e92cb 100644
--- a/core/src/main/java/org/apache/calcite/schema/impl/AbstractTable.java
+++ b/core/src/main/java/org/apache/calcite/schema/impl/AbstractTable.java
@@ -21,6 +21,7 @@ import org.apache.calcite.schema.Schema;
 import org.apache.calcite.schema.Statistic;
 import org.apache.calcite.schema.Statistics;
 import org.apache.calcite.schema.Table;
+import org.apache.calcite.schema.Wrapper;
 import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlNode;
 
@@ -32,7 +33,7 @@ import org.apache.calcite.sql.SqlNode;
  * if their table can potentially contain rolled up values. This information is
  * used by the validator to check for illegal uses of these columns.
  */
-public abstract class AbstractTable implements Table {
+public abstract class AbstractTable implements Table, Wrapper {
   protected AbstractTable() {
   }
 
@@ -45,13 +46,19 @@ public abstract class AbstractTable implements Table {
     return Schema.TableType.TABLE;
   }
 
+  public <C> C unwrap(Class<C> aClass) {
+    if (aClass.isInstance(this)) {
+      return aClass.cast(this);
+    }
+    return null;
+  }
+
   @Override public boolean isRolledUp(String column) {
     return false;
   }
 
-  @Override public boolean rolledUpColumnValidInsideAgg(String column, SqlCall call,
-                                                        SqlNode parent,
-                                                        CalciteConnectionConfig config) {
+  @Override public boolean rolledUpColumnValidInsideAgg(String column,
+      SqlCall call, SqlNode parent, CalciteConnectionConfig config) {
     return true;
   }
 }

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/schema/impl/ModifiableViewTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/schema/impl/ModifiableViewTable.java b/core/src/main/java/org/apache/calcite/schema/impl/ModifiableViewTable.java
index 241927b..a312188 100644
--- a/core/src/main/java/org/apache/calcite/schema/impl/ModifiableViewTable.java
+++ b/core/src/main/java/org/apache/calcite/schema/impl/ModifiableViewTable.java
@@ -25,6 +25,7 @@ import org.apache.calcite.rel.type.RelDataTypeImpl;
 import org.apache.calcite.rel.type.RelProtoDataType;
 import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.schema.ColumnStrategy;
 import org.apache.calcite.schema.ExtensibleTable;
 import org.apache.calcite.schema.ModifiableView;
 import org.apache.calcite.schema.Path;
@@ -92,7 +93,7 @@ public class ModifiableViewTable extends ViewTable
     } else if (aClass.isInstance(table)) {
       return aClass.cast(table);
     }
-    return null;
+    return super.unwrap(aClass);
   }
 
   /**
@@ -192,9 +193,31 @@ public class ModifiableViewTable extends ViewTable
       this.projectMap = ImmutableMap.copyOf(projectMap);
     }
 
-    @Override public boolean isGeneratedAlways(RelOptTable table, int iColumn) {
-      assert table.unwrap(ModifiableViewTable.class) != null;
-      return false;
+    @Override public ColumnStrategy generationStrategy(RelOptTable table,
+        int iColumn) {
+      final ModifiableViewTable viewTable =
+          table.unwrap(ModifiableViewTable.class);
+      assert iColumn < viewTable.columnMapping.size();
+
+      // Use the view constraint to generate the default value if the column is
+      // constrained.
+      final int mappedOrdinal = viewTable.columnMapping.get(iColumn);
+      final RexNode viewConstraint = projectMap.get(mappedOrdinal);
+      if (viewConstraint != null) {
+        return ColumnStrategy.DEFAULT;
+      }
+
+      // Otherwise use the default value of the underlying table.
+      final Table schemaTable = viewTable.getTable();
+      if (schemaTable instanceof Wrapper) {
+        final InitializerExpressionFactory initializerExpressionFactory =
+            ((Wrapper) schemaTable).unwrap(InitializerExpressionFactory.class);
+        if (initializerExpressionFactory != null) {
+          return initializerExpressionFactory.generationStrategy(table,
+              iColumn);
+        }
+      }
+      return super.generationStrategy(table, iColumn);
     }
 
     @Override public RexNode newColumnDefaultValue(RelOptTable table,
@@ -214,7 +237,7 @@ public class ModifiableViewTable extends ViewTable
       }
 
       // Otherwise use the default value of the underlying table.
-      final Table schemaTable = viewTable.unwrap(Table.class);
+      final Table schemaTable = viewTable.getTable();
       if (schemaTable instanceof Wrapper) {
         final InitializerExpressionFactory initializerExpressionFactory =
             ((Wrapper) schemaTable).unwrap(InitializerExpressionFactory.class);

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/sql/SqlCreate.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlCreate.java b/core/src/main/java/org/apache/calcite/sql/SqlCreate.java
index 57e9a71..b03390e 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlCreate.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlCreate.java
@@ -23,14 +23,25 @@ import org.apache.calcite.sql.parser.SqlParserPos;
  * statement covered by this class is "CREATE [ OR REPLACE ]". Subclasses handle
  * whatever comes afterwards.
  */
-public abstract class SqlCreate extends SqlCall {
+public abstract class SqlCreate extends SqlDdl {
 
   /** Whether "OR REPLACE" was specified. */
   boolean replace;
 
-  public SqlCreate(SqlParserPos pos, boolean replace) {
-    super(pos);
+  /** Whether "IF NOT EXISTS" was specified. */
+  protected final boolean ifNotExists;
+
+  /** Creates a SqlCreate. */
+  public SqlCreate(SqlOperator operator, SqlParserPos pos, boolean replace,
+      boolean ifNotExists) {
+    super(operator, pos);
     this.replace = replace;
+    this.ifNotExists = ifNotExists;
+  }
+
+  @Deprecated // to be removed before 2.0
+  public SqlCreate(SqlParserPos pos, boolean replace) {
+    this(SqlDdl.DDL_OPERATOR, pos, replace, false);
   }
 
   public boolean getReplace() {

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/sql/SqlDdl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlDdl.java b/core/src/main/java/org/apache/calcite/sql/SqlDdl.java
new file mode 100644
index 0000000..c22abb6
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/sql/SqlDdl.java
@@ -0,0 +1,42 @@
+/*
+ * 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.sql;
+
+import org.apache.calcite.sql.parser.SqlParserPos;
+
+import com.google.common.base.Preconditions;
+
+/** Base class for CREATE, DROP and other DDL statements. */
+public abstract class SqlDdl extends SqlCall {
+  /** Use this operator only if you don't have a better one. */
+  protected static final SqlOperator DDL_OPERATOR =
+      new SqlSpecialOperator("DDL", SqlKind.OTHER_DDL);
+
+  private final SqlOperator operator;
+
+  /** Creates a SqlDdl. */
+  public SqlDdl(SqlOperator operator, SqlParserPos pos) {
+    super(pos);
+    this.operator = Preconditions.checkNotNull(operator);
+  }
+
+  public SqlOperator getOperator() {
+    return operator;
+  }
+}
+
+// End SqlDdl.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/sql/SqlDrop.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlDrop.java b/core/src/main/java/org/apache/calcite/sql/SqlDrop.java
index 1716d32..55dc217 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlDrop.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlDrop.java
@@ -23,10 +23,20 @@ import org.apache.calcite.sql.parser.SqlParserPos;
  * statement covered by this class is "DROP". Subclasses handle
  * whatever comes afterwards.
  */
-public abstract class SqlDrop extends SqlCall {
+public abstract class SqlDrop extends SqlDdl {
 
+  /** Whether "IF EXISTS" was specified. */
+  protected final boolean ifExists;
+
+  /** Creates a SqlDrop. */
+  public SqlDrop(SqlOperator operator, SqlParserPos pos, boolean ifExists) {
+    super(operator, pos);
+    this.ifExists = ifExists;
+  }
+
+  @Deprecated // to be removed before 2.0
   public SqlDrop(SqlParserPos pos) {
-    super(pos);
+    this(DDL_OPERATOR, pos, false);
   }
 
 }

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/sql/SqlExecutableStatement.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlExecutableStatement.java b/core/src/main/java/org/apache/calcite/sql/SqlExecutableStatement.java
index 06ca55f..c309a27 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlExecutableStatement.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlExecutableStatement.java
@@ -17,6 +17,7 @@
 package org.apache.calcite.sql;
 
 import org.apache.calcite.jdbc.CalcitePrepare;
+import org.apache.calcite.linq4j.function.Experimental;
 
 /**
  * Mix-in interface for {@link SqlNode} that allows DDL commands to be
@@ -24,6 +25,7 @@ import org.apache.calcite.jdbc.CalcitePrepare;
  *
  * <p>NOTE: Subject to change without notice.
  */
+@Experimental
 public interface SqlExecutableStatement {
   void execute(CalcitePrepare.Context context);
 }

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/sql/SqlKind.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlKind.java b/core/src/main/java/org/apache/calcite/sql/SqlKind.java
index 8d7c8aa..76d7f3c 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlKind.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlKind.java
@@ -938,6 +938,21 @@ public enum SqlKind {
    * the {@link #SESSION} group function. */
   SESSION_END,
 
+  /** Column declaration. */
+  COLUMN_DECL,
+
+  /** {@code CHECK} constraint. */
+  CHECK,
+
+  /** {@code UNIQUE} constraint. */
+  UNIQUE,
+
+  /** {@code PRIMARY KEY} constraint. */
+  PRIMARY_KEY,
+
+  /** {@code FOREIGN KEY} constraint. */
+  FOREIGN_KEY,
+
   // DDL and session control statements follow. The list is not exhaustive: feel
   // free to add more.
 
@@ -950,6 +965,15 @@ public enum SqlKind {
   /** {@code ALTER SESSION} DDL statement. */
   ALTER_SESSION,
 
+  /** {@code CREATE SCHEMA} DDL statement. */
+  CREATE_SCHEMA,
+
+  /** {@code CREATE FOREIGN SCHEMA} DDL statement. */
+  CREATE_FOREIGN_SCHEMA,
+
+  /** {@code DROP SCHEMA} DDL statement. */
+  DROP_SCHEMA,
+
   /** {@code CREATE TABLE} DDL statement. */
   CREATE_TABLE,
 
@@ -968,6 +992,15 @@ public enum SqlKind {
   /** {@code DROP VIEW} DDL statement. */
   DROP_VIEW,
 
+  /** {@code CREATE MATERIALIZED VIEW} DDL statement. */
+  CREATE_MATERIALIZED_VIEW,
+
+  /** {@code ALTER MATERIALIZED VIEW} DDL statement. */
+  ALTER_MATERIALIZED_VIEW,
+
+  /** {@code DROP MATERIALIZED VIEW} DDL statement. */
+  DROP_MATERIALIZED_VIEW,
+
   /** {@code CREATE SEQUENCE} DDL statement. */
   CREATE_SEQUENCE,
 
@@ -1045,8 +1078,11 @@ public enum SqlKind {
    */
   public static final EnumSet<SqlKind> DDL =
       EnumSet.of(COMMIT, ROLLBACK, ALTER_SESSION,
+          CREATE_SCHEMA, CREATE_FOREIGN_SCHEMA, DROP_SCHEMA,
           CREATE_TABLE, ALTER_TABLE, DROP_TABLE,
           CREATE_VIEW, ALTER_VIEW, DROP_VIEW,
+          CREATE_MATERIALIZED_VIEW, ALTER_MATERIALIZED_VIEW,
+          DROP_MATERIALIZED_VIEW,
           CREATE_SEQUENCE, ALTER_SEQUENCE, DROP_SEQUENCE,
           CREATE_INDEX, ALTER_INDEX, DROP_INDEX,
           SET_OPTION, OTHER_DDL);

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/sql/validate/SqlNameMatcher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlNameMatcher.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlNameMatcher.java
index 104f3d2..c8d75ee 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlNameMatcher.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlNameMatcher.java
@@ -49,7 +49,7 @@ public interface SqlNameMatcher {
    * throws {@link UnsupportedOperationException}. */
   String bestString();
 
-  /** Finds a field with a given name, using the currenct case-sensitivity,
+  /** Finds a field with a given name, using the current case-sensitivity,
    * returning null if not found.
    *
    * @param rowType    Row type

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
index 940c8ac..cb134cf 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
@@ -37,6 +37,7 @@ import org.apache.calcite.runtime.CalciteContextException;
 import org.apache.calcite.runtime.CalciteException;
 import org.apache.calcite.runtime.Feature;
 import org.apache.calcite.runtime.Resources;
+import org.apache.calcite.schema.ColumnStrategy;
 import org.apache.calcite.schema.Table;
 import org.apache.calcite.schema.impl.ModifiableViewTable;
 import org.apache.calcite.sql.JoinConditionType;
@@ -3727,7 +3728,7 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
       }
     }
     final SqlValidatorScope orderScope = getOrderScope(select);
-    Preconditions.checkNotNull(orderScope != null);
+    Preconditions.checkNotNull(orderScope);
 
     List<SqlNode> expandList = new ArrayList<>();
     for (SqlNode orderItem : orderList) {
@@ -4154,8 +4155,8 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
     final RelDataType logicalSourceRowType =
         getLogicalSourceRowType(sourceRowType, insert);
 
-    checkFieldCount(insert.getTargetTable(), table, logicalSourceRowType,
-        logicalTargetRowType);
+    checkFieldCount(insert.getTargetTable(), table, source,
+        logicalSourceRowType, logicalTargetRowType);
 
     checkTypeAssignment(logicalSourceRowType, logicalTargetRowType, insert);
 
@@ -4260,10 +4261,8 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
     }
   }
 
-  private void checkFieldCount(
-      SqlNode node,
-      SqlValidatorTable table,
-      RelDataType logicalSourceRowType,
+  private void checkFieldCount(SqlNode node, SqlValidatorTable table,
+      SqlNode source, RelDataType logicalSourceRowType,
       RelDataType logicalTargetRowType) {
     final int sourceFieldCount = logicalSourceRowType.getFieldCount();
     final int targetFieldCount = logicalTargetRowType.getFieldCount();
@@ -4277,19 +4276,61 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
           public RexBuilder getRexBuilder() {
             return new RexBuilder(typeFactory);
           }
+
+          public RexNode convertExpression(SqlNode e) {
+            throw new UnsupportedOperationException();
+          }
         };
+    final List<ColumnStrategy> strategies =
+        table.unwrap(RelOptTable.class).getColumnStrategies();
     for (final RelDataTypeField field : table.getRowType().getFieldList()) {
-      if (!field.getType().isNullable()) {
-        final RelDataTypeField targetField =
-            logicalTargetRowType.getField(field.getName(), true, false);
-        if (targetField == null
-            && !table.columnHasDefaultValue(table.getRowType(),
-                field.getIndex(), rexBuilder)) {
+      final RelDataTypeField targetField =
+          logicalTargetRowType.getField(field.getName(), true, false);
+      switch (strategies.get(field.getIndex())) {
+      case NOT_NULLABLE:
+        assert !field.getType().isNullable();
+        if (targetField == null) {
           throw newValidationError(node,
               RESOURCE.columnNotNullable(field.getName()));
         }
+        break;
+      case NULLABLE:
+        assert field.getType().isNullable();
+        break;
+      case VIRTUAL:
+      case STORED:
+        if (targetField != null
+            && !isValuesWithDefault(source, targetField.getIndex())) {
+          throw newValidationError(node,
+              RESOURCE.insertIntoAlwaysGenerated(field.getName()));
+        }
+      }
+    }
+  }
+
+  /** Returns whether a query uses {@code DEFAULT} to populate a given
+   *  column. */
+  private boolean isValuesWithDefault(SqlNode source, int column) {
+    switch (source.getKind()) {
+    case VALUES:
+      for (SqlNode operand : ((SqlCall) source).getOperandList()) {
+        if (!isRowWithDefault(operand, column)) {
+          return false;
+        }
       }
+      return true;
     }
+    return false;
+  }
+
+  private boolean isRowWithDefault(SqlNode operand, int column) {
+    switch (operand.getKind()) {
+    case ROW:
+      final SqlCall row = (SqlCall) operand;
+      return row.getOperandList().size() >= column
+          && row.getOperandList().get(column).getKind() == SqlKind.DEFAULT;
+    }
+    return false;
   }
 
   protected RelDataType getLogicalTargetRowType(

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorTable.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorTable.java
index fd923f0..b660050 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorTable.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorTable.java
@@ -17,6 +17,7 @@
 package org.apache.calcite.sql.validate;
 
 import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.schema.Wrapper;
 import org.apache.calcite.sql.SqlAccessType;
 import org.apache.calcite.sql2rel.InitializerContext;
 
@@ -27,7 +28,7 @@ import java.util.List;
  *
  * @see SqlValidatorCatalogReader
  */
-public interface SqlValidatorTable {
+public interface SqlValidatorTable extends Wrapper {
 
   //~ Methods ----------------------------------------------------------------
 
@@ -50,13 +51,10 @@ public interface SqlValidatorTable {
   /**
    * Returns whether the ordinal column has a default value.
    */
+  @Deprecated // to be removed before 2.0
   boolean columnHasDefaultValue(RelDataType rowType, int ordinal,
       InitializerContext initializerContext);
 
-  /**
-   * Finds an interface implemented by this table.
-   */
-  <T> T unwrap(Class<T> clazz);
 }
 
 // End SqlValidatorTable.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/sql2rel/InitializerContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/InitializerContext.java b/core/src/main/java/org/apache/calcite/sql2rel/InitializerContext.java
index 66692e3..b16bede 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/InitializerContext.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/InitializerContext.java
@@ -17,12 +17,16 @@
 package org.apache.calcite.sql2rel;
 
 import org.apache.calcite.rex.RexBuilder;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.sql.SqlNode;
 
 /**
  * Provides context for {@link InitializerExpressionFactory} methods.
  */
 public interface InitializerContext {
   RexBuilder getRexBuilder();
+
+  RexNode convertExpression(SqlNode e);
 }
 
 // End InitializerContext.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/sql2rel/InitializerExpressionFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/InitializerExpressionFactory.java b/core/src/main/java/org/apache/calcite/sql2rel/InitializerExpressionFactory.java
index 4fa40b9..3f300ab 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/InitializerExpressionFactory.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/InitializerExpressionFactory.java
@@ -19,6 +19,7 @@ package org.apache.calcite.sql2rel;
 import org.apache.calcite.plan.RelOptTable;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.schema.ColumnStrategy;
 import org.apache.calcite.sql.SqlFunction;
 
 import java.util.List;
@@ -32,12 +33,32 @@ public interface InitializerExpressionFactory {
   /**
    * Whether a column is always generated. If a column is always generated,
    * then non-generated values cannot be inserted into the column.
+   *
+   * @see #generationStrategy(RelOptTable, int)
+   *
+   * @deprecated Use {@code c.generationStrategy(t, i) == VIRTUAL
+   * || c.generationStrategy(t, i) == STORED}
    */
+  @Deprecated // to be removed before 2.0
   boolean isGeneratedAlways(
       RelOptTable table,
       int iColumn);
 
   /**
+   * Returns how a column is populated.
+   *
+   * @param table   the table containing the column
+   * @param iColumn the 0-based offset of the column in the table
+   *
+   * @return generation strategy, never null
+   *
+   * @see RelOptTable#getColumnStrategies()
+   */
+  ColumnStrategy generationStrategy(
+      RelOptTable table,
+      int iColumn);
+
+  /**
    * Creates an expression which evaluates to the default value for a
    * particular column.
    *

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/sql2rel/NullInitializerExpressionFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/NullInitializerExpressionFactory.java b/core/src/main/java/org/apache/calcite/sql2rel/NullInitializerExpressionFactory.java
index 09925f0..1959790 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/NullInitializerExpressionFactory.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/NullInitializerExpressionFactory.java
@@ -19,6 +19,7 @@ package org.apache.calcite.sql2rel;
 import org.apache.calcite.plan.RelOptTable;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.schema.ColumnStrategy;
 import org.apache.calcite.sql.SqlFunction;
 
 import java.util.List;
@@ -28,11 +29,27 @@ import java.util.List;
  */
 public class NullInitializerExpressionFactory implements InitializerExpressionFactory {
 
+  public static final InitializerExpressionFactory INSTANCE =
+      new NullInitializerExpressionFactory();
+
   public NullInitializerExpressionFactory() {
   }
 
+  @SuppressWarnings("deprecation")
   public boolean isGeneratedAlways(RelOptTable table, int iColumn) {
-    return false;
+    switch (generationStrategy(table, iColumn)) {
+    case VIRTUAL:
+    case STORED:
+      return true;
+    default:
+      return false;
+    }
+  }
+
+  public ColumnStrategy generationStrategy(RelOptTable table, int iColumn) {
+    return table.getRowType().getFieldList().get(iColumn).getType().isNullable()
+        ? ColumnStrategy.NULLABLE
+        : ColumnStrategy.NOT_NULLABLE;
   }
 
   public RexNode newColumnDefaultValue(RelOptTable table, int iColumn,

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
index 08fc4b0..24fd111 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -85,6 +85,7 @@ import org.apache.calcite.rex.RexShuttle;
 import org.apache.calcite.rex.RexSubQuery;
 import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.rex.RexWindowBound;
+import org.apache.calcite.schema.ColumnStrategy;
 import org.apache.calcite.schema.ModifiableTable;
 import org.apache.calcite.schema.ModifiableView;
 import org.apache.calcite.schema.Table;
@@ -170,6 +171,7 @@ import org.apache.calcite.util.trace.CalciteTrace;
 
 import com.google.common.base.Function;
 import com.google.common.base.Preconditions;
+import com.google.common.base.Supplier;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableList.Builder;
 import com.google.common.collect.ImmutableMap;
@@ -198,7 +200,6 @@ import java.util.Set;
 import java.util.TreeSet;
 
 import static org.apache.calcite.sql.SqlUtil.stripAs;
-import static org.apache.calcite.util.Static.RESOURCE;
 
 /**
  * Converts a SQL parse tree (consisting of
@@ -3110,7 +3111,8 @@ public class SqlToRelConverter {
   private RelNode createModify(RelOptTable targetTable, RelNode source) {
     final ModifiableTable modifiableTable =
         targetTable.unwrap(ModifiableTable.class);
-    if (modifiableTable != null) {
+    if (modifiableTable != null
+        && modifiableTable == targetTable.unwrap(Table.class)) {
       return modifiableTable.toModificationRel(cluster, targetTable,
           catalogReader, source, LogicalTableModify.Operation.INSERT, null,
           null, false);
@@ -3199,8 +3201,44 @@ public class SqlToRelConverter {
     };
   }
 
-  public RelNode toRel(RelOptTable table) {
-    return table.toRel(createToRelContext());
+  public RelNode toRel(final RelOptTable table) {
+    final RelNode scan = table.toRel(createToRelContext());
+
+    final InitializerExpressionFactory ief =
+        Util.first(table.unwrap(InitializerExpressionFactory.class),
+            NullInitializerExpressionFactory.INSTANCE);
+
+    // Lazily create a blackboard that contains all non-generated columns.
+    final Supplier<Blackboard> bb = new Supplier<Blackboard>() {
+      public Blackboard get() {
+        RexNode sourceRef = rexBuilder.makeRangeReference(scan);
+        return createInsertBlackboard(table, sourceRef,
+            table.getRowType().getFieldNames());
+      }
+    };
+
+    int virtualCount = 0;
+    final List<RexNode> list = new ArrayList<>();
+    for (RelDataTypeField f : table.getRowType().getFieldList()) {
+      final ColumnStrategy strategy =
+          ief.generationStrategy(table, f.getIndex());
+      switch (strategy) {
+      case VIRTUAL:
+        list.add(ief.newColumnDefaultValue(table, f.getIndex(), bb.get()));
+        ++virtualCount;
+        break;
+      default:
+        list.add(
+            rexBuilder.makeInputRef(scan,
+                RelOptTableImpl.realOrdinal(table, f.getIndex())));
+      }
+    }
+    if (virtualCount > 0) {
+      relBuilder.push(scan);
+      relBuilder.project(list);
+      return relBuilder.build();
+    }
+    return scan;
   }
 
   protected RelOptTable getTargetTable(SqlNode call) {
@@ -3226,13 +3264,11 @@ public class SqlToRelConverter {
    * default values and the source expressions provided.
    *
    * @param call      Insert expression
-   * @param sourceRel Source relational expression
+   * @param source Source relational expression
    * @return Converted INSERT statement
    */
-  protected RelNode convertColumnList(
-      SqlInsert call,
-      RelNode sourceRel) {
-    RelDataType sourceRowType = sourceRel.getRowType();
+  protected RelNode convertColumnList(final SqlInsert call, RelNode source) {
+    RelDataType sourceRowType = source.getRowType();
     final RexNode sourceRef =
         rexBuilder.makeRangeReference(sourceRowType, 0, false);
     final List<String> targetColumnNames = new ArrayList<>();
@@ -3240,9 +3276,8 @@ public class SqlToRelConverter {
     collectInsertTargets(call, sourceRef, targetColumnNames, columnExprs);
 
     final RelOptTable targetTable = getTargetTable(call);
-    final RelDataType targetRowType = targetTable.getRowType();
-    final List<RelDataTypeField> targetFields =
-        targetRowType.getFieldList();
+    final RelDataType targetRowType = RelOptTableImpl.realRowType(targetTable);
+    final List<RelDataTypeField> targetFields = targetRowType.getFieldList();
     final List<RexNode> sourceExps =
         new ArrayList<>(
             Collections.<RexNode>nCopies(targetFields.size(), null));
@@ -3264,32 +3299,56 @@ public class SqlToRelConverter {
       sourceExps.set(field.getIndex(), p.right);
     }
 
+    // Lazily create a blackboard that contains all non-generated columns.
+    final Supplier<Blackboard> bb = new Supplier<Blackboard>() {
+      public Blackboard get() {
+        return createInsertBlackboard(targetTable, sourceRef,
+            targetColumnNames);
+      }
+    };
+
     // Walk the expression list and get default values for any columns
     // that were not supplied in the statement. Get field names too.
     for (int i = 0; i < targetFields.size(); ++i) {
       final RelDataTypeField field = targetFields.get(i);
       final String fieldName = field.getName();
       fieldNames.set(i, fieldName);
-      if (sourceExps.get(i) != null) {
-        if (initializerFactory.isGeneratedAlways(targetTable, i)) {
-          throw RESOURCE.insertIntoAlwaysGenerated(fieldName).ex();
-        }
-        continue;
-      }
-      sourceExps.set(i,
-          initializerFactory.newColumnDefaultValue(targetTable, i,
-              new InitializerContext() {
-                public RexBuilder getRexBuilder() {
-                  return rexBuilder;
-                }
-              }));
+      if (sourceExps.get(i) == null
+          || sourceExps.get(i).getKind() == SqlKind.DEFAULT) {
+        sourceExps.set(i,
+            initializerFactory.newColumnDefaultValue(targetTable, i, bb.get()));
 
-      // bare nulls are dangerous in the wrong hands
-      sourceExps.set(i,
-          castNullLiteralIfNeeded(sourceExps.get(i), field.getType()));
+        // bare nulls are dangerous in the wrong hands
+        sourceExps.set(i,
+            castNullLiteralIfNeeded(sourceExps.get(i), field.getType()));
+      }
     }
 
-    return RelOptUtil.createProject(sourceRel, sourceExps, fieldNames, true);
+    return RelOptUtil.createProject(source, sourceExps, fieldNames, true);
+  }
+
+  /** Creates a blackboard for translating the expressions of generated columns
+   * in an INSERT statement. */
+  private Blackboard createInsertBlackboard(RelOptTable targetTable,
+      RexNode sourceRef, List<String> targetColumnNames) {
+    final Map<String, RexNode> nameToNodeMap = new HashMap<>();
+    int j = 0;
+
+    // Assign expressions for non-generated columns.
+    final List<ColumnStrategy> strategies = targetTable.getColumnStrategies();
+    final List<String> targetFields = targetTable.getRowType().getFieldNames();
+    for (String targetColumnName : targetColumnNames) {
+      final int i = targetFields.indexOf(targetColumnName);
+      switch (strategies.get(i)) {
+      case STORED:
+      case VIRTUAL:
+        break;
+      default:
+        nameToNodeMap.put(targetColumnName,
+            rexBuilder.makeFieldAccess(sourceRef, j++));
+      }
+    }
+    return createBlackboard(null, nameToNodeMap, false);
   }
 
   private InitializerExpressionFactory getInitializerFactory(
@@ -3303,7 +3362,7 @@ public class SqlToRelConverter {
         return f;
       }
     }
-    return new NullInitializerExpressionFactory();
+    return NullInitializerExpressionFactory.INSTANCE;
   }
 
   private static <T> T unwrap(Object o, Class<T> clazz) {
@@ -3359,10 +3418,38 @@ public class SqlToRelConverter {
       }
     }
 
-    for (int i = 0; i < targetColumnNames.size(); i++) {
-      final RexNode expr = rexBuilder.makeFieldAccess(sourceRef, i);
+    final Blackboard bb =
+        createInsertBlackboard(targetTable, sourceRef, targetColumnNames);
+
+    // Next, assign expressions for generated columns.
+    final List<ColumnStrategy> strategies = targetTable.getColumnStrategies();
+    for (String columnName : targetColumnNames) {
+      final int i = tableRowType.getFieldNames().indexOf(columnName);
+      final RexNode expr;
+      switch (strategies.get(i)) {
+      case STORED:
+        final InitializerExpressionFactory f =
+            Util.first(targetTable.unwrap(InitializerExpressionFactory.class),
+                NullInitializerExpressionFactory.INSTANCE);
+        expr = f.newColumnDefaultValue(targetTable, i, bb);
+        break;
+      case VIRTUAL:
+        expr = null;
+        break;
+      default:
+        expr = bb.nameToNodeMap.get(columnName);
+      }
       columnExprs.add(expr);
     }
+
+    // Remove virtual columns from the list.
+    for (int i = 0; i < targetColumnNames.size(); i++) {
+      if (columnExprs.get(i) == null) {
+        columnExprs.remove(i);
+        targetColumnNames.remove(i);
+        --i;
+      }
+    }
   }
 
   private RelNode convertDelete(SqlDelete call) {
@@ -3890,7 +3977,8 @@ public class SqlToRelConverter {
   /**
    * Workspace for translating an individual SELECT statement (or sub-SELECT).
    */
-  protected class Blackboard implements SqlRexContext, SqlVisitor<RexNode> {
+  protected class Blackboard implements SqlRexContext, SqlVisitor<RexNode>,
+      InitializerContext {
     /**
      * Collection of {@link RelNode} objects which correspond to a SELECT
      * statement.
@@ -4231,6 +4319,9 @@ public class SqlToRelConverter {
     }
 
     RelDataTypeField getRootField(RexInputRef inputRef) {
+      if (inputs == null) {
+        return null;
+      }
       int fieldOffset = inputRef.getIndex();
       for (RelNode input : inputs) {
         RelDataType rowType = input.getRowType();

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
index 158ffa6..fe92d4b 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
@@ -781,6 +781,10 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
       public RexBuilder getRexBuilder() {
         return rexBuilder;
       }
+
+      public RexNode convertExpression(SqlNode e) {
+        throw new UnsupportedOperationException();
+      }
     };
     for (int i = 0; i < n; ++i) {
       initializationExprs.add(

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/util/NameMap.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/NameMap.java b/core/src/main/java/org/apache/calcite/util/NameMap.java
index 19a5507..3a34d51 100644
--- a/core/src/main/java/org/apache/calcite/util/NameMap.java
+++ b/core/src/main/java/org/apache/calcite/util/NameMap.java
@@ -16,6 +16,8 @@
  */
 package org.apache.calcite.util;
 
+import org.apache.calcite.linq4j.function.Experimental;
+
 import com.google.common.collect.ImmutableSortedMap;
 
 import java.util.Locale;
@@ -78,6 +80,11 @@ public class NameMap<V> {
   public NavigableMap<String, V> map() {
     return map;
   }
+
+  @Experimental
+  public V remove(String key) {
+    return map.remove(key);
+  }
 }
 
 // End NameMap.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/util/NameMultimap.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/NameMultimap.java b/core/src/main/java/org/apache/calcite/util/NameMultimap.java
index 4d42a29..5422983 100644
--- a/core/src/main/java/org/apache/calcite/util/NameMultimap.java
+++ b/core/src/main/java/org/apache/calcite/util/NameMultimap.java
@@ -16,6 +16,8 @@
  */
 package org.apache.calcite.util;
 
+import org.apache.calcite.linq4j.function.Experimental;
+
 import com.google.common.collect.ImmutableList;
 
 import java.util.ArrayList;
@@ -56,6 +58,18 @@ public class NameMultimap<V> {
     list.add(v);
   }
 
+  /** Removes all entries that have the given case-sensitive key.
+   *
+   * @return Whether a value was removed */
+  @Experimental
+  public boolean remove(String key, V value) {
+    final List<V> list = map.get(key);
+    if (list == null) {
+      return false;
+    }
+    return list.remove(value);
+  }
+
   /** Returns a map containing all the entries in this multimap that match the
    * given name. */
   public Collection<Map.Entry<String, V>> range(String name,

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/util/Static.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/Static.java b/core/src/main/java/org/apache/calcite/util/Static.java
index a3badca..0e05e0b 100644
--- a/core/src/main/java/org/apache/calcite/util/Static.java
+++ b/core/src/main/java/org/apache/calcite/util/Static.java
@@ -18,8 +18,11 @@ package org.apache.calcite.util;
 
 import org.apache.calcite.runtime.CalciteResource;
 
+import org.apache.calcite.runtime.ConsList;
 import org.apache.calcite.runtime.Resources;
 
+import java.util.List;
+
 /**
  * Definitions of objects to be statically imported.
  *
@@ -45,6 +48,11 @@ public abstract class Static {
   /** Resources. */
   public static final CalciteResource RESOURCE =
       Resources.create(CalciteResource.class);
+
+  /** Builds a list. */
+  public static <E> List<E> cons(E first, List<? extends E> rest) {
+    return ConsList.of(first, rest);
+  }
 }
 
 // End Static.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/util/Util.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/Util.java b/core/src/main/java/org/apache/calcite/util/Util.java
index bdea891..ae9286f 100644
--- a/core/src/main/java/org/apache/calcite/util/Util.java
+++ b/core/src/main/java/org/apache/calcite/util/Util.java
@@ -225,8 +225,10 @@ public class Util {
    * you are not interested in, but you don't want the compiler to warn that
    * you are not using it.
    */
-  public static boolean discard(boolean b) {
-    return b;
+  public static void discard(boolean b) {
+    if (false) {
+      discard(b);
+    }
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/calcite/blob/238b3225/core/src/main/java/org/apache/calcite/util/graph/Graphs.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/graph/Graphs.java b/core/src/main/java/org/apache/calcite/util/graph/Graphs.java
index 72d691f..cd230c1 100644
--- a/core/src/main/java/org/apache/calcite/util/graph/Graphs.java
+++ b/core/src/main/java/org/apache/calcite/util/graph/Graphs.java
@@ -16,7 +16,6 @@
  */
 package org.apache.calcite.util.graph;
 
-import org.apache.calcite.runtime.ConsList;
 import org.apache.calcite.util.Pair;
 
 import com.google.common.collect.ImmutableList;
@@ -29,6 +28,8 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import static org.apache.calcite.util.Static.cons;
+
 /**
  * Miscellaneous graph utilities.
  */
@@ -80,7 +81,7 @@ public class Graphs {
             if ((bestPath == null)
                 || (bestPath.size() > (arc2Path.size() + 1))) {
               shortestPaths.put(key,
-                  ConsList.of(graph1.source(edge), arc2Path));
+                  cons(graph1.source(edge), arc2Path));
               changeCount++;
             }
           }


Mime
View raw message