diff --git a/src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java b/src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java index 27880a2c7..cd4bfba7e 100644 --- a/src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java +++ b/src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java @@ -37,7 +37,15 @@ public enum Dialect { Feature.allowHashLineComments, Feature.allowDoubleQuotedStrings), SQLSERVER(AdjacentStringLiterals.OFF, Feature.allowSquareBracketQuotation), POSTGRESQL( - AdjacentStringLiterals.NEWLINE), H2, EXASOL; + AdjacentStringLiterals.NEWLINE), H2, EXASOL, BIGQUERY( + AdjacentStringLiterals.WHITESPACE, + Feature.allowDoubleQuotedStrings, + Feature.allowHashLineComments, + Feature.allowBackslashEscapeCharacter), DATABRICKS( + AdjacentStringLiterals.WHITESPACE, + Feature.allowDoubleQuotedStrings, + Feature.allowBackslashEscapeCharacter), SNOWFLAKE( + Feature.allowBackslashEscapeCharacter); private final Set lexerFeatures; private final AdjacentStringLiterals adjacentStringLiterals; diff --git a/src/site/sphinx/usage.rst b/src/site/sphinx/usage.rst index 3ad3190d9..e92173be9 100644 --- a/src/site/sphinx/usage.rst +++ b/src/site/sphinx/usage.rst @@ -319,7 +319,7 @@ Additionally there are Features to control the Parser's effort at the cost of th .withBackslashEscapeCharacter(true) ); -Instead of turning the individual Parser Features on one by one, a ``Dialect`` preset selects the features of that database dialect: ``withDialect(Dialect.MYSQL)`` turns on ``withBackslashEscapeCharacter``, ``withHashLineComments`` and ``withDoubleQuotedStrings`` (MySQL and MariaDB syntax, the latter for the default sql_mode), ``withDialect(Dialect.SQLSERVER)`` turns on ``withSquareBracketQuotation``. ``withDialect(Dialect.POSTGRESQL)`` and ``withDialect(Dialect.ANSI_SQL)`` turn on the newline rule for adjacent String Literals. Features set explicitly after the dialect preset win over the preset. +Instead of turning the individual Parser Features on one by one, a ``Dialect`` preset selects the features of that database dialect: ``withDialect(Dialect.MYSQL)`` turns on ``withBackslashEscapeCharacter``, ``withHashLineComments`` and ``withDoubleQuotedStrings`` (MySQL and MariaDB syntax, the latter for the default sql_mode), ``withDialect(Dialect.SQLSERVER)`` turns on ``withSquareBracketQuotation``. ``withDialect(Dialect.POSTGRESQL)`` and ``withDialect(Dialect.ANSI_SQL)`` turn on the newline rule for adjacent String Literals. ``withDialect(Dialect.BIGQUERY)`` and ``withDialect(Dialect.DATABRICKS)`` turn on ``withDoubleQuotedStrings`` and ``withBackslashEscapeCharacter`` plus the any-whitespace rule for adjacent String Literals, the BigQuery preset additionally ``withHashLineComments``; ``withDialect(Dialect.SNOWFLAKE)`` turns on ``withBackslashEscapeCharacter`` only, keeping double quotes as quoted identifiers. Features set explicitly after the dialect preset win over the preset. .. code-block:: java diff --git a/src/test/java/net/sf/jsqlparser/parser/CCJSqlParserUtilTest.java b/src/test/java/net/sf/jsqlparser/parser/CCJSqlParserUtilTest.java index 8add3b1bc..40e61e708 100644 --- a/src/test/java/net/sf/jsqlparser/parser/CCJSqlParserUtilTest.java +++ b/src/test/java/net/sf/jsqlparser/parser/CCJSqlParserUtilTest.java @@ -641,19 +641,51 @@ public void testDoubleQuotedStringsFeature() throws Exception { .parse("SELECT * FROM \"t\"", p -> p.withDoubleQuotedStrings(true)).toString()); } + @Test + public void testDialectPresetsWarehouses() throws Exception { + // BIGQUERY: double quoted strings, # line comments and backslash + // escapes (GoogleSQL "Lexical structure and syntax", identifiers are + // backticked), backticks stay unconditional + assertEquals("SELECT `col` FROM t WHERE a = 'x\\'yz' AND b = 42", CCJSqlParserUtil + .parse("SELECT `col` FROM t WHERE a = 'x\\'yz' AND b = 42#24", + p -> p.withDialect(AbstractJSqlParser.Dialect.BIGQUERY)) + .toString()); + // DATABRICKS: double quoted strings and backslash escapes (Spark + // "Literals"), `#` stays the #2507 operator + assertEquals("SELECT \"a\" FROM t WHERE x = 'it\\'s'", CCJSqlParserUtil + .parse("SELECT \"a\" FROM t WHERE x = 'it\\'s'", + p -> p.withDialect(AbstractJSqlParser.Dialect.DATABRICKS)) + .toString()); + assertEquals("SELECT 42 # 24", CCJSqlParserUtil.parse("SELECT 42 # 24", + p -> p.withDialect(AbstractJSqlParser.Dialect.DATABRICKS)).toString()); + // SNOWFLAKE: backslash escape sequences ("String & binary data + // types"), `#` stays the operator + assertEquals("SELECT col FROM t WHERE a = 'x\\'yz'", CCJSqlParserUtil + .parse("SELECT col FROM t WHERE a = 'x\\'yz'", + p -> p.withDialect(AbstractJSqlParser.Dialect.SNOWFLAKE)) + .toString()); + assertEquals("SELECT 42 # 24", CCJSqlParserUtil.parse("SELECT 42 # 24", + p -> p.withDialect(AbstractJSqlParser.Dialect.SNOWFLAKE)).toString()); + } + @Test public void testDoubleQuotedStringsPreset() throws Exception { - // MYSQL and MARIADB presets carry the switch (default sql_mode reading) + // the string-default dialects: MYSQL and MARIADB (default sql_mode), + // BIGQUERY and DATABRICKS (string literals, identifiers are backticked) for (AbstractJSqlParser.Dialect dialect : new AbstractJSqlParser.Dialect[] { - AbstractJSqlParser.Dialect.MYSQL, AbstractJSqlParser.Dialect.MARIADB}) { + AbstractJSqlParser.Dialect.MYSQL, AbstractJSqlParser.Dialect.MARIADB, + AbstractJSqlParser.Dialect.BIGQUERY, AbstractJSqlParser.Dialect.DATABRICKS}) { PlainSelect select = (PlainSelect) ((Select) CCJSqlParserUtil .parse("SELECT \"abc\"", p -> p.withDialect(dialect))).getSelectBody(); assertTrue(select.getSelectItems().get(0).getExpression() instanceof StringValue); } // the identifier-default dialects keep the quoted identifier reading - PlainSelect select = (PlainSelect) ((Select) CCJSqlParserUtil.parse("SELECT \"abc\"", - p -> p.withDialect(AbstractJSqlParser.Dialect.SQLSERVER))).getSelectBody(); - assertTrue(select.getSelectItems().get(0).getExpression() instanceof Column); + for (AbstractJSqlParser.Dialect dialect : new AbstractJSqlParser.Dialect[] { + AbstractJSqlParser.Dialect.SQLSERVER, AbstractJSqlParser.Dialect.SNOWFLAKE}) { + PlainSelect select = (PlainSelect) ((Select) CCJSqlParserUtil.parse("SELECT \"abc\"", + p -> p.withDialect(dialect))).getSelectBody(); + assertTrue(select.getSelectItems().get(0).getExpression() instanceof Column); + } } @Test @@ -717,6 +749,15 @@ public void testAdjacentStringLiteralsWhitespace() throws Exception { p -> p.withDoubleQuotedStrings(true).withAdjacentStringLiterals( AbstractJSqlParser.AdjacentStringLiterals.WHITESPACE)) .toString()); + // the BigQuery and Databricks presets carry it, the Snowflake preset + // does not (no adjacent-literal concatenation documented) + for (AbstractJSqlParser.Dialect dialect : new AbstractJSqlParser.Dialect[] { + AbstractJSqlParser.Dialect.BIGQUERY, AbstractJSqlParser.Dialect.DATABRICKS}) { + assertEquals("SELECT 'ab'", CCJSqlParserUtil.parse("SELECT 'a' 'b'", + p -> p.withDialect(dialect)).toString()); + } + assertEquals("SELECT 'a' 'b'", CCJSqlParserUtil.parse("SELECT 'a' 'b'", + p -> p.withDialect(AbstractJSqlParser.Dialect.SNOWFLAKE)).toString()); } @Test