diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 77101a873..36ae59339 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -1300,7 +1300,8 @@ pub enum Statement { Rollback { chain: bool }, /// CREATE SCHEMA CreateSchema { - schema_name: ObjectName, + /// ` | AUTHORIZATION | AUTHORIZATION ` + schema_name: SchemaName, if_not_exists: bool, }, /// CREATE DATABASE @@ -3275,6 +3276,36 @@ impl fmt::Display for CreateFunctionUsing { } } +/// Schema possible naming variants ([1]). +/// +/// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#schema-definition +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub enum SchemaName { + /// Only schema name specified: ``. + Simple(ObjectName), + /// Only authorization identifier specified: `AUTHORIZATION `. + UnnamedAuthorization(Ident), + /// Both schema name and authorization identifier specified: ` AUTHORIZATION `. + NamedAuthorization(ObjectName, Ident), +} + +impl fmt::Display for SchemaName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + SchemaName::Simple(name) => { + write!(f, "{name}") + } + SchemaName::UnnamedAuthorization(authorization) => { + write!(f, "AUTHORIZATION {authorization}") + } + SchemaName::NamedAuthorization(name, authorization) => { + write!(f, "{name} AUTHORIZATION {authorization}") + } + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/parser.rs b/src/parser.rs index 2944b5586..897e74c66 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1896,13 +1896,32 @@ impl<'a> Parser<'a> { pub fn parse_create_schema(&mut self) -> Result { let if_not_exists = self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]); - let schema_name = self.parse_object_name()?; + + let schema_name = self.parse_schema_name()?; + Ok(Statement::CreateSchema { schema_name, if_not_exists, }) } + fn parse_schema_name(&mut self) -> Result { + if self.parse_keyword(Keyword::AUTHORIZATION) { + Ok(SchemaName::UnnamedAuthorization(self.parse_identifier()?)) + } else { + let name = self.parse_object_name()?; + + if self.parse_keyword(Keyword::AUTHORIZATION) { + Ok(SchemaName::NamedAuthorization( + name, + self.parse_identifier()?, + )) + } else { + Ok(SchemaName::Simple(name)) + } + } + } + pub fn parse_create_database(&mut self) -> Result { let ine = self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]); let db_name = self.parse_object_name()?; @@ -5345,4 +5364,37 @@ mod tests { }); } } + + #[test] + fn test_parse_schema_name() { + // The expected name should be identical as the input name, that's why I don't receive both + macro_rules! test_parse_schema_name { + ($input:expr, $expected_name:expr $(,)?) => {{ + all_dialects().run_parser_method(&*$input, |parser| { + let schema_name = parser.parse_schema_name().unwrap(); + // Validate that the structure is the same as expected + assert_eq!(schema_name, $expected_name); + // Validate that the input and the expected structure serialization are the same + assert_eq!(schema_name.to_string(), $input.to_string()); + }); + }}; + } + + let dummy_name = ObjectName(vec![Ident::new("dummy_name")]); + let dummy_authorization = Ident::new("dummy_authorization"); + + test_parse_schema_name!( + format!("{dummy_name}"), + SchemaName::Simple(dummy_name.clone()) + ); + + test_parse_schema_name!( + format!("AUTHORIZATION {dummy_authorization}"), + SchemaName::UnnamedAuthorization(dummy_authorization.clone()), + ); + test_parse_schema_name!( + format!("{dummy_name} AUTHORIZATION {dummy_authorization}"), + SchemaName::NamedAuthorization(dummy_name.clone(), dummy_authorization.clone()), + ); + } } diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index ec2ab6e81..106502be1 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -2133,6 +2133,30 @@ fn parse_create_schema() { } } +#[test] +fn parse_create_schema_with_authorization() { + let sql = "CREATE SCHEMA AUTHORIZATION Y"; + + match verified_stmt(sql) { + Statement::CreateSchema { schema_name, .. } => { + assert_eq!(schema_name.to_string(), "AUTHORIZATION Y".to_owned()) + } + _ => unreachable!(), + } +} + +#[test] +fn parse_create_schema_with_name_and_authorization() { + let sql = "CREATE SCHEMA X AUTHORIZATION Y"; + + match verified_stmt(sql) { + Statement::CreateSchema { schema_name, .. } => { + assert_eq!(schema_name.to_string(), "X AUTHORIZATION Y".to_owned()) + } + _ => unreachable!(), + } +} + #[test] fn parse_drop_schema() { let sql = "DROP SCHEMA X";