mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-22 15:04:04 +00:00
Added support for CREATE DOMAIN
(#1830)
This commit is contained in:
parent
a497358c3a
commit
ac1c339666
5 changed files with 183 additions and 6 deletions
|
@ -2153,6 +2153,55 @@ impl fmt::Display for ClusteredBy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||||
|
/// ```sql
|
||||||
|
/// CREATE DOMAIN name [ AS ] data_type
|
||||||
|
/// [ COLLATE collation ]
|
||||||
|
/// [ DEFAULT expression ]
|
||||||
|
/// [ domain_constraint [ ... ] ]
|
||||||
|
///
|
||||||
|
/// where domain_constraint is:
|
||||||
|
///
|
||||||
|
/// [ CONSTRAINT constraint_name ]
|
||||||
|
/// { NOT NULL | NULL | CHECK (expression) }
|
||||||
|
/// ```
|
||||||
|
/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createdomain.html)
|
||||||
|
pub struct CreateDomain {
|
||||||
|
/// The name of the domain to be created.
|
||||||
|
pub name: ObjectName,
|
||||||
|
/// The data type of the domain.
|
||||||
|
pub data_type: DataType,
|
||||||
|
/// The collation of the domain.
|
||||||
|
pub collation: Option<Ident>,
|
||||||
|
/// The default value of the domain.
|
||||||
|
pub default: Option<Expr>,
|
||||||
|
/// The constraints of the domain.
|
||||||
|
pub constraints: Vec<TableConstraint>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for CreateDomain {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"CREATE DOMAIN {name} AS {data_type}",
|
||||||
|
name = self.name,
|
||||||
|
data_type = self.data_type
|
||||||
|
)?;
|
||||||
|
if let Some(collation) = &self.collation {
|
||||||
|
write!(f, " COLLATE {collation}")?;
|
||||||
|
}
|
||||||
|
if let Some(default) = &self.default {
|
||||||
|
write!(f, " DEFAULT {default}")?;
|
||||||
|
}
|
||||||
|
if !self.constraints.is_empty() {
|
||||||
|
write!(f, " {}", display_separated(&self.constraints, " "))?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||||
|
|
|
@ -55,12 +55,12 @@ pub use self::ddl::{
|
||||||
AlterTableAlgorithm, AlterTableLock, AlterTableOperation, AlterType, AlterTypeAddValue,
|
AlterTableAlgorithm, AlterTableLock, AlterTableOperation, AlterType, AlterTypeAddValue,
|
||||||
AlterTypeAddValuePosition, AlterTypeOperation, AlterTypeRename, AlterTypeRenameValue,
|
AlterTypeAddValuePosition, AlterTypeOperation, AlterTypeRename, AlterTypeRenameValue,
|
||||||
ClusteredBy, ColumnDef, ColumnOption, ColumnOptionDef, ColumnPolicy, ColumnPolicyProperty,
|
ClusteredBy, ColumnDef, ColumnOption, ColumnOptionDef, ColumnPolicy, ColumnPolicyProperty,
|
||||||
ConstraintCharacteristics, CreateConnector, CreateFunction, Deduplicate, DeferrableInitial,
|
ConstraintCharacteristics, CreateConnector, CreateDomain, CreateFunction, Deduplicate,
|
||||||
DropBehavior, GeneratedAs, GeneratedExpressionMode, IdentityParameters, IdentityProperty,
|
DeferrableInitial, DropBehavior, GeneratedAs, GeneratedExpressionMode, IdentityParameters,
|
||||||
IdentityPropertyFormatKind, IdentityPropertyKind, IdentityPropertyOrder, IndexOption,
|
IdentityProperty, IdentityPropertyFormatKind, IdentityPropertyKind, IdentityPropertyOrder,
|
||||||
IndexType, KeyOrIndexDisplay, NullsDistinctOption, Owner, Partition, ProcedureParam,
|
IndexOption, IndexType, KeyOrIndexDisplay, NullsDistinctOption, Owner, Partition,
|
||||||
ReferentialAction, TableConstraint, TagsColumnOption, UserDefinedTypeCompositeAttributeDef,
|
ProcedureParam, ReferentialAction, TableConstraint, TagsColumnOption,
|
||||||
UserDefinedTypeRepresentation, ViewColumnDef,
|
UserDefinedTypeCompositeAttributeDef, UserDefinedTypeRepresentation, ViewColumnDef,
|
||||||
};
|
};
|
||||||
pub use self::dml::{CreateIndex, CreateTable, Delete, IndexColumn, Insert};
|
pub use self::dml::{CreateIndex, CreateTable, Delete, IndexColumn, Insert};
|
||||||
pub use self::operator::{BinaryOperator, UnaryOperator};
|
pub use self::operator::{BinaryOperator, UnaryOperator};
|
||||||
|
@ -4049,6 +4049,8 @@ pub enum Statement {
|
||||||
sequence_options: Vec<SequenceOptions>,
|
sequence_options: Vec<SequenceOptions>,
|
||||||
owned_by: Option<ObjectName>,
|
owned_by: Option<ObjectName>,
|
||||||
},
|
},
|
||||||
|
/// A `CREATE DOMAIN` statement.
|
||||||
|
CreateDomain(CreateDomain),
|
||||||
/// ```sql
|
/// ```sql
|
||||||
/// CREATE TYPE <name>
|
/// CREATE TYPE <name>
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -4598,6 +4600,7 @@ impl fmt::Display for Statement {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Statement::CreateFunction(create_function) => create_function.fmt(f),
|
Statement::CreateFunction(create_function) => create_function.fmt(f),
|
||||||
|
Statement::CreateDomain(create_domain) => create_domain.fmt(f),
|
||||||
Statement::CreateTrigger {
|
Statement::CreateTrigger {
|
||||||
or_alter,
|
or_alter,
|
||||||
or_replace,
|
or_replace,
|
||||||
|
|
|
@ -483,6 +483,7 @@ impl Spanned for Statement {
|
||||||
Statement::CreateSchema { .. } => Span::empty(),
|
Statement::CreateSchema { .. } => Span::empty(),
|
||||||
Statement::CreateDatabase { .. } => Span::empty(),
|
Statement::CreateDatabase { .. } => Span::empty(),
|
||||||
Statement::CreateFunction { .. } => Span::empty(),
|
Statement::CreateFunction { .. } => Span::empty(),
|
||||||
|
Statement::CreateDomain { .. } => Span::empty(),
|
||||||
Statement::CreateTrigger { .. } => Span::empty(),
|
Statement::CreateTrigger { .. } => Span::empty(),
|
||||||
Statement::DropTrigger { .. } => Span::empty(),
|
Statement::DropTrigger { .. } => Span::empty(),
|
||||||
Statement::CreateProcedure { .. } => Span::empty(),
|
Statement::CreateProcedure { .. } => Span::empty(),
|
||||||
|
|
|
@ -4625,6 +4625,8 @@ impl<'a> Parser<'a> {
|
||||||
self.parse_create_external_table(or_replace)
|
self.parse_create_external_table(or_replace)
|
||||||
} else if self.parse_keyword(Keyword::FUNCTION) {
|
} else if self.parse_keyword(Keyword::FUNCTION) {
|
||||||
self.parse_create_function(or_alter, or_replace, temporary)
|
self.parse_create_function(or_alter, or_replace, temporary)
|
||||||
|
} else if self.parse_keyword(Keyword::DOMAIN) {
|
||||||
|
self.parse_create_domain()
|
||||||
} else if self.parse_keyword(Keyword::TRIGGER) {
|
} else if self.parse_keyword(Keyword::TRIGGER) {
|
||||||
self.parse_create_trigger(or_alter, or_replace, false)
|
self.parse_create_trigger(or_alter, or_replace, false)
|
||||||
} else if self.parse_keywords(&[Keyword::CONSTRAINT, Keyword::TRIGGER]) {
|
} else if self.parse_keywords(&[Keyword::CONSTRAINT, Keyword::TRIGGER]) {
|
||||||
|
@ -5974,6 +5976,35 @@ impl<'a> Parser<'a> {
|
||||||
Ok(owner)
|
Ok(owner)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parses a [Statement::CreateDomain] statement.
|
||||||
|
fn parse_create_domain(&mut self) -> Result<Statement, ParserError> {
|
||||||
|
let name = self.parse_object_name(false)?;
|
||||||
|
self.expect_keyword_is(Keyword::AS)?;
|
||||||
|
let data_type = self.parse_data_type()?;
|
||||||
|
let collation = if self.parse_keyword(Keyword::COLLATE) {
|
||||||
|
Some(self.parse_identifier()?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
let default = if self.parse_keyword(Keyword::DEFAULT) {
|
||||||
|
Some(self.parse_expr()?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
let mut constraints = Vec::new();
|
||||||
|
while let Some(constraint) = self.parse_optional_table_constraint()? {
|
||||||
|
constraints.push(constraint);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Statement::CreateDomain(CreateDomain {
|
||||||
|
name,
|
||||||
|
data_type,
|
||||||
|
collation,
|
||||||
|
default,
|
||||||
|
constraints,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
/// ```sql
|
/// ```sql
|
||||||
/// CREATE POLICY name ON table_name [ AS { PERMISSIVE | RESTRICTIVE } ]
|
/// CREATE POLICY name ON table_name [ AS { PERMISSIVE | RESTRICTIVE } ]
|
||||||
/// [ FOR { ALL | SELECT | INSERT | UPDATE | DELETE } ]
|
/// [ FOR { ALL | SELECT | INSERT | UPDATE | DELETE } ]
|
||||||
|
|
|
@ -5153,6 +5153,99 @@ fn test_escaped_string_literal() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_create_domain() {
|
||||||
|
let sql1 = "CREATE DOMAIN my_domain AS INTEGER CHECK (VALUE > 0)";
|
||||||
|
let expected = Statement::CreateDomain(CreateDomain {
|
||||||
|
name: ObjectName::from(vec![Ident::new("my_domain")]),
|
||||||
|
data_type: DataType::Integer(None),
|
||||||
|
collation: None,
|
||||||
|
default: None,
|
||||||
|
constraints: vec![TableConstraint::Check {
|
||||||
|
name: None,
|
||||||
|
expr: Box::new(Expr::BinaryOp {
|
||||||
|
left: Box::new(Expr::Identifier(Ident::new("VALUE"))),
|
||||||
|
op: BinaryOperator::Gt,
|
||||||
|
right: Box::new(Expr::Value(test_utils::number("0").into())),
|
||||||
|
}),
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(pg().verified_stmt(sql1), expected);
|
||||||
|
|
||||||
|
let sql2 = "CREATE DOMAIN my_domain AS INTEGER COLLATE \"en_US\" CHECK (VALUE > 0)";
|
||||||
|
let expected = Statement::CreateDomain(CreateDomain {
|
||||||
|
name: ObjectName::from(vec![Ident::new("my_domain")]),
|
||||||
|
data_type: DataType::Integer(None),
|
||||||
|
collation: Some(Ident::with_quote('"', "en_US")),
|
||||||
|
default: None,
|
||||||
|
constraints: vec![TableConstraint::Check {
|
||||||
|
name: None,
|
||||||
|
expr: Box::new(Expr::BinaryOp {
|
||||||
|
left: Box::new(Expr::Identifier(Ident::new("VALUE"))),
|
||||||
|
op: BinaryOperator::Gt,
|
||||||
|
right: Box::new(Expr::Value(test_utils::number("0").into())),
|
||||||
|
}),
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(pg().verified_stmt(sql2), expected);
|
||||||
|
|
||||||
|
let sql3 = "CREATE DOMAIN my_domain AS INTEGER DEFAULT 1 CHECK (VALUE > 0)";
|
||||||
|
let expected = Statement::CreateDomain(CreateDomain {
|
||||||
|
name: ObjectName::from(vec![Ident::new("my_domain")]),
|
||||||
|
data_type: DataType::Integer(None),
|
||||||
|
collation: None,
|
||||||
|
default: Some(Expr::Value(test_utils::number("1").into())),
|
||||||
|
constraints: vec![TableConstraint::Check {
|
||||||
|
name: None,
|
||||||
|
expr: Box::new(Expr::BinaryOp {
|
||||||
|
left: Box::new(Expr::Identifier(Ident::new("VALUE"))),
|
||||||
|
op: BinaryOperator::Gt,
|
||||||
|
right: Box::new(Expr::Value(test_utils::number("0").into())),
|
||||||
|
}),
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(pg().verified_stmt(sql3), expected);
|
||||||
|
|
||||||
|
let sql4 = "CREATE DOMAIN my_domain AS INTEGER COLLATE \"en_US\" DEFAULT 1 CHECK (VALUE > 0)";
|
||||||
|
let expected = Statement::CreateDomain(CreateDomain {
|
||||||
|
name: ObjectName::from(vec![Ident::new("my_domain")]),
|
||||||
|
data_type: DataType::Integer(None),
|
||||||
|
collation: Some(Ident::with_quote('"', "en_US")),
|
||||||
|
default: Some(Expr::Value(test_utils::number("1").into())),
|
||||||
|
constraints: vec![TableConstraint::Check {
|
||||||
|
name: None,
|
||||||
|
expr: Box::new(Expr::BinaryOp {
|
||||||
|
left: Box::new(Expr::Identifier(Ident::new("VALUE"))),
|
||||||
|
op: BinaryOperator::Gt,
|
||||||
|
right: Box::new(Expr::Value(test_utils::number("0").into())),
|
||||||
|
}),
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(pg().verified_stmt(sql4), expected);
|
||||||
|
|
||||||
|
let sql5 = "CREATE DOMAIN my_domain AS INTEGER CONSTRAINT my_constraint CHECK (VALUE > 0)";
|
||||||
|
let expected = Statement::CreateDomain(CreateDomain {
|
||||||
|
name: ObjectName::from(vec![Ident::new("my_domain")]),
|
||||||
|
data_type: DataType::Integer(None),
|
||||||
|
collation: None,
|
||||||
|
default: None,
|
||||||
|
constraints: vec![TableConstraint::Check {
|
||||||
|
name: Some(Ident::new("my_constraint")),
|
||||||
|
expr: Box::new(Expr::BinaryOp {
|
||||||
|
left: Box::new(Expr::Identifier(Ident::new("VALUE"))),
|
||||||
|
op: BinaryOperator::Gt,
|
||||||
|
right: Box::new(Expr::Value(test_utils::number("0").into())),
|
||||||
|
}),
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(pg().verified_stmt(sql5), expected);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_create_simple_before_insert_trigger() {
|
fn parse_create_simple_before_insert_trigger() {
|
||||||
let sql = "CREATE TRIGGER check_insert BEFORE INSERT ON accounts FOR EACH ROW EXECUTE FUNCTION check_account_insert";
|
let sql = "CREATE TRIGGER check_insert BEFORE INSERT ON accounts FOR EACH ROW EXECUTE FUNCTION check_account_insert";
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue