diff --git a/crates/squawk_parser/src/grammar.rs b/crates/squawk_parser/src/grammar.rs index 5cdc3d8c..c8661411 100644 --- a/crates/squawk_parser/src/grammar.rs +++ b/crates/squawk_parser/src/grammar.rs @@ -5146,7 +5146,7 @@ fn partition_item(p: &mut Parser<'_>, allow_extra_params: bool) -> CompletedMark } opt_collate(p); // [ opclass ] - opt_ident(p); + opt_index_opclass(p); if allow_extra_params { // [ ( opclass_parameter = value [, ... ] ) ] if p.at(L_PAREN) { @@ -5165,6 +5165,14 @@ fn opt_partition_item(p: &mut Parser<'_>, allow_extra_params: bool) -> Option) { + // at nulls_order + if p.at(NULLS_KW) && (p.nth_at(1, FIRST_KW) || p.nth_at(1, LAST_KW)) { + return; + } + opt_path_name_ref(p); +} + // [ NULLS { FIRST | LAST } ] fn opt_nulls_order(p: &mut Parser<'_>) { let m = p.start(); @@ -13381,7 +13389,7 @@ fn opt_conflict_index_item(p: &mut Parser<'_>) -> bool { } opt_collate(p); // [ opclass ] - opt_ident(p); + opt_index_opclass(p); m.complete(p, CONFLICT_INDEX_ITEM); true } diff --git a/crates/squawk_parser/tests/data/ok/create_index.sql b/crates/squawk_parser/tests/data/ok/create_index.sql index 40e60317..260e9937 100644 --- a/crates/squawk_parser/tests/data/ok/create_index.sql +++ b/crates/squawk_parser/tests/data/ok/create_index.sql @@ -60,3 +60,8 @@ CREATE INDEX pointloc CREATE INDEX CONCURRENTLY sales_quantity_index ON sales_table (quantity); +create index idx on t using gin (c nulls first); +create index idx on t using gin (c nulls nulls first); + +-- regression, see issue#1187 +CREATE INDEX index_name ON public.table_name USING GIN (column_name public.gin__int_ops); diff --git a/crates/squawk_parser/tests/data/ok/insert.sql b/crates/squawk_parser/tests/data/ok/insert.sql index 8e4628b9..505f3a0a 100644 --- a/crates/squawk_parser/tests/data/ok/insert.sql +++ b/crates/squawk_parser/tests/data/ok/insert.sql @@ -72,6 +72,12 @@ INSERT INTO distributors (did, dname) VALUES (7, 'Redline GmbH') insert into t (a, b, c) values (1, 2, 3) on conflict (a, b) do nothing; +insert into t (c) values (1) + on conflict (c public.gin__int_ops) do nothing; + +insert into t (c) values (1) + on conflict (c nulls) do nothing; + -- Don't update existing distributors based in a certain ZIP code INSERT INTO distributors AS d (did, dname) VALUES (8, 'Anvil Distribution') ON CONFLICT (did) DO UPDATE diff --git a/crates/squawk_parser/tests/snapshots/tests__create_index_ok.snap b/crates/squawk_parser/tests/snapshots/tests__create_index_ok.snap index e9fae74b..8e013bc7 100644 --- a/crates/squawk_parser/tests/snapshots/tests__create_index_ok.snap +++ b/crates/squawk_parser/tests/snapshots/tests__create_index_ok.snap @@ -161,7 +161,10 @@ SOURCE_FILE NAME_REF IDENT "a" WHITESPACE " " - IDENT "text_pattern_ops" + PATH + PATH_SEGMENT + NAME_REF + IDENT "text_pattern_ops" WHITESPACE " " ATTRIBUTE_LIST L_PAREN "(" @@ -190,7 +193,10 @@ SOURCE_FILE NAME_REF IDENT "b" WHITESPACE " " - IDENT "text_pattern_ops" + PATH + PATH_SEGMENT + NAME_REF + IDENT "text_pattern_ops" WHITESPACE " " ATTRIBUTE_LIST L_PAREN "(" @@ -787,3 +793,125 @@ SOURCE_FILE R_PAREN ")" SEMICOLON ";" WHITESPACE "\n\n" + CREATE_INDEX + CREATE_KW "create" + WHITESPACE " " + INDEX_KW "index" + WHITESPACE " " + NAME + IDENT "idx" + WHITESPACE " " + ON_KW "on" + WHITESPACE " " + RELATION_NAME + PATH + PATH_SEGMENT + NAME_REF + IDENT "t" + WHITESPACE " " + USING_METHOD + USING_KW "using" + WHITESPACE " " + NAME_REF + IDENT "gin" + WHITESPACE " " + PARTITION_ITEM_LIST + L_PAREN "(" + PARTITION_ITEM + NAME_REF + IDENT "c" + WHITESPACE " " + NULLS_FIRST + NULLS_KW "nulls" + WHITESPACE " " + FIRST_KW "first" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n" + CREATE_INDEX + CREATE_KW "create" + WHITESPACE " " + INDEX_KW "index" + WHITESPACE " " + NAME + IDENT "idx" + WHITESPACE " " + ON_KW "on" + WHITESPACE " " + RELATION_NAME + PATH + PATH_SEGMENT + NAME_REF + IDENT "t" + WHITESPACE " " + USING_METHOD + USING_KW "using" + WHITESPACE " " + NAME_REF + IDENT "gin" + WHITESPACE " " + PARTITION_ITEM_LIST + L_PAREN "(" + PARTITION_ITEM + NAME_REF + IDENT "c" + WHITESPACE " " + PATH + PATH_SEGMENT + NAME_REF + NULLS_KW "nulls" + WHITESPACE " " + NULLS_FIRST + NULLS_KW "nulls" + WHITESPACE " " + FIRST_KW "first" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n\n" + COMMENT "-- regression, see issue#1187" + WHITESPACE "\n" + CREATE_INDEX + CREATE_KW "CREATE" + WHITESPACE " " + INDEX_KW "INDEX" + WHITESPACE " " + NAME + IDENT "index_name" + WHITESPACE " " + ON_KW "ON" + WHITESPACE " " + RELATION_NAME + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "public" + DOT "." + PATH_SEGMENT + NAME_REF + IDENT "table_name" + WHITESPACE " " + USING_METHOD + USING_KW "USING" + WHITESPACE " " + NAME_REF + IDENT "GIN" + WHITESPACE " " + PARTITION_ITEM_LIST + L_PAREN "(" + PARTITION_ITEM + NAME_REF + IDENT "column_name" + WHITESPACE " " + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "public" + DOT "." + PATH_SEGMENT + NAME_REF + IDENT "gin__int_ops" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n" diff --git a/crates/squawk_parser/tests/snapshots/tests__create_table_ok.snap b/crates/squawk_parser/tests/snapshots/tests__create_table_ok.snap index 0bfb82fe..8539b2b5 100644 --- a/crates/squawk_parser/tests/snapshots/tests__create_table_ok.snap +++ b/crates/squawk_parser/tests/snapshots/tests__create_table_ok.snap @@ -470,7 +470,10 @@ SOURCE_FILE NAME_REF IDENT "\"fr_FR\"" WHITESPACE " " - IDENT "text_pattern_ops" + PATH + PATH_SEGMENT + NAME_REF + IDENT "text_pattern_ops" COMMA "," WHITESPACE " \n " PARTITION_ITEM diff --git a/crates/squawk_parser/tests/snapshots/tests__insert_ok.snap b/crates/squawk_parser/tests/snapshots/tests__insert_ok.snap index 5aea3598..de5d214b 100644 --- a/crates/squawk_parser/tests/snapshots/tests__insert_ok.snap +++ b/crates/squawk_parser/tests/snapshots/tests__insert_ok.snap @@ -1177,6 +1177,113 @@ SOURCE_FILE NOTHING_KW "nothing" SEMICOLON ";" WHITESPACE "\n\n" + INSERT + INSERT_KW "insert" + WHITESPACE " " + INTO_KW "into" + WHITESPACE " " + PATH + PATH_SEGMENT + NAME_REF + IDENT "t" + WHITESPACE " " + COLUMN_LIST + L_PAREN "(" + COLUMN + NAME_REF + IDENT "c" + R_PAREN ")" + WHITESPACE " " + VALUES + VALUES_KW "values" + WHITESPACE " " + ROW_LIST + ROW + L_PAREN "(" + LITERAL + INT_NUMBER "1" + R_PAREN ")" + WHITESPACE "\n " + ON_CONFLICT_CLAUSE + ON_KW "on" + WHITESPACE " " + CONFLICT_KW "conflict" + WHITESPACE " " + CONFLICT_ON_INDEX + CONFLICT_INDEX_ITEM_LIST + L_PAREN "(" + CONFLICT_INDEX_ITEM + NAME_REF + IDENT "c" + WHITESPACE " " + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "public" + DOT "." + PATH_SEGMENT + NAME_REF + IDENT "gin__int_ops" + R_PAREN ")" + WHITESPACE " " + CONFLICT_DO_NOTHING + DO_KW "do" + WHITESPACE " " + NOTHING_KW "nothing" + SEMICOLON ";" + WHITESPACE "\n\n" + INSERT + INSERT_KW "insert" + WHITESPACE " " + INTO_KW "into" + WHITESPACE " " + PATH + PATH_SEGMENT + NAME_REF + IDENT "t" + WHITESPACE " " + COLUMN_LIST + L_PAREN "(" + COLUMN + NAME_REF + IDENT "c" + R_PAREN ")" + WHITESPACE " " + VALUES + VALUES_KW "values" + WHITESPACE " " + ROW_LIST + ROW + L_PAREN "(" + LITERAL + INT_NUMBER "1" + R_PAREN ")" + WHITESPACE "\n " + ON_CONFLICT_CLAUSE + ON_KW "on" + WHITESPACE " " + CONFLICT_KW "conflict" + WHITESPACE " " + CONFLICT_ON_INDEX + CONFLICT_INDEX_ITEM_LIST + L_PAREN "(" + CONFLICT_INDEX_ITEM + NAME_REF + IDENT "c" + WHITESPACE " " + PATH + PATH_SEGMENT + NAME_REF + NULLS_KW "nulls" + R_PAREN ")" + WHITESPACE " " + CONFLICT_DO_NOTHING + DO_KW "do" + WHITESPACE " " + NOTHING_KW "nothing" + SEMICOLON ";" + WHITESPACE "\n\n" COMMENT "-- Don't update existing distributors based in a certain ZIP code" WHITESPACE "\n" INSERT diff --git a/crates/squawk_syntax/src/ast/generated/nodes.rs b/crates/squawk_syntax/src/ast/generated/nodes.rs index d3b986de..7419b1ca 100644 --- a/crates/squawk_syntax/src/ast/generated/nodes.rs +++ b/crates/squawk_syntax/src/ast/generated/nodes.rs @@ -3687,8 +3687,8 @@ impl ConflictIndexItem { support::child(&self.syntax) } #[inline] - pub fn ident_token(&self) -> Option { - support::token(&self.syntax, SyntaxKind::IDENT) + pub fn path(&self) -> Option { + support::child(&self.syntax) } } @@ -14005,6 +14005,10 @@ pub struct PartitionItem { pub(crate) syntax: SyntaxNode, } impl PartitionItem { + #[inline] + pub fn attribute_list(&self) -> Option { + support::child(&self.syntax) + } #[inline] pub fn collate(&self) -> Option { support::child(&self.syntax) @@ -14013,6 +14017,30 @@ impl PartitionItem { pub fn expr(&self) -> Option { support::child(&self.syntax) } + #[inline] + pub fn nulls_first(&self) -> Option { + support::child(&self.syntax) + } + #[inline] + pub fn nulls_last(&self) -> Option { + support::child(&self.syntax) + } + #[inline] + pub fn path(&self) -> Option { + support::child(&self.syntax) + } + #[inline] + pub fn sort_asc(&self) -> Option { + support::child(&self.syntax) + } + #[inline] + pub fn sort_desc(&self) -> Option { + support::child(&self.syntax) + } + #[inline] + pub fn sort_using(&self) -> Option { + support::child(&self.syntax) + } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] diff --git a/crates/squawk_syntax/src/postgresql.ungram b/crates/squawk_syntax/src/postgresql.ungram index 47bd4cd6..73bc9c12 100644 --- a/crates/squawk_syntax/src/postgresql.ungram +++ b/crates/squawk_syntax/src/postgresql.ungram @@ -1365,7 +1365,7 @@ ConflictIndexItemList = '(' (ConflictIndexItem (',' ConflictIndexItem)*) ')' ConflictIndexItem = - Expr Collate? '#ident'? + Expr Collate? Path? ConflictAction = ConflictDoNothing @@ -3155,7 +3155,12 @@ OnTable = 'on' Path PartitionItem = - Expr Collate? + Expr + Collate? + Path? + AttributeList? + (SortAsc | SortDesc | SortUsing)? + (NullsFirst | NullsLast)? PartitionItemList = '(' (PartitionItem (',' PartitionItem)*) ')'