mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-24 07:54:06 +00:00
Add support for CREATE TYPE (AS) statements (#888)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
This commit is contained in:
parent
e8cad6ab65
commit
2b37e4ae6e
4 changed files with 120 additions and 0 deletions
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue