Skip to content

Commit 9553b4f

Browse files
authored
parser: fix paren select issues (#539)
we weren't parsing trailing clauses for paren select and had some dupe paren select logic hanging around.
1 parent 60834d8 commit 9553b4f

File tree

7 files changed

+33
-117
lines changed

7 files changed

+33
-117
lines changed

crates/squawk_parser/src/grammar.rs

Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ fn array_expr(p: &mut Parser<'_>, m: Option<Marker>) -> CompletedMarker {
6868
m.complete(p, ARRAY_EXPR)
6969
}
7070

71-
fn paren_select(p: &mut Parser<'_>) -> Option<CompletedMarker> {
71+
fn opt_paren_select(p: &mut Parser<'_>) -> Option<CompletedMarker> {
7272
let m = p.start();
7373
if !p.eat(L_PAREN) {
7474
m.abandon(p);
@@ -81,15 +81,22 @@ fn paren_select(p: &mut Parser<'_>) -> Option<CompletedMarker> {
8181
if p.at_ts(SELECT_FIRST) && (select(p, None).is_none() || p.at(EOF) || p.at(R_PAREN)) {
8282
break;
8383
}
84-
if paren_select(p).is_none() {
84+
if opt_paren_select(p).is_none() {
8585
break;
8686
}
8787
if !p.at(R_PAREN) {
8888
break;
8989
}
9090
}
9191
p.expect(R_PAREN);
92-
Some(m.complete(p, PAREN_SELECT))
92+
let cm = m.complete(p, PAREN_SELECT);
93+
let cm = if p.at_ts(COMPOUND_SELECT_FIRST) {
94+
compound_select(p, cm)
95+
} else {
96+
cm
97+
};
98+
select_trailing_clauses(p);
99+
Some(cm)
93100
}
94101

95102
const SELECT_FIRST: TokenSet = TokenSet::new(&[SELECT_KW, TABLE_KW, WITH_KW, VALUES_KW]);
@@ -2436,7 +2443,7 @@ fn compound_select(p: &mut Parser<'_>, cm: CompletedMarker) -> CompletedMarker {
24362443
p.eat(DISTINCT_KW);
24372444
}
24382445
if p.at(L_PAREN) {
2439-
tuple_expr(p);
2446+
opt_paren_select(p);
24402447
} else {
24412448
if p.at_ts(SELECT_FIRST) {
24422449
select(p, None);
@@ -2488,6 +2495,11 @@ fn select(p: &mut Parser, m: Option<Marker>) -> Option<CompletedMarker> {
24882495
let cm = m.complete(p, SELECT);
24892496
return Some(compound_select(p, cm));
24902497
}
2498+
select_trailing_clauses(p);
2499+
Some(m.complete(p, out_kind))
2500+
}
2501+
2502+
fn select_trailing_clauses(p: &mut Parser<'_>) {
24912503
opt_order_by_clause(p);
24922504
let mut has_locking_clause = false;
24932505
while p.at(FOR_KW) {
@@ -2505,7 +2517,6 @@ fn select(p: &mut Parser, m: Option<Marker>) -> Option<CompletedMarker> {
25052517
opt_locking_clause(p);
25062518
}
25072519
}
2508-
Some(m.complete(p, out_kind))
25092520
}
25102521

25112522
// INTO [ TEMPORARY | TEMP | UNLOGGED ] [ TABLE ] new_table
@@ -2778,11 +2789,14 @@ const FUNC_EXPR_COMMON_SUBEXPR_FIRST: TokenSet = TokenSet::new(&[
27782789
GREATEST_KW,
27792790
JSON_KW,
27802791
JSON_ARRAY_KW,
2792+
JSON_ARRAYAGG_KW,
27812793
JSON_EXISTS_KW,
27822794
JSON_OBJECT_KW,
2795+
JSON_OBJECTAGG_KW,
27832796
JSON_QUERY_KW,
27842797
JSON_SCALAR_KW,
27852798
JSON_SERIALIZE_KW,
2799+
JSON_TABLE_KW,
27862800
JSON_VALUE_KW,
27872801
LEAST_KW,
27882802
LOCALTIME_KW,
@@ -2806,6 +2820,7 @@ const FUNC_EXPR_COMMON_SUBEXPR_FIRST: TokenSet = TokenSet::new(&[
28062820
XMLPI_KW,
28072821
XMLROOT_KW,
28082822
XMLSERIALIZE_KW,
2823+
XMLTABLE_KW,
28092824
]);
28102825

28112826
const FROM_ITEM_KEYWORDS_FIRST: TokenSet = TokenSet::new(&[])
@@ -2993,29 +3008,23 @@ fn xml_namespace_element(p: &mut Parser<'_>) {
29933008
}
29943009
}
29953010

2996-
fn paren_data_source(p: &mut Parser<'_>) -> CompletedMarker {
3011+
fn paren_data_source(p: &mut Parser<'_>) -> Option<CompletedMarker> {
29973012
assert!(p.at(L_PAREN));
3013+
if p.at(L_PAREN) && p.nth_at_ts(1, SELECT_FIRST) {
3014+
return opt_paren_select(p);
3015+
}
29983016
let m = p.start();
29993017
p.bump(L_PAREN);
3000-
3001-
// Try to parse as a SELECT statement first
3002-
if p.at_ts(SELECT_FIRST) {
3003-
if select(p, None).is_some() {
3004-
p.expect(R_PAREN);
3005-
return m.complete(p, PAREN_SELECT);
3006-
}
3007-
}
3008-
30093018
// Then try to parse as a FROM_ITEM (which includes table references and joins)
30103019
if opt_from_item(p) {
30113020
p.expect(R_PAREN);
3012-
return m.complete(p, PAREN_EXPR);
3021+
return Some(m.complete(p, PAREN_EXPR));
30133022
} else {
30143023
p.error("expected table name or SELECT");
30153024
}
30163025

30173026
p.expect(R_PAREN);
3018-
m.complete(p, PAREN_EXPR)
3027+
Some(m.complete(p, PAREN_EXPR))
30193028
}
30203029

30213030
// USING data_source ON join_condition
@@ -5289,17 +5298,7 @@ fn stmt(p: &mut Parser, r: &StmtRestrictions) -> Option<CompletedMarker> {
52895298
(INSERT_KW, _) => Some(insert(p, None)),
52905299
(L_PAREN, _) if p.nth_at_ts(1, SELECT_FIRST) || p.at(L_PAREN) => {
52915300
// can have select nested in parens, i.e., ((select 1));
5292-
let cm = paren_select(p)?;
5293-
let cm = if p.at_ts(COMPOUND_SELECT_FIRST) {
5294-
compound_select(p, cm)
5295-
} else {
5296-
cm
5297-
};
5298-
// TODO: this needs to be rethinked
5299-
if p.at(ORDER_KW) {
5300-
opt_order_by_clause(p);
5301-
}
5302-
Some(cm)
5301+
opt_paren_select(p)
53035302
}
53045303
(LISTEN_KW, _) => Some(listen(p)),
53055304
(LOAD_KW, _) => Some(load(p)),
@@ -11987,7 +11986,7 @@ fn create_schema(p: &mut Parser<'_>) -> CompletedMarker {
1198711986

1198811987
fn query(p: &mut Parser<'_>) {
1198911988
// TODO: this needs to be more general
11990-
if (!p.at_ts(SELECT_FIRST) || select(p, None).is_none()) && paren_select(p).is_none() {
11989+
if (!p.at_ts(SELECT_FIRST) || select(p, None).is_none()) && opt_paren_select(p).is_none() {
1199111990
p.error("expected select stmt")
1199211991
}
1199311992
}

crates/squawk_parser/tests/snapshots/tests__regression_inherit.snap

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,4 @@
22
source: crates/squawk_parser/tests/tests.rs
33
input_file: crates/squawk_parser/tests/data/regression_suite/inherit.sql
44
---
5-
ERROR@30331: expected R_PAREN
6-
ERROR@30426: missing comma
7-
ERROR@30455: expected SEMICOLON
8-
ERROR@30455: expected command, found R_PAREN
9-
ERROR@30457: expected command, found FROM_KW
10-
ERROR@30462: expected command, found IDENT
11-
ERROR@30478: expected R_PAREN
12-
ERROR@30478: expected SEMICOLON
13-
ERROR@30478: expected command, found INT_NUMBER
14-
ERROR@30479: expected command, found COMMA
15-
ERROR@30481: expected command, found INT_NUMBER
16-
ERROR@30482: expected command, found R_PAREN
17-
ERROR@30484: expected command, found IDENT
18-
ERROR@30486: expected R_PAREN
19-
ERROR@30486: expected SEMICOLON
20-
ERROR@30486: expected command, found IDENT
21-
ERROR@30487: expected command, found R_PAREN
22-
ERROR@30594: expected R_PAREN
23-
ERROR@30689: missing comma
24-
ERROR@30718: expected SEMICOLON
25-
ERROR@30718: expected command, found R_PAREN
26-
ERROR@30720: expected command, found FROM_KW
27-
ERROR@30725: expected command, found IDENT
28-
ERROR@30741: expected R_PAREN
29-
ERROR@30741: expected SEMICOLON
30-
ERROR@30741: expected command, found INT_NUMBER
31-
ERROR@30742: expected command, found COMMA
32-
ERROR@30744: expected command, found INT_NUMBER
33-
ERROR@30745: expected command, found R_PAREN
34-
ERROR@30747: expected command, found IDENT
35-
ERROR@30749: expected R_PAREN
36-
ERROR@30749: expected SEMICOLON
37-
ERROR@30749: expected command, found IDENT
38-
ERROR@30750: expected command, found R_PAREN
5+

crates/squawk_parser/tests/snapshots/tests__regression_join.snap

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,4 @@
22
source: crates/squawk_parser/tests/tests.rs
33
input_file: crates/squawk_parser/tests/data/regression_suite/join.sql
44
---
5-
ERROR@93160: expected R_PAREN
6-
ERROR@93186: expected SEMICOLON
7-
ERROR@93186: expected command, found R_PAREN
8-
ERROR@93188: expected command, found AS_KW
9-
ERROR@93191: expected command, found IDENT
10-
ERROR@93196: expected command, found CROSS_KW
11-
ERROR@93202: expected command, found JOIN_KW
12-
ERROR@93207: expected command, found LATERAL_KW
13-
ERROR@93255: expected R_PAREN
14-
ERROR@93282: expected R_PAREN
15-
ERROR@93282: expected SEMICOLON
16-
ERROR@93283: expected command, found AS_KW
17-
ERROR@93286: expected command, found IDENT
18-
ERROR@93288: expected command, found R_PAREN
19-
ERROR@93293: expected command, found UNION_KW
20-
ERROR@93299: expected command, found ALL_KW
21-
ERROR@93319: expected SEMICOLON
22-
ERROR@93322: expected command, found R_PAREN
23-
ERROR@93324: expected command, found AS_KW
24-
ERROR@93327: expected command, found IDENT
5+

crates/squawk_parser/tests/snapshots/tests__regression_privileges.snap

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,4 @@
22
source: crates/squawk_parser/tests/tests.rs
33
input_file: crates/squawk_parser/tests/data/regression_suite/privileges.sql
44
---
5-
ERROR@17722: expected R_PAREN
6-
ERROR@17782: expected SEMICOLON
7-
ERROR@17782: expected command, found R_PAREN
8-
ERROR@17784: expected command, found IDENT
9-
ERROR@17787: expected command, found WHERE_KW
10-
ERROR@17793: expected command, found FALSE_KW
11-
ERROR@17906: expected R_PAREN
12-
ERROR@17980: expected SEMICOLON
13-
ERROR@17980: expected command, found R_PAREN
14-
ERROR@17982: expected command, found IDENT
15-
ERROR@17985: expected command, found WHERE_KW
16-
ERROR@17991: expected command, found IDENT
17-
ERROR@17993: expected command, found L_ANGLE
18-
ERROR@17995: expected command, found INT_NUMBER
5+

crates/squawk_parser/tests/snapshots/tests__regression_suite_errors.snap

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,6 @@
22
source: crates/squawk_parser/tests/tests.rs
33
expression: "out.join(\"\\n\")"
44
---
5-
tests/snapshots/tests__regression_inherit.snap:34
6-
tests/snapshots/tests__regression_join.snap:20
75
tests/snapshots/tests__regression_merge.snap:61
8-
tests/snapshots/tests__regression_privileges.snap:14
96
tests/snapshots/tests__regression_strings.snap:49
10-
tests/snapshots/tests__regression_union.snap:15
117
tests/snapshots/tests__regression_xml.snap:382

crates/squawk_parser/tests/snapshots/tests__regression_union.snap

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,4 @@
22
source: crates/squawk_parser/tests/tests.rs
33
input_file: crates/squawk_parser/tests/data/regression_suite/union.sql
44
---
5-
ERROR@996: expected SEMICOLON
6-
ERROR@997: expected command, found ORDER_KW
7-
ERROR@1003: expected command, found BY_KW
8-
ERROR@1006: expected command, found INT_NUMBER
9-
ERROR@10339: expected SEMICOLON
10-
ERROR@10340: expected command, found ORDER_KW
11-
ERROR@10346: expected command, found BY_KW
12-
ERROR@10349: expected command, found INT_NUMBER
13-
ERROR@11233: expected SEMICOLON
14-
ERROR@11234: expected command, found ORDER_KW
15-
ERROR@11240: expected command, found BY_KW
16-
ERROR@11243: expected command, found INT_NUMBER
17-
ERROR@18725: expected SEMICOLON
18-
ERROR@18726: expected command, found LIMIT_KW
19-
ERROR@18732: expected command, found INT_NUMBER
5+

crates/squawk_parser/tests/snapshots/tests__select_compound_union_select_ok.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ SOURCE_FILE
7777
WHITESPACE "\n "
7878
UNION_KW "UNION"
7979
WHITESPACE "\n "
80-
PAREN_EXPR
80+
PAREN_SELECT
8181
L_PAREN "("
8282
SELECT
8383
SELECT_CLAUSE

0 commit comments

Comments
 (0)