This is an automated email from the ASF dual-hosted git repository. jhyde pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/calcite.git
commit f1cad57035db0f94190433aa6db2352228a641e0 Author: Julian Hyde <[email protected]> AuthorDate: Wed Apr 24 15:54:44 2019 -0700 [CALCITE-3022] Babel: Various SQL parsing issues * Allow 'DATE(x)' function, per PostgreSQL and Redshift * Allow "TIMESTAMP 'yyyy-mm-dd'" literal (missing time part), per PostgreSQL and Redshift --- babel/src/main/codegen/config.fmpp | 10 +++++++++ babel/src/main/codegen/includes/parserImpls.ftl | 20 +++++++++++++++++ .../org/apache/calcite/test/BabelParserTest.java | 25 +++++++++++++++++++++- core/src/main/codegen/config.fmpp | 6 ++++++ core/src/main/codegen/templates/Parser.jj | 14 +++--------- .../apache/calcite/sql/parser/SqlParserUtil.java | 15 ++++++++++--- core/src/test/codegen/config.fmpp | 6 ++++++ server/src/main/codegen/config.fmpp | 6 ++++++ 8 files changed, 87 insertions(+), 15 deletions(-) diff --git a/babel/src/main/codegen/config.fmpp b/babel/src/main/codegen/config.fmpp index 9ff0556..d46f8ca 100644 --- a/babel/src/main/codegen/config.fmpp +++ b/babel/src/main/codegen/config.fmpp @@ -824,14 +824,24 @@ data: { ] # List of methods for parsing custom literals. + # Return type of method implementation should be "SqlNode". # Example: ParseJsonLiteral(). literalParserMethods: [ ] # List of methods for parsing custom data types. + # Return type of method implementation should be "SqlIdentifier". + # Example: SqlParseTimeStampZ(). dataTypeParserMethods: [ ] + # List of methods for parsing builtin function calls. + # Return type of method implementation should be "SqlNode". + # Example: DateFunctionCall(). + builtinFunctionCallMethods: [ + "DateFunctionCall()" + ] + # List of methods for parsing extensions to "ALTER <scope>" calls. # Each must accept arguments "(SqlParserPos pos, String scope)". alterStatementParserMethods: [ diff --git a/babel/src/main/codegen/includes/parserImpls.ftl b/babel/src/main/codegen/includes/parserImpls.ftl index 09b5d3d..934830a 100644 --- a/babel/src/main/codegen/includes/parserImpls.ftl +++ b/babel/src/main/codegen/includes/parserImpls.ftl @@ -22,4 +22,24 @@ JoinType LeftSemiJoin() : <LEFT> <SEMI> <JOIN> { return JoinType.LEFT_SEMI_JOIN; } } +SqlNode DateFunctionCall() : +{ + final SqlFunctionCategory funcType = SqlFunctionCategory.USER_DEFINED_FUNCTION; + final SqlIdentifier qualifiedName; + final Span s; + final SqlLiteral quantifier; + final List<? extends SqlNode> args; +} +{ + <DATE> { + s = span(); + qualifiedName = new SqlIdentifier(unquotedIdentifier(), getPos()); + } + args = FunctionParameterList(ExprContext.ACCEPT_SUB_QUERY) { + quantifier = (SqlLiteral) args.get(0); + args.remove(0); + return createCall(qualifiedName, s.end(this), funcType, quantifier, args); + } +} + // End parserImpls.ftl diff --git a/babel/src/test/java/org/apache/calcite/test/BabelParserTest.java b/babel/src/test/java/org/apache/calcite/test/BabelParserTest.java index 0029f82..aceb9a2 100644 --- a/babel/src/test/java/org/apache/calcite/test/BabelParserTest.java +++ b/babel/src/test/java/org/apache/calcite/test/BabelParserTest.java @@ -155,8 +155,31 @@ public class BabelParserTest extends SqlParserTest { "(?s)Encountered \"when then\" at .*"); } + /** In Redshift, DATE is a function. It requires special treatment in the + * parser because it is a reserved keyword. + * (Curiously, TIMESTAMP and TIME are not functions.) */ + @Test public void testDateFunction() { + final String expected = "SELECT `DATE`(`X`)\n" + + "FROM `T`"; + sql("select date(x) from t").ok(expected); + } + + /** PostgreSQL and Redshift allow TIMESTAMP literals that contain only a + * date part. */ + @Test public void testShortTimestampLiteral() { + sql("select timestamp '1969-07-20'") + .ok("SELECT TIMESTAMP '1969-07-20 00:00:00'"); + // PostgreSQL allows the following. We should too. + sql("select ^timestamp '1969-07-20 1:2'^") + .fails("Illegal TIMESTAMP literal '1969-07-20 1:2': not in format " + + "'yyyy-MM-dd HH:mm:ss'"); // PostgreSQL gives 1969-07-20 01:02:00 + sql("select ^timestamp '1969-07-20:23:'^") + .fails("Illegal TIMESTAMP literal '1969-07-20:23:': not in format " + + "'yyyy-MM-dd HH:mm:ss'"); // PostgreSQL gives 1969-07-20 23:00:00 + } + /** - * Babel parser's global {@code OOKAHEAD} is larger than the core + * Babel parser's global {@code LOOKAHEAD} is larger than the core * parser's. This causes different parse error message between these two * parsers. Here we define a looser error checker for Babel, so that we can * reuse failure testing codes from {@link SqlParserTest}. diff --git a/core/src/main/codegen/config.fmpp b/core/src/main/codegen/config.fmpp index 278e0d0..9687338 100644 --- a/core/src/main/codegen/config.fmpp +++ b/core/src/main/codegen/config.fmpp @@ -378,6 +378,12 @@ data: { dataTypeParserMethods: [ ] + # List of methods for parsing builtin function calls. + # Return type of method implementation should be "SqlNode". + # Example: DateFunctionCall(). + builtinFunctionCallMethods: [ + ] + # List of methods for parsing extensions to "ALTER <scope>" calls. # Each must accept arguments "(SqlParserPos pos, String scope)". # Example: "SqlUploadJarNode" diff --git a/core/src/main/codegen/templates/Parser.jj b/core/src/main/codegen/templates/Parser.jj index 192f65b..06cf491 100644 --- a/core/src/main/codegen/templates/Parser.jj +++ b/core/src/main/codegen/templates/Parser.jj @@ -294,16 +294,6 @@ void SqlInsertKeywords(List<SqlLiteral> keywords) : E() } -SqlNode ExtendedBuiltinFunctionCall() : -{ -} -{ - UnusedExtension() - { - return null; - } -} - /* * Parse Floor/Ceil function parameters */ @@ -4906,8 +4896,10 @@ SqlNode BuiltinFunctionCall() : | node = TimestampDiffFunctionCall() { return node; } | - node = ExtendedBuiltinFunctionCall() { return node; } +<#list parser.builtinFunctionCallMethods as method> + node = ${method} { return node; } | +</#list> node = MatchRecognizeFunctionCall() { return node; } | node = JsonExistsFunctionCall() { return node; } 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 5f0f729..83c1f3a 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 @@ -171,9 +171,18 @@ public final class SqlParserUtil { public static SqlTimestampLiteral parseTimestampLiteral(String s, SqlParserPos pos) { final String dateStr = parseString(s); - final DateTimeUtils.PrecisionTime pt = - DateTimeUtils.parsePrecisionDateTimeLiteral(dateStr, - Format.PER_THREAD.get().timestamp, DateTimeUtils.UTC_ZONE, -1); + final Format format = Format.PER_THREAD.get(); + DateTimeUtils.PrecisionTime pt = null; + // Allow timestamp literals with and without time fields (as does + // PostgreSQL); TODO: require time fields except in Babel's lenient mode + final DateFormat[] dateFormats = {format.timestamp, format.date}; + for (DateFormat dateFormat : dateFormats) { + pt = DateTimeUtils.parsePrecisionDateTimeLiteral(dateStr, + dateFormat, DateTimeUtils.UTC_ZONE, -1); + if (pt != null) { + break; + } + } if (pt == null) { throw SqlUtil.newContextException(pos, RESOURCE.illegalLiteral("TIMESTAMP", s, diff --git a/core/src/test/codegen/config.fmpp b/core/src/test/codegen/config.fmpp index a135836..8a451e3 100644 --- a/core/src/test/codegen/config.fmpp +++ b/core/src/test/codegen/config.fmpp @@ -358,6 +358,12 @@ data: { dataTypeParserMethods: [ ] + # List of methods for parsing builtin function calls. + # Return type of method implementation should be "SqlNode". + # Example: DateFunctionCall(). + builtinFunctionCallMethods: [ + ] + # List of methods for parsing extensions to "ALTER <scope>" calls. # Each must accept arguments "(SqlParserPos pos, String scope)". alterStatementParserMethods: [ diff --git a/server/src/main/codegen/config.fmpp b/server/src/main/codegen/config.fmpp index faa22dd..0fbb139 100644 --- a/server/src/main/codegen/config.fmpp +++ b/server/src/main/codegen/config.fmpp @@ -374,6 +374,12 @@ data: { dataTypeParserMethods: [ ] + # List of methods for parsing builtin function calls. + # Return type of method implementation should be "SqlNode". + # Example: DateFunctionCall(). + builtinFunctionCallMethods: [ + ] + # List of methods for parsing extensions to "ALTER <scope>" calls. # Each must accept arguments "(SqlParserPos pos, String scope)". alterStatementParserMethods: [
