From 6747d5a6472dd142548e89bbbb86d38cbbaa77b2 Mon Sep 17 00:00:00 2001 From: Ben King <9087625+benfdking@users.noreply.github.com> Date: Tue, 15 Sep 2026 14:05:55 +0200 Subject: [PATCH] fix: parse PostgreSQL VARIADIC function arguments (7002) Ported from SQLFluff b8f99fd9d4acb2a9df139f183df7025fef4906aa https://github.com/sqlfluff/sqlfluff/pull/7002 --- .sqlfluff-sha | 2 +- crates/lib-dialects/src/postgres.rs | 5 + .../dialects/postgres/sqlfluff/variadic.sql | 22 ++ .../dialects/postgres/sqlfluff/variadic.yml | 217 ++++++++++++++++++ 4 files changed, 245 insertions(+), 1 deletion(-) diff --git a/.sqlfluff-sha b/.sqlfluff-sha index f7deab60c..d4d4293fb 100644 --- a/.sqlfluff-sha +++ b/.sqlfluff-sha @@ -1 +1 @@ -25ff42a977cd3b7fbce2d1e211af2fa366cb62ec +b8f99fd9d4acb2a9df139f183df7025fef4906aa diff --git a/crates/lib-dialects/src/postgres.rs b/crates/lib-dialects/src/postgres.rs index 1cbae000e..eee878a97 100644 --- a/crates/lib-dialects/src/postgres.rs +++ b/crates/lib-dialects/src/postgres.rs @@ -9171,6 +9171,11 @@ pub fn raw_dialect() -> Dialect { .copy( Some(vec![ position_function_contents(true), + Sequence::new(vec![ + Ref::keyword("VARIADIC").to_matchable(), + Ref::new("ExpressionSegment").to_matchable(), + ]) + .to_matchable(), Delimited::new(vec![ Sequence::new(vec![ Ref::new("ExpressionSegment").to_matchable(), diff --git a/crates/lib-dialects/test/fixtures/dialects/postgres/sqlfluff/variadic.sql b/crates/lib-dialects/test/fixtures/dialects/postgres/sqlfluff/variadic.sql index 9126b5b64..229e17b03 100644 --- a/crates/lib-dialects/test/fixtures/dialects/postgres/sqlfluff/variadic.sql +++ b/crates/lib-dialects/test/fixtures/dialects/postgres/sqlfluff/variadic.sql @@ -15,3 +15,25 @@ $$ LANGUAGE SQL; CREATE FUNCTION concat_values(text, VARIADIC anyarray) RETURNS text AS $$ SELECT array_to_string($2, $1); $$ LANGUAGE SQL; + +SELECT my_function(other_function( + VARIADIC ARRAY_REMOVE(ARRAY[ + a.value1, + b.value2, + c.value3 + ], NULL) +)) +FROM a +FULL OUTER JOIN b USING (id) +FULL OUTER JOIN c USING (id); + +SELECT json_extract_path_text(t.col::json, VARIADIC ARRAY['foo'::text]) +FROM t; + +SELECT my_function(VARIADIC ARRAY[ + CASE WHEN x > 0 THEN x ELSE 0 END, + y + z, + 'literal' +]); + +SELECT my_function(VARIADIC ARRAY(SELECT value FROM table1)); diff --git a/crates/lib-dialects/test/fixtures/dialects/postgres/sqlfluff/variadic.yml b/crates/lib-dialects/test/fixtures/dialects/postgres/sqlfluff/variadic.yml index 2bbda5aec..6af322d87 100644 --- a/crates/lib-dialects/test/fixtures/dialects/postgres/sqlfluff/variadic.yml +++ b/crates/lib-dialects/test/fixtures/dialects/postgres/sqlfluff/variadic.yml @@ -172,3 +172,220 @@ file: - keyword: LANGUAGE - naked_identifier: SQL - statement_terminator: ; +- statement: + - select_statement: + - select_clause: + - keyword: SELECT + - select_clause_element: + - function: + - function_name: + - function_name_identifier: my_function + - function_contents: + - bracketed: + - start_bracket: ( + - expression: + - function: + - function_name: + - function_name_identifier: other_function + - function_contents: + - bracketed: + - start_bracket: ( + - keyword: VARIADIC + - expression: + - function: + - function_name: + - function_name_identifier: ARRAY_REMOVE + - function_contents: + - bracketed: + - start_bracket: ( + - expression: + - typed_array_literal: + - array_type: + - keyword: ARRAY + - array_literal: + - start_square_bracket: '[' + - column_reference: + - naked_identifier: a + - dot: . + - naked_identifier: value1 + - comma: ',' + - column_reference: + - naked_identifier: b + - dot: . + - naked_identifier: value2 + - comma: ',' + - column_reference: + - naked_identifier: c + - dot: . + - naked_identifier: value3 + - end_square_bracket: ']' + - comma: ',' + - expression: + - null_literal: 'NULL' + - end_bracket: ) + - end_bracket: ) + - end_bracket: ) + - from_clause: + - keyword: FROM + - from_expression: + - from_expression_element: + - table_expression: + - table_reference: + - naked_identifier: a + - join_clause: + - keyword: FULL + - keyword: OUTER + - keyword: JOIN + - from_expression_element: + - table_expression: + - table_reference: + - naked_identifier: b + - keyword: USING + - bracketed: + - start_bracket: ( + - naked_identifier: id + - end_bracket: ) + - join_clause: + - keyword: FULL + - keyword: OUTER + - keyword: JOIN + - from_expression_element: + - table_expression: + - table_reference: + - naked_identifier: c + - keyword: USING + - bracketed: + - start_bracket: ( + - naked_identifier: id + - end_bracket: ) +- statement_terminator: ; +- statement: + - select_statement: + - select_clause: + - keyword: SELECT + - select_clause_element: + - function: + - function_name: + - function_name_identifier: json_extract_path_text + - function_contents: + - bracketed: + - start_bracket: ( + - expression: + - cast_expression: + - column_reference: + - naked_identifier: t + - dot: . + - naked_identifier: col + - casting_operator: '::' + - data_type: + - keyword: json + - comma: ',' + - expression: + - typed_array_literal: + - keyword: VARIADIC + - array_type: + - keyword: ARRAY + - array_literal: + - start_square_bracket: '[' + - expression: + - cast_expression: + - quoted_literal: '''foo''' + - casting_operator: '::' + - data_type: + - keyword: text + - end_square_bracket: ']' + - end_bracket: ) + - from_clause: + - keyword: FROM + - from_expression: + - from_expression_element: + - table_expression: + - table_reference: + - naked_identifier: t +- statement_terminator: ; +- statement: + - select_statement: + - select_clause: + - keyword: SELECT + - select_clause_element: + - function: + - function_name: + - function_name_identifier: my_function + - function_contents: + - bracketed: + - start_bracket: ( + - expression: + - typed_array_literal: + - keyword: VARIADIC + - array_type: + - keyword: ARRAY + - array_literal: + - start_square_bracket: '[' + - expression: + - case_expression: + - keyword: CASE + - when_clause: + - keyword: WHEN + - expression: + - column_reference: + - naked_identifier: x + - comparison_operator: + - raw_comparison_operator: '>' + - numeric_literal: '0' + - keyword: THEN + - expression: + - column_reference: + - naked_identifier: x + - else_clause: + - keyword: ELSE + - expression: + - numeric_literal: '0' + - keyword: END + - comma: ',' + - expression: + - column_reference: + - naked_identifier: y + - binary_operator: + + - column_reference: + - naked_identifier: z + - comma: ',' + - quoted_literal: '''literal''' + - end_square_bracket: ']' + - end_bracket: ) +- statement_terminator: ; +- statement: + - select_statement: + - select_clause: + - keyword: SELECT + - select_clause_element: + - function: + - function_name: + - function_name_identifier: my_function + - function_contents: + - bracketed: + - start_bracket: ( + - keyword: VARIADIC + - expression: + - function: + - function_name: + - function_name_identifier: ARRAY + - function_contents: + - bracketed: + - start_bracket: ( + - expression: + - select_statement: + - select_clause: + - keyword: SELECT + - select_clause_element: + - column_reference: + - naked_identifier: value + - from_clause: + - keyword: FROM + - from_expression: + - from_expression_element: + - table_expression: + - table_reference: + - naked_identifier: table1 + - end_bracket: ) + - end_bracket: ) +- statement_terminator: ;