Add support for CREATE TYPE (AS) statements (#888)

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
This commit is contained in:
Sam Rijs 2023-06-08 12:56:39 +02:00 committed by GitHub
parent e8cad6ab65
commit 2b37e4ae6e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 120 additions and 0 deletions

View file

@ -715,3 +715,43 @@ impl fmt::Display for ReferentialAction {
})
}
}
/// SQL user defined type definition
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum UserDefinedTypeRepresentation {
Composite {
attributes: Vec<UserDefinedTypeCompositeAttributeDef>,
},
}
impl fmt::Display for UserDefinedTypeRepresentation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
UserDefinedTypeRepresentation::Composite { attributes } => {
write!(f, "({})", display_comma_separated(attributes))
}
}
}
}
/// SQL user defined type attribute definition
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct UserDefinedTypeCompositeAttributeDef {
pub name: Ident,
pub data_type: DataType,
pub collation: Option<ObjectName>,
}
impl fmt::Display for UserDefinedTypeCompositeAttributeDef {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {}", self.name, self.data_type)?;
if let Some(collation) = &self.collation {
write!(f, " COLLATE {collation}")?;
}
Ok(())
}
}

View file

@ -31,6 +31,7 @@ pub use self::data_type::{
pub use self::ddl::{
AlterColumnOperation, AlterIndexOperation, AlterTableOperation, ColumnDef, ColumnOption,
ColumnOptionDef, GeneratedAs, IndexType, KeyOrIndexDisplay, ReferentialAction, TableConstraint,
UserDefinedTypeCompositeAttributeDef, UserDefinedTypeRepresentation,
};
pub use self::operator::{BinaryOperator, UnaryOperator};
pub use self::query::{
@ -1711,6 +1712,11 @@ pub enum Statement {
sequence_options: Vec<SequenceOptions>,
owned_by: Option<ObjectName>,
},
/// CREATE TYPE `<name>`
CreateType {
name: ObjectName,
representation: UserDefinedTypeRepresentation,
},
}
impl fmt::Display for Statement {
@ -2921,6 +2927,12 @@ impl fmt::Display for Statement {
}
Ok(())
}
Statement::CreateType {
name,
representation,
} => {
write!(f, "CREATE TYPE {name} AS {representation}")
}
}
}
}

View file

@ -2365,6 +2365,8 @@ impl<'a> Parser<'a> {
self.parse_create_role()
} else if self.parse_keyword(Keyword::SEQUENCE) {
self.parse_create_sequence(temporary)
} else if self.parse_keyword(Keyword::TYPE) {
self.parse_create_type()
} else {
self.expected("an object type after CREATE", self.peek_token())
}
@ -7053,6 +7055,46 @@ impl<'a> Parser<'a> {
window_frame,
})
}
pub fn parse_create_type(&mut self) -> Result<Statement, ParserError> {
let name = self.parse_object_name()?;
self.expect_keyword(Keyword::AS)?;
let mut attributes = vec![];
if !self.consume_token(&Token::LParen) || self.consume_token(&Token::RParen) {
return Ok(Statement::CreateType {
name,
representation: UserDefinedTypeRepresentation::Composite { attributes },
});
}
loop {
let attr_name = self.parse_identifier()?;
let attr_data_type = self.parse_data_type()?;
let attr_collation = if self.parse_keyword(Keyword::COLLATE) {
Some(self.parse_object_name()?)
} else {
None
};
attributes.push(UserDefinedTypeCompositeAttributeDef {
name: attr_name,
data_type: attr_data_type,
collation: attr_collation,
});
let comma = self.consume_token(&Token::Comma);
if self.consume_token(&Token::RParen) {
// allow a trailing comma
break;
} else if !comma {
return self.expected("',' or ')' after attribute definition", self.peek_token());
}
}
Ok(Statement::CreateType {
name,
representation: UserDefinedTypeRepresentation::Composite { attributes },
})
}
}
impl Word {

View file

@ -7092,3 +7092,29 @@ fn parse_trailing_comma() {
trailing_commas.verified_stmt("SELECT DISTINCT ON (album_id) name FROM track");
}
#[test]
fn parse_create_type() {
let create_type =
verified_stmt("CREATE TYPE db.type_name AS (foo INT, bar TEXT COLLATE \"de_DE\")");
assert_eq!(
Statement::CreateType {
name: ObjectName(vec![Ident::new("db"), Ident::new("type_name")]),
representation: UserDefinedTypeRepresentation::Composite {
attributes: vec![
UserDefinedTypeCompositeAttributeDef {
name: Ident::new("foo"),
data_type: DataType::Int(None),
collation: None,
},
UserDefinedTypeCompositeAttributeDef {
name: Ident::new("bar"),
data_type: DataType::Text,
collation: Some(ObjectName(vec![Ident::with_quote('\"', "de_DE")])),
}
]
}
},
create_type
);
}