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);
}
}
}