mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-30 18:57:21 +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::{
|
pub use self::ddl::{
|
||||||
AlterColumnOperation, AlterIndexOperation, AlterTableOperation, ColumnDef, ColumnOption,
|
AlterColumnOperation, AlterIndexOperation, AlterTableOperation, ColumnDef, ColumnOption,
|
||||||
ColumnOptionDef, GeneratedAs, IndexType, KeyOrIndexDisplay, ReferentialAction, TableConstraint,
|
ColumnOptionDef, GeneratedAs, IndexType, KeyOrIndexDisplay, ReferentialAction, TableConstraint,
|
||||||
|
UserDefinedTypeCompositeAttributeDef, UserDefinedTypeRepresentation,
|
||||||
};
|
};
|
||||||
pub use self::operator::{BinaryOperator, UnaryOperator};
|
pub use self::operator::{BinaryOperator, UnaryOperator};
|
||||||
pub use self::query::{
|
pub use self::query::{
|
||||||
|
@ -1711,6 +1712,11 @@ pub enum Statement {
|
||||||
sequence_options: Vec<SequenceOptions>,
|
sequence_options: Vec<SequenceOptions>,
|
||||||
owned_by: Option<ObjectName>,
|
owned_by: Option<ObjectName>,
|
||||||
},
|
},
|
||||||
|
/// CREATE TYPE `<name>`
|
||||||
|
CreateType {
|
||||||
|
name: ObjectName,
|
||||||
|
representation: UserDefinedTypeRepresentation,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Statement {
|
impl fmt::Display for Statement {
|
||||||
|
@ -2921,6 +2927,12 @@ impl fmt::Display for Statement {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Statement::CreateType {
|
||||||
|
name,
|
||||||
|
representation,
|
||||||
|
} => {
|
||||||
|
write!(f, "CREATE TYPE {name} AS {representation}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2365,6 +2365,8 @@ impl<'a> Parser<'a> {
|
||||||
self.parse_create_role()
|
self.parse_create_role()
|
||||||
} else if self.parse_keyword(Keyword::SEQUENCE) {
|
} else if self.parse_keyword(Keyword::SEQUENCE) {
|
||||||
self.parse_create_sequence(temporary)
|
self.parse_create_sequence(temporary)
|
||||||
|
} else if self.parse_keyword(Keyword::TYPE) {
|
||||||
|
self.parse_create_type()
|
||||||
} else {
|
} else {
|
||||||
self.expected("an object type after CREATE", self.peek_token())
|
self.expected("an object type after CREATE", self.peek_token())
|
||||||
}
|
}
|
||||||
|
@ -7053,6 +7055,46 @@ impl<'a> Parser<'a> {
|
||||||
window_frame,
|
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 {
|
impl Word {
|
||||||
|
|
|
@ -7092,3 +7092,29 @@ fn parse_trailing_comma() {
|
||||||
|
|
||||||
trailing_commas.verified_stmt("SELECT DISTINCT ON (album_id) name FROM track");
|
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