calcite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jh...@apache.org
Subject [2/3] calcite git commit: [CALCITE-1709] Support mixing table columns with extended columns in DML (Rajeshbabu Chintaguntla)
Date Tue, 27 Jun 2017 22:33:17 GMT
[CALCITE-1709] Support mixing table columns with extended columns in DML (Rajeshbabu Chintaguntla)

Close apache/calcite#482


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

Branch: refs/heads/master
Commit: a6fbafde75a8b603128cb47306d719d25ba6bbc8
Parents: c030757
Author: Rajeshbabu Chintaguntla <rajeshbabu@apache.org>
Authored: Thu Jun 22 10:27:40 2017 +0530
Committer: Julian Hyde <jhyde@apache.org>
Committed: Mon Jun 26 18:03:46 2017 -0700

----------------------------------------------------------------------
 core/src/main/codegen/templates/Parser.jj       | 69 ++++++++++++++++----
 .../apache/calcite/runtime/CalciteResource.java |  2 +
 .../sql/validate/SqlAbstractConformance.java    |  3 +
 .../calcite/sql/validate/SqlConformance.java    | 20 ++++++
 .../sql/validate/SqlConformanceEnum.java        |  8 +++
 .../calcite/sql/validate/SqlValidatorUtil.java  |  2 +-
 .../calcite/runtime/CalciteResource.properties  |  1 +
 .../calcite/sql/parser/SqlParserTest.java       | 16 ++++-
 .../apache/calcite/test/SqlValidatorTest.java   | 21 ++++++
 site/_docs/reference.md                         |  9 +++
 10 files changed, 134 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/a6fbafde/core/src/main/codegen/templates/Parser.jj
----------------------------------------------------------------------
diff --git a/core/src/main/codegen/templates/Parser.jj b/core/src/main/codegen/templates/Parser.jj
index c6a657f..7ee3f1e 100644
--- a/core/src/main/codegen/templates/Parser.jj
+++ b/core/src/main/codegen/templates/Parser.jj
@@ -103,6 +103,7 @@ import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.sql.validate.SqlConformance;
 import org.apache.calcite.util.Glossary;
 import org.apache.calcite.util.NlsString;
+import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Util;
 import org.apache.calcite.util.trace.CalciteTrace;
 
@@ -1228,7 +1229,7 @@ SqlNode SqlInsert() :
     }
     <INTO> table = CompoundIdentifier()
     [
-        LOOKAHEAD(3)
+        LOOKAHEAD(5)
         [ <EXTEND> ]
         extendList = ExtendList() {
             table = extend(table, extendList);
@@ -1236,7 +1237,15 @@ SqlNode SqlInsert() :
     ]
     [
         LOOKAHEAD(2)
-        columnList = ParenthesizedCompoundIdentifierList()
+        { final Pair<SqlNodeList, SqlNodeList> p; }
+        p = ParenthesizedCompoundIdentifierList() {
+            if (p.right.size() > 0) {
+                table = extend(table, p.right);
+            }
+            if (p.left.size() > 0) {
+                columnList = p.left;
+            }
+        }
     ]
     source = OrderedQueryOrExpr(ExprContext.ACCEPT_QUERY) {
         return new SqlInsert(s.end(source), keywordList, table, source,
@@ -1911,7 +1920,7 @@ void ColumnType(List<SqlNode> list) :
     boolean nullable = true;
 }
 {
-    name = SimpleIdentifier()
+    name = CompoundIdentifier()
     type = DataType()
     [
         <NOT> <NULL> {
@@ -1924,6 +1933,38 @@ void ColumnType(List<SqlNode> list) :
     }
 }
 
+/**
+ * Parses a compound identifier with optional type.
+ */
+void CompoundIdentifierType(List<SqlNode> list, List<SqlNode> extendList) :
+{
+    final SqlIdentifier name;
+    SqlDataTypeSpec type = null;
+    boolean nullable = true;
+}
+{
+    name = CompoundIdentifier()
+    [
+        type = DataType() {
+            if (!this.conformance.allowExtend()) {
+                throw new ParseException(RESOURCE.extendNotAllowed().str());
+            }
+        }
+        [
+            <NOT> <NULL> {
+                nullable = false;
+            }
+        ]
+    ]
+    {
+       if (type != null) {
+           extendList.add(name);
+           extendList.add(type.withNullable(nullable));
+       }
+       list.add(name);
+    }
+}
+
 SqlNode TableFunctionCall(SqlParserPos pos) :
 {
     SqlNode call;
@@ -4099,29 +4140,29 @@ SqlIdentifier CompoundIdentifier() :
 /**
  * Parses a comma-separated list of compound identifiers.
  */
-void CompoundIdentifierCommaList(List<SqlNode> list) :
+void CompoundIdentifierTypeCommaList(List<SqlNode> list, List<SqlNode> extendList)
:
 {
-    SqlIdentifier id;
 }
 {
-    id = CompoundIdentifier() {list.add(id);}
-    (<COMMA> id = CompoundIdentifier() {list.add(id);})*
+    CompoundIdentifierType(list, extendList)
+    (<COMMA> CompoundIdentifierType(list, extendList))*
 }
 
 /**
-  * List of compound identifiers in parentheses. The position extends from the
-  * open parenthesis to the close parenthesis.
-  */
-SqlNodeList ParenthesizedCompoundIdentifierList() :
+ * List of compound identifiers in parentheses. The position extends from the
+ * open parenthesis to the close parenthesis.
+ */
+Pair<SqlNodeList, SqlNodeList> ParenthesizedCompoundIdentifierList() :
 {
     final Span s;
     final List<SqlNode> list = new ArrayList<SqlNode>();
+    final List<SqlNode> extendList = new ArrayList<SqlNode>();
 }
 {
     <LPAREN> { s = span(); }
-    CompoundIdentifierCommaList(list)
+    CompoundIdentifierTypeCommaList(list, extendList)
     <RPAREN> {
-        return new SqlNodeList(list, s.end(this));
+        return Pair.of(new SqlNodeList(list, s.end(this)), new SqlNodeList(extendList, s.end(this)));
     }
 }
 <#else>
@@ -4675,7 +4716,7 @@ SqlCall MatchRecognizeFunctionCall() :
         <MATCH_NUMBER> { s = span(); } <LPAREN> <RPAREN> {
             func = SqlStdOperatorTable.MATCH_NUMBER.createCall(s.end(this));
         }
-    |    
+    |
         func = MatchRecognizeNavigationLogical()
     |
         func = MatchRecognizeNavigationPhysical()

http://git-wip-us.apache.org/repos/asf/calcite/blob/a6fbafde/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 e785a15..f79fa36 100644
--- a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
+++ b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
@@ -699,6 +699,8 @@ public interface CalciteResource {
   @BaseMessage("Unknown pattern ''{0}''")
   ExInst<SqlValidatorException> unknownPattern(String call);
 
+  @BaseMessage("Extended columns not allowed under the current SQL conformance level")
+  ExInst<SqlValidatorException> extendNotAllowed();
 }
 
 // End CalciteResource.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/a6fbafde/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 0c27dca..78f2df3 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
@@ -71,6 +71,9 @@ public abstract class SqlAbstractConformance implements SqlConformance {
     return SqlConformanceEnum.DEFAULT.allowNiladicParentheses();
   }
 
+  public boolean allowExtend() {
+    return SqlConformanceEnum.DEFAULT.allowExtend();
+  }
 }
 
 // End SqlAbstractConformance.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/a6fbafde/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 9d18268..835b763 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
@@ -239,6 +239,26 @@ public interface SqlConformance {
    */
   boolean allowNiladicParentheses();
 
+  /**
+   * Whether to allow mixing table columns with extended columns in
+   * {@code INSERT} (or {@code UPSERT}).
+   *
+   * <p>For example, suppose that the declaration of table {@code T} has columns
+   * {@code A} and {@code B}, and you want to insert data of column
+   * {@code C INTEGER} not present in the table declaration as an extended
+   * column. You can specify the columns in an {@code INSERT} statement as
+   * follows:
+   *
+   * <blockquote>
+   *   <code>INSERT INTO T (A, B, C INTEGER) VALUES (1, 2, 3)</code>
+   * </blockquote>
+   *
+   * <p>Among the built-in conformance levels, true in
+   * {@link SqlConformanceEnum#LENIENT};
+   * false otherwise.
+   */
+  boolean allowExtend();
+
 }
 
 // End SqlConformance.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/a6fbafde/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 226ec21..b65042e 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
@@ -189,6 +189,14 @@ public enum SqlConformanceEnum implements SqlConformance {
     }
   }
 
+  public boolean allowExtend() {
+    switch (this) {
+    case LENIENT:
+      return true;
+    default:
+      return false;
+    }
+  }
 }
 
 // End SqlConformanceEnum.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/a6fbafde/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java
index 5fd15b4..c64e93d 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java
@@ -155,7 +155,7 @@ public class SqlValidatorUtil {
       final SqlIdentifier identifier = pair.left;
       final SqlDataTypeSpec type = pair.right;
       extendedFields.add(
-          new RelDataTypeFieldImpl(identifier.getSimple(),
+          new RelDataTypeFieldImpl(identifier.toString(),
               extendedFieldOffset++,
               type.deriveType(typeFactory)));
     }

http://git-wip-us.apache.org/repos/asf/calcite/blob/a6fbafde/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 0006022..8451ed3 100644
--- a/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
+++ b/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
@@ -227,4 +227,5 @@ PatternFunctionVariableCheck=Multiple pattern variables in ''{0}''
 FunctionMatchRecognizeOnly=Function ''{0}'' can only be used in MATCH_RECOGNIZE
 PatternFunctionNullCheck=Null parameters in ''{0}''
 UnknownPattern=Unknown pattern ''{0}''
+ExtendNotAllowed=Extended columns not allowed under the current SQL conformance level
 # End CalciteResource.properties

http://git-wip-us.apache.org/repos/asf/calcite/blob/a6fbafde/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java b/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
index f132a24..a3e7a5a 100644
--- a/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
@@ -3254,11 +3254,17 @@ public class SqlParserTest {
   }
 
   @Test public void testInsertExtendedColumnList() {
-    final String expected = "INSERT INTO `EMPS` EXTEND (`Z` BOOLEAN) (`X`, `Y`)\n"
+    String expected = "INSERT INTO `EMPS` EXTEND (`Z` BOOLEAN) (`X`, `Y`)\n"
         + "(SELECT *\n"
         + "FROM `EMPS`)";
     sql("insert into emps(z boolean)(x,y) select * from emps")
         .ok(expected);
+    conformance = SqlConformanceEnum.LENIENT;
+    expected = "INSERT INTO `EMPS` EXTEND (`Z` BOOLEAN) (`X`, `Y`, `Z`)\n"
+        + "(SELECT *\n"
+        + "FROM `EMPS`)";
+    sql("insert into emps(x, y, z boolean) select * from emps")
+        .ok(expected);
   }
 
   @Test public void testUpdateExtendedColumnList() {
@@ -3291,11 +3297,17 @@ public class SqlParserTest {
   }
 
   @Test public void testInsertCaseSensitiveExtendedColumnList() {
-    final String expected = "INSERT INTO `emps` EXTEND (`z` BOOLEAN) (`x`, `y`)\n"
+    String expected = "INSERT INTO `emps` EXTEND (`z` BOOLEAN) (`x`, `y`)\n"
         + "(SELECT *\n"
         + "FROM `EMPS`)";
     sql("insert into \"emps\"(\"z\" boolean)(\"x\",\"y\") select * from emps")
         .ok(expected);
+    conformance = SqlConformanceEnum.LENIENT;
+    expected = "INSERT INTO `emps` EXTEND (`z` BOOLEAN) (`x`, `y`, `z`)\n"
+        + "(SELECT *\n"
+        + "FROM `EMPS`)";
+    sql("insert into \"emps\"(\"x\", \"y\", \"z\" boolean) select * from emps")
+        .ok(expected);
   }
 
   @Test public void testExplainInsert() {

http://git-wip-us.apache.org/repos/asf/calcite/blob/a6fbafde/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 e306db3..c8ede98 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
@@ -8641,6 +8641,27 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
     sql(sql2).ok().bindType(expected2);
   }
 
+
+  @Test public void testInsertWithExtendedColumns() {
+    final SqlTester lenient =
+        tester.withConformance(SqlConformanceEnum.LENIENT);
+    final SqlTester strict =
+        tester.withConformance(SqlConformanceEnum.STRICT_2003);
+
+    String sql0 = "insert into empnullables (empno, ename, \"f.dc\" varchar(10))\n"
+            + "values (?, ?, ?)";
+    sql(sql0).tester(lenient).ok()
+            .bindType("RecordType(INTEGER ?0, VARCHAR(20) ?1, VARCHAR(10) ?2)")
+            .tester(strict).fails("Extended columns not allowed under "
+                + "the current SQL conformance level");
+    sql0 = "insert into empnullables (empno, ename, dynamic_column double not null)\n"
+        + "values (?, ?, ?)";
+    sql(sql0).tester(lenient).ok()
+        .bindType("RecordType(INTEGER ?0, VARCHAR(20) ?1, DOUBLE ?2)")
+        .tester(strict).fails("Extended columns not allowed under "
+            + "the current SQL conformance level");
+  }
+
   @Test public void testInsertBindSubset() {
     final SqlTester pragmaticTester =
         tester.withConformance(SqlConformanceEnum.PRAGMATIC_2003);

http://git-wip-us.apache.org/repos/asf/calcite/blob/a6fbafde/site/_docs/reference.md
----------------------------------------------------------------------
diff --git a/site/_docs/reference.md b/site/_docs/reference.md
index 5c140d4..5ff91ea 100644
--- a/site/_docs/reference.md
+++ b/site/_docs/reference.md
@@ -200,10 +200,14 @@ tableReference:
 tablePrimary:
       [ [ catalogName . ] schemaName . ] tableName
       '(' TABLE [ [ catalogName . ] schemaName . ] tableName ')'
+  |   tablePrimary [ EXTEND ] '(' columnDecl [, columnDecl ]* ')'
   |   [ LATERAL ] '(' query ')'
   |   UNNEST '(' expression ')' [ WITH ORDINALITY ]
   |   [ LATERAL ] TABLE '(' [ SPECIFIC ] functionName '(' expression [, expression ]* ')'
')'
 
+columnDecl:
+      column type [ NOT NULL ]
+
 values:
       VALUES expression [, expression ]*
 
@@ -239,6 +243,11 @@ columns as the target table, except in certain
 In *merge*, at least one of the WHEN MATCHED and WHEN NOT MATCHED clauses must
 be present.
 
+*tablePrimary* may only contain an EXTEND clause in certain
+[conformance levels]({{ site.apiRoot }}/org/apache/calcite/sql/validate/SqlConformance.html#allowExtend--);
+in those same conformance levels, any *column* in *insert* may be replaced by
+*columnDecl*, which has a similar effect to including it in an EXTEND clause.
+
 In *orderItem*, if *expression* is a positive integer *n*, it denotes
 the <em>n</em>th item in the SELECT clause.
 


Mime
View raw message