Skip to content

Commit 6288d49

Browse files
authored
parser: fix json_table, table, values, group by clause & more (#536)
1 parent a368f9e commit 6288d49

27 files changed

+1029
-1341
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@
99
dist
1010

1111
.DS_Store
12+
temp.sql

crates/squawk_parser/src/generated/syntax_kind.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: 111 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -584,20 +584,7 @@ fn json_table_arg_list(p: &mut Parser<'_>) {
584584
name(p);
585585
}
586586
// [ PASSING { value AS varname } [, ...] ]
587-
if p.eat(PASSING_KW) {
588-
while !p.at(EOF) {
589-
// value
590-
if expr(p).is_none() {
591-
p.error("expected expression");
592-
}
593-
opt_json_format_clause(p);
594-
p.expect(AS_KW);
595-
col_label(p);
596-
if !p.eat(COMMA) {
597-
break;
598-
}
599-
}
600-
}
587+
opt_json_passing_clause(p);
601588
// COLUMNS ( json_table_column [, ...] )
602589
if p.eat(COLUMNS_KW) {
603590
p.expect(L_PAREN);
@@ -609,12 +596,7 @@ fn json_table_arg_list(p: &mut Parser<'_>) {
609596
}
610597
p.expect(R_PAREN);
611598
}
612-
// [ { ERROR | EMPTY [ARRAY]} ON ERROR ]
613-
if p.eat(ERROR_KW) {
614-
p.expect(ON_KW);
615-
p.expect(ERROR_KW);
616-
} else if p.eat(EMPTY_KW) {
617-
p.eat(ARRAY_KW);
599+
if opt_json_behavior(p) {
618600
p.expect(ON_KW);
619601
p.expect(ERROR_KW);
620602
}
@@ -633,6 +615,7 @@ fn json_table_arg_list(p: &mut Parser<'_>) {
633615
// [ { ERROR | TRUE | FALSE | UNKNOWN } ON ERROR ]
634616
// | NESTED [ PATH ] path_expression [ AS json_path_name ] COLUMNS ( json_table_column [, ...] )
635617
fn json_table_column(p: &mut Parser<'_>) {
618+
let m = p.start();
636619
// NESTED [ PATH ] path_expression [ AS json_path_name ] COLUMNS ( json_table_column [, ...] )
637620
if p.eat(NESTED_KW) {
638621
p.eat(PATH_KW);
@@ -669,60 +652,22 @@ fn json_table_column(p: &mut Parser<'_>) {
669652
p.error("expected expression");
670653
}
671654
}
672-
// [ { ERROR | TRUE | FALSE | UNKNOWN } ON ERROR ]
673-
if p.at(ERROR_KW) || p.at(TRUE_KW) || p.at(FALSE_KW) || p.at(UNKNOWN_KW) {
674-
p.expect(ON_KW);
675-
p.expect(ERROR_KW);
676-
}
655+
opt_json_behavior_clause(p);
677656
} else {
678657
// [ FORMAT JSON [ENCODING UTF8]]
679658
opt_json_format_clause(p);
680659
// [ PATH path_expression ]
681660
if p.eat(PATH_KW) {
682661
// path_expression
683-
if expr(p).is_none() {
684-
p.error("expected expression");
685-
}
686-
}
687-
// [ { WITHOUT | WITH { CONDITIONAL | [UNCONDITIONAL] } } [ ARRAY ] WRAPPER ]
688-
if p.at(WITHOUT_KW) || p.at(WITH_KW) {
689-
if p.eat(WITH_KW) {
690-
let _ = p.eat(CONDITIONAL_KW) || p.eat(UNCONDITIONAL_KW);
691-
} else {
692-
p.bump(WITHOUT_KW);
693-
}
694-
p.eat(ARRAY_KW);
695-
p.expect(WRAPPER_KW);
696-
}
697-
// [ { KEEP | OMIT } QUOTES [ ON SCALAR STRING ] ]
698-
if p.eat(KEEP_KW) || p.eat(OMIT_KW) {
699-
p.expect(QUOTES_KW);
700-
if p.eat(ON_KW) {
701-
p.expect(SCALAR_KW);
702-
p.expect(STRING_KW);
703-
}
704-
}
705-
// [ { ERROR | NULL | EMPTY { [ARRAY] | OBJECT } | DEFAULT expression } ON EMPTY ]
706-
// [ { ERROR | NULL | EMPTY { [ARRAY] | OBJECT } | DEFAULT expression } ON ERROR ]
707-
if p.at(ERROR_KW) || p.at(NULL_KW) || p.at(EMPTY_KW) || p.at(DEFAULT_KW) {
708-
// EMPTY { [ARRAY] | OBJECT }
709-
if p.eat(EMPTY_KW) {
710-
let _ = p.eat(ARRAY_KW) || p.expect(OBJECT_KW);
711-
// DEFAULT
712-
} else if p.eat(DEFAULT_KW) {
713-
if expr(p).is_none() {
714-
p.error("expected an expression");
715-
}
716-
// ERROR | NULL
717-
} else {
718-
p.bump_any();
719-
}
720-
p.expect(ON_KW);
721-
let _ = p.eat(EMPTY_KW) || p.expect(ERROR_KW);
662+
string_literal(p);
722663
}
664+
opt_json_wrapper_behavior(p);
665+
opt_json_quotes_clause(p);
666+
opt_json_behavior_clause(p);
723667
}
724668
}
725669
}
670+
m.complete(p, JSON_TABLE_COLUMN);
726671
}
727672

728673
// json_array (
@@ -2508,11 +2453,9 @@ fn compound_select(p: &mut Parser<'_>, cm: CompletedMarker) -> CompletedMarker {
25082453
fn select(p: &mut Parser, m: Option<Marker>) -> Option<CompletedMarker> {
25092454
assert!(p.at_ts(SELECT_FIRST));
25102455
let m = m.unwrap_or_else(|| p.start());
2511-
// table [only] name [*]
2512-
if p.eat(TABLE_KW) {
2513-
relation_name(p);
2514-
return Some(m.complete(p, TABLE));
2515-
}
2456+
2457+
let mut out_kind = SELECT;
2458+
25162459
// with aka cte
25172460
// [ WITH [ RECURSIVE ] with_query [, ...] ]
25182461
if p.at(WITH_KW) {
@@ -2526,8 +2469,16 @@ fn select(p: &mut Parser, m: Option<Marker>) -> Option<CompletedMarker> {
25262469
return Some(cm);
25272470
}
25282471
}
2529-
select_clause(p);
2530-
let is_select_into = opt_into_clause(p).is_some();
2472+
// table [only] name [*]
2473+
if p.eat(TABLE_KW) {
2474+
relation_name(p);
2475+
out_kind = TABLE;
2476+
} else {
2477+
select_clause(p);
2478+
}
2479+
if opt_into_clause(p).is_some() {
2480+
out_kind = SELECT_INTO;
2481+
}
25312482
opt_from_clause(p);
25322483
opt_where_clause(p);
25332484
opt_group_by_clause(p);
@@ -2554,7 +2505,7 @@ fn select(p: &mut Parser, m: Option<Marker>) -> Option<CompletedMarker> {
25542505
opt_locking_clause(p);
25552506
}
25562507
}
2557-
Some(m.complete(p, if is_select_into { SELECT_INTO } else { SELECT }))
2508+
Some(m.complete(p, out_kind))
25582509
}
25592510

25602511
// INTO [ TEMPORARY | TEMP | UNLOGGED ] [ TABLE ] new_table
@@ -2918,8 +2869,11 @@ fn data_source(p: &mut Parser<'_>) {
29182869
p.expect(FROM_KW);
29192870
p.expect(L_PAREN);
29202871
call_expr(p);
2921-
// TODO: we should restrict this more
29222872
opt_alias(p);
2873+
while !p.at(EOF) && p.eat(COMMA) {
2874+
call_expr(p);
2875+
opt_alias(p);
2876+
}
29232877
p.expect(R_PAREN);
29242878
// [ WITH ORDINALITY ]
29252879
if p.eat(WITH_KW) {
@@ -4153,27 +4107,59 @@ fn opt_group_by_clause(p: &mut Parser<'_>) -> Option<CompletedMarker> {
41534107
if p.at(ALL_KW) || p.at(DISTINCT_KW) {
41544108
p.bump_any();
41554109
}
4110+
group_by_list(p);
4111+
4112+
Some(m.complete(p, GROUP_BY_CLAUSE))
4113+
}
4114+
4115+
fn group_by_list(p: &mut Parser<'_>) {
41564116
// From pg docs:
41574117
// An expression used inside a grouping_element can be an input column name,
41584118
// or the name or ordinal number of an output column (SELECT list item), or
41594119
// an arbitrary expression formed from input-column values. In case of
41604120
// ambiguity, a GROUP BY name will be interpreted as an input-column name
41614121
// rather than an output column name.
41624122
while !p.at(EOF) && !p.at(SEMICOLON) {
4163-
// TODO: handle errors?
4164-
p.eat(ROLLUP_KW);
4165-
p.eat(CUBE_KW);
4166-
if p.eat(GROUPING_KW) {
4167-
p.expect(SETS_KW);
4168-
}
4169-
if expr(p).is_none() {
4170-
p.error("expected an expression");
4171-
}
4123+
let m = p.start();
4124+
let kind = match p.current() {
4125+
ROLLUP_KW => {
4126+
p.bump_any();
4127+
p.expect(L_PAREN);
4128+
if !expr_list(p) {
4129+
p.error("expected expression list");
4130+
};
4131+
p.expect(R_PAREN);
4132+
GROUPING_ROLLUP
4133+
}
4134+
CUBE_KW => {
4135+
p.bump_any();
4136+
p.expect(L_PAREN);
4137+
if !expr_list(p) {
4138+
p.error("expected expression list");
4139+
};
4140+
p.expect(R_PAREN);
4141+
GROUPING_CUBE
4142+
}
4143+
GROUPING_KW if p.nth_at(1, SETS_KW) => {
4144+
p.bump(GROUPING_KW);
4145+
p.bump(SETS_KW);
4146+
p.expect(L_PAREN);
4147+
group_by_list(p);
4148+
p.expect(R_PAREN);
4149+
GROUPING_SETS
4150+
}
4151+
_ => {
4152+
if expr(p).is_none() {
4153+
p.error("expected an expression");
4154+
}
4155+
GROUPING_EXPR
4156+
}
4157+
};
4158+
m.complete(p, kind);
41724159
if !p.eat(COMMA) {
41734160
break;
41744161
}
41754162
}
4176-
Some(m.complete(p, GROUP_BY_CLAUSE))
41774163
}
41784164

41794165
/// <https://www.postgresql.org/docs/17/sql-select.html#SQL-HAVING>
@@ -4196,22 +4182,20 @@ fn opt_having_clause(p: &mut Parser<'_>) -> Option<CompletedMarker> {
41964182
// offset PRECEDING
41974183
// offset FOLLOWING
41984184
fn frame_start_end(p: &mut Parser<'_>) {
4199-
if p.eat(UNBOUNDED_KW) {
4200-
if p.at(PRECEDING_KW) || p.at(FOLLOWING_KW) {
4185+
match (p.current(), p.nth(1)) {
4186+
(CURRENT_KW, ROW_KW) | (UNBOUNDED_KW, PRECEDING_KW | FOLLOWING_KW) => {
42014187
p.bump_any();
4202-
} else {
4203-
p.err_and_bump("expected preceding or following");
4204-
}
4205-
} else if p.eat(CURRENT_KW) {
4206-
p.expect(ROW_KW);
4207-
} else {
4208-
if expr(p).is_none() {
4209-
p.error("expected an expression");
4210-
}
4211-
if p.at(PRECEDING_KW) || p.at(FOLLOWING_KW) {
42124188
p.bump_any();
4213-
} else {
4214-
p.err_and_bump("expected preceding or following");
4189+
}
4190+
_ => {
4191+
if expr(p).is_none() {
4192+
p.error("expected an expression");
4193+
}
4194+
if p.at(PRECEDING_KW) || p.at(FOLLOWING_KW) {
4195+
p.bump_any();
4196+
} else {
4197+
p.err_and_bump("expected preceding or following");
4198+
}
42154199
}
42164200
}
42174201
}
@@ -4290,12 +4274,19 @@ fn opt_window_clause(p: &mut Parser<'_>) -> Option<CompletedMarker> {
42904274
}
42914275
let m = p.start();
42924276
p.bump(WINDOW_KW);
4293-
p.expect(IDENT);
4277+
window_def(p);
4278+
while !p.at(EOF) && p.eat(COMMA) {
4279+
window_def(p);
4280+
}
4281+
Some(m.complete(p, WINDOW_CLAUSE))
4282+
}
4283+
4284+
fn window_def(p: &mut Parser<'_>) {
4285+
name(p);
42944286
p.expect(AS_KW);
42954287
p.expect(L_PAREN);
42964288
window_definition(p);
42974289
p.expect(R_PAREN);
4298-
Some(m.complete(p, WINDOW_CLAUSE))
42994290
}
43004291

43014292
// [ LIMIT { count | ALL } ]
@@ -4848,13 +4839,20 @@ fn create_table(p: &mut Parser<'_>) -> CompletedMarker {
48484839
// AS query
48494840
// [ WITH [ NO ] DATA ]
48504841
if p.eat(AS_KW) {
4851-
// query
4852-
if p.at_ts(SELECT_FIRST) {
4853-
select(p, None);
4854-
} else if p.at(EXECUTE_KW) {
4855-
execute(p);
4856-
} else {
4857-
p.error("expected SELECT, TABLE, VALUES, or EXECUTE");
4842+
match stmt(
4843+
p,
4844+
&StmtRestrictions {
4845+
begin_end_allowed: false,
4846+
},
4847+
)
4848+
.map(|x| x.kind())
4849+
{
4850+
Some(
4851+
SELECT | COMPOUND_SELECT | SELECT_INTO | PAREN_SELECT | TABLE | VALUES | EXECUTE,
4852+
) => (),
4853+
_ => {
4854+
p.error("expected SELECT, TABLE, VALUES, or EXECUTE");
4855+
}
48584856
}
48594857
if p.eat(WITH_KW) {
48604858
p.eat(NO_KW);
@@ -5272,7 +5270,7 @@ fn stmt(p: &mut Parser, r: &StmtRestrictions) -> Option<CompletedMarker> {
52725270
(GRANT_KW, _) => Some(grant(p)),
52735271
(IMPORT_KW, FOREIGN_KW) => Some(import_foreign_schema(p)),
52745272
(INSERT_KW, _) => Some(insert(p, None)),
5275-
(L_PAREN, L_PAREN | SELECT_KW) => {
5273+
(L_PAREN, _) if p.nth_at_ts(1, SELECT_FIRST) || p.at(L_PAREN) => {
52765274
// can have select nested in parens, i.e., ((select 1));
52775275
let cm = paren_select(p)?;
52785276
let cm = if p.at_ts(COMPOUND_SELECT_FIRST) {
@@ -6913,11 +6911,15 @@ fn alter_default_privileges(p: &mut Parser<'_>) -> CompletedMarker {
69136911

69146912
fn privilege_target_type(p: &mut Parser<'_>) {
69156913
match p.current() {
6914+
LARGE_KW => {
6915+
p.bump(LARGE_KW);
6916+
p.expect(OBJECTS_KW);
6917+
}
69166918
TABLES_KW | FUNCTIONS_KW | ROUTINES_KW | SEQUENCES_KW | TYPES_KW | SCHEMAS_KW => {
69176919
p.bump_any();
69186920
}
69196921
_ => p.error(
6920-
"expected privilege target, TABLES, FUNCTIONS, ROUTINES, SEQEUNCES, TYPES, SCHEMAS",
6922+
"expected privilege target, TABLES, FUNCTIONS, ROUTINES, SEQEUNCES, TYPES, SCHEMAS, LARGE OBJECTS",
69216923
),
69226924
}
69236925
}
@@ -10387,7 +10389,7 @@ fn grant_role_option_list(p: &mut Parser<'_>) {
1038710389
p.error("expected OPTION, TRUE, or FALSE")
1038810390
}
1038910391
if !p.eat(COMMA) {
10390-
if p.at_ts(COL_LABEL_FIRST) {
10392+
if p.at_ts(COL_LABEL_FIRST) && !p.at(GRANTED_KW) {
1039110393
p.error("missing comma");
1039210394
} else {
1039310395
break;

crates/squawk_parser/tests/data/ok/select_funcs.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,3 +249,7 @@ select max(a) over (partition by b) as c from t;
249249

250250
-- window name
251251
select max(a) over w_name from t;
252+
253+
-- window clause
254+
select * from t window owner as (order by a), w2 as (order by b);
255+
-- ^^^^^ make sure we allow using keywords

0 commit comments

Comments
 (0)