diff --git a/core/src/main/java/org/apache/calcite/sql/parser/SqlAbstractParserImpl.java b/core/src/main/java/org/apache/calcite/sql/parser/SqlAbstractParserImpl.java index 389a6fa56152..8315a4dac1fb 100644 --- a/core/src/main/java/org/apache/calcite/sql/parser/SqlAbstractParserImpl.java +++ b/core/src/main/java/org/apache/calcite/sql/parser/SqlAbstractParserImpl.java @@ -619,9 +619,11 @@ public static LexicalState forConfig(SqlParser.Config config) { return BQID; case BACK_TICK: if (config.conformance().allowHyphenInUnquotedTableName() - && config.charLiteralStyles().equals( + && (config.charLiteralStyles().equals( EnumSet.of(CharLiteralStyle.BQ_SINGLE, - CharLiteralStyle.BQ_DOUBLE))) { + CharLiteralStyle.BQ_DOUBLE)) + || config.charLiteralStyles().equals( + EnumSet.of(CharLiteralStyle.STANDARD)))) { return BQID; } if (!config.conformance().allowHyphenInUnquotedTableName() diff --git a/testkit/src/main/java/org/apache/calcite/sql/parser/SqlParserFixture.java b/testkit/src/main/java/org/apache/calcite/sql/parser/SqlParserFixture.java index 34fc7ac1140e..8a016ea29494 100644 --- a/testkit/src/main/java/org/apache/calcite/sql/parser/SqlParserFixture.java +++ b/testkit/src/main/java/org/apache/calcite/sql/parser/SqlParserFixture.java @@ -189,6 +189,10 @@ public SqlParserFixture withTester(SqlParserTest.Tester tester) { convertToLinux, parserChecker); } + public SqlParserFixture withQuoting(Quoting quoting) { + return withConfig(c -> c.withQuoting(quoting)); + } + /** * Sets whether to convert actual strings to Linux (converting Windows * CR-LF line endings to Linux LF) before comparing them to expected. diff --git a/testkit/src/main/java/org/apache/calcite/sql/parser/SqlParserTest.java b/testkit/src/main/java/org/apache/calcite/sql/parser/SqlParserTest.java index f7704aa842bb..da6adfdce411 100644 --- a/testkit/src/main/java/org/apache/calcite/sql/parser/SqlParserTest.java +++ b/testkit/src/main/java/org/apache/calcite/sql/parser/SqlParserTest.java @@ -892,6 +892,12 @@ private void checkLarge(int n) { } @Test void testHyphenatedTableName() { + final SqlConformance nonBigQueryConformance = new SqlAbstractConformance() { + @Override public boolean allowHyphenInUnquotedTableName() { + return true; + } + }; + sql("select * from bigquery^-^foo-bar.baz") .fails("(?s)Encountered \"-\" at .*") .withDialect(BIG_QUERY) @@ -913,7 +919,12 @@ private void checkLarge(int n) { .ok("SELECT baz.buzz\n" + "FROM `foo-bar`.baz") .withDialect(MYSQL) - .fails("(?s)Encountered \"-\" at .*"); + .fails("(?s)Encountered \"-\" at .*") + // It should allow if enabled via SqlConformance + .withConformance(nonBigQueryConformance) + .withQuoting(Quoting.BACK_TICK) + .ok("SELECT `baz`.`buzz`\n" + + "FROM `foo-bar`.`baz`"); // No hyphenated identifiers as table aliases. sql("select * from foo.baz as hyphenated^-^alias-not-allowed") @@ -923,7 +934,12 @@ private void checkLarge(int n) { sql("select * from foo.baz as `hyphenated-alias-allowed-if-quoted`") .withDialect(BIG_QUERY) .ok("SELECT *\n" - + "FROM foo.baz AS `hyphenated-alias-allowed-if-quoted`"); + + "FROM foo.baz AS `hyphenated-alias-allowed-if-quoted`") + .withDialect(MYSQL) + .withQuoting(Quoting.BACK_TICK) + .withConformance(nonBigQueryConformance) + .ok("SELECT *\n" + + "FROM `foo`.`baz` AS `hyphenated-alias-allowed-if-quoted`"); // No hyphenated identifiers as column names. sql("select * from foo-bar.baz cross join (select alpha-omega from t) as t") @@ -931,28 +947,53 @@ private void checkLarge(int n) { .ok("SELECT *\n" + "FROM `foo-bar`.baz\n" + "CROSS JOIN (SELECT (alpha - omega)\n" - + "FROM t) AS t"); + + "FROM t) AS t") + .withDialect(MYSQL) + .withQuoting(Quoting.BACK_TICK) + .withConformance(nonBigQueryConformance) + .ok("SELECT *\n" + + "FROM `foo-bar`.`baz`\n" + + "CROSS JOIN (SELECT (`alpha` - `omega`)\n" + + "FROM `t`) AS `t`"); sql("select * from bigquery-foo-bar.baz as hyphenated^-^alias-not-allowed") .withDialect(BIG_QUERY) + .fails("(?s)Encountered \"-\" at .*") + .withDialect(MYSQL) + .withQuoting(Quoting.BACK_TICK) + .withConformance(nonBigQueryConformance) .fails("(?s)Encountered \"-\" at .*"); sql("insert into bigquery^-^public-data.foo values (1)") .fails("Non-query expression encountered in illegal context") .withDialect(BIG_QUERY) .ok("INSERT INTO `bigquery-public-data`.foo\n" + + "VALUES (1)") + .withDialect(MYSQL) + .withQuoting(Quoting.BACK_TICK) + .withConformance(nonBigQueryConformance) + .ok("INSERT INTO `bigquery-public-data`.`foo`\n" + "VALUES (1)"); sql("update bigquery^-^public-data.foo set a = b") .fails("(?s)Encountered \"-\" at .*") .withDialect(BIG_QUERY) - .ok("UPDATE `bigquery-public-data`.foo SET a = b"); + .ok("UPDATE `bigquery-public-data`.foo SET a = b") + .withDialect(MYSQL) + .withQuoting(Quoting.BACK_TICK) + .withConformance(nonBigQueryConformance) + .ok("UPDATE `bigquery-public-data`.`foo` SET `a` = `b`"); sql("delete from bigquery^-^public-data.foo where a = 5") .fails("(?s)Encountered \"-\" at .*") .withDialect(BIG_QUERY) .ok("DELETE FROM `bigquery-public-data`.foo\n" - + "WHERE (a = 5)"); + + "WHERE (a = 5)") + .withDialect(MYSQL) + .withQuoting(Quoting.BACK_TICK) + .withConformance(nonBigQueryConformance) + .ok("DELETE FROM `bigquery-public-data`.`foo`\n" + + "WHERE (`a` = 5)"); final String mergeSql = "merge into bigquery^-^public-data.emps e\n" + "using (\n" @@ -977,10 +1018,25 @@ private void checkLarge(int n) { + "WHEN NOT MATCHED THEN" + " INSERT (name, dept, salary)" + " VALUES (t.name, 10, (t.salary * 0.15))"; + final String nonBigQueryMergeExpected = "MERGE INTO `bigquery-public-data`.`emps` AS `e`\n" + + "USING (SELECT *\n" + + "FROM `bigquery-public-data`.`tempemps`\n" + + "WHERE (`deptno` IS NULL)) AS `t`\n" + + "ON (`e`.`empno` = `t`.`empno`)\n" + + "WHEN MATCHED THEN" + + " UPDATE SET `name` = `t`.`name`, `deptno` = `t`.`deptno`," + + " `salary` = (`t`.`salary` * 0.1)\n" + + "WHEN NOT MATCHED THEN" + + " INSERT (`name`, `dept`, `salary`)" + + " VALUES (`t`.`name`, 10, (`t`.`salary` * 0.15))"; sql(mergeSql) .fails("(?s)Encountered \"-\" at .*") .withDialect(BIG_QUERY) - .ok(mergeExpected); + .ok(mergeExpected) + .withDialect(MYSQL) + .withQuoting(Quoting.BACK_TICK) + .withConformance(nonBigQueryConformance) + .ok(nonBigQueryMergeExpected); // Hyphenated identifiers may not contain spaces, even in BigQuery. sql("select * from bigquery ^-^ foo - bar as t where x < y")