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 2017/02/07 17:00:10 UTC

[1/2] calcite git commit: [CALCITE-1510] In INSERT/UPSERT without an explicit target column list, allow fewer source columns than table (Kevin Liew)

Repository: calcite
Updated Branches:
  refs/heads/master 6759218b0 -> 08b1dddd5


http://git-wip-us.apache.org/repos/asf/calcite/blob/08b1dddd/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java b/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
index a74415c..d0661cd 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
@@ -93,8 +93,8 @@ public abstract class SqlToRelTestBase {
   }
 
   protected Tester createTester() {
-    return new TesterImpl(getDiffRepos(), false, false, true, false, null,
-        null);
+    return new TesterImpl(getDiffRepos(), false, false, true, false,
+        null, null);
   }
 
   /**
@@ -226,6 +226,9 @@ public abstract class SqlToRelTestBase {
      * {@code SqlToRelConverter.Config}. */
     Tester withConfig(SqlToRelConverter.Config config);
 
+    /** Returns a tester with a {@link SqlConformance}. */
+    Tester withConformance(SqlConformance conformance);
+
     Tester withCatalogReaderFactory(
         Function<RelDataTypeFactory, Prepare.CatalogReader> factory);
 
@@ -477,6 +480,7 @@ public abstract class SqlToRelTestBase {
     private final boolean enableLateDecorrelate;
     private final boolean enableTrim;
     private final boolean enableExpand;
+    private final SqlConformance conformance;
     private final Function<RelDataTypeFactory, Prepare.CatalogReader>
     catalogReaderFactory;
     private final Function<RelOptCluster, RelOptCluster> clusterFactory;
@@ -500,17 +504,19 @@ public abstract class SqlToRelTestBase {
             catalogReaderFactory,
         Function<RelOptCluster, RelOptCluster> clusterFactory) {
       this(diffRepos, enableDecorrelate, enableTrim, enableExpand,
-          enableLateDecorrelate, catalogReaderFactory, clusterFactory,
-          SqlToRelConverter.Config.DEFAULT);
+          enableLateDecorrelate,
+          catalogReaderFactory,
+          clusterFactory,
+          SqlToRelConverter.Config.DEFAULT,
+          SqlConformanceEnum.DEFAULT);
     }
 
     protected TesterImpl(DiffRepository diffRepos, boolean enableDecorrelate,
-        boolean enableTrim, boolean enableExpand,
-        boolean enableLateDecorrelate,
+        boolean enableTrim, boolean enableExpand, boolean enableLateDecorrelate,
         Function<RelDataTypeFactory, Prepare.CatalogReader>
             catalogReaderFactory,
         Function<RelOptCluster, RelOptCluster> clusterFactory,
-        SqlToRelConverter.Config config) {
+        SqlToRelConverter.Config config, SqlConformance conformance) {
       this.diffRepos = diffRepos;
       this.enableDecorrelate = enableDecorrelate;
       this.enableTrim = enableTrim;
@@ -519,6 +525,7 @@ public abstract class SqlToRelTestBase {
       this.catalogReaderFactory = catalogReaderFactory;
       this.clusterFactory = clusterFactory;
       this.config = config;
+      this.conformance = conformance;
     }
 
     public RelRoot convertSqlToRel(String sql) {
@@ -607,7 +614,7 @@ public abstract class SqlToRelTestBase {
     }
 
     public SqlConformance getConformance() {
-      return SqlConformanceEnum.DEFAULT;
+      return conformance;
     }
 
     public SqlValidator createValidator(
@@ -709,7 +716,7 @@ public abstract class SqlToRelTestBase {
           ? this
           : new TesterImpl(diffRepos, enableDecorrelate, enableTrim,
               enableExpand, enableLateDecorrelate, catalogReaderFactory,
-              clusterFactory);
+              clusterFactory, config, conformance);
     }
 
     public Tester withLateDecorrelation(boolean enableLateDecorrelate) {
@@ -717,7 +724,7 @@ public abstract class SqlToRelTestBase {
           ? this
           : new TesterImpl(diffRepos, enableDecorrelate, enableTrim,
               enableExpand, enableLateDecorrelate, catalogReaderFactory,
-              clusterFactory);
+              clusterFactory, config, conformance);
     }
 
     public TesterImpl withConfig(SqlToRelConverter.Config config) {
@@ -725,7 +732,7 @@ public abstract class SqlToRelTestBase {
           ? this
           : new TesterImpl(diffRepos, enableDecorrelate, enableTrim,
               enableExpand, enableLateDecorrelate, catalogReaderFactory,
-              clusterFactory, config);
+              clusterFactory, config, conformance);
     }
 
     public Tester withTrim(boolean enableTrim) {
@@ -733,7 +740,7 @@ public abstract class SqlToRelTestBase {
           ? this
           : new TesterImpl(diffRepos, enableDecorrelate, enableTrim,
               enableExpand, enableLateDecorrelate, catalogReaderFactory,
-              clusterFactory);
+              clusterFactory, config, conformance);
     }
 
     public Tester withExpand(boolean enableExpand) {
@@ -741,20 +748,27 @@ public abstract class SqlToRelTestBase {
           ? this
           : new TesterImpl(diffRepos, enableDecorrelate, enableTrim,
               enableExpand, enableLateDecorrelate, catalogReaderFactory,
-              clusterFactory);
+              clusterFactory, config, conformance);
+    }
+
+    public Tester withConformance(SqlConformance conformance) {
+      return new TesterImpl(diffRepos, enableDecorrelate, false,
+          enableExpand, enableLateDecorrelate, catalogReaderFactory,
+          clusterFactory, config, conformance);
     }
 
     public Tester withCatalogReaderFactory(
         Function<RelDataTypeFactory, Prepare.CatalogReader> factory) {
       return new TesterImpl(diffRepos, enableDecorrelate, false,
           enableExpand, enableLateDecorrelate, factory,
-          clusterFactory);
+          clusterFactory, config, conformance);
     }
 
     public Tester withClusterFactory(
         Function<RelOptCluster, RelOptCluster> clusterFactory) {
-      return new TesterImpl(diffRepos, enableDecorrelate, false, enableExpand,
-          enableLateDecorrelate, catalogReaderFactory, clusterFactory);
+      return new TesterImpl(diffRepos, enableDecorrelate, false,
+          enableExpand, enableLateDecorrelate, catalogReaderFactory,
+          clusterFactory, config, conformance);
     }
 
     public boolean isLateDecorrelate() {

http://git-wip-us.apache.org/repos/asf/calcite/blob/08b1dddd/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
index 65e760f..5ff4f52 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
@@ -8065,40 +8065,89 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
   }
 
   @Test public void testInsert() {
-    tester.checkQuery("insert into emp (empno, deptno) values (1, 1)");
-    tester.checkQuery("insert into emp (empno, deptno)\n"
-        + "select 1, 1 from (values 'a')");
+    tester.checkQuery("insert into empnullables (empno, ename)\n"
+        + "values (1, 'Ambrosia')");
+    tester.checkQuery("insert into empnullables (empno, ename)\n"
+        + "select 1, 'Ardy' from (values 'a')");
+    final String sql = "insert into emp\n"
+        + "values (1, 'nom', 'job', 0, timestamp '1970-01-01 00:00:00', 1, 1,\n"
+        + "  1, false)";
+    tester.checkQuery(sql);
+    final String sql2 = "insert into emp (empno, ename, job, mgr, hiredate,\n"
+        + "  sal, comm, deptno, slacker)\n"
+        + "select 1, 'nom', 'job', 0, timestamp '1970-01-01 00:00:00',\n"
+        + "  1, 1, 1, false\n"
+        + "from (values 'a')";
+    tester.checkQuery(sql2);
+    tester.checkQuery("insert into empnullables (ename, empno, deptno)\n"
+        + "values ('Pat', 1, null)");
+
+    final String sql3 = "insert into empnullables (\n"
+        + "  empno, ename, job, hiredate)\n"
+        + "values (1, 'Jim', 'Baker', timestamp '1970-01-01 00:00:00')";
+    tester.checkQuery(sql3);
+
+    tester.checkQuery("insert into empnullables (empno, ename)\n"
+        + "select 1, 'b' from (values 'a')");
+
+    tester.checkQuery("insert into empnullables (empno, ename)\n"
+        + "values (1, 'Karl')");
+  }
+
+  @Test public void testInsertSubset() {
+    final SqlTester pragmaticTester =
+        tester.withConformance(SqlConformanceEnum.PRAGMATIC_2003);
+    final String sql1 = "insert into empnullables\n"
+        + "values (1, 'nom', 'job', 0, timestamp '1970-01-01 00:00:00')";
+    pragmaticTester.checkQuery(sql1);
+    final String sql2 = "insert into empnullables\n"
+        + "values (1, 'nom', null, 0, null)";
+    pragmaticTester.checkQuery(sql2);
+  }
+
+  @Test public void testInsertView() {
+    tester.checkQuery("insert into empnullables_20 (ename, empno, comm)\n"
+        + "values ('Karl', 1, 1)");
+  }
+
+  @Test public void testInsertSubsetView() {
+    final SqlTester pragmaticTester =
+        tester.withConformance(SqlConformanceEnum.PRAGMATIC_2003);
+    pragmaticTester.checkQuery("insert into empnullables_20\n"
+        + "values (1, 'Karl')");
   }
 
   @Test public void testInsertBind() {
     // VALUES
-    sql("insert into emp (empno, deptno) values (?, ?)")
-        .ok()
-        .bindType("RecordType(INTEGER ?0, INTEGER ?1)");
+    final String sql0 = "insert into empnullables (empno, ename, deptno)\n"
+        + "values (?, ?, ?)";
+    sql(sql0).ok()
+        .bindType("RecordType(INTEGER ?0, VARCHAR(20) ?1, INTEGER ?2)");
 
     // multiple VALUES
-    sql("insert into emp (empno, deptno) values (?, 1), (2, ?), (3, null)")
-        .ok()
-        .bindType("RecordType(INTEGER ?0, INTEGER ?1)");
+    final String sql1 = "insert into empnullables (empno, ename, deptno)\n"
+        + "values (?, 'Pat', 1), (2, ?, ?), (3, 'Tod', ?), (4, 'Arthur', null)";
+    sql(sql1).ok()
+        .bindType("RecordType(INTEGER ?0, VARCHAR(20) ?1, INTEGER ?2, INTEGER ?3)");
 
     // VALUES with expression
-    sql("insert into emp (ename, deptno) values (?, ? + 1)")
+    sql("insert into empnullables (ename, empno) values (?, ? + 1)")
         .ok()
         .bindType("RecordType(VARCHAR(20) ?0, INTEGER ?1)");
 
     // SELECT
-    sql("insert into emp (ename, deptno) select ?, ? from (values (1))")
-        .ok()
-        .bindType("RecordType(VARCHAR(20) ?0, INTEGER ?1)");
+    sql("insert into empnullables (ename, empno) select ?, ? from (values (1))")
+        .ok().bindType("RecordType(VARCHAR(20) ?0, INTEGER ?1)");
 
     // WITH
-    final String sql = "insert into emp (ename, deptno)\n"
+    final String sql3 = "insert into empnullables (ename, empno)\n"
         + "with v as (values ('a'))\n"
         + "select ?, ? from (values (1))";
-    sql(sql).ok().bindType("RecordType(VARCHAR(20) ?0, INTEGER ?1)");
+    sql(sql3).ok()
+        .bindType("RecordType(VARCHAR(20) ?0, INTEGER ?1)");
 
     // UNION
-    final String sql2 = "insert into emp (ename, deptno)\n"
+    final String sql2 = "insert into empnullables (ename, empno)\n"
         + "select ?, ? from (values (1))\n"
         + "union all\n"
         + "select ?, ? from (values (time '1:2:3'))";
@@ -8107,7 +8156,188 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
     sql(sql2).ok().bindType(expected2);
   }
 
+  @Test public void testInsertBindSubset() {
+    final SqlTester pragmaticTester =
+        tester.withConformance(SqlConformanceEnum.PRAGMATIC_2003);
+    // VALUES
+    final String sql0 = "insert into empnullables \n"
+        + "values (?, ?, ?)";
+    sql(sql0).tester(pragmaticTester).ok()
+        .bindType("RecordType(INTEGER ?0, VARCHAR(20) ?1, VARCHAR(10) ?2)");
+
+    // multiple VALUES
+    final String sql1 = "insert into empnullables\n"
+        + "values (?, 'Pat', 'Tailor'), (2, ?, ?),\n"
+        + " (3, 'Tod', ?), (4, 'Arthur', null)";
+    sql(sql1).tester(pragmaticTester).ok()
+        .bindType("RecordType(INTEGER ?0, VARCHAR(20) ?1, VARCHAR(10) ?2, VARCHAR(10) ?3)");
+
+    // VALUES with expression
+    sql("insert into empnullables values (? + 1, ?)")
+        .tester(pragmaticTester)
+        .ok()
+        .bindType("RecordType(INTEGER ?0, VARCHAR(20) ?1)");
+
+    // SELECT
+    sql("insert into empnullables select ?, ? from (values (1))")
+        .tester(pragmaticTester)
+        .ok()
+        .bindType("RecordType(INTEGER ?0, VARCHAR(20) ?1)");
+
+    // WITH
+    final String sql3 = "insert into empnullables \n"
+        + "with v as (values ('a'))\n"
+        + "select ?, ? from (values (1))";
+    sql(sql3).tester(pragmaticTester).ok()
+        .bindType("RecordType(INTEGER ?0, VARCHAR(20) ?1)");
+
+    // UNION
+    final String sql2 = "insert into empnullables \n"
+        + "select ?, ? from (values (1))\n"
+        + "union all\n"
+        + "select ?, ? from (values (time '1:2:3'))";
+    final String expected2 = "RecordType(INTEGER ?0, VARCHAR(20) ?1,"
+        + " INTEGER ?2, VARCHAR(20) ?3)";
+    sql(sql2).tester(pragmaticTester).ok().bindType(expected2);
+  }
+
+  @Test public void testInsertFailNullability() {
+    tester.checkQueryFails(
+        "insert into ^empnullables^ (ename) values ('Kevin')",
+        "Column 'EMPNO' has no default value and does not allow NULLs");
+    tester.checkQueryFails(
+        "insert into ^empnullables^ (empno) values (10)",
+        "Column 'ENAME' has no default value and does not allow NULLs");
+    tester.checkQueryFails(
+        "insert into empnullables (empno, ename, deptno) ^values (5, null, 5)^",
+        "Column 'ENAME' has no default value and does not allow NULLs");
+  }
+
+  @Test public void testInsertSubsetFailNullability() {
+    final SqlTester pragmaticTester =
+        tester.withConformance(SqlConformanceEnum.PRAGMATIC_2003);
+    pragmaticTester.checkQueryFails("insert into ^empnullables^ values (1)",
+        "Column 'ENAME' has no default value and does not allow NULLs");
+    pragmaticTester.checkQueryFails("insert into empnullables ^values (null, 'Liam')^",
+        "Column 'EMPNO' has no default value and does not allow NULLs");
+    pragmaticTester.checkQueryFails("insert into empnullables ^values (45, null, 5)^",
+        "Column 'ENAME' has no default value and does not allow NULLs");
+  }
+
+  @Test public void testInsertViewFailNullability() {
+    tester.checkQueryFails(
+        "insert into ^empnullables_20^ (ename) values ('Jake')",
+        "Column 'EMPNO' has no default value and does not allow NULLs");
+    tester.checkQueryFails(
+        "insert into ^empnullables_20^ (empno) values (9)",
+        "Column 'ENAME' has no default value and does not allow NULLs");
+    tester.checkQueryFails(
+        "insert into empnullables_20 (empno, ename, mgr) ^values (5, null, 5)^",
+        "Column 'ENAME' has no default value and does not allow NULLs");
+  }
+
+  @Test public void testInsertSubsetViewFailNullability() {
+    final SqlTester pragmaticTester =
+        tester.withConformance(SqlConformanceEnum.PRAGMATIC_2003);
+    pragmaticTester.checkQueryFails("insert into ^empnullables_20^ values (1)",
+        "Column 'ENAME' has no default value and does not allow NULLs");
+    pragmaticTester.checkQueryFails("insert into empnullables_20 ^values (null, 'Liam')^",
+        "Column 'EMPNO' has no default value and does not allow NULLs");
+    pragmaticTester.checkQueryFails("insert into empnullables_20 ^values (45, null)^",
+        "Column 'ENAME' has no default value and does not allow NULLs");
+  }
+
+  @Test public void testInsertBindFailNullability() {
+    tester.checkQueryFails("insert into ^emp^ (ename) values (?)",
+        "Column 'EMPNO' has no default value and does not allow NULLs");
+    tester.checkQueryFails(
+        "insert into ^emp^ (empno) values (?)",
+        "Column 'ENAME' has no default value and does not allow NULLs");
+    tester.checkQueryFails(
+        "insert into emp (empno, ename, deptno) ^values (?, null, 5)^",
+        "Column 'ENAME' has no default value and does not allow NULLs");
+  }
+
+  @Test public void testInsertBindSubsetFailNullability() {
+    final SqlTester pragmaticTester =
+        tester.withConformance(SqlConformanceEnum.PRAGMATIC_2003);
+    pragmaticTester.checkQueryFails("insert into ^empnullables^ values (?)",
+        "Column 'ENAME' has no default value and does not allow NULLs");
+    pragmaticTester.checkQueryFails("insert into empnullables ^values (null, ?)^",
+        "Column 'EMPNO' has no default value and does not allow NULLs");
+    pragmaticTester.checkQueryFails("insert into empnullables ^values (?, null)^",
+        "Column 'ENAME' has no default value and does not allow NULLs");
+  }
+
+  @Test public void testInsertSubsetDisallowed() {
+    tester.checkQueryFails("insert into ^emp^ values (1)",
+        "Number of INSERT target columns \\(9\\) does not equal number of source items \\(1\\)");
+    tester.checkQueryFails("insert into ^emp^ values (null)",
+        "Number of INSERT target columns \\(9\\) does not equal number of source items \\(1\\)");
+    tester.checkQueryFails("insert into ^emp^ values (1, 'Kevin')",
+        "Number of INSERT target columns \\(9\\) does not equal number of source items \\(2\\)");
+  }
+
+  @Test public void testInsertSubsetViewDisallowed() {
+    tester.checkQueryFails("insert into ^emp_20^ values (1)",
+        "Number of INSERT target columns \\(8\\) does not equal number of source items \\(1\\)");
+    tester.checkQueryFails("insert into ^emp_20^ values (null)",
+        "Number of INSERT target columns \\(8\\) does not equal number of source items \\(1\\)");
+    tester.checkQueryFails("insert into ^emp_20^ values (?, ?)",
+        "Number of INSERT target columns \\(8\\) does not equal number of source items \\(2\\)");
+  }
+
+  @Test public void testInsertBindSubsetDisallowed() {
+    tester.checkQueryFails("insert into ^emp^ values (?)",
+        "Number of INSERT target columns \\(9\\) does not equal number of source items \\(1\\)");
+    tester.checkQueryFails("insert into ^emp^ values (?, ?)",
+        "Number of INSERT target columns \\(9\\) does not equal number of source items \\(2\\)");
+  }
+
+  @Test public void testInsertWithCustomInitializerExpressionFactory() {
+    tester.checkQuery("insert into empdefaults (deptno) values (1)");
+    tester.checkQuery("insert into empdefaults (ename, empno) values ('Quan', 50)");
+    tester.checkQueryFails("insert into empdefaults (ename, deptno) ^values (null, 1)^",
+        "Column 'ENAME' has no default value and does not allow NULLs");
+    tester.checkQueryFails("insert into ^empdefaults^ values (null, 'Tod')",
+        "Number of INSERT target columns \\(9\\) does not equal number of source items \\(2\\)");
+  }
+
+  @Test public void testInsertSubsetWithCustomInitializerExpressionFactory() {
+    final SqlTester pragmaticTester =
+        tester.withConformance(SqlConformanceEnum.PRAGMATIC_2003);
+    pragmaticTester.checkQuery("insert into empdefaults values (101)");
+    pragmaticTester.checkQuery("insert into empdefaults values (101, 'Coral')");
+    pragmaticTester.checkQueryFails("insert into empdefaults ^values (null, 'Tod')^",
+        "Column 'EMPNO' has no default value and does not allow NULLs");
+    pragmaticTester.checkQueryFails("insert into empdefaults ^values (78, null)^",
+        "Column 'ENAME' has no default value and does not allow NULLs");
+  }
+
+  @Test public void testInsertBindWithCustomInitializerExpressionFactory() {
+    sql("insert into empdefaults (deptno) values (?)").ok()
+        .bindType("RecordType(INTEGER ?0)");
+    sql("insert into empdefaults (ename, empno) values (?, ?)").ok()
+        .bindType("RecordType(VARCHAR(20) ?0, INTEGER ?1)");
+    tester.checkQueryFails("insert into empdefaults (ename, deptno) ^values (null, ?)^",
+        "Column 'ENAME' has no default value and does not allow NULLs");
+    tester.checkQueryFails("insert into ^empdefaults^ values (null, ?)",
+        "Number of INSERT target columns \\(9\\) does not equal number of source items \\(2\\)");
+  }
+
+  @Test public void testInsertBindSubsetWithCustomInitializerExpressionFactory() {
+    final SqlTester pragmaticTester =
+        tester.withConformance(SqlConformanceEnum.PRAGMATIC_2003);
+    sql("insert into empdefaults values (101, ?)").tester(pragmaticTester).ok()
+        .bindType("RecordType(VARCHAR(20) ?0)");
+    pragmaticTester.checkQueryFails("insert into empdefaults ^values (null, ?)^",
+        "Column 'EMPNO' has no default value and does not allow NULLs");
+  }
+
   @Test public void testInsertBindWithCustomColumnResolving() {
+    final SqlTester pragmaticTester =
+        tester.withConformance(SqlConformanceEnum.PRAGMATIC_2003);
+
     final String sql = "insert into struct.t\n"
         + "values (?, ?, ?, ?, ?, ?, ?, ?, ?)";
     final String expected = "RecordType(VARCHAR(20) ?0, VARCHAR(20) ?1,"
@@ -8116,24 +8346,30 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
     sql(sql).ok().bindType(expected);
 
     final String sql2 =
-        "insert into struct.t (c0, c2, c1) values (?, ?, ?)";
+        "insert into struct.t_nullables (c0, c2, c1) values (?, ?, ?)";
     final String expected2 =
         "RecordType(INTEGER ?0, INTEGER ?1, VARCHAR(20) ?2)";
-    sql(sql2).ok().bindType(expected2);
+    sql(sql2).tester(pragmaticTester).ok().bindType(expected2);
 
     final String sql3 =
-        "insert into struct.t (f1.c0, f1.c2, f0.c1) values (?, ?, ?)";
+        "insert into struct.t_nullables (f1.c0, f1.c2, f0.c1) values (?, ?, ?)";
     final String expected3 =
         "RecordType(INTEGER ?0, INTEGER ?1, INTEGER ?2)";
-    sql(sql3).ok().bindType(expected3);
+    sql(sql3).tester(pragmaticTester).ok().bindType(expected3);
 
-    sql("insert into struct.t (c0, ^c4^, c1) values (?, ?, ?)")
+    sql("insert into struct.t_nullables (c0, ^c4^, c1) values (?, ?, ?)")
+        .tester(pragmaticTester)
         .fails("Unknown target column 'C4'");
-    sql("insert into struct.t (^a0^, c2, c1) values (?, ?, ?)")
+    sql("insert into struct.t_nullables (^a0^, c2, c1) values (?, ?, ?)")
+        .tester(pragmaticTester)
         .fails("Unknown target column 'A0'");
-    sql("insert into struct.t (f1.c0, ^f0.a0^, f0.c1) values (?, ?, ?)")
+    final String sql4 = "insert into struct.t_nullables (\n"
+        + "  f1.c0, ^f0.a0^, f0.c1) values (?, ?, ?)";
+    sql(sql4).tester(pragmaticTester)
         .fails("Unknown target column 'F0.A0'");
-    sql("insert into struct.t (f1.c0, f1.c2, ^f1.c0^) values (?, ?, ?)")
+    final String sql5 = "insert into struct.t_nullables (\n"
+        + "  f1.c0, f1.c2, ^f1.c0^) values (?, ?, ?)";
+    sql(sql5).tester(pragmaticTester)
         .fails("Target column '\"F1\".\"C0\"' is assigned more than once");
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/08b1dddd/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
index 5da57fd..443d764 100644
--- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
@@ -2603,16 +2603,54 @@ LogicalProject(DEPTNO=[$0], B=[>($1, $2)])
     </TestCase>
     <TestCase name="testInsert">
         <Resource name="sql">
-            <![CDATA[insert into emp (deptno, empno, ename) values (10, 150, 'Fred')]]>
+            <![CDATA[insert into empnullables (deptno, empno, ename) values (10, 150, 'Fred')]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
-LogicalTableModify(table=[[CATALOG, SALES, EMP]], operation=[INSERT], flattened=[true])
+LogicalTableModify(table=[[CATALOG, SALES, EMPNULLABLES]], operation=[INSERT], flattened=[true])
   LogicalProject(EMPNO=[$1], ENAME=[$2], JOB=[null], MGR=[null], HIREDATE=[null], SAL=[null], COMM=[null], DEPTNO=[$0], SLACKER=[null])
     LogicalValues(tuples=[[{ 10, 150, 'Fred' }]])
 ]]>
         </Resource>
     </TestCase>
+    <TestCase name="testInsertSubset">
+        <Resource name="sql">
+            <![CDATA[insert into empnullables values (10, 150, 'Fred')]]>
+        </Resource>
+        <Resource name="plan">
+            <![CDATA[
+LogicalTableModify(table=[[CATALOG, SALES, EMPNULLABLES]], operation=[INSERT], flattened=[true])
+  LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[null], MGR=[null], HIREDATE=[null], SAL=[null], COMM=[null], DEPTNO=[null], SLACKER=[null])
+    LogicalValues(tuples=[[{ 50, 'Fred' }]])
+]]>
+        </Resource>
+    </TestCase>
+    <TestCase name="testInsertBind">
+        <Resource name="sql">
+            <![CDATA[insert into empnullables (deptno, empno, ename) values (?, ?, ?)]]>
+        </Resource>
+        <Resource name="plan">
+            <![CDATA[
+LogicalTableModify(table=[[CATALOG, SALES, EMPNULLABLES]], operation=[INSERT], flattened=[true])
+  LogicalProject(EMPNO=[$1], ENAME=[$2], JOB=[null], MGR=[null], HIREDATE=[null], SAL=[null], COMM=[null], DEPTNO=[$0], SLACKER=[null])
+    LogicalProject(EXPR$0=[?0], EXPR$1=[?1], EXPR$2=[?2])
+      LogicalValues(tuples=[[{ 0 }]])
+]]>
+        </Resource>
+    </TestCase>
+    <TestCase name="testInsertBindSubset">
+        <Resource name="sql">
+            <![CDATA[insert into empnullables values (?, ?, ?)]]>
+        </Resource>
+        <Resource name="plan">
+            <![CDATA[
+LogicalTableModify(table=[[CATALOG, SALES, EMPNULLABLES]], operation=[INSERT], flattened=[true])
+  LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[null], MGR=[null], HIREDATE=[null], SAL=[null], COMM=[null], DEPTNO=[null], SLACKER=[null])
+    LogicalProject(EXPR$0=[?0], EXPR$1=[?1])
+      LogicalValues(tuples=[[{ 0 }]])
+]]>
+        </Resource>
+    </TestCase>
     <TestCase name="testSelectView">
         <Resource name="sql">
             <![CDATA[select * from emp_20 where empno > 100]]>
@@ -2629,18 +2667,82 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
     </TestCase>
     <TestCase name="testInsertView">
         <Resource name="sql">
-            <![CDATA[insert into emp_20 (empno, ename) values (150, 'Fred')]]>
+            <![CDATA[insert into empnullables_20 (empno, ename) values (150, 'Fred')]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
-LogicalTableModify(table=[[CATALOG, SALES, EMP]], operation=[INSERT], flattened=[true])
+LogicalTableModify(table=[[CATALOG, SALES, EMPNULLABLES]], operation=[INSERT], flattened=[true])
   LogicalFilter(condition=[>($5, 1000)])
-    LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[CAST($2):VARCHAR(10) CHARACTER SET "ISO-8859-1" COLLATE "ISO-8859-1$en_US$primary" NOT NULL], MGR=[$3], HIREDATE=[CAST($4):TIMESTAMP(0) NOT NULL], SAL=[CAST($5):INTEGER NOT NULL], COMM=[CAST($6):INTEGER NOT NULL], DEPTNO=[20], SLACKER=[CAST($7):BOOLEAN NOT NULL])
+    LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[20], SLACKER=[$7])
       LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[null], MGR=[null], HIREDATE=[null], SAL=[null], COMM=[null], SLACKER=[null])
         LogicalValues(tuples=[[{ 150, 'Fred' }]])
 ]]>
         </Resource>
     </TestCase>
+    <TestCase name="testInsertSubsetView">
+        <Resource name="sql">
+            <![CDATA[insert into empnullables_20 (empno, ename) values (150, 'Fred')]]>
+        </Resource>
+        <Resource name="plan">
+            <![CDATA[
+LogicalTableModify(table=[[CATALOG, SALES, EMPNULLABLES]], operation=[INSERT], flattened=[true])
+  LogicalFilter(condition=[>($5, 1000)])
+    LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[20], SLACKER=[$7])
+      LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[null], MGR=[null], HIREDATE=[null], SAL=[null], COMM=[null], SLACKER=[null])
+        LogicalValues(tuples=[[{ 10, 'Fred' }]])
+]]>
+        </Resource>
+    </TestCase>
+    <TestCase name="testInsertWithCustomInitializerExpressionFactory">
+        <Resource name="sql">
+            <![CDATA[insert into empdefaults (deptno) values (300)]]>
+        </Resource>
+        <Resource name="plan">
+            <![CDATA[
+LogicalTableModify(table=[[CATALOG, SALES, EMPDEFAULTS]], operation=[INSERT], flattened=[true])
+  LogicalProject(EMPNO=[123], ENAME=['Bob'], JOB=[null], MGR=[null], HIREDATE=[null], SAL=[555], COMM=[null], DEPTNO=[$0], SLACKER=[null])
+    LogicalValues(tuples=[[{ 300 }]])
+]]>
+        </Resource>
+    </TestCase>
+    <TestCase name="testInsertSubsetWithCustomInitializerExpressionFactory">
+        <Resource name="sql">
+            <![CDATA[insert into empdefaults values (100)]]>
+        </Resource>
+        <Resource name="plan">
+            <![CDATA[
+LogicalTableModify(table=[[CATALOG, SALES, EMPDEFAULTS]], operation=[INSERT], flattened=[true])
+  LogicalProject(EMPNO=[$0], ENAME=['Bob'], JOB=[null], MGR=[null], HIREDATE=[null], SAL=[555], COMM=[null], DEPTNO=[null], SLACKER=[null])
+    LogicalValues(tuples=[[{ 100 }]])
+]]>
+        </Resource>
+    </TestCase>
+    <TestCase name="testInsertBindWithCustomInitializerExpressionFactory">
+        <Resource name="sql">
+            <![CDATA[nsert into empdefaults (deptno) values (?)]]>
+        </Resource>
+        <Resource name="plan">
+            <![CDATA[
+LogicalTableModify(table=[[CATALOG, SALES, EMPDEFAULTS]], operation=[INSERT], flattened=[true])
+  LogicalProject(EMPNO=[123], ENAME=['Bob'], JOB=[null], MGR=[null], HIREDATE=[null], SAL=[555], COMM=[null], DEPTNO=[$0], SLACKER=[null])
+    LogicalProject(EXPR$0=[?0])
+      LogicalValues(tuples=[[{ 0 }]])
+]]>
+        </Resource>
+    </TestCase>
+    <TestCase name="testInsertBindSubsetWithCustomInitializerExpressionFactory">
+        <Resource name="sql">
+            <![CDATA[insert into empdefaults values (?)]]>
+        </Resource>
+        <Resource name="plan">
+            <![CDATA[
+LogicalTableModify(table=[[CATALOG, SALES, EMPDEFAULTS]], operation=[INSERT], flattened=[true])
+  LogicalProject(EMPNO=[$0], ENAME=['Bob'], JOB=[null], MGR=[null], HIREDATE=[null], SAL=[555], COMM=[null], DEPTNO=[null], SLACKER=[null])
+    LogicalProject(EXPR$0=[?0])
+      LogicalValues(tuples=[[{ 0 }]])
+]]>
+        </Resource>
+    </TestCase>
     <TestCase name="testInsertWithCustomColumnResolving">
         <Resource name="sql">
             <![CDATA[insert into struct.t values (?, ?, ?, ?, ?, ?, ?, ?, ?)]]>
@@ -2655,11 +2757,12 @@ LogicalTableModify(table=[[CATALOG, STRUCT, T]], operation=[INSERT], flattened=[
     </TestCase>
     <TestCase name="testInsertWithCustomColumnResolving2">
         <Resource name="sql">
-            <![CDATA[insert into struct.t (c0, c2, c1) values (?, ?, ?)]]>
+            <![CDATA[insert into struct.t_nullables (f0.c0, f1.c2, c1)
+values (?, ?, ?)]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
-LogicalTableModify(table=[[CATALOG, STRUCT, T]], operation=[INSERT], flattened=[true])
+LogicalTableModify(table=[[CATALOG, STRUCT, T_NULLABLES]], operation=[INSERT], flattened=[true])
   LogicalProject("K0"=[null], "C1"=[$2], "F1"."A0"=[null], "F2"."A0"=[null], "F0"."C0"=[$0], "F1"."C0"=[null], "F0"."C1"=[null], "F1"."C2"=[$1], "F2"."C3"=[null])
     LogicalProject(EXPR$0=[?0], EXPR$1=[?1], EXPR$2=[?2])
       LogicalValues(tuples=[[{ 0 }]])
@@ -2668,15 +2771,17 @@ LogicalTableModify(table=[[CATALOG, STRUCT, T]], operation=[INSERT], flattened=[
     </TestCase>
     <TestCase name="testInsertViewWithCustomColumnResolving">
         <Resource name="sql">
-            <![CDATA[insert into struct.t_10 (c0, c2, c1) values (?, ?, ?)]]>
+            <![CDATA[insert into struct.t_10 (f0.c0, f1.c2, c1, k0,
+  f1.a0, f2.a0, f0.c1, f2.c3)
+values (?, ?, ?, ?, ?, ?, ?, ?)]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
 LogicalTableModify(table=[[CATALOG, STRUCT, T]], operation=[INSERT], flattened=[true])
   LogicalFilter(condition=[=($4, 10)])
     LogicalProject("K0"=[CAST($0):VARCHAR(20) CHARACTER SET "ISO-8859-1" COLLATE "ISO-8859-1$en_US$primary" NOT NULL], "C1"=[CAST($1):VARCHAR(20) CHARACTER SET "ISO-8859-1" COLLATE "ISO-8859-1$en_US$primary" NOT NULL], "F1"."A0"=[CAST($2):INTEGER NOT NULL], "F2"."A0"=[CAST($3):BOOLEAN NOT NULL], "F0"."C0"=[CAST($4):INTEGER NOT NULL], "F1"."C0"=[$5], "F0"."C1"=[CAST($6):INTEGER NOT NULL], "F1"."C2"=[CAST($7):INTEGER NOT NULL], "F2"."C3"=[CAST($8):INTEGER NOT NULL])
-      LogicalProject("K0"=[null], "C1"=[$2], "F1"."A0"=[null], "F2"."A0"=[null], "F0"."C0"=[$0], "F1"."C0"=[null], "F0"."C1"=[null], "F1"."C2"=[$1], "F2"."C3"=[null])
-        LogicalProject(EXPR$0=[?0], EXPR$1=[?1], EXPR$2=[?2])
+      LogicalProject("K0"=[$3], "C1"=[$2], "F1"."A0"=[$4], "F2"."A0"=[$5], "F0"."C0"=[$0], "F1"."C0"=[null], "F0"."C1"=[$6], "F1"."C2"=[$1], "F2"."C3"=[$7])
+        LogicalProject(EXPR$0=[?0], EXPR$1=[?1], EXPR$2=[?2], EXPR$3=[?3], EXPR$4=[?4], EXPR$5=[?5], EXPR$6=[?6], EXPR$7=[?7])
           LogicalValues(tuples=[[{ 0 }]])
 ]]>
         </Resource>

http://git-wip-us.apache.org/repos/asf/calcite/blob/08b1dddd/site/_docs/reference.md
----------------------------------------------------------------------
diff --git a/site/_docs/reference.md b/site/_docs/reference.md
index 37f33d9..fcf465c 100644
--- a/site/_docs/reference.md
+++ b/site/_docs/reference.md
@@ -175,6 +175,11 @@ windowSpec:
       ')'
 {% endhighlight %}
 
+In *insert*, if the INSERT or UPSERT statement does not specify a
+list of target columns, the query must have the same number of
+columns as the target table, except in certain
+[conformance levels]({{ site.apiRoot }}/org/apache/calcite/sql/validate/SqlConformance.html#isInsertSubsetColumnsAllowed--).
+
 In *merge*, at least one of the WHEN MATCHED and WHEN NOT MATCHED clauses must
 be present.
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/08b1dddd/src/main/config/checkstyle/checker.xml
----------------------------------------------------------------------
diff --git a/src/main/config/checkstyle/checker.xml b/src/main/config/checkstyle/checker.xml
index 167511b..86156ad 100644
--- a/src/main/config/checkstyle/checker.xml
+++ b/src/main/config/checkstyle/checker.xml
@@ -227,7 +227,7 @@ limitations under the License.
     </module>
       <!-- Over time, we will revise this down -->
     <module name="MethodLength">
-      <property name="max" value="390"/>
+      <property name="max" value="370"/>
     </module>
 
     <!-- Checks for whitespace (tree walker)                 -->


[2/2] calcite git commit: [CALCITE-1510] In INSERT/UPSERT without an explicit target column list, allow fewer source columns than table (Kevin Liew)

Posted by jh...@apache.org.
[CALCITE-1510] In INSERT/UPSERT without an explicit target column list, allow fewer source columns than table (Kevin Liew)

This functionality is enabled by a new conformance property,
SqlConformance.isInsertSubsetColumnsAllowed.


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

Branch: refs/heads/master
Commit: 08b1dddd586c705b5aace5b386693ffb0e6a73de
Parents: 6759218
Author: Kevin Liew <kl...@apache.org>
Authored: Fri Feb 3 14:48:02 2017 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Sat Feb 4 13:51:19 2017 -0800

----------------------------------------------------------------------
 .../java/org/apache/calcite/plan/Context.java   |  15 +-
 .../org/apache/calcite/plan/RelOptTable.java    |   8 +-
 .../calcite/prepare/CalciteSqlValidator.java    |   8 +-
 .../org/apache/calcite/prepare/Prepare.java     |  26 +
 .../apache/calcite/prepare/RelOptTableImpl.java |   2 +-
 .../apache/calcite/runtime/CalciteResource.java |   3 +
 .../java/org/apache/calcite/schema/Wrapper.java |   3 +-
 .../calcite/sql/advise/SqlAdvisorValidator.java |  14 +-
 .../sql/validate/SqlAbstractConformance.java    |   4 +
 .../calcite/sql/validate/SqlConformance.java    |  20 +
 .../sql/validate/SqlConformanceEnum.java        |  10 +
 .../sql/validate/SqlDelegatingConformance.java  |   4 +
 .../calcite/sql/validate/SqlValidatorImpl.java  |  56 +-
 .../calcite/sql/validate/SqlValidatorTable.java |  10 +
 .../calcite/sql2rel/DefaultValueFactory.java    |  73 ---
 .../sql2rel/InitializerExpressionFactory.java   |  69 +++
 .../NullInitializerExpressionFactory.java       |  52 ++
 .../apache/calcite/sql2rel/SqlRexContext.java   |   2 +-
 .../calcite/sql2rel/SqlToRelConverter.java      |  96 ++--
 .../sql2rel/StandardConvertletTable.java        |   2 +-
 .../calcite/runtime/CalciteResource.properties  |   1 +
 .../apache/calcite/sql/test/SqlAdvisorTest.java |   3 +
 .../apache/calcite/test/MockCatalogReader.java  | 520 ++++++++++++-------
 .../calcite/test/SqlToRelConverterTest.java     |  88 +++-
 .../apache/calcite/test/SqlToRelTestBase.java   |  46 +-
 .../apache/calcite/test/SqlValidatorTest.java   | 284 +++++++++-
 .../calcite/test/SqlToRelConverterTest.xml      | 125 ++++-
 site/_docs/reference.md                         |   5 +
 src/main/config/checkstyle/checker.xml          |   2 +-
 29 files changed, 1153 insertions(+), 398 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/08b1dddd/core/src/main/java/org/apache/calcite/plan/Context.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/Context.java b/core/src/main/java/org/apache/calcite/plan/Context.java
index 3537d98..764d3a8 100644
--- a/core/src/main/java/org/apache/calcite/plan/Context.java
+++ b/core/src/main/java/org/apache/calcite/plan/Context.java
@@ -16,20 +16,17 @@
  */
 package org.apache.calcite.plan;
 
+import org.apache.calcite.schema.Wrapper;
+
 /**
  * Provides library users a way to store data within the planner session and
  * access it within rules. Frameworks can implement their own implementation
  * of Context and pass that as part of the FrameworkConfig.
+ *
+ * <p>Simply implement the {@link #unwrap} method to return any sub-objects
+ * that you wish to provide.
  */
-public interface Context {
-
-  /**
-   * If assignable to clazz, provide the underlying clazz.
-   * @param clazz The Class object of the desired class.
-   * @return Underlying object if matches, otherwise null.
-   */
-  <T> T unwrap(Class<T> clazz);
-
+public interface Context extends Wrapper {
 }
 
 // End Context.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/08b1dddd/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 2c2321b..d5980b2 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptTable.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptTable.java
@@ -24,6 +24,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.Wrapper;
 import org.apache.calcite.util.ImmutableBitSet;
 
 import java.util.List;
@@ -32,7 +33,7 @@ import java.util.List;
  * Represents a relational dataset in a {@link RelOptSchema}. It has methods to
  * describe and implement itself.
  */
-public interface RelOptTable {
+public interface RelOptTable extends Wrapper {
   //~ Methods ----------------------------------------------------------------
 
   /**
@@ -97,11 +98,6 @@ public interface RelOptTable {
   boolean isKey(ImmutableBitSet columns);
 
   /**
-   * Finds an interface implemented by this table.
-   */
-  <T> T unwrap(Class<T> clazz);
-
-  /**
    * Generates code for this table.
    *
    * @param clazz The desired collection class; for example {@code Queryable}.

http://git-wip-us.apache.org/repos/asf/calcite/blob/08b1dddd/core/src/main/java/org/apache/calcite/prepare/CalciteSqlValidator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/CalciteSqlValidator.java b/core/src/main/java/org/apache/calcite/prepare/CalciteSqlValidator.java
index a7fc2fe..68e9d0f 100644
--- a/core/src/main/java/org/apache/calcite/prepare/CalciteSqlValidator.java
+++ b/core/src/main/java/org/apache/calcite/prepare/CalciteSqlValidator.java
@@ -33,12 +33,16 @@ class CalciteSqlValidator extends SqlValidatorImpl {
 
   @Override protected RelDataType getLogicalSourceRowType(
       RelDataType sourceRowType, SqlInsert insert) {
-    return ((JavaTypeFactory) typeFactory).toSql(sourceRowType);
+    final RelDataType superType =
+        super.getLogicalSourceRowType(sourceRowType, insert);
+    return ((JavaTypeFactory) typeFactory).toSql(superType);
   }
 
   @Override protected RelDataType getLogicalTargetRowType(
       RelDataType targetRowType, SqlInsert insert) {
-    return ((JavaTypeFactory) typeFactory).toSql(targetRowType);
+    final RelDataType superType =
+        super.getLogicalTargetRowType(targetRowType, insert);
+    return ((JavaTypeFactory) typeFactory).toSql(superType);
   }
 }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/08b1dddd/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 988b37b..26a6bff 100644
--- a/core/src/main/java/org/apache/calcite/prepare/Prepare.java
+++ b/core/src/main/java/org/apache/calcite/prepare/Prepare.java
@@ -39,6 +39,8 @@ 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.Table;
+import org.apache.calcite.schema.Wrapper;
 import org.apache.calcite.schema.impl.StarTable;
 import org.apache.calcite.sql.SqlExplain;
 import org.apache.calcite.sql.SqlExplainFormat;
@@ -46,9 +48,11 @@ import org.apache.calcite.sql.SqlExplainLevel;
 import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlOperatorTable;
+import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.sql.validate.SqlValidator;
 import org.apache.calcite.sql.validate.SqlValidatorCatalogReader;
 import org.apache.calcite.sql.validate.SqlValidatorTable;
+import org.apache.calcite.sql2rel.InitializerExpressionFactory;
 import org.apache.calcite.sql2rel.SqlToRelConverter;
 import org.apache.calcite.tools.Program;
 import org.apache.calcite.tools.Programs;
@@ -394,6 +398,28 @@ public abstract class Prepare {
       extends RelOptTable, SqlValidatorTable {
   }
 
+  /** Abstract implementation of {@link PreparingTable} with an implementation
+   * for {@link #columnHasDefaultValue}. */
+  public abstract static class AbstractPreparingTable
+      implements PreparingTable {
+    public boolean columnHasDefaultValue(RelDataType rowType, int ordinal) {
+      final Table table = this.unwrap(Table.class);
+      if (table != null && table instanceof Wrapper) {
+        final InitializerExpressionFactory initializerExpressionFactory =
+            ((Wrapper) table).unwrap(InitializerExpressionFactory.class);
+        if (initializerExpressionFactory != null) {
+          return !initializerExpressionFactory
+              .newColumnDefaultValue(this, ordinal)
+              .getType().getSqlTypeName().equals(SqlTypeName.NULL);
+        }
+      }
+      if (ordinal >= rowType.getFieldList().size()) {
+        return true;
+      }
+      return !rowType.getFieldList().get(ordinal).getType().isNullable();
+    }
+  }
+
   /**
    * PreparedExplanation is a PreparedResult for an EXPLAIN PLAN statement.
    * It's always good to have an explanation prepared.

http://git-wip-us.apache.org/repos/asf/calcite/blob/08b1dddd/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 a9c381e..cddee2b 100644
--- a/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java
@@ -65,7 +65,7 @@ import java.util.Set;
 /**
  * Implementation of {@link org.apache.calcite.plan.RelOptTable}.
  */
-public class RelOptTableImpl implements Prepare.PreparingTable {
+public class RelOptTableImpl extends Prepare.AbstractPreparingTable {
   private final RelOptSchema schema;
   private final RelDataType rowType;
   private final Table table;

http://git-wip-us.apache.org/repos/asf/calcite/blob/08b1dddd/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 bf277a6..4c9fa57 100644
--- a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
+++ b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
@@ -151,6 +151,9 @@ public interface CalciteResource {
   @BaseMessage("Number of INSERT target columns ({0,number}) does not equal number of source items ({1,number})")
   ExInst<SqlValidatorException> unmatchInsertColumn(int a0, int a1);
 
+  @BaseMessage("Column ''{0}'' has no default value and does not allow NULLs")
+  ExInst<SqlValidatorException> columnNotNullable(String a0);
+
   @BaseMessage("Cannot assign to target field ''{0}'' of type {1} from source field ''{2}'' of type {3}")
   ExInst<SqlValidatorException> typeNotAssignable(String a0, String a1,
       String a2, String a3);

http://git-wip-us.apache.org/repos/asf/calcite/blob/08b1dddd/core/src/main/java/org/apache/calcite/schema/Wrapper.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/schema/Wrapper.java b/core/src/main/java/org/apache/calcite/schema/Wrapper.java
index c14439d..8b527df 100644
--- a/core/src/main/java/org/apache/calcite/schema/Wrapper.java
+++ b/core/src/main/java/org/apache/calcite/schema/Wrapper.java
@@ -20,7 +20,8 @@ package org.apache.calcite.schema;
  * Mix-in interface that allows you to find sub-objects.
  */
 public interface Wrapper {
-  /** Returns an instance of a class, or null. */
+  /** Finds an instance of an interface implemented by this object,
+   * or returns null if this object does not support that interface. */
   <C> C unwrap(Class<C> aClass);
 }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/08b1dddd/core/src/main/java/org/apache/calcite/sql/advise/SqlAdvisorValidator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/advise/SqlAdvisorValidator.java b/core/src/main/java/org/apache/calcite/sql/advise/SqlAdvisorValidator.java
index 4d07e79..3dc1087 100644
--- a/core/src/main/java/org/apache/calcite/sql/advise/SqlAdvisorValidator.java
+++ b/core/src/main/java/org/apache/calcite/sql/advise/SqlAdvisorValidator.java
@@ -47,8 +47,7 @@ import java.util.Set;
 public class SqlAdvisorValidator extends SqlValidatorImpl {
   //~ Instance fields --------------------------------------------------------
 
-  private final Set<SqlValidatorNamespace> activeNamespaces =
-      new HashSet<SqlValidatorNamespace>();
+  private final Set<SqlValidatorNamespace> activeNamespaces = new HashSet<>();
 
   private final RelDataType emptyStructType =
       SqlTypeUtil.createEmptyStructType(typeFactory);
@@ -69,15 +68,12 @@ public class SqlAdvisorValidator extends SqlValidatorImpl {
       RelDataTypeFactory typeFactory,
       SqlConformance conformance) {
     super(opTab, catalogReader, typeFactory, conformance);
-    assert opTab != null;
-    assert catalogReader != null;
-    assert typeFactory != null;
   }
 
   //~ Methods ----------------------------------------------------------------
 
   /**
-   * Registers the identifier and its scope into a map keyed by ParserPostion.
+   * Registers the identifier and its scope into a map keyed by ParserPosition.
    */
   public void validateIdentifier(SqlIdentifier id, SqlValidatorScope scope) {
     registerId(id, scope);
@@ -124,11 +120,7 @@ public class SqlAdvisorValidator extends SqlValidatorImpl {
     // Util.permAssert that throws Error
     try {
       return super.deriveType(scope, operand);
-    } catch (CalciteException e) {
-      return unknownType;
-    } catch (UnsupportedOperationException e) {
-      return unknownType;
-    } catch (Error e) {
+    } catch (CalciteException | UnsupportedOperationException | Error e) {
       return unknownType;
     }
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/08b1dddd/core/src/main/java/org/apache/calcite/sql/validate/SqlAbstractConformance.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlAbstractConformance.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlAbstractConformance.java
index 766e209..52a5241 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlAbstractConformance.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlAbstractConformance.java
@@ -51,6 +51,10 @@ public abstract class SqlAbstractConformance implements SqlConformance {
     return SqlConformanceEnum.DEFAULT.isApplyAllowed();
   }
 
+  public boolean isInsertSubsetColumnsAllowed() {
+    return SqlConformanceEnum.DEFAULT.isInsertSubsetColumnsAllowed();
+  }
+
 }
 
 // End SqlAbstractConformance.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/08b1dddd/core/src/main/java/org/apache/calcite/sql/validate/SqlConformance.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlConformance.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlConformance.java
index 5999a9f..3c0ffb8 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlConformance.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlConformance.java
@@ -158,6 +158,26 @@ public interface SqlConformance {
    * false otherwise.
    */
   boolean isApplyAllowed();
+
+  /**
+   * Whether to allow {@code INSERT} (or {@code UPSERT}) with no column list
+   * but fewer values than the target table.
+   *
+   * <p>The N values provided are assumed to match the first N columns of the
+   * table, and for each of the remaining columns, the default value of the
+   * column is used. It is an error if any of these columns has no default
+   * value.
+   *
+   * <p>The default value of a column is specified by the {@code DEFAULT}
+   * clause in the {@code CREATE TABLE} statement, or is {@code NULL} if the
+   * column is not declared {@code NOT NULL}.
+   *
+   * <p>Among the built-in conformance levels, true in
+   * {@link SqlConformanceEnum#PRAGMATIC_99},
+   * {@link SqlConformanceEnum#PRAGMATIC_2003};
+   * false otherwise.
+   */
+  boolean isInsertSubsetColumnsAllowed();
 }
 
 // End SqlConformance.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/08b1dddd/core/src/main/java/org/apache/calcite/sql/validate/SqlConformanceEnum.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlConformanceEnum.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlConformanceEnum.java
index 20bdefb..63dde33 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlConformanceEnum.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlConformanceEnum.java
@@ -134,6 +134,16 @@ public enum SqlConformanceEnum implements SqlConformance {
     }
   }
 
+  public boolean isInsertSubsetColumnsAllowed() {
+    switch (this) {
+    case PRAGMATIC_99:
+    case PRAGMATIC_2003:
+      return true;
+    default:
+      return false;
+    }
+  }
+
 }
 
 // End SqlConformanceEnum.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/08b1dddd/core/src/main/java/org/apache/calcite/sql/validate/SqlDelegatingConformance.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlDelegatingConformance.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlDelegatingConformance.java
index 3722c2f..f5e02c5 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlDelegatingConformance.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlDelegatingConformance.java
@@ -52,6 +52,10 @@ public class SqlDelegatingConformance extends SqlAbstractConformance {
   @Override public boolean isMinusAllowed() {
     return delegate.isMinusAllowed();
   }
+
+  @Override public boolean isInsertSubsetColumnsAllowed() {
+    return delegate.isInsertSubsetColumnsAllowed();
+  }
 }
 
 // End SqlDelegatingConformance.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/08b1dddd/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 f4a6631..66c467e 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
@@ -3785,7 +3785,7 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
     RelDataType logicalSourceRowType =
         getLogicalSourceRowType(sourceRowType, insert);
 
-    checkFieldCount(insert, logicalSourceRowType, logicalTargetRowType);
+    checkFieldCount(insert, table, logicalSourceRowType, logicalTargetRowType);
 
     checkTypeAssignment(logicalSourceRowType, logicalTargetRowType, insert);
 
@@ -3794,6 +3794,7 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
 
   private void checkFieldCount(
       SqlNode node,
+      SqlValidatorTable table,
       RelDataType logicalSourceRowType,
       RelDataType logicalTargetRowType) {
     final int sourceFieldCount = logicalSourceRowType.getFieldCount();
@@ -3802,12 +3803,43 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
       throw newValidationError(node,
           RESOURCE.unmatchInsertColumn(targetFieldCount, sourceFieldCount));
     }
+    // Ensure that non-nullable fields are targeted.
+    for (final RelDataTypeField field : table.getRowType().getFieldList()) {
+      if (!field.getType().isNullable()) {
+        final RelDataTypeField targetField =
+            logicalTargetRowType.getField(field.getName(), true, false);
+        final boolean haveDefaultValue =
+            table.columnHasDefaultValue(table.getRowType(), field.getIndex());
+        if (targetField == null && !haveDefaultValue) {
+          throw newValidationError(node,
+              RESOURCE.columnNotNullable(field.getName()));
+        }
+      }
+    }
   }
 
   protected RelDataType getLogicalTargetRowType(
       RelDataType targetRowType,
       SqlInsert insert) {
-    return targetRowType;
+    if (insert.getTargetColumnList() == null
+        && conformance.isInsertSubsetColumnsAllowed()) {
+      // Target an implicit subset of columns.
+      final SqlNode source = insert.getSource();
+      final RelDataType sourceRowType = getNamespace(source).getRowType();
+      final RelDataType logicalSourceRowType =
+          getLogicalSourceRowType(sourceRowType, insert);
+      final RelDataType implicitTargetRowType =
+          typeFactory.createStructType(
+              targetRowType.getFieldList()
+                  .subList(0, logicalSourceRowType.getFieldCount()));
+      final SqlValidatorNamespace targetNamespace = getNamespace(insert);
+      validateNamespace(targetNamespace, implicitTargetRowType);
+      return implicitTargetRowType;
+    } else {
+      // Either the set of columns are explicitly targeted, or target the full
+      // set of columns.
+      return targetRowType;
+    }
   }
 
   protected RelDataType getLogicalSourceRowType(
@@ -4024,7 +4056,13 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
       }
 
       SqlCall rowConstructor = (SqlCall) operand;
-      if (targetRowType.isStruct()
+      if (conformance.isInsertSubsetColumnsAllowed() && targetRowType.isStruct()
+          && rowConstructor.operandCount() < targetRowType.getFieldCount()) {
+        targetRowType =
+            typeFactory.createStructType(
+                targetRowType.getFieldList()
+                    .subList(0, rowConstructor.operandCount()));
+      } else if (targetRowType.isStruct()
           && rowConstructor.operandCount() != targetRowType.getFieldCount()) {
         return;
       }
@@ -4033,6 +4071,18 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
           targetRowType,
           scope,
           rowConstructor);
+
+      if (targetRowType.isStruct()) {
+        for (Pair<SqlNode, RelDataTypeField> pair
+            : Pair.zip(rowConstructor.getOperandList(),
+                targetRowType.getFieldList())) {
+          if (!pair.right.getType().isNullable()
+              && SqlUtil.isNullLiteral(pair.left, false)) {
+            throw newValidationError(node,
+                RESOURCE.columnNotNullable(pair.right.getName()));
+          }
+        }
+      }
     }
 
     for (SqlNode operand : operands) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/08b1dddd/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 e442cdc..66eec0a 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
@@ -44,6 +44,16 @@ public interface SqlValidatorTable {
   SqlAccessType getAllowedAccess();
 
   boolean supportsModality(SqlModality modality);
+
+  /**
+   * Returns whether the ordinal column has a default value.
+   */
+  boolean columnHasDefaultValue(RelDataType rowType, int ordinal);
+
+  /**
+   * 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/08b1dddd/core/src/main/java/org/apache/calcite/sql2rel/DefaultValueFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/DefaultValueFactory.java b/core/src/main/java/org/apache/calcite/sql2rel/DefaultValueFactory.java
deleted file mode 100644
index 1e34826..0000000
--- a/core/src/main/java/org/apache/calcite/sql2rel/DefaultValueFactory.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * 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.sql2rel;
-
-import org.apache.calcite.plan.RelOptTable;
-import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.rex.RexNode;
-import org.apache.calcite.sql.SqlFunction;
-
-import java.util.List;
-
-/**
- * DefaultValueFactory supplies default values for INSERT, UPDATE, and NEW.
- *
- * <p>TODO jvs 26-Feb-2005: rename this to InitializerExpressionFactory, since
- * it is in the process of being generalized to handle constructor invocations
- * and eventually generated columns.
- */
-public interface DefaultValueFactory {
-  //~ Methods ----------------------------------------------------------------
-
-  /**
-   * Whether a column is always generated. If a column is always generated,
-   * then non-generated values cannot be inserted into the column.
-   */
-  boolean isGeneratedAlways(
-      RelOptTable table,
-      int iColumn);
-
-  /**
-   * Creates an expression which evaluates to the default value for a
-   * particular column.
-   *
-   * @param table   the table containing the column
-   * @param iColumn the 0-based offset of the column in the table
-   * @return default value expression
-   */
-  RexNode newColumnDefaultValue(
-      RelOptTable table,
-      int iColumn);
-
-  /**
-   * Creates an expression which evaluates to the initializer expression for a
-   * particular attribute of a structured type.
-   *
-   * @param type            the structured type
-   * @param constructor     the constructor invoked to initialize the type
-   * @param iAttribute      the 0-based offset of the attribute in the type
-   * @param constructorArgs arguments passed to the constructor invocation
-   * @return default value expression
-   */
-  RexNode newAttributeInitializer(
-      RelDataType type,
-      SqlFunction constructor,
-      int iAttribute,
-      List<RexNode> constructorArgs);
-}
-
-// End DefaultValueFactory.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/08b1dddd/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
new file mode 100644
index 0000000..44eb0be
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/sql2rel/InitializerExpressionFactory.java
@@ -0,0 +1,69 @@
+/*
+ * 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.sql2rel;
+
+import org.apache.calcite.plan.RelOptTable;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.sql.SqlFunction;
+
+import java.util.List;
+
+/**
+ * InitializerExpressionFactory supplies default values for INSERT, UPDATE, and NEW.
+ */
+public interface InitializerExpressionFactory {
+  //~ Methods ----------------------------------------------------------------
+
+  /**
+   * Whether a column is always generated. If a column is always generated,
+   * then non-generated values cannot be inserted into the column.
+   */
+  boolean isGeneratedAlways(
+      RelOptTable table,
+      int iColumn);
+
+  /**
+   * Creates an expression which evaluates to the default value for a
+   * particular column.
+   *
+   * @param table   the table containing the column
+   * @param iColumn the 0-based offset of the column in the table
+   * @return default value expression
+   */
+  RexNode newColumnDefaultValue(
+      RelOptTable table,
+      int iColumn);
+
+  /**
+   * Creates an expression which evaluates to the initializer expression for a
+   * particular attribute of a structured type.
+   *
+   * @param type            the structured type
+   * @param constructor     the constructor invoked to initialize the type
+   * @param iAttribute      the 0-based offset of the attribute in the type
+   * @param constructorArgs arguments passed to the constructor invocation
+   * @return default value expression
+   */
+  RexNode newAttributeInitializer(
+      RelDataType type,
+      SqlFunction constructor,
+      int iAttribute,
+      List<RexNode> constructorArgs);
+}
+
+// End InitializerExpressionFactory.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/08b1dddd/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
new file mode 100644
index 0000000..83ecdf3
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/sql2rel/NullInitializerExpressionFactory.java
@@ -0,0 +1,52 @@
+/*
+ * 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.sql2rel;
+
+import org.apache.calcite.plan.RelOptTable;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.rex.RexBuilder;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.sql.SqlFunction;
+
+import java.util.List;
+
+/**
+ * An implementation of {@link InitializerExpressionFactory} that always supplies NULL.
+ */
+public class NullInitializerExpressionFactory implements InitializerExpressionFactory {
+  private final RexBuilder rexBuilder;
+
+  public NullInitializerExpressionFactory(RelDataTypeFactory typeFactory) {
+    this.rexBuilder = new RexBuilder(typeFactory);
+  }
+
+  public boolean isGeneratedAlways(RelOptTable table, int iColumn) {
+    return false;
+  }
+
+  public RexNode newColumnDefaultValue(RelOptTable table, int iColumn) {
+    return rexBuilder.constantNull();
+  }
+
+  public RexNode newAttributeInitializer(RelDataType type,
+      SqlFunction constructor, int iAttribute, List<RexNode> constructorArgs) {
+    return rexBuilder.constantNull();
+  }
+}
+
+// End NullInitializerExpressionFactory.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/08b1dddd/core/src/main/java/org/apache/calcite/sql2rel/SqlRexContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/SqlRexContext.java b/core/src/main/java/org/apache/calcite/sql2rel/SqlRexContext.java
index 2d7575c..f3e2f58 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlRexContext.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlRexContext.java
@@ -82,7 +82,7 @@ public interface SqlRexContext {
    * Returns the factory which supplies default values for INSERT, UPDATE, and
    * NEW.
    */
-  DefaultValueFactory getDefaultValueFactory();
+  InitializerExpressionFactory getInitializerExpressionFactory();
 
   /**
    * Returns the validator.

http://git-wip-us.apache.org/repos/asf/calcite/blob/08b1dddd/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 eca1456..33afe15 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -87,6 +87,7 @@ import org.apache.calcite.schema.ModifiableTable;
 import org.apache.calcite.schema.ModifiableView;
 import org.apache.calcite.schema.Table;
 import org.apache.calcite.schema.TranslatableTable;
+import org.apache.calcite.schema.Wrapper;
 import org.apache.calcite.sql.JoinConditionType;
 import org.apache.calcite.sql.JoinType;
 import org.apache.calcite.sql.SemiJoinType;
@@ -150,6 +151,7 @@ import org.apache.calcite.sql.validate.SqlValidator;
 import org.apache.calcite.sql.validate.SqlValidatorImpl;
 import org.apache.calcite.sql.validate.SqlValidatorNamespace;
 import org.apache.calcite.sql.validate.SqlValidatorScope;
+import org.apache.calcite.sql.validate.SqlValidatorTable;
 import org.apache.calcite.sql.validate.SqlValidatorUtil;
 import org.apache.calcite.tools.RelBuilder;
 import org.apache.calcite.util.ImmutableBitSet;
@@ -222,7 +224,6 @@ public class SqlToRelConverter {
   protected final RexBuilder rexBuilder;
   protected final Prepare.CatalogReader catalogReader;
   protected final RelOptCluster cluster;
-  private DefaultValueFactory defaultValueFactory;
   private SubQueryConverter subQueryConverter;
   protected final List<RelNode> leaves = new ArrayList<>();
   private final List<SqlDynamicParam> dynamicParamSqlNodes = new ArrayList<>();
@@ -304,7 +305,6 @@ public class SqlToRelConverter {
             : validator.getOperatorTable();
     this.validator = validator;
     this.catalogReader = catalogReader;
-    this.defaultValueFactory = new NullDefaultValueFactory();
     this.subQueryConverter = new NoOpSubQueryConverter();
     this.rexBuilder = cluster.getRexBuilder();
     this.typeFactory = rexBuilder.getTypeFactory();
@@ -390,16 +390,6 @@ public class SqlToRelConverter {
   }
 
   /**
-   * Set a new DefaultValueFactory. To have any effect, this must be called
-   * before any convert method.
-   *
-   * @param factory new DefaultValueFactory
-   */
-  public void setDefaultValueFactory(DefaultValueFactory factory) {
-    defaultValueFactory = factory;
-  }
-
-  /**
    * Sets a new SubQueryConverter. To have any effect, this must be called
    * before any convert method.
    *
@@ -3070,6 +3060,9 @@ public class SqlToRelConverter {
         new ArrayList<>(
             Collections.<String>nCopies(targetFields.size(), null));
 
+    final InitializerExpressionFactory initializerFactory =
+        getInitializerFactory(validator.getNamespace(call).getTable());
+
     // Walk the name list and place the associated value in the
     // expression list according to the ordinal value returned from
     // the table construct, leaving nulls in the list for columns
@@ -3088,24 +3081,43 @@ public class SqlToRelConverter {
       final String fieldName = field.getName();
       fieldNames.set(i, fieldName);
       if (sourceExps.get(i) != null) {
-        if (defaultValueFactory.isGeneratedAlways(targetTable, i)) {
+        if (initializerFactory.isGeneratedAlways(targetTable, i)) {
           throw RESOURCE.insertIntoAlwaysGenerated(fieldName).ex();
         }
         continue;
       }
-      sourceExps.set(
-          i, defaultValueFactory.newColumnDefaultValue(targetTable, i));
+      sourceExps.set(i,
+          initializerFactory.newColumnDefaultValue(targetTable, i));
 
       // bare nulls are dangerous in the wrong hands
-      sourceExps.set(
-          i,
-          castNullLiteralIfNeeded(
-              sourceExps.get(i), field.getType()));
+      sourceExps.set(i,
+          castNullLiteralIfNeeded(sourceExps.get(i), field.getType()));
     }
 
     return RelOptUtil.createProject(sourceRel, sourceExps, fieldNames, true);
   }
 
+  private InitializerExpressionFactory getInitializerFactory(
+      SqlValidatorTable validatorTable) {
+    // We might unwrap a null instead of a InitializerExpressionFactory.
+    final Table table = unwrap(validatorTable, Table.class);
+    if (table != null) {
+      InitializerExpressionFactory f =
+          unwrap(table, InitializerExpressionFactory.class);
+      if (f != null) {
+        return f;
+      }
+    }
+    return new NullInitializerExpressionFactory(typeFactory);
+  }
+
+  private static <T> T unwrap(Object o, Class<T> clazz) {
+    if (o instanceof Wrapper) {
+      return ((Wrapper) o).unwrap(clazz);
+    }
+    return null;
+  }
+
   private RexNode castNullLiteralIfNeeded(RexNode node, RelDataType type) {
     if (!RexLiteral.isNullLiteral(node)) {
       return node;
@@ -3129,16 +3141,24 @@ public class SqlToRelConverter {
       final List<String> targetColumnNames,
       List<RexNode> columnExprs) {
     final RelOptTable targetTable = getTargetTable(call);
-    final RelDataType targetRowType = targetTable.getRowType();
+    final RelDataType tableRowType = targetTable.getRowType();
     SqlNodeList targetColumnList = call.getTargetColumnList();
     if (targetColumnList == null) {
-      targetColumnNames.addAll(targetRowType.getFieldNames());
+      if (validator.getConformance().isInsertSubsetColumnsAllowed()) {
+        final RelDataType targetRowType =
+            typeFactory.createStructType(
+                tableRowType.getFieldList()
+                    .subList(0, sourceRef.getType().getFieldCount()));
+        targetColumnNames.addAll(targetRowType.getFieldNames());
+      } else {
+        targetColumnNames.addAll(tableRowType.getFieldNames());
+      }
     } else {
       for (int i = 0; i < targetColumnList.size(); i++) {
         SqlIdentifier id = (SqlIdentifier) targetColumnList.get(i);
         RelDataTypeField field =
             SqlValidatorUtil.getTargetField(
-                targetRowType, typeFactory, id, catalogReader, targetTable);
+                tableRowType, typeFactory, id, catalogReader, targetTable);
         assert field != null : "column " + id.toString() + " not found";
         targetColumnNames.add(field.getName());
       }
@@ -3708,6 +3728,9 @@ public class SqlToRelConverter {
     private final List<RelDataTypeField> systemFieldList = new ArrayList<>();
     final boolean top;
 
+    private final InitializerExpressionFactory initializerExpressionFactory =
+        new NullInitializerExpressionFactory(typeFactory);
+
     /**
      * Creates a Blackboard.
      *
@@ -4257,8 +4280,8 @@ public class SqlToRelConverter {
       return typeFactory;
     }
 
-    public DefaultValueFactory getDefaultValueFactory() {
-      return defaultValueFactory;
+    public InitializerExpressionFactory getInitializerExpressionFactory() {
+      return initializerExpressionFactory;
     }
 
     public SqlValidator getValidator() {
@@ -4337,31 +4360,6 @@ public class SqlToRelConverter {
   }
 
   /**
-   * An implementation of DefaultValueFactory which always supplies NULL.
-   */
-  class NullDefaultValueFactory implements DefaultValueFactory {
-    public boolean isGeneratedAlways(
-        RelOptTable table,
-        int iColumn) {
-      return false;
-    }
-
-    public RexNode newColumnDefaultValue(
-        RelOptTable table,
-        int iColumn) {
-      return rexBuilder.constantNull();
-    }
-
-    public RexNode newAttributeInitializer(
-        RelDataType type,
-        SqlFunction constructor,
-        int iAttribute,
-        List<RexNode> constructorArgs) {
-      return rexBuilder.constantNull();
-    }
-  }
-
-  /**
    * A default implementation of SubQueryConverter that does no conversion.
    */
   private class NoOpSubQueryConverter implements SubQueryConverter {

http://git-wip-us.apache.org/repos/asf/calcite/blob/08b1dddd/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 40fecf7..f7f121b 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
@@ -900,7 +900,7 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
         ImmutableList.builder();
     for (int i = 0; i < n; ++i) {
       initializationExprs.add(
-          cx.getDefaultValueFactory().newAttributeInitializer(
+          cx.getInitializerExpressionFactory().newAttributeInitializer(
               type, constructor, i, exprs));
     }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/08b1dddd/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
----------------------------------------------------------------------
diff --git a/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties b/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
index 83aeb7f..ed3d96b 100644
--- a/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
+++ b/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
@@ -55,6 +55,7 @@ UnknownField=Unknown field ''{0}''
 UnknownTargetColumn=Unknown target column ''{0}''
 DuplicateTargetColumn=Target column ''{0}'' is assigned more than once
 UnmatchInsertColumn=Number of INSERT target columns ({0,number}) does not equal number of source items ({1,number})
+ColumnNotNullable=Column ''{0}'' has no default value and does not allow NULLs
 TypeNotAssignable=Cannot assign to target field ''{0}'' of type {1} from source field ''{2}'' of type {3}
 TableNameNotFound=Table ''{0}'' not found
 TableNotFound=Table ''{0}'' not found

http://git-wip-us.apache.org/repos/asf/calcite/blob/08b1dddd/core/src/test/java/org/apache/calcite/sql/test/SqlAdvisorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/test/SqlAdvisorTest.java b/core/src/test/java/org/apache/calcite/sql/test/SqlAdvisorTest.java
index b318b7c..76bfc51 100644
--- a/core/src/test/java/org/apache/calcite/sql/test/SqlAdvisorTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/test/SqlAdvisorTest.java
@@ -69,8 +69,11 @@ public class SqlAdvisorTest extends SqlValidatorTestCase {
       Arrays.asList(
           "SCHEMA(CATALOG.SALES)",
           "TABLE(CATALOG.SALES.EMP)",
+          "TABLE(CATALOG.SALES.EMPDEFAULTS)",
+          "TABLE(CATALOG.SALES.EMPNULLABLES)",
           "TABLE(CATALOG.SALES.EMP_B)",
           "TABLE(CATALOG.SALES.EMP_20)",
+          "TABLE(CATALOG.SALES.EMPNULLABLES_20)",
           "TABLE(CATALOG.SALES.EMP_ADDRESS)",
           "TABLE(CATALOG.SALES.DEPT)",
           "TABLE(CATALOG.SALES.DEPT_NESTED)",

http://git-wip-us.apache.org/repos/asf/calcite/blob/08b1dddd/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java b/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java
index 18ce756..9d84d9f 100644
--- a/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java
+++ b/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java
@@ -73,6 +73,8 @@ import org.apache.calcite.sql.validate.SqlMonotonicity;
 import org.apache.calcite.sql.validate.SqlNameMatcher;
 import org.apache.calcite.sql.validate.SqlNameMatchers;
 import org.apache.calcite.sql.validate.SqlValidatorCatalogReader;
+import org.apache.calcite.sql2rel.InitializerExpressionFactory;
+import org.apache.calcite.sql2rel.NullInitializerExpressionFactory;
 import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.ImmutableIntList;
 import org.apache.calcite.util.Litmus;
@@ -144,51 +146,8 @@ public class MockCatalogReader extends CalciteCatalogReader {
    * Initializes this catalog reader.
    */
   public MockCatalogReader init() {
-    final RelDataType intType =
-        typeFactory.createSqlType(SqlTypeName.INTEGER);
-    final RelDataType intTypeNull =
-        typeFactory.createTypeWithNullability(intType, true);
-    final RelDataType varchar10Type =
-        typeFactory.createSqlType(SqlTypeName.VARCHAR, 10);
-    final RelDataType varchar20Type =
-        typeFactory.createSqlType(SqlTypeName.VARCHAR, 20);
-    final RelDataType timestampType =
-        typeFactory.createSqlType(SqlTypeName.TIMESTAMP);
-    final RelDataType dateType =
-        typeFactory.createSqlType(SqlTypeName.DATE);
-    final RelDataType booleanType =
-        typeFactory.createSqlType(SqlTypeName.BOOLEAN);
-    final RelDataType rectilinearCoordType =
-        typeFactory.builder()
-            .add("X", intType)
-            .add("Y", intType)
-            .build();
-    final RelDataType rectilinearPeekCoordType =
-        typeFactory.builder()
-            .add("X", intType)
-            .add("Y", intType)
-            .kind(StructKind.PEEK_FIELDS)
-            .build();
-    final RelDataType empRecordType =
-        typeFactory.builder()
-            .add("EMPNO", intType)
-            .add("ENAME", varchar10Type).build();
-    final RelDataType empListType =
-        typeFactory.createArrayType(empRecordType, -1);
-
-    // TODO jvs 12-Feb-2005: register this canonical instance with type
-    // factory
-    addressType =
-        new ObjectSqlType(
-            SqlTypeName.STRUCTURED,
-            new SqlIdentifier("ADDRESS", SqlParserPos.ZERO),
-            false,
-            Arrays.asList(
-                new RelDataTypeFieldImpl("STREET", 0, varchar20Type),
-                new RelDataTypeFieldImpl("CITY", 1, varchar20Type),
-                new RelDataTypeFieldImpl("ZIP", 2, intType),
-                new RelDataTypeFieldImpl("STATE", 3, varchar20Type)),
-            RelDataTypeComparability.NONE);
+    final Fixture f = new Fixture();
+    addressType = f.addressType;
 
     // Register "SALES" schema.
     MockSchema salesSchema = new MockSchema("SALES");
@@ -197,67 +156,115 @@ public class MockCatalogReader extends CalciteCatalogReader {
     // Register "EMP" table.
     final MockTable empTable =
         MockTable.create(this, salesSchema, "EMP", false, 14);
-    empTable.addColumn("EMPNO", intType, true);
-    empTable.addColumn("ENAME", varchar20Type);
-    empTable.addColumn("JOB", varchar10Type);
-    empTable.addColumn("MGR", intTypeNull);
-    empTable.addColumn("HIREDATE", timestampType);
-    empTable.addColumn("SAL", intType);
-    empTable.addColumn("COMM", intType);
-    empTable.addColumn("DEPTNO", intType);
-    empTable.addColumn("SLACKER", booleanType);
+    empTable.addColumn("EMPNO", f.intType, true);
+    empTable.addColumn("ENAME", f.varchar20Type);
+    empTable.addColumn("JOB", f.varchar10Type);
+    empTable.addColumn("MGR", f.intTypeNull);
+    empTable.addColumn("HIREDATE", f.timestampType);
+    empTable.addColumn("SAL", f.intType);
+    empTable.addColumn("COMM", f.intType);
+    empTable.addColumn("DEPTNO", f.intType);
+    empTable.addColumn("SLACKER", f.booleanType);
     registerTable(empTable);
 
+    // Register "EMPNULLABLES" table with nullable columns.
+    final MockTable empNullablesTable =
+        MockTable.create(this, salesSchema, "EMPNULLABLES", false, 14);
+    empNullablesTable.addColumn("EMPNO", f.intType, true);
+    empNullablesTable.addColumn("ENAME", f.varchar20Type);
+    empNullablesTable.addColumn("JOB", f.varchar10TypeNull);
+    empNullablesTable.addColumn("MGR", f.intTypeNull);
+    empNullablesTable.addColumn("HIREDATE", f.timestampTypeNull);
+    empNullablesTable.addColumn("SAL", f.intTypeNull);
+    empNullablesTable.addColumn("COMM", f.intTypeNull);
+    empNullablesTable.addColumn("DEPTNO", f.intTypeNull);
+    empNullablesTable.addColumn("SLACKER", f.booleanTypeNull);
+    registerTable(empNullablesTable);
+
+    // Register "EMPDEFAULTS" table with default values for some columns.
+    final InitializerExpressionFactory empInitializerExpressionFactory =
+        new NullInitializerExpressionFactory(typeFactory) {
+          @Override public RexNode newColumnDefaultValue(RelOptTable table,
+              int iColumn) {
+            final RexBuilder rexBuilder = new RexBuilder(typeFactory);
+            switch (iColumn) {
+            case 0:
+              return rexBuilder.makeExactLiteral(new BigDecimal(123),
+                  typeFactory.createSqlType(SqlTypeName.INTEGER));
+            case 1:
+              return rexBuilder.makeLiteral("Bob");
+            case 5:
+              return rexBuilder.makeExactLiteral(new BigDecimal(555),
+                  typeFactory.createSqlType(SqlTypeName.INTEGER));
+            default:
+              return rexBuilder.constantNull();
+            }
+          }
+        };
+    final MockTable empDefaultsTable =
+        MockTable.create(this, salesSchema, "EMPDEFAULTS", false, 14, null,
+            empInitializerExpressionFactory);
+    empDefaultsTable.addColumn("EMPNO", f.intType, true);
+    empDefaultsTable.addColumn("ENAME", f.varchar20Type);
+    empDefaultsTable.addColumn("JOB", f.varchar10TypeNull);
+    empDefaultsTable.addColumn("MGR", f.intTypeNull);
+    empDefaultsTable.addColumn("HIREDATE", f.timestampTypeNull);
+    empDefaultsTable.addColumn("SAL", f.intTypeNull);
+    empDefaultsTable.addColumn("COMM", f.intTypeNull);
+    empDefaultsTable.addColumn("DEPTNO", f.intTypeNull);
+    empDefaultsTable.addColumn("SLACKER", f.booleanTypeNull);
+    registerTable(empDefaultsTable);
+
     // Register "EMP_B" table. As "EMP", birth with a "BIRTHDATE" column.
     final MockTable empBTable =
         MockTable.create(this, salesSchema, "EMP_B", false, 14);
-    empBTable.addColumn("EMPNO", intType, true);
-    empBTable.addColumn("ENAME", varchar20Type);
-    empBTable.addColumn("JOB", varchar10Type);
-    empBTable.addColumn("MGR", intTypeNull);
-    empBTable.addColumn("HIREDATE", timestampType);
-    empBTable.addColumn("SAL", intType);
-    empBTable.addColumn("COMM", intType);
-    empBTable.addColumn("DEPTNO", intType);
-    empBTable.addColumn("SLACKER", booleanType);
-    empBTable.addColumn("BIRTHDATE", dateType);
+    empBTable.addColumn("EMPNO", f.intType, true);
+    empBTable.addColumn("ENAME", f.varchar20Type);
+    empBTable.addColumn("JOB", f.varchar10Type);
+    empBTable.addColumn("MGR", f.intTypeNull);
+    empBTable.addColumn("HIREDATE", f.timestampType);
+    empBTable.addColumn("SAL", f.intType);
+    empBTable.addColumn("COMM", f.intType);
+    empBTable.addColumn("DEPTNO", f.intType);
+    empBTable.addColumn("SLACKER", f.booleanType);
+    empBTable.addColumn("BIRTHDATE", f.dateType);
     registerTable(empBTable);
 
     // Register "DEPT" table.
     MockTable deptTable = MockTable.create(this, salesSchema, "DEPT", false, 4);
-    deptTable.addColumn("DEPTNO", intType, true);
-    deptTable.addColumn("NAME", varchar10Type);
+    deptTable.addColumn("DEPTNO", f.intType, true);
+    deptTable.addColumn("NAME", f.varchar10Type);
     registerTable(deptTable);
 
     // Register "DEPT_NESTED" table.
     MockTable deptNestedTable =
         MockTable.create(this, salesSchema, "DEPT_NESTED", false, 4);
-    deptNestedTable.addColumn("DEPTNO", intType, true);
-    deptNestedTable.addColumn("NAME", varchar10Type);
-    deptNestedTable.addColumn("EMPLOYEES", empListType);
+    deptNestedTable.addColumn("DEPTNO", f.intType, true);
+    deptNestedTable.addColumn("NAME", f.varchar10Type);
+    deptNestedTable.addColumn("EMPLOYEES", f.empListType);
     registerTable(deptNestedTable);
 
     // Register "BONUS" table.
     MockTable bonusTable =
         MockTable.create(this, salesSchema, "BONUS", false, 0);
-    bonusTable.addColumn("ENAME", varchar20Type);
-    bonusTable.addColumn("JOB", varchar10Type);
-    bonusTable.addColumn("SAL", intType);
-    bonusTable.addColumn("COMM", intType);
+    bonusTable.addColumn("ENAME", f.varchar20Type);
+    bonusTable.addColumn("JOB", f.varchar10Type);
+    bonusTable.addColumn("SAL", f.intType);
+    bonusTable.addColumn("COMM", f.intType);
     registerTable(bonusTable);
 
     // Register "SALGRADE" table.
     MockTable salgradeTable =
         MockTable.create(this, salesSchema, "SALGRADE", false, 5);
-    salgradeTable.addColumn("GRADE", intType, true);
-    salgradeTable.addColumn("LOSAL", intType);
-    salgradeTable.addColumn("HISAL", intType);
+    salgradeTable.addColumn("GRADE", f.intType, true);
+    salgradeTable.addColumn("LOSAL", f.intType);
+    salgradeTable.addColumn("HISAL", f.intType);
     registerTable(salgradeTable);
 
     // Register "EMP_ADDRESS" table
     MockTable contactAddressTable =
         MockTable.create(this, salesSchema, "EMP_ADDRESS", false, 26);
-    contactAddressTable.addColumn("EMPNO", intType, true);
+    contactAddressTable.addColumn("EMPNO", f.intType, true);
     contactAddressTable.addColumn("HOME_ADDRESS", addressType);
     contactAddressTable.addColumn("MAILING_ADDRESS", addressType);
     registerTable(contactAddressTable);
@@ -283,129 +290,184 @@ public class MockCatalogReader extends CalciteCatalogReader {
     // Register "CONTACT" table.
     MockTable contactTable = MockTable.create(this, customerSchema, "CONTACT",
         false, 1000);
-    contactTable.addColumn("CONTACTNO", intType);
-    contactTable.addColumn("FNAME", varchar10Type);
-    contactTable.addColumn("LNAME", varchar10Type);
-    contactTable.addColumn("EMAIL", varchar20Type);
-    contactTable.addColumn("COORD", rectilinearCoordType);
+    contactTable.addColumn("CONTACTNO", f.intType);
+    contactTable.addColumn("FNAME", f.varchar10Type);
+    contactTable.addColumn("LNAME", f.varchar10Type);
+    contactTable.addColumn("EMAIL", f.varchar20Type);
+    contactTable.addColumn("COORD", f.rectilinearCoordType);
     registerTable(contactTable);
 
     // Register "CONTACT_PEEK" table. The
     MockTable contactPeekTable =
         MockTable.create(this, customerSchema, "CONTACT_PEEK", false, 1000);
-    contactPeekTable.addColumn("CONTACTNO", intType);
-    contactPeekTable.addColumn("FNAME", varchar10Type);
-    contactPeekTable.addColumn("LNAME", varchar10Type);
-    contactPeekTable.addColumn("EMAIL", varchar20Type);
-    contactPeekTable.addColumn("COORD", rectilinearPeekCoordType);
+    contactPeekTable.addColumn("CONTACTNO", f.intType);
+    contactPeekTable.addColumn("FNAME", f.varchar10Type);
+    contactPeekTable.addColumn("LNAME", f.varchar10Type);
+    contactPeekTable.addColumn("EMAIL", f.varchar20Type);
+    contactPeekTable.addColumn("COORD", f.rectilinearPeekCoordType);
     registerTable(contactPeekTable);
 
     // Register "ACCOUNT" table.
     MockTable accountTable = MockTable.create(this, customerSchema, "ACCOUNT",
         false, 457);
-    accountTable.addColumn("ACCTNO", intType);
-    accountTable.addColumn("TYPE", varchar20Type);
-    accountTable.addColumn("BALANCE", intType);
+    accountTable.addColumn("ACCTNO", f.intType);
+    accountTable.addColumn("TYPE", f.varchar20Type);
+    accountTable.addColumn("BALANCE", f.intType);
     registerTable(accountTable);
 
     // Register "ORDERS" stream.
     MockTable ordersStream = MockTable.create(this, salesSchema, "ORDERS",
         true, Double.POSITIVE_INFINITY);
-    ordersStream.addColumn("ROWTIME", timestampType);
+    ordersStream.addColumn("ROWTIME", f.timestampType);
     ordersStream.addMonotonic("ROWTIME");
-    ordersStream.addColumn("PRODUCTID", intType);
-    ordersStream.addColumn("ORDERID", intType);
+    ordersStream.addColumn("PRODUCTID", f.intType);
+    ordersStream.addColumn("ORDERID", f.intType);
     registerTable(ordersStream);
 
     // Register "SHIPMENTS" stream.
     MockTable shipmentsStream = MockTable.create(this, salesSchema, "SHIPMENTS",
         true, Double.POSITIVE_INFINITY);
-    shipmentsStream.addColumn("ROWTIME", timestampType);
+    shipmentsStream.addColumn("ROWTIME", f.timestampType);
     shipmentsStream.addMonotonic("ROWTIME");
-    shipmentsStream.addColumn("ORDERID", intType);
+    shipmentsStream.addColumn("ORDERID", f.intType);
     registerTable(shipmentsStream);
 
     // Register "PRODUCTS" table.
     MockTable productsTable = MockTable.create(this, salesSchema, "PRODUCTS",
         false, 200D);
-    productsTable.addColumn("PRODUCTID", intType);
-    productsTable.addColumn("NAME", varchar20Type);
-    productsTable.addColumn("SUPPLIERID", intType);
+    productsTable.addColumn("PRODUCTID", f.intType);
+    productsTable.addColumn("NAME", f.varchar20Type);
+    productsTable.addColumn("SUPPLIERID", f.intType);
     registerTable(productsTable);
 
     // Register "SUPPLIERS" table.
     MockTable suppliersTable = MockTable.create(this, salesSchema, "SUPPLIERS",
         false, 10D);
-    suppliersTable.addColumn("SUPPLIERID", intType);
-    suppliersTable.addColumn("NAME", varchar20Type);
-    suppliersTable.addColumn("CITY", intType);
+    suppliersTable.addColumn("SUPPLIERID", f.intType);
+    suppliersTable.addColumn("NAME", f.varchar20Type);
+    suppliersTable.addColumn("CITY", f.intType);
     registerTable(suppliersTable);
 
-    // Register "EMP_20" view.
-    // Same columns as "EMP",
+    // Register "EMP_20" and "EMPNULLABLES_20 views.
+    // Same columns as "EMP" amd "EMPNULLABLES",
     // but "DEPTNO" not visible and set to 20 by default
     // and "SAL" is visible but must be greater than 1000,
     // which is the equivalent of:
     //   SELECT EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, SLACKER
     //   FROM EMP
     //   WHERE DEPTNO = 20 AND SAL > 1000
-    MockTable emp20View = new MockViewTable(this, salesSchema.getCatalogName(),
-        salesSchema.name, "EMP_20", false, 600, empTable,
-        ImmutableIntList.of(0, 1, 2, 3, 4, 5, 6, 8), null) {
-
-      @Override public RexNode getConstraint(RexBuilder rexBuilder,
-          RelDataType tableRowType) {
-        final RelDataTypeField deptnoField =
-            tableRowType.getFieldList().get(7);
-        final RelDataTypeField salField =
-            tableRowType.getFieldList().get(5);
-        final List<RexNode> nodes = Arrays.asList(
-            rexBuilder.makeCall(SqlStdOperatorTable.EQUALS,
-                rexBuilder.makeInputRef(deptnoField.getType(),
-                    deptnoField.getIndex()),
-                rexBuilder.makeExactLiteral(BigDecimal.valueOf(20L),
-                    deptnoField.getType())),
-            rexBuilder.makeCall(SqlStdOperatorTable.GREATER_THAN,
-                rexBuilder.makeInputRef(salField.getType(),
-                    salField.getIndex()),
-                rexBuilder.makeExactLiteral(BigDecimal.valueOf(1000L),
-                    salField.getType())));
-        return RexUtil.composeConjunction(rexBuilder, nodes, false);
-      }
-    };
+    final NullInitializerExpressionFactory nullInitializerFactory =
+        new NullInitializerExpressionFactory(this.typeFactory);
+    final ImmutableIntList m0 = ImmutableIntList.of(0, 1, 2, 3, 4, 5, 6, 8);
+    MockTable emp20View =
+        new MockViewTable(this, salesSchema.getCatalogName(), salesSchema.name,
+            "EMP_20", false, 600, empTable, m0, null, nullInitializerFactory) {
+          public RexNode getConstraint(RexBuilder rexBuilder,
+              RelDataType tableRowType) {
+            final RelDataTypeField deptnoField =
+                tableRowType.getFieldList().get(7);
+            final RelDataTypeField salField =
+                tableRowType.getFieldList().get(5);
+            final List<RexNode> nodes = Arrays.asList(
+                rexBuilder.makeCall(SqlStdOperatorTable.EQUALS,
+                    rexBuilder.makeInputRef(deptnoField.getType(),
+                        deptnoField.getIndex()),
+                    rexBuilder.makeExactLiteral(BigDecimal.valueOf(20L),
+                        deptnoField.getType())),
+                rexBuilder.makeCall(SqlStdOperatorTable.GREATER_THAN,
+                    rexBuilder.makeInputRef(salField.getType(),
+                        salField.getIndex()),
+                    rexBuilder.makeExactLiteral(BigDecimal.valueOf(1000L),
+                        salField.getType())));
+            return RexUtil.composeConjunction(rexBuilder, nodes, false);
+          }
+        };
     salesSchema.addTable(Util.last(emp20View.getQualifiedName()));
-    emp20View.addColumn("EMPNO", intType);
-    emp20View.addColumn("ENAME", varchar20Type);
-    emp20View.addColumn("JOB", varchar10Type);
-    emp20View.addColumn("MGR", intTypeNull);
-    emp20View.addColumn("HIREDATE", timestampType);
-    emp20View.addColumn("SAL", intType);
-    emp20View.addColumn("COMM", intType);
-    emp20View.addColumn("SLACKER", booleanType);
+    emp20View.addColumn("EMPNO", f.intType);
+    emp20View.addColumn("ENAME", f.varchar20Type);
+    emp20View.addColumn("JOB", f.varchar10Type);
+    emp20View.addColumn("MGR", f.intTypeNull);
+    emp20View.addColumn("HIREDATE", f.timestampType);
+    emp20View.addColumn("SAL", f.intType);
+    emp20View.addColumn("COMM", f.intType);
+    emp20View.addColumn("SLACKER", f.booleanType);
     registerTable(emp20View);
 
+    MockTable empNullables20View =
+        new MockViewTable(this, salesSchema.getCatalogName(), salesSchema.name,
+            "EMPNULLABLES_20", false, 600, empNullablesTable, m0, null,
+            nullInitializerFactory) {
+          public RexNode getConstraint(RexBuilder rexBuilder,
+              RelDataType tableRowType) {
+            final RelDataTypeField deptnoField =
+                tableRowType.getFieldList().get(7);
+            final RelDataTypeField salField =
+                tableRowType.getFieldList().get(5);
+            final List<RexNode> nodes = Arrays.asList(
+                rexBuilder.makeCall(SqlStdOperatorTable.EQUALS,
+                    rexBuilder.makeInputRef(deptnoField.getType(),
+                        deptnoField.getIndex()),
+                    rexBuilder.makeExactLiteral(BigDecimal.valueOf(20L),
+                        deptnoField.getType())),
+                rexBuilder.makeCall(SqlStdOperatorTable.GREATER_THAN,
+                    rexBuilder.makeInputRef(salField.getType(),
+                        salField.getIndex()),
+                    rexBuilder.makeExactLiteral(BigDecimal.valueOf(1000L),
+                        salField.getType())));
+            return RexUtil.composeConjunction(rexBuilder, nodes, false);
+          }
+        };
+    salesSchema.addTable(Util.last(empNullables20View.getQualifiedName()));
+    empNullables20View.addColumn("EMPNO", f.intType);
+    empNullables20View.addColumn("ENAME", f.varchar20Type);
+    empNullables20View.addColumn("JOB", f.varchar10TypeNull);
+    empNullables20View.addColumn("MGR", f.intTypeNull);
+    empNullables20View.addColumn("HIREDATE", f.timestampTypeNull);
+    empNullables20View.addColumn("SAL", f.intTypeNull);
+    empNullables20View.addColumn("COMM", f.intTypeNull);
+    empNullables20View.addColumn("SLACKER", f.booleanTypeNull);
+    registerTable(empNullables20View);
+
     MockSchema structTypeSchema = new MockSchema("STRUCT");
     registerSchema(structTypeSchema);
     final List<CompoundNameColumn> columns = Arrays.asList(
-        new CompoundNameColumn("", "K0", varchar20Type),
-        new CompoundNameColumn("", "C1", varchar20Type),
-        new CompoundNameColumn("F1", "A0", intType),
-        new CompoundNameColumn("F2", "A0", booleanType),
-        new CompoundNameColumn("F0", "C0", intType),
-        new CompoundNameColumn("F1", "C0", intTypeNull),
-        new CompoundNameColumn("F0", "C1", intType),
-        new CompoundNameColumn("F1", "C2", intType),
-        new CompoundNameColumn("F2", "C3", intType));
+        new CompoundNameColumn("", "K0", f.varchar20Type),
+        new CompoundNameColumn("", "C1", f.varchar20Type),
+        new CompoundNameColumn("F1", "A0", f.intType),
+        new CompoundNameColumn("F2", "A0", f.booleanType),
+        new CompoundNameColumn("F0", "C0", f.intType),
+        new CompoundNameColumn("F1", "C0", f.intTypeNull),
+        new CompoundNameColumn("F0", "C1", f.intType),
+        new CompoundNameColumn("F1", "C2", f.intType),
+        new CompoundNameColumn("F2", "C3", f.intType));
     final CompoundNameColumnResolver structTypeTableResolver =
         new CompoundNameColumnResolver(columns, "F0");
-    final MockTable structTypeTable = new MockTable(this,
-        structTypeSchema.getCatalogName(), structTypeSchema.name,
-        "T", false, 100, structTypeTableResolver);
+    final MockTable structTypeTable =
+        MockTable.create(this, structTypeSchema, "T", false, 100,
+            structTypeTableResolver);
     for (CompoundNameColumn column : columns) {
       structTypeTable.addColumn(column.getName(), column.type);
     }
     registerTable(structTypeTable);
 
+    final List<CompoundNameColumn> columnsNullable = Arrays.asList(
+        new CompoundNameColumn("", "K0", f.varchar20TypeNull),
+        new CompoundNameColumn("", "C1", f.varchar20TypeNull),
+        new CompoundNameColumn("F1", "A0", f.intTypeNull),
+        new CompoundNameColumn("F2", "A0", f.booleanTypeNull),
+        new CompoundNameColumn("F0", "C0", f.intTypeNull),
+        new CompoundNameColumn("F1", "C0", f.intTypeNull),
+        new CompoundNameColumn("F0", "C1", f.intTypeNull),
+        new CompoundNameColumn("F1", "C2", f.intType),
+        new CompoundNameColumn("F2", "C3", f.intTypeNull));
+    final MockTable structNullableTypeTable =
+        MockTable.create(this, structTypeSchema, "T_NULLABLES", false, 100,
+            structTypeTableResolver);
+    for (CompoundNameColumn column : columnsNullable) {
+      structNullableTypeTable.addColumn(column.getName(), column.type);
+    }
+    registerTable(structNullableTypeTable);
+
     // Register "STRUCT.T_10" view.
     // Same columns as "STRUCT.T",
     // but "F0.C0" is set to 10 by default,
@@ -413,23 +475,22 @@ public class MockCatalogReader extends CalciteCatalogReader {
     //   SELECT *
     //   FROM T
     //   WHERE F0.C0 = 10
-    MockTable struct10View = new MockViewTable(this,
-        structTypeSchema.getCatalogName(),
-        structTypeSchema.name, "T_10", false, 20,
-        structTypeTable, ImmutableIntList.of(0, 1, 2, 3, 4, 5, 6, 7, 8),
-        structTypeTableResolver) {
-
-      @Override public RexNode getConstraint(RexBuilder rexBuilder,
-          RelDataType tableRowType) {
-        final RelDataTypeField c0Field =
-            tableRowType.getFieldList().get(4);
-        return rexBuilder.makeCall(SqlStdOperatorTable.EQUALS,
-            rexBuilder.makeInputRef(c0Field.getType(),
-                c0Field.getIndex()),
-            rexBuilder.makeExactLiteral(BigDecimal.valueOf(10L),
-                c0Field.getType()));
-      }
-    };
+    final ImmutableIntList m1 = ImmutableIntList.of(0, 1, 2, 3, 4, 5, 6, 7, 8);
+    MockTable struct10View =
+        new MockViewTable(this, structTypeSchema.getCatalogName(),
+            structTypeSchema.name, "T_10", false, 20, structTypeTable,
+            m1, structTypeTableResolver, nullInitializerFactory) {
+          @Override public RexNode getConstraint(RexBuilder rexBuilder,
+              RelDataType tableRowType) {
+            final RelDataTypeField c0Field =
+                tableRowType.getFieldList().get(4);
+            return rexBuilder.makeCall(SqlStdOperatorTable.EQUALS,
+                rexBuilder.makeInputRef(c0Field.getType(),
+                    c0Field.getIndex()),
+                rexBuilder.makeExactLiteral(BigDecimal.valueOf(10L),
+                    c0Field.getType()));
+          }
+        };
     structTypeSchema.addTable(Util.last(struct10View.getQualifiedName()));
     for (CompoundNameColumn column : columns) {
       struct10View.addColumn(column.getName(), column.type);
@@ -527,7 +588,7 @@ public class MockCatalogReader extends CalciteCatalogReader {
    * Mock implementation of
    * {@link org.apache.calcite.prepare.Prepare.PreparingTable}.
    */
-  public static class MockTable implements Prepare.PreparingTable {
+  public static class MockTable extends Prepare.AbstractPreparingTable {
     protected final MockCatalogReader catalogReader;
     private final boolean stream;
     private final double rowCount;
@@ -540,20 +601,23 @@ public class MockCatalogReader extends CalciteCatalogReader {
     private final Set<String> monotonicColumnSet = Sets.newHashSet();
     private StructKind kind = StructKind.FULLY_QUALIFIED;
     protected final ColumnResolver resolver;
+    private final InitializerExpressionFactory initializerFactory;
 
     public MockTable(MockCatalogReader catalogReader, String catalogName,
         String schemaName, String name, boolean stream, double rowCount,
-        ColumnResolver resolver) {
+        ColumnResolver resolver,
+        InitializerExpressionFactory initializerFactory) {
       this.catalogReader = catalogReader;
       this.stream = stream;
       this.rowCount = rowCount;
       this.names = ImmutableList.of(catalogName, schemaName, name);
       this.resolver = resolver;
+      this.initializerFactory = initializerFactory;
     }
 
     /** Implementation of AbstractModifiableTable. */
-    private class ModifiableTable extends JdbcTest.AbstractModifiableTable {
-
+    private class ModifiableTable extends JdbcTest.AbstractModifiableTable
+        implements Wrapper {
       protected ModifiableTable(String tableName) {
         super(tableName);
       }
@@ -581,6 +645,13 @@ public class MockCatalogReader extends CalciteCatalogReader {
           String tableName, Class clazz) {
         return null;
       }
+
+      @Override public <C> C unwrap(Class<C> aClass) {
+        if (aClass.isInstance(initializerFactory)) {
+          return aClass.cast(initializerFactory);
+        }
+        return null;
+      }
     }
 
     /**
@@ -588,7 +659,7 @@ public class MockCatalogReader extends CalciteCatalogReader {
      * CustomColumnResolvingTable.
      */
     private class ModifiableTableWithCustomColumnResolving
-        extends ModifiableTable implements CustomColumnResolvingTable {
+        extends ModifiableTable implements CustomColumnResolvingTable, Wrapper {
 
       protected ModifiableTableWithCustomColumnResolving(String tableName) {
         super(tableName);
@@ -599,13 +670,33 @@ public class MockCatalogReader extends CalciteCatalogReader {
         return resolver.resolveColumn(rowType, typeFactory, names);
       }
 
+      @Override public <C> C unwrap(Class<C> aClass) {
+        if (aClass.isInstance(initializerFactory)) {
+          return aClass.cast(initializerFactory);
+        }
+        return null;
+      }
     }
 
     public static MockTable create(MockCatalogReader catalogReader,
         MockSchema schema, String name, boolean stream, double rowCount) {
+      return create(catalogReader, schema, name, stream, rowCount, null);
+    }
+
+    public static MockTable create(MockCatalogReader catalogReader,
+        MockSchema schema, String name, boolean stream, double rowCount,
+        ColumnResolver resolver) {
+      return create(catalogReader, schema, name, stream, rowCount, resolver,
+          new NullInitializerExpressionFactory(catalogReader.typeFactory));
+    }
+
+    public static MockTable create(MockCatalogReader catalogReader,
+        MockSchema schema, String name, boolean stream, double rowCount,
+        ColumnResolver resolver,
+        InitializerExpressionFactory initializerExpressionFactory) {
       MockTable table =
           new MockTable(catalogReader, schema.getCatalogName(), schema.name,
-              name, stream, rowCount, null);
+              name, stream, rowCount, resolver, initializerExpressionFactory);
       schema.addTable(name);
       return table;
     }
@@ -698,7 +789,8 @@ public class MockCatalogReader extends CalciteCatalogReader {
 
     public RelOptTable extend(List<RelDataTypeField> extendedFields) {
       final MockTable table = new MockTable(catalogReader, names.get(0),
-          names.get(1), names.get(2), stream, rowCount, resolver);
+          names.get(1), names.get(2), stream, rowCount, resolver,
+          initializerFactory);
       table.columnList.addAll(columnList);
       table.columnList.addAll(extendedFields);
       table.onRegister(catalogReader.typeFactory);
@@ -725,17 +817,18 @@ public class MockCatalogReader extends CalciteCatalogReader {
 
     MockViewTable(MockCatalogReader catalogReader, String catalogName,
         String schemaName, String name, boolean stream, double rowCount,
-        MockTable fromTable, ImmutableIntList mapping, ColumnResolver resolver) {
-      super(catalogReader, catalogName,
-          schemaName, name, stream, rowCount, resolver);
+        MockTable fromTable, ImmutableIntList mapping, ColumnResolver resolver,
+        NullInitializerExpressionFactory initializerFactory) {
+      super(catalogReader, catalogName, schemaName, name, stream, rowCount,
+          resolver, initializerFactory);
       this.fromTable = fromTable;
       this.table = fromTable.unwrap(Table.class);
       this.mapping = mapping;
     }
 
     /** Implementation of AbstractModifiableView. */
-    private class ModifiableView extends JdbcTest.AbstractModifiableView {
-
+    private class ModifiableView extends JdbcTest.AbstractModifiableView
+        implements Wrapper {
       @Override public Table getTable() {
         return fromTable.unwrap(Table.class);
       }
@@ -773,6 +866,13 @@ public class MockCatalogReader extends CalciteCatalogReader {
               }
             });
       }
+
+      @Override public <C> C unwrap(Class<C> aClass) {
+        if (table instanceof Wrapper) {
+          return ((Wrapper) table).unwrap(aClass);
+        }
+        return null;
+      }
     }
 
     /**
@@ -780,12 +880,19 @@ public class MockCatalogReader extends CalciteCatalogReader {
      * CustomColumnResolvingTable.
      */
     private class ModifiableViewWithCustomColumnResolving
-      extends ModifiableView implements CustomColumnResolvingTable {
+      extends ModifiableView implements CustomColumnResolvingTable, Wrapper {
 
       @Override public List<Pair<RelDataTypeField, List<String>>> resolveColumn(
           RelDataType rowType, RelDataTypeFactory typeFactory, List<String> names) {
         return resolver.resolveColumn(rowType, typeFactory, names);
       }
+
+      @Override public <C> C unwrap(Class<C> aClass) {
+        if (table instanceof Wrapper) {
+          return ((Wrapper) table).unwrap(aClass);
+        }
+        return null;
+      }
     }
 
     protected abstract RexNode getConstraint(RexBuilder rexBuilder,
@@ -837,7 +944,8 @@ public class MockCatalogReader extends CalciteCatalogReader {
   public static class MockDynamicTable extends MockTable {
     MockDynamicTable(MockCatalogReader catalogReader, String catalogName,
         String schemaName, String name, boolean stream, double rowCount) {
-      super(catalogReader, catalogName, schemaName, name, stream, rowCount, null);
+      super(catalogReader, catalogName, schemaName, name, stream, rowCount,
+          null, new NullInitializerExpressionFactory(catalogReader.typeFactory));
     }
 
     public void onRegister(RelDataTypeFactory typeFactory) {
@@ -1157,6 +1265,62 @@ public class MockCatalogReader extends CalciteCatalogReader {
       return this;
     }
   }
+
+  /** Types used during initialization. */
+  private class Fixture {
+    final RelDataType intType =
+        typeFactory.createSqlType(SqlTypeName.INTEGER);
+    final RelDataType intTypeNull =
+        typeFactory.createTypeWithNullability(intType, true);
+    final RelDataType varchar10Type =
+        typeFactory.createSqlType(SqlTypeName.VARCHAR, 10);
+    final RelDataType varchar10TypeNull =
+        typeFactory.createTypeWithNullability(varchar10Type, true);
+    final RelDataType varchar20Type =
+        typeFactory.createSqlType(SqlTypeName.VARCHAR, 20);
+    final RelDataType varchar20TypeNull =
+        typeFactory.createTypeWithNullability(varchar20Type, true);
+    final RelDataType timestampType =
+        typeFactory.createSqlType(SqlTypeName.TIMESTAMP);
+    final RelDataType timestampTypeNull =
+        typeFactory.createTypeWithNullability(timestampType, true);
+    final RelDataType dateType =
+        typeFactory.createSqlType(SqlTypeName.DATE);
+    final RelDataType booleanType =
+        typeFactory.createSqlType(SqlTypeName.BOOLEAN);
+    final RelDataType booleanTypeNull =
+        typeFactory.createTypeWithNullability(booleanType, true);
+    final RelDataType rectilinearCoordType =
+        typeFactory.builder()
+            .add("X", intType)
+            .add("Y", intType)
+            .build();
+    final RelDataType rectilinearPeekCoordType =
+        typeFactory.builder()
+            .add("X", intType)
+            .add("Y", intType)
+            .kind(StructKind.PEEK_FIELDS)
+            .build();
+    final RelDataType empRecordType =
+        typeFactory.builder()
+            .add("EMPNO", intType)
+            .add("ENAME", varchar10Type).build();
+    final RelDataType empListType =
+        typeFactory.createArrayType(empRecordType, -1);
+
+    // TODO jvs 12-Feb-2005: register this canonical instance with type
+    // factory
+    final ObjectSqlType addressType =
+        new ObjectSqlType(SqlTypeName.STRUCTURED,
+            new SqlIdentifier("ADDRESS", SqlParserPos.ZERO),
+            false,
+            Arrays.asList(
+                new RelDataTypeFieldImpl("STREET", 0, varchar20Type),
+                new RelDataTypeFieldImpl("CITY", 1, varchar20Type),
+                new RelDataTypeFieldImpl("ZIP", 2, intType),
+                new RelDataTypeFieldImpl("STATE", 3, varchar20Type)),
+            RelDataTypeComparability.NONE);
+  }
 }
 
 // End MockCatalogReader.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/08b1dddd/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
index 375e7c5..ce7248a 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
@@ -27,6 +27,8 @@ import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.sql.SqlExplainLevel;
 import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.sql.validate.SqlConformance;
+import org.apache.calcite.sql.validate.SqlConformanceEnum;
 import org.apache.calcite.sql2rel.SqlToRelConverter;
 import org.apache.calcite.util.Bug;
 import org.apache.calcite.util.Litmus;
@@ -65,7 +67,7 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
   /** Sets the SQL statement for a test. */
   public final Sql sql(String sql) {
     return new Sql(sql, true, true, tester, false,
-        SqlToRelConverter.Config.DEFAULT);
+        SqlToRelConverter.Config.DEFAULT, SqlConformanceEnum.DEFAULT);
   }
 
   protected final void check(
@@ -1469,11 +1471,55 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
   }
 
   @Test public void testInsert() {
-    final String sql =
-        "insert into emp (deptno, empno, ename) values (10, 150, 'Fred')";
+    final String sql = "insert into empnullables (deptno, empno, ename)\n"
+        + "values (10, 150, 'Fred')";
+    sql(sql).ok();
+  }
+
+  @Test public void testInsertSubset() {
+    final String sql = "insert into empnullables \n"
+        + "values (50, 'Fred')";
+    sql(sql).conformance(SqlConformanceEnum.PRAGMATIC_2003).ok();
+  }
+
+  @Test public void testInsertWithCustomInitializerExpressionFactory() {
+    final String sql = "insert into empdefaults (deptno) values (300)";
+    sql(sql).ok();
+  }
+
+  @Test public void testInsertSubsetWithCustomInitializerExpressionFactory() {
+    final String sql = "insert into empdefaults values (100)";
+    sql(sql).conformance(SqlConformanceEnum.PRAGMATIC_2003).ok();
+  }
+
+  @Test public void testInsertBind() {
+    final String sql = "insert into empnullables (deptno, empno, ename)\n"
+        + "values (?, ?, ?)";
     sql(sql).ok();
   }
 
+  @Test public void testInsertBindSubset() {
+    final String sql = "insert into empnullables \n"
+        + "values (?, ?)";
+    sql(sql).conformance(SqlConformanceEnum.PRAGMATIC_2003).ok();
+  }
+
+  @Test public void testInsertBindWithCustomInitializerExpressionFactory() {
+    final String sql = "insert into empdefaults (deptno) values (?)";
+    sql(sql).ok();
+  }
+
+  @Test public void testInsertBindSubsetWithCustomInitializerExpressionFactory() {
+    final String sql = "insert into empdefaults values (?)";
+    sql(sql).conformance(SqlConformanceEnum.PRAGMATIC_2003).ok();
+  }
+
+  @Test public void testInsertSubsetView() {
+    final String sql = "insert into empnullables_20 \n"
+        + "values (10, 'Fred')";
+    sql(sql).conformance(SqlConformanceEnum.PRAGMATIC_2003).ok();
+  }
+
   @Test public void testDelete() {
     final String sql = "delete from emp";
     sql(sql).ok();
@@ -1522,7 +1568,8 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
   }
 
   @Test public void testInsertView() {
-    final String sql = "insert into emp_20 (empno, ename) values (150, 'Fred')";
+    final String sql = "insert into empnullables_20 (empno, ename)\n"
+        + "values (150, 'Fred')";
     sql(sql).ok();
   }
 
@@ -1532,12 +1579,15 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
   }
 
   @Test public void testInsertWithCustomColumnResolving2() {
-    final String sql = "insert into struct.t (f0.c0, f1.c2, c1) values (?, ?, ?)";
+    final String sql = "insert into struct.t_nullables (f0.c0, f1.c2, c1)\n"
+        + "values (?, ?, ?)";
     sql(sql).ok();
   }
 
   @Test public void testInsertViewWithCustomColumnResolving() {
-    final String sql = "insert into struct.t_10 (f0.c0, f1.c2, c1) values (?, ?, ?)";
+    final String sql = "insert into struct.t_10 (f0.c0, f1.c2, c1, k0,\n"
+        + "  f1.a0, f2.a0, f0.c1, f2.c3)\n"
+        + "values (?, ?, ?, ?, ?, ?, ?, ?)";
     sql(sql).ok();
   }
 
@@ -2060,15 +2110,18 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
     private final Tester tester;
     private final boolean trim;
     private final SqlToRelConverter.Config config;
+    private final SqlConformance conformance;
 
     Sql(String sql, boolean expand, boolean decorrelate, Tester tester,
-        boolean trim, SqlToRelConverter.Config config) {
+        boolean trim, SqlToRelConverter.Config config,
+        SqlConformance conformance) {
       this.sql = sql;
       this.expand = expand;
       this.decorrelate = decorrelate;
       this.tester = tester;
       this.trim = trim;
       this.config = config;
+      this.conformance = conformance;
     }
 
     public void ok() {
@@ -2078,28 +2131,39 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
     public void convertsTo(String plan) {
       tester.withExpand(expand)
           .withDecorrelation(decorrelate)
+          .withConformance(conformance)
           .withConfig(config)
           .assertConvertsTo(sql, plan, trim);
     }
 
     public Sql withConfig(SqlToRelConverter.Config config) {
-      return new Sql(sql, expand, decorrelate, tester, trim, config);
+      return new Sql(sql, expand, decorrelate, tester, trim, config,
+          conformance);
     }
 
     public Sql expand(boolean expand) {
-      return new Sql(sql, expand, decorrelate, tester, trim, config);
+      return new Sql(sql, expand, decorrelate, tester, trim, config,
+          conformance);
     }
 
     public Sql decorrelate(boolean decorrelate) {
-      return new Sql(sql, expand, decorrelate, tester, trim, config);
+      return new Sql(sql, expand, decorrelate, tester, trim, config,
+          conformance);
     }
 
     public Sql with(Tester tester) {
-      return new Sql(sql, expand, decorrelate, tester, trim, config);
+      return new Sql(sql, expand, decorrelate, tester, trim, config,
+          conformance);
     }
 
     public Sql trim(boolean trim) {
-      return new Sql(sql, expand, decorrelate, tester, trim, config);
+      return new Sql(sql, expand, decorrelate, tester, trim, config,
+          conformance);
+    }
+
+    public Sql conformance(SqlConformance conformance) {
+      return new Sql(sql, expand, decorrelate, tester, trim, config,
+          conformance);
     }
   }
 }