Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions crates/squawk_parser/src/generated/syntax_kind.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions crates/squawk_parser/src/generated/token_sets.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

59 changes: 50 additions & 9 deletions crates/squawk_parser/src/grammar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6229,6 +6229,14 @@ fn alter_publication(p: &mut Parser<'_>) -> CompletedMarker {
SET_KW if p.nth_at(1, L_PAREN) => {
set_options(p);
}
SET_KW if p.nth_at(1, ALL_KW) => {
p.bump(SET_KW);
publication_all_object(p);
while !p.at(EOF) && p.eat(COMMA) {
publication_all_object(p);
}
opt_except_table_clause(p);
}
SET_KW => {
p.bump(SET_KW);
publication_object(p);
Expand Down Expand Up @@ -8895,8 +8903,7 @@ fn edge_left(p: &mut Parser<'_>) {
let m = p.start();
p.bump(L_ANGLE);
p.expect(MINUS);
if p.at(L_BRACK) {
p.bump(L_BRACK);
if p.eat(L_BRACK) {
opt_edge_pattern_inner(p);
p.expect(R_BRACK);
p.expect(MINUS);
Expand Down Expand Up @@ -9799,15 +9806,17 @@ fn opt_except_table_clause(p: &mut Parser<'_>) {

let m = p.start();
p.bump(EXCEPT_KW);
p.expect(TABLE_KW);
delimited(
p,
L_PAREN,
R_PAREN,
COMMA,
|| "unexpected comma".to_string(),
RELATION_NAME_FIRST,
|p| opt_relation_name(p).is_some(),
RELATION_NAME_FIRST.union(TokenSet::new(&[TABLE_KW])),
|p| {
p.eat(TABLE_KW);
opt_relation_name(p).is_some()
},
);
m.complete(p, EXCEPT_TABLE_CLAUSE);
}
Expand Down Expand Up @@ -9993,8 +10002,7 @@ fn create_subscription(p: &mut Parser<'_>) -> CompletedMarker {
p.bump(CREATE_KW);
p.bump(SUBSCRIPTION_KW);
name(p);
if p.at(SERVER_KW) {
p.bump(SERVER_KW);
if p.eat(SERVER_KW) {
name_ref(p);
} else {
p.expect(CONNECTION_KW);
Expand Down Expand Up @@ -12483,7 +12491,7 @@ fn copy_option_list(p: &mut Parser<'_>) {

fn opt_copy_option_item(p: &mut Parser<'_>) -> bool {
match p.current() {
BINARY_KW | FREEZE_KW | CSV_KW | HEADER_KW => {
BINARY_KW | FREEZE_KW | CSV_KW | HEADER_KW | JSON_KW => {
p.bump_any();
}
DELIMITER_KW | NULL_KW | QUOTE_KW | ESCAPE_KW => {
Expand Down Expand Up @@ -13226,6 +13234,7 @@ fn update(p: &mut Parser<'_>, m: Option<Marker>) -> CompletedMarker {
let m = m.unwrap_or_else(|| p.start());
p.bump(UPDATE_KW);
relation_name(p);
opt_for_portion_of(p);
// postgres parser has the same setup, it assumes the alias can never be
// named `SET`
if !p.at(SET_KW) {
Expand All @@ -13242,6 +13251,35 @@ fn update(p: &mut Parser<'_>, m: Option<Marker>) -> CompletedMarker {
m.complete(p, UPDATE)
}

// FOR PORTION OF column_name FROM expr TO expr [ [ AS ] alias ]
// FOR PORTION OF column_name ( expr ) [ [ AS ] alias ]
fn opt_for_portion_of(p: &mut Parser<'_>) {
if !p.at(FOR_KW) {
return;
}
let m = p.start();
p.expect(FOR_KW);
p.expect(PORTION_KW);
p.expect(OF_KW);
name_ref(p);
for_portion_of_target(p);
m.complete(p, FOR_PORTION_OF);
}

fn for_portion_of_target(p: &mut Parser<'_>) {
if p.eat(L_PAREN) {
expr(p);
p.expect(R_PAREN);
} else {
p.expect(FROM_KW);
// start time
expr(p);
p.expect(TO_KW);
// end time
expr(p);
}
}

fn opt_where_or_current_of(p: &mut Parser<'_>) {
if p.at(WHERE_KW) {
if p.nth_at(1, CURRENT_KW) {
Expand Down Expand Up @@ -13291,7 +13329,10 @@ fn delete(p: &mut Parser<'_>, m: Option<Marker>) -> CompletedMarker {
p.bump(DELETE_KW);
p.expect(FROM_KW);
relation_name(p);
opt_as_alias(p);
opt_for_portion_of(p);
if !p.at(FOR_KW) {
opt_as_alias(p);
}
opt_using_clause(p);
// [ WHERE condition | WHERE CURRENT OF cursor_name ]
opt_where_or_current_of(p);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
source: crates/squawk_parser/tests/tests.rs
input_file: postgres/regression_suite/for_portion_of.sql
---

73 changes: 73 additions & 0 deletions crates/squawk_syntax/src/ast/generated/nodes.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion crates/squawk_syntax/src/postgresql.ungram
Original file line number Diff line number Diff line change
Expand Up @@ -1359,12 +1359,17 @@ Update =
WithClause?
'update'
RelationName
ForPortionOf?
Alias?
SetClause
FromClause?
WhereClause?
ReturningClause?

ForPortionOf =
'for' 'portion' 'of' NameRef
('from' Expr 'to' Expr | '(' Expr ')')

ReturningClause =
'returning'
ReturningOptionList
Expand All @@ -1380,7 +1385,9 @@ ReturningOption =

Delete =
WithClause?
'delete' 'from' RelationName Alias?
'delete' 'from' RelationName
ForPortionOf?
Alias?
UsingClause?
(WhereClause | WhereCurrentOf)?
ReturningClause?
Expand Down
4 changes: 4 additions & 0 deletions crates/xtask/src/sync_regression_suite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ const START_END_MARKERS: &[(&str, &str)] = &[
("-- Multiple VALUES clause", "\tINSERT VALUES (1,1), (2,2);"),
("-- SELECT query for INSERT", "\tINSERT SELECT (1, 1);"),
("-- UPDATE tablename", "\tUPDATE target SET balance = 0;"),
(
"-- TO is used for the bound but not the INTERVAL:",
" WHERE id = '[1,2)';",
),
];

const IGNORED_LINES: &[&str] = &[
Expand Down
7 changes: 4 additions & 3 deletions postgres/kwlist.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// synced from:
// commit: ab697307dd0f0b4f6c6671421d4dd0bc20f176cb
// committed at: 2026-03-18T02:04:10Z
// file: https://github.com/postgres/postgres/blob/ab697307dd0f0b4f6c6671421d4dd0bc20f176cb/src/include/parser/kwlist.h
// commit: effaa464afd355e8927bf430cfe6a0ddd2ee5695
// committed at: 2026-04-02T12:39:57Z
// file: https://github.com/postgres/postgres/blob/effaa464afd355e8927bf430cfe6a0ddd2ee5695/src/include/parser/kwlist.h
//
// update via:
// cargo xtask sync-kwlist
Expand Down Expand Up @@ -361,6 +361,7 @@ PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("plan", PLAN, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("policy", POLICY, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("portion", PORTION, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("position", POSITION, COL_NAME_KEYWORD, BARE_LABEL)
PG_KEYWORD("preceding", PRECEDING, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("precision", PRECISION, COL_NAME_KEYWORD, AS_LABEL)
Expand Down
17 changes: 17 additions & 0 deletions postgres/plpgsql/plpgsql_simple.sql
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,20 @@ begin
fetch p_CurData into val;
raise notice 'val = %', val;
end; $$;

-- We now optimize "SELECT simple-expr INTO var" using the simple-expression
-- logic. Verify that error reporting works the same as it did before.

do $$
declare x bigint := 2^30; y int;
begin
-- overflow during assignment step does not get an extra context line
select x*x into y;
end $$;

do $$
declare x bigint := 2^30; y int;
begin
-- overflow during expression evaluation step does get an extra context line
select x*x*x into y;
end $$;
Loading
Loading