diff --git a/src/ast/ddl.rs b/src/ast/ddl.rs index 4578ae8f1..061670d0d 100644 --- a/src/ast/ddl.rs +++ b/src/ast/ddl.rs @@ -1479,6 +1479,8 @@ pub enum UserDefinedTypeRepresentation { Composite { attributes: Vec, }, + /// Note: this is PostgreSQL-specific. See + Enum { labels: Vec }, } impl fmt::Display for UserDefinedTypeRepresentation { @@ -1487,6 +1489,9 @@ impl fmt::Display for UserDefinedTypeRepresentation { UserDefinedTypeRepresentation::Composite { attributes } => { write!(f, "({})", display_comma_separated(attributes)) } + UserDefinedTypeRepresentation::Enum { labels } => { + write!(f, "ENUM ({})", display_comma_separated(labels)) + } } } } diff --git a/src/dialect/postgresql.rs b/src/dialect/postgresql.rs index 945c4fcc0..5ecf8e2ea 100644 --- a/src/dialect/postgresql.rs +++ b/src/dialect/postgresql.rs @@ -28,7 +28,7 @@ // limitations under the License. use log::debug; -use crate::ast::{CommentObject, Statement}; +use crate::ast::{CommentObject, ObjectName, Statement, UserDefinedTypeRepresentation}; use crate::dialect::{Dialect, Precedence}; use crate::keywords::Keyword; use crate::parser::{Parser, ParserError}; @@ -138,6 +138,9 @@ impl Dialect for PostgreSqlDialect { fn parse_statement(&self, parser: &mut Parser) -> Option> { if parser.parse_keyword(Keyword::COMMENT) { Some(parse_comment(parser)) + } else if parser.parse_keyword(Keyword::CREATE) { + parser.prev_token(); // unconsume the CREATE in case we don't end up parsing anything + parse_create(parser) } else { None } @@ -221,3 +224,30 @@ pub fn parse_comment(parser: &mut Parser) -> Result { if_exists, }) } + +pub fn parse_create(parser: &mut Parser) -> Option> { + let name = parser.maybe_parse(|parser| -> Result { + parser.expect_keyword(Keyword::CREATE)?; + parser.expect_keyword(Keyword::TYPE)?; + let name = parser.parse_object_name(false)?; + parser.expect_keyword(Keyword::AS)?; + parser.expect_keyword(Keyword::ENUM)?; + Ok(name) + }); + name.map(|name| parse_create_type_as_enum(parser, name)) +} + +// https://www.postgresql.org/docs/current/sql-createtype.html +pub fn parse_create_type_as_enum( + parser: &mut Parser, + name: ObjectName, +) -> Result { + if !parser.consume_token(&Token::LParen) { + return parser.expected("'(' after CREATE TYPE AS ENUM", parser.peek_token()); + } + + let labels = parser.parse_comma_separated0(|p| p.parse_identifier(false), Token::RParen)?; + parser.expect_token(&Token::RParen)?; + + Ok(Statement::CreateType { name, representation: UserDefinedTypeRepresentation::Enum { labels } }) +} diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index 9ba3e5dbc..092ca0281 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -5113,3 +5113,29 @@ fn arrow_cast_precedence() { } ) } + +#[test] +fn parse_create_type_as_enum() { + let statement = pg().one_statement_parses_to( + r#"CREATE TYPE public.my_type AS ENUM ( + 'label1', + 'label2', + 'label3', + 'label4' + );"#, + "CREATE TYPE public.my_type AS ENUM ('label1', 'label2', 'label3', 'label4')", + ); + match statement { + Statement::CreateType { name, representation: UserDefinedTypeRepresentation::Enum { labels } } => { + assert_eq!("public.my_type", name.to_string()); + assert_eq!( + vec!["label1", "label2", "label3", "label4"] + .into_iter() + .map(|l| Ident::with_quote('\'', l)) + .collect::>(), + labels + ); + } + _ => unreachable!(), + } +}