diff --git a/crates/squawk_parser/src/grammar.rs b/crates/squawk_parser/src/grammar.rs index dbf87856..df7f441c 100644 --- a/crates/squawk_parser/src/grammar.rs +++ b/crates/squawk_parser/src/grammar.rs @@ -2332,7 +2332,15 @@ fn compound_select(p: &mut Parser<'_>, cm: CompletedMarker) -> CompletedMarker { if !p.eat(ALL_KW) { p.eat(DISTINCT_KW); } - select_stmt(p, None); + if p.at(L_PAREN) { + tuple_expr(p); + } else { + if p.at_ts(SELECT_FIRST) { + select_stmt(p, None); + } else { + p.error("expected start of a select statement") + } + } m.complete(p, COMPOUND_SELECT) } diff --git a/crates/squawk_parser/src/snapshots/squawk_parser__test__select_compound_union_select_ok.snap b/crates/squawk_parser/src/snapshots/squawk_parser__test__select_compound_union_select_ok.snap new file mode 100644 index 00000000..9b2878c7 --- /dev/null +++ b/crates/squawk_parser/src/snapshots/squawk_parser__test__select_compound_union_select_ok.snap @@ -0,0 +1,256 @@ +--- +source: crates/squawk_parser/src/test.rs +input_file: crates/squawk_parser/test_data/ok/select_compound_union_select.sql +--- +SOURCE_FILE + SELECT + SELECT_CLAUSE + SELECT_KW "SELECT" + WHITESPACE " " + TARGET_LIST + TARGET + PAREN_EXPR + L_PAREN "(" + WHITESPACE "\n " + COMPOUND_SELECT + PAREN_EXPR + L_PAREN "(" + SELECT + SELECT_CLAUSE + SELECT_KW "SELECT" + WHITESPACE " " + TARGET_LIST + TARGET + NAME_REF + IDENT "id" + WHITESPACE " " + FROM_CLAUSE + FROM_KW "FROM" + WHITESPACE " " + NAME_REF + IDENT "code_categories" + WHITESPACE " " + WHERE_CLAUSE + WHERE_KW "WHERE" + WHITESPACE " " + BIN_EXPR + NAME_REF + IDENT "\"language\"" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PREFIX_EXPR + CUSTOM_OP + AT "@" + CAST_EXPR + NAME_REF + LANGUAGE_KW "language" + COLON2 "::" + CHAR_TYPE + CHAR_KW "char" + L_PAREN "(" + ARG_LIST + ARG + LITERAL + INT_NUMBER "4" + R_PAREN ")" + WHITESPACE " " + ORDER_BY_CLAUSE + ORDER_KW "ORDER" + WHITESPACE " " + BY_KW "BY" + WHITESPACE " " + NAME_REF + IDENT "\"id\"" + WHITESPACE " " + ASC_KW "ASC" + WHITESPACE " " + LIMIT_CLAUSE + LIMIT_KW "LIMIT" + WHITESPACE " " + LITERAL + INT_NUMBER "1" + R_PAREN ")" + WHITESPACE "\n " + UNION_KW "UNION" + WHITESPACE "\n " + PAREN_EXPR + L_PAREN "(" + SELECT + SELECT_CLAUSE + SELECT_KW "SELECT" + WHITESPACE " " + TARGET_LIST + TARGET + NAME_REF + IDENT "id" + WHITESPACE " " + FROM_CLAUSE + FROM_KW "FROM" + WHITESPACE " " + NAME_REF + IDENT "code_categories" + WHITESPACE " " + WHERE_CLAUSE + WHERE_KW "WHERE" + WHITESPACE " " + BIN_EXPR + NAME_REF + IDENT "\"language\"" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + STRING "'nl-NL'" + WHITESPACE " " + ORDER_BY_CLAUSE + ORDER_KW "ORDER" + WHITESPACE " " + BY_KW "BY" + WHITESPACE " " + NAME_REF + IDENT "\"id\"" + WHITESPACE " " + ASC_KW "ASC" + WHITESPACE " " + LIMIT_CLAUSE + LIMIT_KW "LIMIT" + WHITESPACE " " + LITERAL + INT_NUMBER "1" + R_PAREN ")" + WHITESPACE "\n" + R_PAREN ")" + WHITESPACE " " + LIMIT_CLAUSE + LIMIT_KW "LIMIT" + WHITESPACE " " + LITERAL + INT_NUMBER "1" + SEMICOLON ";" + WHITESPACE "\n\n" + COMMENT "-- version without parentheses." + WHITESPACE "\n" + SELECT + SELECT_CLAUSE + SELECT_KW "SELECT" + WHITESPACE " " + TARGET_LIST + TARGET + PAREN_EXPR + L_PAREN "(" + WHITESPACE "\n " + COMPOUND_SELECT + PAREN_EXPR + L_PAREN "(" + SELECT + SELECT_CLAUSE + SELECT_KW "SELECT" + WHITESPACE " " + TARGET_LIST + TARGET + NAME_REF + IDENT "id" + WHITESPACE " " + FROM_CLAUSE + FROM_KW "FROM" + WHITESPACE " " + NAME_REF + IDENT "code_categories" + WHITESPACE " " + WHERE_CLAUSE + WHERE_KW "WHERE" + WHITESPACE " " + BIN_EXPR + NAME_REF + IDENT "\"language\"" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PREFIX_EXPR + CUSTOM_OP + AT "@" + CAST_EXPR + NAME_REF + LANGUAGE_KW "language" + COLON2 "::" + CHAR_TYPE + CHAR_KW "char" + L_PAREN "(" + ARG_LIST + ARG + LITERAL + INT_NUMBER "4" + R_PAREN ")" + WHITESPACE " " + ORDER_BY_CLAUSE + ORDER_KW "ORDER" + WHITESPACE " " + BY_KW "BY" + WHITESPACE " " + NAME_REF + IDENT "\"id\"" + WHITESPACE " " + ASC_KW "ASC" + WHITESPACE " " + LIMIT_CLAUSE + LIMIT_KW "LIMIT" + WHITESPACE " " + LITERAL + INT_NUMBER "1" + R_PAREN ")" + WHITESPACE "\n " + UNION_KW "UNION" + WHITESPACE "\n " + SELECT + SELECT_CLAUSE + SELECT_KW "SELECT" + WHITESPACE " " + TARGET_LIST + TARGET + NAME_REF + IDENT "id" + WHITESPACE " " + FROM_CLAUSE + FROM_KW "FROM" + WHITESPACE " " + NAME_REF + IDENT "code_categories" + WHITESPACE " " + WHERE_CLAUSE + WHERE_KW "WHERE" + WHITESPACE " " + BIN_EXPR + NAME_REF + IDENT "\"language\"" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + STRING "'nl-NL'" + WHITESPACE " " + ORDER_BY_CLAUSE + ORDER_KW "ORDER" + WHITESPACE " " + BY_KW "BY" + WHITESPACE " " + NAME_REF + IDENT "\"id\"" + WHITESPACE " " + ASC_KW "ASC" + WHITESPACE " " + LIMIT_CLAUSE + LIMIT_KW "LIMIT" + WHITESPACE " " + LITERAL + INT_NUMBER "1" + WHITESPACE "\n" + R_PAREN ")" + WHITESPACE " " + LIMIT_CLAUSE + LIMIT_KW "LIMIT" + WHITESPACE " " + LITERAL + INT_NUMBER "1" + SEMICOLON ";" + WHITESPACE "\n" diff --git a/crates/squawk_parser/test_data/ok/select_compound_union_select.sql b/crates/squawk_parser/test_data/ok/select_compound_union_select.sql new file mode 100644 index 00000000..d0031789 --- /dev/null +++ b/crates/squawk_parser/test_data/ok/select_compound_union_select.sql @@ -0,0 +1,12 @@ +SELECT ( + (SELECT id FROM code_categories WHERE "language" = @language::char(4) ORDER BY "id" ASC LIMIT 1) + UNION + (SELECT id FROM code_categories WHERE "language" = 'nl-NL' ORDER BY "id" ASC LIMIT 1) +) LIMIT 1; + +-- version without parentheses. +SELECT ( + (SELECT id FROM code_categories WHERE "language" = @language::char(4) ORDER BY "id" ASC LIMIT 1) + UNION + SELECT id FROM code_categories WHERE "language" = 'nl-NL' ORDER BY "id" ASC LIMIT 1 +) LIMIT 1;