From 72cdaa0cf0b3ff683684efa697c9db26fb2d13c2 Mon Sep 17 00:00:00 2001 From: LucaCappelletti94 Date: Thu, 12 Nov 2026 20:46:04 +0100 Subject: [PATCH] PostgreSQL: Support `AGGREGATE` members in `ALTER EXTENSION` --- fuzz/fuzz_seeds/postgres_alter_extension.sql | 2 ++ src/ast/ddl.rs | 3 ++ src/parser/mod.rs | 4 +++ tests/sqlparser_postgres.rs | 33 ++++++++++++++++++++ 4 files changed, 42 insertions(+) diff --git a/fuzz/fuzz_seeds/postgres_alter_extension.sql b/fuzz/fuzz_seeds/postgres_alter_extension.sql index 101135d03a..83b250d433 100644 --- a/fuzz/fuzz_seeds/postgres_alter_extension.sql +++ b/fuzz/fuzz_seeds/postgres_alter_extension.sql @@ -29,3 +29,5 @@ ALTER EXTENSION citext ADD TABLESPACE ts; ALTER EXTENSION citext ADD FUNCTION public.f(IN a int, text); ALTER EXTENSION citext DROP PROCEDURE public.p(int); ALTER EXTENSION citext ADD ROUTINE public.r(int); +ALTER EXTENSION citext DROP AGGREGATE agg(int ORDER BY text); +ALTER EXTENSION citext ADD AGGREGATE cnt(*); diff --git a/src/ast/ddl.rs b/src/ast/ddl.rs index 526de62e6f..2c6cd08e8e 100644 --- a/src/ast/ddl.rs +++ b/src/ast/ddl.rs @@ -4932,6 +4932,8 @@ pub enum AlterExtensionOperation { pub enum AlterExtensionMember { /// `ACCESS METHOD object_name` AccessMethod(Ident), + /// `AGGREGATE aggregate_name ( aggregate_signature )` + Aggregate(AggregateSignature), /// `COLLATION object_name` Collation(ObjectName), /// `CONVERSION object_name` @@ -5016,6 +5018,7 @@ impl fmt::Display for AlterExtensionMember { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { AlterExtensionMember::AccessMethod(name) => write!(f, "ACCESS METHOD {name}"), + AlterExtensionMember::Aggregate(signature) => write!(f, "AGGREGATE {signature}"), AlterExtensionMember::Collation(name) => write!(f, "COLLATION {name}"), AlterExtensionMember::Conversion(name) => write!(f, "CONVERSION {name}"), AlterExtensionMember::Database(name) => write!(f, "DATABASE {name}"), diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 57ad0df5b5..82a1e14e2d 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -12532,6 +12532,10 @@ impl<'a> Parser<'a> { fn parse_alter_extension_member(&mut self) -> Result { if self.parse_keywords(&[Keyword::ACCESS, Keyword::METHOD]) { Ok(AlterExtensionMember::AccessMethod(self.parse_identifier()?)) + } else if self.parse_keyword(Keyword::AGGREGATE) { + Ok(AlterExtensionMember::Aggregate( + self.parse_alter_aggregate_signature()?, + )) } else if self.parse_keyword(Keyword::COLLATION) { Ok(AlterExtensionMember::Collation( self.parse_object_name(false)?, diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index 450572bcaa..a1471e052e 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -13535,6 +13535,12 @@ fn parse_case_ending_in_end_keyword_is_not_silently_dropped() { fn alter_extension_member_round_trip_forms(action: &str) { let sqls = [ format!("ALTER EXTENSION ext_name {action} ACCESS METHOD btree"), + format!("ALTER EXTENSION ext_name {action} AGGREGATE agg(*)"), + format!("ALTER EXTENSION ext_name {action} AGGREGATE agg(INT)"), + format!("ALTER EXTENSION ext_name {action} AGGREGATE agg(INT, TEXT)"), + format!("ALTER EXTENSION ext_name {action} AGGREGATE agg(IN INT)"), + format!("ALTER EXTENSION ext_name {action} AGGREGATE agg(ORDER BY TEXT)"), + format!("ALTER EXTENSION ext_name {action} AGGREGATE agg(INT ORDER BY TEXT)"), format!("ALTER EXTENSION ext_name {action} COLLATION en_US"), format!("ALTER EXTENSION ext_name {action} COLLATION schema.en_US"), format!("ALTER EXTENSION ext_name {action} CONVERSION conv"), @@ -13712,6 +13718,23 @@ fn parse_alter_extension_add_member() { other => panic!("unexpected statement: {other:?}"), } + assert_eq!( + pg_and_generic() + .verified_stmt("ALTER EXTENSION ext_name ADD AGGREGATE agg(INT ORDER BY TEXT)"), + Statement::AlterExtension(AlterExtension { + name: Ident::new("ext_name"), + operation: AlterExtensionOperation::Add(AlterExtensionMember::Aggregate( + AggregateSignature { + name: ObjectName::from(Ident::new("agg")), + args: AggregateArgs::List { + args: vec![OperateFunctionArg::unnamed(DataType::Int(None))], + order_by: Some(vec![OperateFunctionArg::unnamed(DataType::Text)]), + }, + }, + )), + }) + ); + match pg_and_generic().verified_stmt("ALTER EXTENSION ext_name ADD FUNCTION f(INT)") { Statement::AlterExtension(AlterExtension { operation: AlterExtensionOperation::Add(AlterExtensionMember::Function(function)), @@ -13752,6 +13775,10 @@ fn parse_alter_extension_add_member() { "ALTER EXTENSION ext_name ADD SCHEMA a.b", "Expected: end of statement, found: .", ), + ( + "ALTER EXTENSION ext_name ADD AGGREGATE agg", + "Expected: (, found: EOF", + ), ( "ALTER EXTENSION ext_name ADD FUNCTION 1", "Expected: identifier, found: 1", @@ -13933,3 +13960,9 @@ fn parse_alter_aggregate_signatures() { ); } } + +#[test] +fn display_alter_extension_aggregate_propagates_write_errors() { + let statement = pg().verified_stmt("ALTER EXTENSION ext_name ADD AGGREGATE agg(*)"); + assert_display_propagates_write_errors(&statement, &["AGGREGATE "]); +}