diff --git a/fuzz/fuzz_seeds/postgres_alter_extension.sql b/fuzz/fuzz_seeds/postgres_alter_extension.sql index aeb19f1ff8..789d62a20c 100644 --- a/fuzz/fuzz_seeds/postgres_alter_extension.sql +++ b/fuzz/fuzz_seeds/postgres_alter_extension.sql @@ -35,3 +35,4 @@ ALTER EXTENSION citext ADD OPERATOR - (NONE, int); ALTER EXTENSION citext DROP OPERATOR CLASS oc USING btree; ALTER EXTENSION citext DROP OPERATOR FAMILY of USING btree; ALTER EXTENSION citext ADD CAST (int AS text); +ALTER EXTENSION citext ADD TRANSFORM FOR int LANGUAGE plpgsql; diff --git a/src/ast/ddl.rs b/src/ast/ddl.rs index 074f8f55e5..ed94e4320b 100644 --- a/src/ast/ddl.rs +++ b/src/ast/ddl.rs @@ -5014,6 +5014,13 @@ pub enum AlterExtensionMember { TextSearchParser(ObjectName), /// `TEXT SEARCH TEMPLATE object_name` TextSearchTemplate(ObjectName), + /// `TRANSFORM FOR type_name LANGUAGE lang_name` + Transform { + /// Transformed type. + type_name: DataType, + /// Language name. + language: Ident, + }, /// `VIEW object_name` View(ObjectName), } @@ -5093,6 +5100,10 @@ impl fmt::Display for AlterExtensionMember { AlterExtensionMember::TextSearchTemplate(name) => { write!(f, "TEXT SEARCH TEMPLATE {name}") } + AlterExtensionMember::Transform { + type_name, + language, + } => write!(f, "TRANSFORM FOR {type_name} LANGUAGE {language}"), AlterExtensionMember::View(name) => write!(f, "VIEW {name}"), } } diff --git a/src/keywords.rs b/src/keywords.rs index 3dfc04f476..a14a811beb 100644 --- a/src/keywords.rs +++ b/src/keywords.rs @@ -1118,6 +1118,7 @@ define_keywords!( TRAILING, TRAN, TRANSACTION, + TRANSFORM, TRANSIENT, TRANSLATE, TRANSLATE_REGEX, diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 19e9444594..d058fac244 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -12644,6 +12644,14 @@ impl<'a> Parser<'a> { Ok(AlterExtensionMember::TextSearchTemplate( self.parse_object_name(false)?, )) + } else if self.parse_keywords(&[Keyword::TRANSFORM, Keyword::FOR]) { + let type_name = self.parse_data_type()?; + self.expect_keyword_is(Keyword::LANGUAGE)?; + let language = self.parse_identifier()?; + Ok(AlterExtensionMember::Transform { + type_name, + language, + }) } else if self.parse_keyword(Keyword::VIEW) { Ok(AlterExtensionMember::View(self.parse_object_name(false)?)) } else { diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index 3d816c7af1..c9b9bc27f8 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -13583,6 +13583,7 @@ fn alter_extension_member_round_trip_forms(action: &str) { format!("ALTER EXTENSION ext_name {action} TEXT SEARCH DICTIONARY dict"), format!("ALTER EXTENSION ext_name {action} TEXT SEARCH PARSER pgrm"), format!("ALTER EXTENSION ext_name {action} TEXT SEARCH TEMPLATE tpl"), + format!("ALTER EXTENSION ext_name {action} TRANSFORM FOR my_type LANGUAGE plpgsql"), format!("ALTER EXTENSION ext_name {action} VIEW v"), ]; for sql in sqls { @@ -13801,6 +13802,26 @@ fn parse_alter_extension_add_member() { other => panic!("unexpected statement: {other:?}"), } + match pg_and_generic() + .verified_stmt("ALTER EXTENSION ext_name ADD TRANSFORM FOR my_type LANGUAGE plpgsql") + { + Statement::AlterExtension(AlterExtension { + operation: + AlterExtensionOperation::Add(AlterExtensionMember::Transform { + type_name, + language, + }), + .. + }) => { + assert_eq!( + type_name, + DataType::Custom(ObjectName::from(Ident::new("my_type")), vec![]) + ); + assert_eq!(language, Ident::new("plpgsql")); + } + other => panic!("unexpected statement: {other:?}"), + } + for (sql, error) in [ ( "ALTER EXTENSION ext_name ADD", @@ -13834,6 +13855,10 @@ fn parse_alter_extension_add_member() { "ALTER EXTENSION ext_name ADD CAST (INT)", "Expected: AS, found: )", ), + ( + "ALTER EXTENSION ext_name ADD TRANSFORM FOR my_type", + "Expected: LANGUAGE, found: EOF", + ), ( "ALTER EXTENSION ext_name ADD OPERATOR +", "Expected: (, found: EOF", @@ -13878,6 +13903,14 @@ fn parse_alter_extension_add_member() { "ALTER EXTENSION ext_name ADD OPERATOR FAMILY of USING", "Expected: identifier, found: EOF", ), + ( + "ALTER EXTENSION ext_name ADD TRANSFORM FOR", + "Expected: a data type name, found: EOF", + ), + ( + "ALTER EXTENSION ext_name ADD TRANSFORM FOR my_type LANGUAGE", + "Expected: identifier, found: EOF", + ), ] { assert_eq!( pg_and_generic().parse_sql_statements(sql).unwrap_err(),