Skip to content

Commit 783b731

Browse files
authored
parser: sync pg regressions suite, support ForPortionOf (#1038)
1 parent 6cfd902 commit 783b731

31 files changed

Lines changed: 2266 additions & 77 deletions

crates/squawk_parser/src/generated/syntax_kind.rs

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/squawk_parser/src/generated/token_sets.rs

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/squawk_parser/src/grammar.rs

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6229,6 +6229,14 @@ fn alter_publication(p: &mut Parser<'_>) -> CompletedMarker {
62296229
SET_KW if p.nth_at(1, L_PAREN) => {
62306230
set_options(p);
62316231
}
6232+
SET_KW if p.nth_at(1, ALL_KW) => {
6233+
p.bump(SET_KW);
6234+
publication_all_object(p);
6235+
while !p.at(EOF) && p.eat(COMMA) {
6236+
publication_all_object(p);
6237+
}
6238+
opt_except_table_clause(p);
6239+
}
62326240
SET_KW => {
62336241
p.bump(SET_KW);
62346242
publication_object(p);
@@ -8895,8 +8903,7 @@ fn edge_left(p: &mut Parser<'_>) {
88958903
let m = p.start();
88968904
p.bump(L_ANGLE);
88978905
p.expect(MINUS);
8898-
if p.at(L_BRACK) {
8899-
p.bump(L_BRACK);
8906+
if p.eat(L_BRACK) {
89008907
opt_edge_pattern_inner(p);
89018908
p.expect(R_BRACK);
89028909
p.expect(MINUS);
@@ -9799,15 +9806,17 @@ fn opt_except_table_clause(p: &mut Parser<'_>) {
97999806

98009807
let m = p.start();
98019808
p.bump(EXCEPT_KW);
9802-
p.expect(TABLE_KW);
98039809
delimited(
98049810
p,
98059811
L_PAREN,
98069812
R_PAREN,
98079813
COMMA,
98089814
|| "unexpected comma".to_string(),
9809-
RELATION_NAME_FIRST,
9810-
|p| opt_relation_name(p).is_some(),
9815+
RELATION_NAME_FIRST.union(TokenSet::new(&[TABLE_KW])),
9816+
|p| {
9817+
p.eat(TABLE_KW);
9818+
opt_relation_name(p).is_some()
9819+
},
98119820
);
98129821
m.complete(p, EXCEPT_TABLE_CLAUSE);
98139822
}
@@ -9993,8 +10002,7 @@ fn create_subscription(p: &mut Parser<'_>) -> CompletedMarker {
999310002
p.bump(CREATE_KW);
999410003
p.bump(SUBSCRIPTION_KW);
999510004
name(p);
9996-
if p.at(SERVER_KW) {
9997-
p.bump(SERVER_KW);
10005+
if p.eat(SERVER_KW) {
999810006
name_ref(p);
999910007
} else {
1000010008
p.expect(CONNECTION_KW);
@@ -12483,7 +12491,7 @@ fn copy_option_list(p: &mut Parser<'_>) {
1248312491

1248412492
fn opt_copy_option_item(p: &mut Parser<'_>) -> bool {
1248512493
match p.current() {
12486-
BINARY_KW | FREEZE_KW | CSV_KW | HEADER_KW => {
12494+
BINARY_KW | FREEZE_KW | CSV_KW | HEADER_KW | JSON_KW => {
1248712495
p.bump_any();
1248812496
}
1248912497
DELIMITER_KW | NULL_KW | QUOTE_KW | ESCAPE_KW => {
@@ -13226,6 +13234,7 @@ fn update(p: &mut Parser<'_>, m: Option<Marker>) -> CompletedMarker {
1322613234
let m = m.unwrap_or_else(|| p.start());
1322713235
p.bump(UPDATE_KW);
1322813236
relation_name(p);
13237+
opt_for_portion_of(p);
1322913238
// postgres parser has the same setup, it assumes the alias can never be
1323013239
// named `SET`
1323113240
if !p.at(SET_KW) {
@@ -13242,6 +13251,35 @@ fn update(p: &mut Parser<'_>, m: Option<Marker>) -> CompletedMarker {
1324213251
m.complete(p, UPDATE)
1324313252
}
1324413253

13254+
// FOR PORTION OF column_name FROM expr TO expr [ [ AS ] alias ]
13255+
// FOR PORTION OF column_name ( expr ) [ [ AS ] alias ]
13256+
fn opt_for_portion_of(p: &mut Parser<'_>) {
13257+
if !p.at(FOR_KW) {
13258+
return;
13259+
}
13260+
let m = p.start();
13261+
p.expect(FOR_KW);
13262+
p.expect(PORTION_KW);
13263+
p.expect(OF_KW);
13264+
name_ref(p);
13265+
for_portion_of_target(p);
13266+
m.complete(p, FOR_PORTION_OF);
13267+
}
13268+
13269+
fn for_portion_of_target(p: &mut Parser<'_>) {
13270+
if p.eat(L_PAREN) {
13271+
expr(p);
13272+
p.expect(R_PAREN);
13273+
} else {
13274+
p.expect(FROM_KW);
13275+
// start time
13276+
expr(p);
13277+
p.expect(TO_KW);
13278+
// end time
13279+
expr(p);
13280+
}
13281+
}
13282+
1324513283
fn opt_where_or_current_of(p: &mut Parser<'_>) {
1324613284
if p.at(WHERE_KW) {
1324713285
if p.nth_at(1, CURRENT_KW) {
@@ -13291,7 +13329,10 @@ fn delete(p: &mut Parser<'_>, m: Option<Marker>) -> CompletedMarker {
1329113329
p.bump(DELETE_KW);
1329213330
p.expect(FROM_KW);
1329313331
relation_name(p);
13294-
opt_as_alias(p);
13332+
opt_for_portion_of(p);
13333+
if !p.at(FOR_KW) {
13334+
opt_as_alias(p);
13335+
}
1329513336
opt_using_clause(p);
1329613337
// [ WHERE condition | WHERE CURRENT OF cursor_name ]
1329713338
opt_where_or_current_of(p);
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
source: crates/squawk_parser/tests/tests.rs
3+
input_file: postgres/regression_suite/for_portion_of.sql
4+
---
5+

crates/squawk_syntax/src/ast/generated/nodes.rs

Lines changed: 73 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/squawk_syntax/src/postgresql.ungram

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1359,12 +1359,17 @@ Update =
13591359
WithClause?
13601360
'update'
13611361
RelationName
1362+
ForPortionOf?
13621363
Alias?
13631364
SetClause
13641365
FromClause?
13651366
WhereClause?
13661367
ReturningClause?
13671368

1369+
ForPortionOf =
1370+
'for' 'portion' 'of' NameRef
1371+
('from' Expr 'to' Expr | '(' Expr ')')
1372+
13681373
ReturningClause =
13691374
'returning'
13701375
ReturningOptionList
@@ -1380,7 +1385,9 @@ ReturningOption =
13801385

13811386
Delete =
13821387
WithClause?
1383-
'delete' 'from' RelationName Alias?
1388+
'delete' 'from' RelationName
1389+
ForPortionOf?
1390+
Alias?
13841391
UsingClause?
13851392
(WhereClause | WhereCurrentOf)?
13861393
ReturningClause?

crates/xtask/src/sync_regression_suite.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ const START_END_MARKERS: &[(&str, &str)] = &[
2121
("-- Multiple VALUES clause", "\tINSERT VALUES (1,1), (2,2);"),
2222
("-- SELECT query for INSERT", "\tINSERT SELECT (1, 1);"),
2323
("-- UPDATE tablename", "\tUPDATE target SET balance = 0;"),
24+
(
25+
"-- TO is used for the bound but not the INTERVAL:",
26+
" WHERE id = '[1,2)';",
27+
),
2428
];
2529

2630
const IGNORED_LINES: &[&str] = &[

postgres/kwlist.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// synced from:
2-
// commit: ab697307dd0f0b4f6c6671421d4dd0bc20f176cb
3-
// committed at: 2026-03-18T02:04:10Z
4-
// file: https://github.com/postgres/postgres/blob/ab697307dd0f0b4f6c6671421d4dd0bc20f176cb/src/include/parser/kwlist.h
2+
// commit: effaa464afd355e8927bf430cfe6a0ddd2ee5695
3+
// committed at: 2026-04-02T12:39:57Z
4+
// file: https://github.com/postgres/postgres/blob/effaa464afd355e8927bf430cfe6a0ddd2ee5695/src/include/parser/kwlist.h
55
//
66
// update via:
77
// cargo xtask sync-kwlist
@@ -361,6 +361,7 @@ PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD, BARE_LABEL)
361361
PG_KEYWORD("plan", PLAN, UNRESERVED_KEYWORD, BARE_LABEL)
362362
PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD, BARE_LABEL)
363363
PG_KEYWORD("policy", POLICY, UNRESERVED_KEYWORD, BARE_LABEL)
364+
PG_KEYWORD("portion", PORTION, UNRESERVED_KEYWORD, BARE_LABEL)
364365
PG_KEYWORD("position", POSITION, COL_NAME_KEYWORD, BARE_LABEL)
365366
PG_KEYWORD("preceding", PRECEDING, UNRESERVED_KEYWORD, BARE_LABEL)
366367
PG_KEYWORD("precision", PRECISION, COL_NAME_KEYWORD, AS_LABEL)

postgres/plpgsql/plpgsql_simple.sql

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,20 @@ begin
114114
fetch p_CurData into val;
115115
raise notice 'val = %', val;
116116
end; $$;
117+
118+
-- We now optimize "SELECT simple-expr INTO var" using the simple-expression
119+
-- logic. Verify that error reporting works the same as it did before.
120+
121+
do $$
122+
declare x bigint := 2^30; y int;
123+
begin
124+
-- overflow during assignment step does not get an extra context line
125+
select x*x into y;
126+
end $$;
127+
128+
do $$
129+
declare x bigint := 2^30; y int;
130+
begin
131+
-- overflow during expression evaluation step does get an extra context line
132+
select x*x*x into y;
133+
end $$;

0 commit comments

Comments
 (0)