Skip to content

Commit 5164d7b

Browse files
authored
parser: alter table actions more robust (#549)
1 parent e8b245f commit 5164d7b

File tree

3 files changed

+84
-46
lines changed

3 files changed

+84
-46
lines changed

crates/squawk_parser/src/grammar.rs

Lines changed: 48 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -6024,21 +6024,7 @@ fn alter_materialized_view(p: &mut Parser<'_>) -> CompletedMarker {
60246024
name_ref(p);
60256025
}
60266026
ALTER_KW | CLUSTER_KW | SET_KW | RESET_KW | OWNER_KW => {
6027-
// TODO: we should be robust to missing commas
6028-
while !p.at(EOF) {
6029-
let action = p.start();
6030-
match alter_table_action(p) {
6031-
Some(action_kind) => {
6032-
action.complete(p, action_kind);
6033-
}
6034-
None => {
6035-
action.abandon(p);
6036-
}
6037-
};
6038-
if !p.eat(COMMA) {
6039-
break;
6040-
}
6041-
}
6027+
opt_alter_table_action_list(p);
60426028
}
60436029
_ => {
60446030
p.error("Expected RENAME, SET SCHEMA, [NO] DEPENDS, or action (ALTER, CLUSTER, SET, RESET, OWNER)");
@@ -6048,6 +6034,24 @@ fn alter_materialized_view(p: &mut Parser<'_>) -> CompletedMarker {
60486034
m.complete(p, ALTER_MATERIALIZED_VIEW)
60496035
}
60506036

6037+
fn opt_alter_table_action_list(p: &mut Parser<'_>) {
6038+
while !p.at(EOF) {
6039+
let m = p.start();
6040+
let Some(kind) = opt_alter_table_action(p) else {
6041+
m.abandon(p);
6042+
break;
6043+
};
6044+
m.complete(p, kind);
6045+
if !p.eat(COMMA) {
6046+
if p.at_ts(ALTER_TABLE_ACTION_FIRST) {
6047+
p.error("missing comma");
6048+
} else {
6049+
break;
6050+
}
6051+
}
6052+
}
6053+
}
6054+
60516055
// ALTER LARGE OBJECT large_object_oid OWNER TO { new_owner | CURRENT_ROLE | CURRENT_USER | SESSION_USER }
60526056
fn alter_large_object(p: &mut Parser<'_>) -> CompletedMarker {
60536057
assert!(p.at(ALTER_KW) && p.nth_at(1, LARGE_KW) && p.nth_at(2, OBJECT_KW));
@@ -6352,21 +6356,7 @@ fn alter_foreign_table(p: &mut Parser<'_>) -> CompletedMarker {
63526356
name_ref(p);
63536357
}
63546358
_ => {
6355-
// TODO: we should be robust to missing commas
6356-
while !p.at(EOF) {
6357-
let action = p.start();
6358-
match alter_table_action(p) {
6359-
Some(action_kind) => {
6360-
action.complete(p, action_kind);
6361-
}
6362-
None => {
6363-
action.abandon(p);
6364-
}
6365-
};
6366-
if !p.eat(COMMA) {
6367-
break;
6368-
}
6369-
}
6359+
opt_alter_table_action_list(p);
63706360
}
63716361
}
63726362
m.complete(p, ALTER_FOREIGN_TABLE)
@@ -13278,25 +13268,37 @@ fn alter_table(p: &mut Parser<'_>) -> CompletedMarker {
1327813268
}
1327913269
}
1328013270
}
13281-
// TODO: we should be robust to missing commas
13282-
while !p.at(EOF) {
13283-
let action = p.start();
13284-
match alter_table_action(p) {
13285-
Some(action_kind) => {
13286-
action.complete(p, action_kind);
13287-
}
13288-
None => {
13289-
action.abandon(p);
13290-
}
13291-
};
13292-
if !p.eat(COMMA) {
13293-
break;
13294-
}
13295-
}
13271+
opt_alter_table_action_list(p);
1329613272
m.complete(p, ALTER_TABLE)
1329713273
}
1329813274

13299-
fn alter_table_action(p: &mut Parser<'_>) -> Option<SyntaxKind> {
13275+
const ALTER_TABLE_ACTION_FIRST: TokenSet = TokenSet::new(&[
13276+
VALIDATE_KW,
13277+
REPLICA_KW,
13278+
OF_KW,
13279+
NOT_KW,
13280+
FORCE_KW,
13281+
NO_KW,
13282+
INHERIT_KW,
13283+
ENABLE_KW,
13284+
DISABLE_KW,
13285+
CLUSTER_KW,
13286+
OWNER_KW,
13287+
DETACH_KW,
13288+
DROP_KW,
13289+
ADD_KW,
13290+
ATTACH_KW,
13291+
SET_KW,
13292+
RESET_KW,
13293+
RENAME_KW,
13294+
ALTER_KW,
13295+
OPTIONS_KW,
13296+
]);
13297+
13298+
fn opt_alter_table_action(p: &mut Parser<'_>) -> Option<SyntaxKind> {
13299+
if !p.at_ts(ALTER_TABLE_ACTION_FIRST) {
13300+
return None;
13301+
}
1330013302
let kind = match p.current() {
1330113303
// VALIDATE CONSTRAINT constraint_name
1330213304
VALIDATE_KW => {

crates/squawk_parser/tests/data/err/alter_table.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,9 @@ add column foo boolean;
44
-- mismatch options
55
alter table t alter constraint c not deferrable initially deferred;
66

7+
alter table t
8+
validate constraint foo validate constraint b ;
9+
-- ^ missing comma
10+
711
-- pg 18 only, via: https://www.depesz.com/2025/05/01/waiting-for-postgresql-18-allow-not-null-constraints-to-be-added-as-not-valid/
812
alter table public.copy_2 add constraint id_not_null not null id not valid;

crates/squawk_parser/tests/snapshots/tests__alter_table_err.snap

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,37 @@ SOURCE_FILE
5050
DEFERRED_KW "deferred"
5151
SEMICOLON ";"
5252
WHITESPACE "\n\n"
53+
ALTER_TABLE
54+
ALTER_KW "alter"
55+
WHITESPACE " "
56+
TABLE_KW "table"
57+
WHITESPACE " "
58+
RELATION_NAME
59+
PATH
60+
PATH_SEGMENT
61+
NAME_REF
62+
IDENT "t"
63+
WHITESPACE " \n"
64+
VALIDATE_CONSTRAINT
65+
VALIDATE_KW "validate"
66+
WHITESPACE " "
67+
CONSTRAINT_KW "constraint"
68+
WHITESPACE " "
69+
NAME_REF
70+
IDENT "foo"
71+
WHITESPACE " "
72+
VALIDATE_CONSTRAINT
73+
VALIDATE_KW "validate"
74+
WHITESPACE " "
75+
CONSTRAINT_KW "constraint"
76+
WHITESPACE " "
77+
NAME_REF
78+
IDENT "b"
79+
WHITESPACE " "
80+
SEMICOLON ";"
81+
WHITESPACE "\n"
82+
COMMENT "-- ^ missing comma"
83+
WHITESPACE "\n\n"
5384
COMMENT "-- pg 18 only, via: https://www.depesz.com/2025/05/01/waiting-for-postgresql-18-allow-not-null-constraints-to-be-added-as-not-valid/"
5485
WHITESPACE "\n"
5586
ALTER_TABLE
@@ -95,3 +126,4 @@ ERROR@23: expected command, found ADD_KW
95126
ERROR@27: expected command, found COLUMN_KW
96127
ERROR@34: expected command, found IDENT
97128
ERROR@38: expected command, found BOOLEAN_KW
129+
ERROR@175: missing comma

0 commit comments

Comments
 (0)