Skip to content

Commit

Permalink
Add PostgreSQL specfic "CREATE TYPE t AS ENUM (...)" support.
Browse files Browse the repository at this point in the history
  • Loading branch information
caldwell committed Oct 7, 2024
1 parent 1e0460a commit 36ae291
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 1 deletion.
15 changes: 15 additions & 0 deletions src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3181,6 +3181,14 @@ pub enum Statement {
representation: UserDefinedTypeRepresentation,
},
/// ```sql
/// CREATE TYPE <name> AS ENUM
/// ```
/// Note: this is a PostgreSQL-specific statement. See <https://www.postgresql.org/docs/current/sql-createtype.html>
CreateTypeAsEnum {
name: ObjectName,
labels: Vec<Ident>,
},
/// ```sql
/// PRAGMA <schema-name>.<pragma-name> = <pragma-value>
/// ```
Pragma {
Expand Down Expand Up @@ -4795,6 +4803,13 @@ impl fmt::Display for Statement {
} => {
write!(f, "CREATE TYPE {name} AS {representation}")
}
Statement::CreateTypeAsEnum { name, labels } => {
write!(
f,
"CREATE TYPE {name} AS ENUM ({})",
display_comma_separated(labels)
)
}
Statement::Pragma { name, value, is_eq } => {
write!(f, "PRAGMA {name}")?;
if value.is_some() {
Expand Down
36 changes: 35 additions & 1 deletion src/dialect/postgresql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
// limitations under the License.
use log::debug;

use crate::ast::{CommentObject, Statement};
use crate::ast::{CommentObject, ObjectName, Statement};
use crate::dialect::{Dialect, Precedence};
use crate::keywords::Keyword;
use crate::parser::{Parser, ParserError};
Expand Down Expand Up @@ -138,6 +138,14 @@ impl Dialect for PostgreSqlDialect {
fn parse_statement(&self, parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
if parser.parse_keyword(Keyword::COMMENT) {
Some(parse_comment(parser))
} else if parser.parse_keyword(Keyword::CREATE) {
match parse_create(parser) {
Some(result) => Some(result),
None => {
parser.prev_token(); // unconsume the CREATE if we didn't end up parsing anything
None
}
}
} else {
None
}
Expand Down Expand Up @@ -221,3 +229,29 @@ pub fn parse_comment(parser: &mut Parser) -> Result<Statement, ParserError> {
if_exists,
})
}

pub fn parse_create(parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
let name = parser.maybe_parse(|parser| -> Result<ObjectName, ParserError> {
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<Statement, ParserError> {
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::CreateTypeAsEnum { name, labels })
}
26 changes: 26 additions & 0 deletions tests/sqlparser_postgres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::CreateTypeAsEnum { name, 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::<Vec<Ident>>(),
labels
);
}
_ => unreachable!(),
}
}

0 comments on commit 36ae291

Please sign in to comment.