You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by da...@apache.org on 2019/11/17 05:37:14 UTC

[calcite] branch master updated: [CALCITE-3486] In JDBC adapter, when generating ROW value expression, generates the ROW keyword only if the dialect allows it (quxiucheng)

This is an automated email from the ASF dual-hosted git repository.

danny0405 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git


The following commit(s) were added to refs/heads/master by this push:
     new ce0118b  [CALCITE-3486] In JDBC adapter, when generating ROW value expression, generates the ROW keyword only if the dialect allows it (quxiucheng)
ce0118b is described below

commit ce0118b4149eb303813d0af2537a7185e9945115
Author: yuzhao.cyz <yu...@gmail.com>
AuthorDate: Sun Nov 17 11:36:50 2019 +0800

    [CALCITE-3486] In JDBC adapter, when generating ROW value expression, generates the ROW keyword only if the dialect allows it (quxiucheng)
    
    In JDBC adapter, unparse the ROW keyword for ROW value expression only
    if the SQL dialect allows it.
    
    Fix-up (by Danny):
    * Simplify the logic for ROW value expression in SqlDialect#unparseCall
    * Add test cases in RelToSqlConverterTest
    * Fix SqlParserTest, there is no need to introduce new kind of SQL
    dialect
    
    close apache/calcite#1568
---
 .../java/org/apache/calcite/sql/SqlDialect.java    | 25 +++++++++-
 .../calcite/rel/rel2sql/RelToSqlConverterTest.java | 55 +++++++++++++++++++++-
 .../apache/calcite/sql/parser/SqlParserTest.java   | 31 ++++++++++++
 3 files changed, 109 insertions(+), 2 deletions(-)

diff --git a/core/src/main/java/org/apache/calcite/sql/SqlDialect.java b/core/src/main/java/org/apache/calcite/sql/SqlDialect.java
index be412ff..ddfa1b5 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlDialect.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlDialect.java
@@ -445,7 +445,29 @@ public class SqlDialect {
 
   public void unparseCall(SqlWriter writer, SqlCall call, int leftPrec,
       int rightPrec) {
-    call.getOperator().unparse(writer, call, leftPrec, rightPrec);
+    switch (call.getKind()) {
+    case ROW:
+      // Remove the ROW keyword if the dialect does not allow that.
+      if (!getConformance().allowExplicitRowValueConstructor()) {
+        // Fix the syntax when there is no parentheses after VALUES keyword.
+        if (!writer.isAlwaysUseParentheses()) {
+          writer.print(" ");
+        }
+        final SqlWriter.Frame frame = writer.isAlwaysUseParentheses()
+                ? writer.startList(SqlWriter.FrameTypeEnum.FUN_CALL)
+                : writer.startList(SqlWriter.FrameTypeEnum.FUN_CALL, "(", ")");
+        for (SqlNode operand : call.getOperandList()) {
+          writer.sep(",");
+          operand.unparse(writer, leftPrec, rightPrec);
+        }
+        writer.endList(frame);
+        break;
+      }
+      call.getOperator().unparse(writer, call, leftPrec, rightPrec);
+      break;
+    default:
+      call.getOperator().unparse(writer, call, leftPrec, rightPrec);
+    }
   }
 
   public void unparseDateTimeLiteral(SqlWriter writer,
@@ -1091,6 +1113,7 @@ public class SqlDialect {
    * {@link #databaseProduct}; sub-classes may override. */
   @Nonnull public SqlConformance getConformance() {
     switch (databaseProduct) {
+    case UNKNOWN:
     case CALCITE:
       return SqlConformanceEnum.DEFAULT;
     case MYSQL:
diff --git a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
index c865a1c..f5418a4 100644
--- a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
+++ b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
@@ -112,7 +112,6 @@ public class RelToSqlConverterTest {
   private static Planner getPlanner(List<RelTraitDef> traitDefs,
       SqlParser.Config parserConfig, SchemaPlus schema,
       SqlToRelConverter.Config sqlToRelConf, Program... programs) {
-    final SchemaPlus rootSchema = Frameworks.createRootSchema(true);
     final FrameworkConfig config = Frameworks.newConfigBuilder()
         .parserConfig(parserConfig)
         .defaultSchema(schema)
@@ -4109,6 +4108,56 @@ public class RelToSqlConverterTest {
     sql.ok(expected);
   }
 
+  @Test public void testRowValueExpression() {
+    final String expected0 = "INSERT INTO SCOTT.DEPT (DEPTNO, DNAME, LOC)\n"
+            + "VALUES  (1, 'Fred', 'San Francisco'),\n"
+            + " (2, 'Eric', 'Washington')";
+    String sql = "insert into \"DEPT\"\n"
+            + "values ROW(1,'Fred', 'San Francisco'), ROW(2, 'Eric', 'Washington')";
+    sql(sql)
+        .schema(CalciteAssert.SchemaSpec.JDBC_SCOTT)
+        .withHive()
+        .ok(expected0);
+
+    final String expected1 = "INSERT INTO `SCOTT`.`DEPT` (`DEPTNO`, `DNAME`, `LOC`)\n"
+            + "VALUES  (1, 'Fred', 'San Francisco'),\n"
+            + " (2, 'Eric', 'Washington')";
+    sql(sql)
+        .schema(CalciteAssert.SchemaSpec.JDBC_SCOTT)
+        .withMysql()
+        .ok(expected1);
+
+    final String expected2 = "INSERT INTO \"SCOTT\".\"DEPT\" (\"DEPTNO\", \"DNAME\", \"LOC\")\n"
+            + "VALUES  (1, 'Fred', 'San Francisco'),\n"
+            + " (2, 'Eric', 'Washington')";
+    sql(sql)
+        .schema(CalciteAssert.SchemaSpec.JDBC_SCOTT)
+        .withOracle()
+        .ok(expected2);
+
+    final String expected3 = "INSERT INTO [SCOTT].[DEPT] ([DEPTNO], [DNAME], [LOC])\n"
+            + "VALUES  (1, 'Fred', 'San Francisco'),\n"
+            + " (2, 'Eric', 'Washington')";
+    sql(sql)
+        .schema(CalciteAssert.SchemaSpec.JDBC_SCOTT)
+        .withMssql()
+        .ok(expected3);
+
+    final String expected4 = "INSERT INTO \"SCOTT\".\"DEPT\" (\"DEPTNO\", \"DNAME\", \"LOC\")\n"
+            + "VALUES  (1, 'Fred', 'San Francisco'),\n"
+            + " (2, 'Eric', 'Washington')";
+    sql(sql)
+        .schema(CalciteAssert.SchemaSpec.JDBC_SCOTT)
+        .ok(expected4);
+
+    final String expected5 = "INSERT INTO \"SCOTT\".\"DEPT\" (\"DEPTNO\", \"DNAME\", \"LOC\")\n"
+            + "VALUES  (1, 'Fred', 'San Francisco'),\n"
+            + " (2, 'Eric', 'Washington')";
+    sql(sql).withCalcite()
+            .schema(CalciteAssert.SchemaSpec.JDBC_SCOTT)
+            .ok(expected5);
+  }
+
   /** Fluid interface to run tests. */
   static class Sql {
     private final SchemaPlus schema;
@@ -4142,6 +4191,10 @@ public class RelToSqlConverterTest {
       return new Sql(schema, sql, dialect, config, transforms);
     }
 
+    Sql withCalcite() {
+      return dialect(SqlDialect.DatabaseProduct.CALCITE.getDialect());
+    }
+
     Sql withDb2() {
       return dialect(SqlDialect.DatabaseProduct.DB2.getDialect());
     }
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 2739a60..cc4780f 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
@@ -1145,6 +1145,37 @@ public class SqlParserTest {
     sql(whereRow2).sansCarets().ok(whereExpected);
   }
 
+  @Test public void testRowValueExpression() {
+    final String expected0 = "INSERT INTO \"EMPS\"\n"
+            + "VALUES (ROW(1, 'Fred')),\n"
+            + "(ROW(2, 'Eric'))";
+    String sql = "insert into emps values (1,'Fred'),(2, 'Eric')";
+    sql(sql)
+        .withDialect(SqlDialect.DatabaseProduct.CALCITE.getDialect())
+         .ok(expected0);
+
+    final String expected1 = "INSERT INTO `emps`\n"
+            + "VALUES (1, 'Fred'),\n"
+            + "(2, 'Eric')";
+    sql(sql)
+        .withDialect(SqlDialect.DatabaseProduct.MYSQL.getDialect())
+        .ok(expected1);
+
+    final String expected2 = "INSERT INTO \"EMPS\"\n"
+            + "VALUES (1, 'Fred'),\n"
+            + "(2, 'Eric')";
+    sql(sql)
+        .withDialect(SqlDialect.DatabaseProduct.ORACLE.getDialect())
+        .ok(expected2);
+
+    final String expected3 = "INSERT INTO [EMPS]\n"
+            + "VALUES (1, 'Fred'),\n"
+            + "(2, 'Eric')";
+    sql(sql)
+        .withDialect(SqlDialect.DatabaseProduct.MSSQL.getDialect())
+        .ok(expected3);
+  }
+
   /** Whether this is a sub-class that tests un-parsing as well as parsing. */
   protected boolean isUnparserTest() {
     return false;