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 be9a4e1  [CALCITE-4115] Improve the prompt of using SQL keywords for 
sql parser
be9a4e1 is described below

commit be9a4e177957ea07498e680269ceff126a170317
Author: yuzhao.cyz <[email protected]>
AuthorDate: Thu Jul 9 18:17:46 2020 +0800

    [CALCITE-4115] Improve the prompt of using SQL keywords for sql parser
    
    When the parser encounters a reserved-keyword and throws, change the
    error message format to:
    
    Incorrect syntax near the keyword '{keyword}' at line {line_number}, column 
{column_number}.
    
    The new format indicates that the next token is a keyword clearly so
    that user can choose to use a non-reserved keyword or quotes the keyword 
instead.
---
 core/src/main/codegen/templates/Parser.jj                | 16 ++++++++++++++++
 .../java/org/apache/calcite/sql/parser/SqlParser.java    | 12 +-----------
 .../org/apache/calcite/sql/parser/SqlParserUtil.java     | 15 +++++++++++++++
 .../org/apache/calcite/sql/parser/SqlParserTest.java     | 14 +++++++-------
 .../parserextensiontesting/ExtensionSqlParserTest.java   |  2 +-
 .../org/apache/calcite/sql/test/SqlOperatorBaseTest.java |  2 +-
 .../java/org/apache/calcite/test/SqlValidatorTest.java   |  2 +-
 7 files changed, 42 insertions(+), 21 deletions(-)

diff --git a/core/src/main/codegen/templates/Parser.jj 
b/core/src/main/codegen/templates/Parser.jj
index 835fd4a..9986798 100644
--- a/core/src/main/codegen/templates/Parser.jj
+++ b/core/src/main/codegen/templates/Parser.jj
@@ -437,6 +437,22 @@ JAVACODE SqlParseException convertException(Throwable ex)
         tokenImage = pex.tokenImage;
         if (pex.currentToken != null) {
             final Token token = pex.currentToken.next;
+            // Checks token.image.equals("1") to avoid recursive call.
+            // The SqlAbstractParserImpl#MetadataImpl constructor uses 
constant "1" to
+            // throw intentionally to collect the expected tokens.
+            if (!token.image.equals("1") && 
getMetadata().isKeyword(token.image)) {
+                // If the next token is a keyword, reformat the error message 
as:
+
+                // Incorrect syntax near the keyword '{keyword}' at line 
{line_number},
+                // column {column_number}.
+                final String errorMsg = String.format("Incorrect syntax near 
the keyword '%s' "
+                        + "at line %d, column %d.",
+                    token.image,
+                    token.beginLine,
+                    token.beginColumn);
+                // Replace the ParseException with explicit error message.
+                ex = new ParseException(errorMsg);
+            }
             pos = new SqlParserPos(
                 token.beginLine,
                 token.beginColumn,
diff --git a/core/src/main/java/org/apache/calcite/sql/parser/SqlParser.java 
b/core/src/main/java/org/apache/calcite/sql/parser/SqlParser.java
index b6eabb9..ed4c2f2 100644
--- a/core/src/main/java/org/apache/calcite/sql/parser/SqlParser.java
+++ b/core/src/main/java/org/apache/calcite/sql/parser/SqlParser.java
@@ -54,17 +54,7 @@ public class SqlParser {
     parser.setUnquotedCasing(config.unquotedCasing());
     parser.setIdentifierMaxLength(config.identifierMaxLength());
     parser.setConformance(config.conformance());
-    switch (config.quoting()) {
-    case DOUBLE_QUOTE:
-      parser.switchTo("DQID");
-      break;
-    case BACK_TICK:
-      parser.switchTo("BTID");
-      break;
-    case BRACKET:
-      parser.switchTo("DEFAULT");
-      break;
-    }
+    parser.switchTo(SqlParserUtil.quotingToParserState(config.quoting()));
   }
 
   //~ Methods ----------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/calcite/sql/parser/SqlParserUtil.java 
b/core/src/main/java/org/apache/calcite/sql/parser/SqlParserUtil.java
index 0cf9738..aec0c6f 100644
--- a/core/src/main/java/org/apache/calcite/sql/parser/SqlParserUtil.java
+++ b/core/src/main/java/org/apache/calcite/sql/parser/SqlParserUtil.java
@@ -18,6 +18,7 @@ package org.apache.calcite.sql.parser;
 
 import org.apache.calcite.avatica.util.Casing;
 import org.apache.calcite.avatica.util.DateTimeUtils;
+import org.apache.calcite.avatica.util.Quoting;
 import org.apache.calcite.config.CalciteSystemProperty;
 import org.apache.calcite.rel.type.RelDataTypeSystem;
 import org.apache.calcite.runtime.CalciteContextException;
@@ -732,6 +733,20 @@ public final class SqlParserUtil {
     return c;
   }
 
+  /** Returns the corresponding parser state with the give quoting. */
+  public static String quotingToParserState(Quoting quoting) {
+    switch (quoting) {
+    case DOUBLE_QUOTE:
+      return "DQID";
+    case BACK_TICK:
+      return "BTID";
+    case BRACKET:
+      return "DEFAULT";
+    default:
+      throw new AssertionError(quoting);
+    }
+  }
+
   //~ Inner Classes ----------------------------------------------------------
 
   /** The components of a collation definition, per the SQL standard. */
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 19cd942..919643a 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
@@ -1788,7 +1788,7 @@ public class SqlParserTest {
 
   @Test void testDefault() {
     sql("select ^DEFAULT^ from emp")
-        .fails("(?s)Encountered \"DEFAULT\" at .*");
+        .fails("(?s)Incorrect syntax near the keyword 'DEFAULT' at .*");
     sql("select cast(empno ^+^ DEFAULT as double) from emp")
         .fails("(?s)Encountered \"\\+ DEFAULT\" at .*");
     sql("select empno ^+^ DEFAULT + deptno from emp")
@@ -1796,11 +1796,11 @@ public class SqlParserTest {
     sql("select power(0, DEFAULT ^+^ empno) from emp")
         .fails("(?s)Encountered \"\\+\" at .*");
     sql("select * from emp join dept on ^DEFAULT^")
-        .fails("(?s)Encountered \"DEFAULT\" at .*");
+        .fails("(?s)Incorrect syntax near the keyword 'DEFAULT' at .*");
     sql("select * from emp where empno ^>^ DEFAULT or deptno < 10")
         .fails("(?s)Encountered \"> DEFAULT\" at .*");
     sql("select * from emp order by ^DEFAULT^ desc")
-        .fails("(?s)Encountered \"DEFAULT\" at .*");
+        .fails("(?s)Incorrect syntax near the keyword 'DEFAULT' at .*");
     final String expected = "INSERT INTO `DEPT` (`NAME`, `DEPTNO`)\n"
         + "VALUES (ROW('a', DEFAULT))";
     sql("insert into dept (name, deptno) values ('a', DEFAULT)")
@@ -1808,7 +1808,7 @@ public class SqlParserTest {
     sql("insert into dept (name, deptno) values ('a', 1 ^+^ DEFAULT)")
         .fails("(?s)Encountered \"\\+ DEFAULT\" at .*");
     sql("insert into dept (name, deptno) select 'a', ^DEFAULT^ from (values 
0)")
-        .fails("(?s)Encountered \"DEFAULT\" at .*");
+        .fails("(?s)Incorrect syntax near the keyword 'DEFAULT' at .*");
   }
 
   @Test void testAggregateFilter() {
@@ -4309,7 +4309,7 @@ public class SqlParserTest {
     expr("CAST(12 AS DATE)")
         .ok("CAST(12 AS DATE)");
     sql("CAST('2000-12-21' AS DATE ^NOT^ NULL)")
-        .fails("(?s).*Encountered \"NOT\" at line 1, column 27.*");
+        .fails("(?s).*Incorrect syntax near the keyword 'NOT' at line 1, 
column 27.*");
     sql("CAST('foo' as ^1^)")
         .fails("(?s).*Encountered \"1\" at line 1, column 15.*");
     expr("Cast(DATE '2004-12-21' AS VARCHAR(10))")
@@ -4395,9 +4395,9 @@ public class SqlParserTest {
     expr("{fn convert(1, VARCHAR^(^5))}")
         .fails("(?s)Encountered \"\\(\" at.*");
     expr("{fn convert(1, ^INTERVAL^ YEAR TO MONTH)}")
-        .fails("(?s)Encountered \"INTERVAL\" at.*");
+        .fails("(?s)Incorrect syntax near the keyword 'INTERVAL' at.*");
     expr("{fn convert(1, ^INTERVAL^ YEAR)}")
-        .fails("(?s)Encountered \"INTERVAL\" at.*");
+        .fails("(?s)Incorrect syntax near the keyword 'INTERVAL' at.*");
   }
 
   @Test void testWindowReference() {
diff --git 
a/core/src/test/java/org/apache/calcite/sql/parser/parserextensiontesting/ExtensionSqlParserTest.java
 
b/core/src/test/java/org/apache/calcite/sql/parser/parserextensiontesting/ExtensionSqlParserTest.java
index 7070b10..bd0068e 100644
--- 
a/core/src/test/java/org/apache/calcite/sql/parser/parserextensiontesting/ExtensionSqlParserTest.java
+++ 
b/core/src/test/java/org/apache/calcite/sql/parser/parserextensiontesting/ExtensionSqlParserTest.java
@@ -55,6 +55,6 @@ class ExtensionSqlParserTest extends SqlParserTest {
     sql("DESCRIBE SPACE POWER")
         .node(new IsNull<SqlNode>());
     sql("DESCRIBE SEA ^POWER^")
-        .fails("(?s)Encountered \"POWER\" at line 1, column 14..*");
+        .fails("(?s)Incorrect syntax near the keyword 'POWER' at line 1, 
column 14.*");
   }
 }
diff --git 
a/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java 
b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
index 2315934..0d2f838 100644
--- a/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
@@ -8350,7 +8350,7 @@ public abstract class SqlOperatorBaseTest {
     tester.checkFails("timestampdiff(CENTURY, "
         + "timestamp '2014-02-24 12:42:25', "
         + "timestamp '2614-02-24 12:42:25')",
-        "(?s)Encountered \"CENTURY\" at .*", false);
+        "(?s)Incorrect syntax near the keyword 'CENTURY' at .*", false);
     tester.checkScalar("timestampdiff(QUARTER, "
         + "timestamp '2014-02-24 12:42:25', "
         + "cast(null as timestamp))",
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 b141a3f..efa267b 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
@@ -1566,7 +1566,7 @@ class SqlValidatorTest extends SqlValidatorTestCase {
       expr("\"TRIM\"('b')").ok();
     } else {
       expr("^\"TRIM\"('b' FROM 'a')^")
-          .fails("(?s).*Encountered \"FROM\" at .*");
+          .fails("(?s).*Incorrect syntax near the keyword 'FROM' at .*");
 
       // Without the "FROM" noise word, TRIM is parsed as a regular
       // function without quoting and built-in function with quoting.

Reply via email to