mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-07-07 17:04:59 +00:00
Postgres: support ADD CONSTRAINT NOT VALID
and VALIDATE CONSTRAINT
(#1908)
This commit is contained in:
parent
015caca611
commit
418b94227a
7 changed files with 99 additions and 22 deletions
|
@ -67,8 +67,11 @@ impl fmt::Display for ReplicaIdentity {
|
||||||
#[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))]
|
||||||
pub enum AlterTableOperation {
|
pub enum AlterTableOperation {
|
||||||
/// `ADD <table_constraint>`
|
/// `ADD <table_constraint> [NOT VALID]`
|
||||||
AddConstraint(TableConstraint),
|
AddConstraint {
|
||||||
|
constraint: TableConstraint,
|
||||||
|
not_valid: bool,
|
||||||
|
},
|
||||||
/// `ADD [COLUMN] [IF NOT EXISTS] <column_def>`
|
/// `ADD [COLUMN] [IF NOT EXISTS] <column_def>`
|
||||||
AddColumn {
|
AddColumn {
|
||||||
/// `[COLUMN]`.
|
/// `[COLUMN]`.
|
||||||
|
@ -344,6 +347,10 @@ pub enum AlterTableOperation {
|
||||||
equals: bool,
|
equals: bool,
|
||||||
value: ValueWithSpan,
|
value: ValueWithSpan,
|
||||||
},
|
},
|
||||||
|
/// `VALIDATE CONSTRAINT <name>`
|
||||||
|
ValidateConstraint {
|
||||||
|
name: Ident,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An `ALTER Policy` (`Statement::AlterPolicy`) operation
|
/// An `ALTER Policy` (`Statement::AlterPolicy`) operation
|
||||||
|
@ -494,7 +501,16 @@ impl fmt::Display for AlterTableOperation {
|
||||||
display_separated(new_partitions, " "),
|
display_separated(new_partitions, " "),
|
||||||
ine = if *if_not_exists { " IF NOT EXISTS" } else { "" }
|
ine = if *if_not_exists { " IF NOT EXISTS" } else { "" }
|
||||||
),
|
),
|
||||||
AlterTableOperation::AddConstraint(c) => write!(f, "ADD {c}"),
|
AlterTableOperation::AddConstraint {
|
||||||
|
not_valid,
|
||||||
|
constraint,
|
||||||
|
} => {
|
||||||
|
write!(f, "ADD {constraint}")?;
|
||||||
|
if *not_valid {
|
||||||
|
write!(f, " NOT VALID")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
AlterTableOperation::AddColumn {
|
AlterTableOperation::AddColumn {
|
||||||
column_keyword,
|
column_keyword,
|
||||||
if_not_exists,
|
if_not_exists,
|
||||||
|
@ -772,6 +788,9 @@ impl fmt::Display for AlterTableOperation {
|
||||||
AlterTableOperation::ReplicaIdentity { identity } => {
|
AlterTableOperation::ReplicaIdentity { identity } => {
|
||||||
write!(f, "REPLICA IDENTITY {identity}")
|
write!(f, "REPLICA IDENTITY {identity}")
|
||||||
}
|
}
|
||||||
|
AlterTableOperation::ValidateConstraint { name } => {
|
||||||
|
write!(f, "VALIDATE CONSTRAINT {name}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1075,7 +1075,10 @@ impl Spanned for CreateTableOptions {
|
||||||
impl Spanned for AlterTableOperation {
|
impl Spanned for AlterTableOperation {
|
||||||
fn span(&self) -> Span {
|
fn span(&self) -> Span {
|
||||||
match self {
|
match self {
|
||||||
AlterTableOperation::AddConstraint(table_constraint) => table_constraint.span(),
|
AlterTableOperation::AddConstraint {
|
||||||
|
constraint,
|
||||||
|
not_valid: _,
|
||||||
|
} => constraint.span(),
|
||||||
AlterTableOperation::AddColumn {
|
AlterTableOperation::AddColumn {
|
||||||
column_keyword: _,
|
column_keyword: _,
|
||||||
if_not_exists: _,
|
if_not_exists: _,
|
||||||
|
@ -1196,6 +1199,7 @@ impl Spanned for AlterTableOperation {
|
||||||
AlterTableOperation::AutoIncrement { value, .. } => value.span(),
|
AlterTableOperation::AutoIncrement { value, .. } => value.span(),
|
||||||
AlterTableOperation::Lock { .. } => Span::empty(),
|
AlterTableOperation::Lock { .. } => Span::empty(),
|
||||||
AlterTableOperation::ReplicaIdentity { .. } => Span::empty(),
|
AlterTableOperation::ReplicaIdentity { .. } => Span::empty(),
|
||||||
|
AlterTableOperation::ValidateConstraint { name } => name.span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -981,6 +981,7 @@ define_keywords!(
|
||||||
UUID,
|
UUID,
|
||||||
VACUUM,
|
VACUUM,
|
||||||
VALID,
|
VALID,
|
||||||
|
VALIDATE,
|
||||||
VALIDATION_MODE,
|
VALIDATION_MODE,
|
||||||
VALUE,
|
VALUE,
|
||||||
VALUES,
|
VALUES,
|
||||||
|
|
|
@ -8477,7 +8477,11 @@ impl<'a> Parser<'a> {
|
||||||
pub fn parse_alter_table_operation(&mut self) -> Result<AlterTableOperation, ParserError> {
|
pub fn parse_alter_table_operation(&mut self) -> Result<AlterTableOperation, ParserError> {
|
||||||
let operation = if self.parse_keyword(Keyword::ADD) {
|
let operation = if self.parse_keyword(Keyword::ADD) {
|
||||||
if let Some(constraint) = self.parse_optional_table_constraint()? {
|
if let Some(constraint) = self.parse_optional_table_constraint()? {
|
||||||
AlterTableOperation::AddConstraint(constraint)
|
let not_valid = self.parse_keywords(&[Keyword::NOT, Keyword::VALID]);
|
||||||
|
AlterTableOperation::AddConstraint {
|
||||||
|
constraint,
|
||||||
|
not_valid,
|
||||||
|
}
|
||||||
} else if dialect_of!(self is ClickHouseDialect|GenericDialect)
|
} else if dialect_of!(self is ClickHouseDialect|GenericDialect)
|
||||||
&& self.parse_keyword(Keyword::PROJECTION)
|
&& self.parse_keyword(Keyword::PROJECTION)
|
||||||
{
|
{
|
||||||
|
@ -8886,6 +8890,9 @@ impl<'a> Parser<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
AlterTableOperation::ReplicaIdentity { identity }
|
AlterTableOperation::ReplicaIdentity { identity }
|
||||||
|
} else if self.parse_keywords(&[Keyword::VALIDATE, Keyword::CONSTRAINT]) {
|
||||||
|
let name = self.parse_identifier()?;
|
||||||
|
AlterTableOperation::ValidateConstraint { name }
|
||||||
} else {
|
} else {
|
||||||
let options: Vec<SqlOption> =
|
let options: Vec<SqlOption> =
|
||||||
self.parse_options_with_keywords(&[Keyword::SET, Keyword::TBLPROPERTIES])?;
|
self.parse_options_with_keywords(&[Keyword::SET, Keyword::TBLPROPERTIES])?;
|
||||||
|
|
|
@ -479,20 +479,25 @@ pub fn index_column(stmt: Statement) -> Expr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Statement::AlterTable { operations, .. } => match operations.first().unwrap() {
|
Statement::AlterTable { operations, .. } => match operations.first().unwrap() {
|
||||||
AlterTableOperation::AddConstraint(TableConstraint::Index { columns, .. }) => {
|
AlterTableOperation::AddConstraint { constraint, .. } => {
|
||||||
columns.first().unwrap().column.expr.clone()
|
match constraint {
|
||||||
|
TableConstraint::Index { columns, .. } => {
|
||||||
|
columns.first().unwrap().column.expr.clone()
|
||||||
|
}
|
||||||
|
TableConstraint::Unique { columns, .. } => {
|
||||||
|
columns.first().unwrap().column.expr.clone()
|
||||||
|
}
|
||||||
|
TableConstraint::PrimaryKey { columns, .. } => {
|
||||||
|
columns.first().unwrap().column.expr.clone()
|
||||||
|
}
|
||||||
|
TableConstraint::FulltextOrSpatial {
|
||||||
|
columns,
|
||||||
|
..
|
||||||
|
} => columns.first().unwrap().column.expr.clone(),
|
||||||
|
_ => panic!("Expected an index, unique, primary, full text, or spatial constraint (foreign key does not support general key part expressions)"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
AlterTableOperation::AddConstraint(TableConstraint::Unique { columns, .. }) => {
|
_ => panic!("Expected a constraint"),
|
||||||
columns.first().unwrap().column.expr.clone()
|
|
||||||
}
|
|
||||||
AlterTableOperation::AddConstraint(TableConstraint::PrimaryKey { columns, .. }) => {
|
|
||||||
columns.first().unwrap().column.expr.clone()
|
|
||||||
}
|
|
||||||
AlterTableOperation::AddConstraint(TableConstraint::FulltextOrSpatial {
|
|
||||||
columns,
|
|
||||||
..
|
|
||||||
}) => columns.first().unwrap().column.expr.clone(),
|
|
||||||
_ => panic!("Expected an index, unique, primary, full text, or spatial constraint (foreign key does not support general key part expressions)"),
|
|
||||||
},
|
},
|
||||||
_ => panic!("Expected CREATE INDEX, ALTER TABLE, or CREATE TABLE, got: {stmt:?}"),
|
_ => panic!("Expected CREATE INDEX, ALTER TABLE, or CREATE TABLE, got: {stmt:?}"),
|
||||||
}
|
}
|
||||||
|
|
|
@ -4956,7 +4956,7 @@ fn parse_alter_table_constraints() {
|
||||||
match alter_table_op(verified_stmt(&format!(
|
match alter_table_op(verified_stmt(&format!(
|
||||||
"ALTER TABLE tab ADD {constraint_text}"
|
"ALTER TABLE tab ADD {constraint_text}"
|
||||||
))) {
|
))) {
|
||||||
AlterTableOperation::AddConstraint(constraint) => {
|
AlterTableOperation::AddConstraint { constraint, .. } => {
|
||||||
assert_eq!(constraint_text, constraint.to_string());
|
assert_eq!(constraint_text, constraint.to_string());
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
|
|
@ -606,9 +606,10 @@ fn parse_alter_table_constraints_unique_nulls_distinct() {
|
||||||
.verified_stmt("ALTER TABLE t ADD CONSTRAINT b UNIQUE NULLS NOT DISTINCT (c)")
|
.verified_stmt("ALTER TABLE t ADD CONSTRAINT b UNIQUE NULLS NOT DISTINCT (c)")
|
||||||
{
|
{
|
||||||
Statement::AlterTable { operations, .. } => match &operations[0] {
|
Statement::AlterTable { operations, .. } => match &operations[0] {
|
||||||
AlterTableOperation::AddConstraint(TableConstraint::Unique {
|
AlterTableOperation::AddConstraint {
|
||||||
nulls_distinct, ..
|
constraint: TableConstraint::Unique { nulls_distinct, .. },
|
||||||
}) => {
|
..
|
||||||
|
} => {
|
||||||
assert_eq!(nulls_distinct, &NullsDistinctOption::NotDistinct)
|
assert_eq!(nulls_distinct, &NullsDistinctOption::NotDistinct)
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
@ -6229,3 +6230,43 @@ fn parse_ts_datatypes() {
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_alter_table_constraint_not_valid() {
|
||||||
|
match pg_and_generic().verified_stmt(
|
||||||
|
"ALTER TABLE foo ADD CONSTRAINT bar FOREIGN KEY (baz) REFERENCES other(ref) NOT VALID",
|
||||||
|
) {
|
||||||
|
Statement::AlterTable { operations, .. } => {
|
||||||
|
assert_eq!(
|
||||||
|
operations,
|
||||||
|
vec![AlterTableOperation::AddConstraint {
|
||||||
|
constraint: TableConstraint::ForeignKey {
|
||||||
|
name: Some("bar".into()),
|
||||||
|
index_name: None,
|
||||||
|
columns: vec!["baz".into()],
|
||||||
|
foreign_table: ObjectName::from(vec!["other".into()]),
|
||||||
|
referred_columns: vec!["ref".into()],
|
||||||
|
on_delete: None,
|
||||||
|
on_update: None,
|
||||||
|
characteristics: None,
|
||||||
|
},
|
||||||
|
not_valid: true,
|
||||||
|
}]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_alter_table_validate_constraint() {
|
||||||
|
match pg_and_generic().verified_stmt("ALTER TABLE foo VALIDATE CONSTRAINT bar") {
|
||||||
|
Statement::AlterTable { operations, .. } => {
|
||||||
|
assert_eq!(
|
||||||
|
operations,
|
||||||
|
vec![AlterTableOperation::ValidateConstraint { name: "bar".into() }]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue