This is an automated email from the ASF dual-hosted git repository. jhyde pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/calcite.git
commit d40b55cb7af21d170ff10eff026351d8b034b917 Author: Julian Hyde <jh...@apache.org> AuthorDate: Wed Jun 22 17:26:56 2022 -0700 [CALCITE-5194] Cannot parse parenthesized UNION in FROM --- core/src/main/codegen/templates/Parser.jj | 6 +- .../apache/calcite/sql/parser/SqlParserTest.java | 96 ++++++++++++++++++++++ 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/core/src/main/codegen/templates/Parser.jj b/core/src/main/codegen/templates/Parser.jj index c7186f3fbd..f466664850 100644 --- a/core/src/main/codegen/templates/Parser.jj +++ b/core/src/main/codegen/templates/Parser.jj @@ -612,6 +612,7 @@ JAVACODE boolean matchesPrefix(int[] seq, int[][] prefixes) SqlNode ExprOrJoinOrOrderedQuery(ExprContext exprContext) : { SqlNode e; + final List<Object> list = new ArrayList<Object>(); } { // Lookhead to distinguish between "TABLE emp" (which will be @@ -621,11 +622,14 @@ SqlNode ExprOrJoinOrOrderedQuery(ExprContext exprContext) : LOOKAHEAD(2) e = Query(exprContext) e = OrderByLimitOpt(e) + { return e; } | e = TableRef1(ExprContext.ACCEPT_QUERY_OR_JOIN) ( e = JoinTable(e) )* + { list.add(e); } + ( AddSetOpQuery(list, exprContext) )* + { return SqlParserUtil.toTree(list); } ) - { return e; } } /** 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 6be9d3e3e8..fd6d29cd8d 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 @@ -8186,6 +8186,102 @@ public class SqlParserTest { sql(sql2).ok(expected2); } + /** Test case for + * <a href="https://issues.apache.org/jira/browse/CALCITE-5194">[CALCITE-5194] + * Cannot parse parenthesized UNION in FROM</a>. */ + @Test void testParenthesizedUnionInFrom() { + final String sql = "select *\n" + + "from (\n" + + " (select x from a)\n" + + " union\n" + + " (select y from b))"; + final String expected = "SELECT *\n" + + "FROM (SELECT `X`\n" + + "FROM `A`\n" + + "UNION\n" + + "SELECT `Y`\n" + + "FROM `B`)"; + sql(sql).ok(expected); + } + + @Test void testParenthesizedUnionAndJoinInFrom() { + final String sql = "select *\n" + + "from (\n" + + " (select x from a) as a" + + " cross join\n" + + " (select x from a\n" + + " union\n" + + " select y from b) as b)"; + final String expected = "SELECT *\n" + + "FROM (SELECT `X`\n" + + "FROM `A`) AS `A`\n" + + "CROSS JOIN (SELECT `X`\n" + + "FROM `A`\n" + + "UNION\n" + + "SELECT `Y`\n" + + "FROM `B`) AS `B`"; + sql(sql).ok(expected); + } + + /** As {@link #testParenthesizedUnionAndJoinInFrom()} + * but the UNION is the first input to the JOIN. */ + @Test void testParenthesizedUnionAndJoinInFrom2() { + final String sql = "select *\n" + + "from (\n" + + " (select x from a\n" + + " union\n" + + " select y from b) as b\n" + + " cross join\n" + + " (select x from a) as a)"; + final String expected = "SELECT *\n" + + "FROM (SELECT `X`\n" + + "FROM `A`\n" + + "UNION\n" + + "SELECT `Y`\n" + + "FROM `B`) AS `B`\n" + + "CROSS JOIN (SELECT `X`\n" + + "FROM `A`) AS `A`"; + sql(sql).ok(expected); + } + + /** As {@link #testParenthesizedUnionAndJoinInFrom2()} + * but INNER JOIN rather than CROSS JOIN. */ + @Test void testParenthesizedUnionAndJoinInFrom3() { + final String sql = "select *\n" + + "from (\n" + + " (select x from a\n" + + " union\n" + + " select y from b) as b\n" + + " join\n" + + " (select x from a) as a on b.x = a.x)"; + final String expected = "SELECT *\n" + + "FROM (SELECT `X`\n" + + "FROM `A`\n" + + "UNION\n" + + "SELECT `Y`\n" + + "FROM `B`) AS `B`\n" + + "INNER JOIN (SELECT `X`\n" + + "FROM `A`) AS `A` ON (`B`.`X` = `A`.`X`)"; + sql(sql).ok(expected); + } + + @Test void testParenthesizedUnion() { + final String sql = "(select x from a\n" + + " union\n" + + " select y from b)\n" + + "except\n" + + "(select z from c)"; + final String expected = "((SELECT `X`\n" + + "FROM `A`\n" + + "UNION\n" + + "SELECT `Y`\n" + + "FROM `B`)\n" + + "EXCEPT\n" + + "SELECT `Z`\n" + + "FROM `C`)"; + sql(sql).ok(expected); + } + @Test void testFromExpr() { String sql0 = "select * from a cross join b"; String sql1 = "select * from (a cross join b)";