Skip to content

Commit 418b942

Browse files
Postgres: support ADD CONSTRAINT NOT VALID and VALIDATE CONSTRAINT (#1908)
1 parent 015caca commit 418b942

File tree

7 files changed

+99
-22
lines changed

7 files changed

+99
-22
lines changed

src/ast/ddl.rs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,11 @@ impl fmt::Display for ReplicaIdentity {
6767
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6868
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6969
pub enum AlterTableOperation {
70-
/// `ADD <table_constraint>`
71-
AddConstraint(TableConstraint),
70+
/// `ADD <table_constraint> [NOT VALID]`
71+
AddConstraint {
72+
constraint: TableConstraint,
73+
not_valid: bool,
74+
},
7275
/// `ADD [COLUMN] [IF NOT EXISTS] <column_def>`
7376
AddColumn {
7477
/// `[COLUMN]`.
@@ -344,6 +347,10 @@ pub enum AlterTableOperation {
344347
equals: bool,
345348
value: ValueWithSpan,
346349
},
350+
/// `VALIDATE CONSTRAINT <name>`
351+
ValidateConstraint {
352+
name: Ident,
353+
},
347354
}
348355

349356
/// An `ALTER Policy` (`Statement::AlterPolicy`) operation
@@ -494,7 +501,16 @@ impl fmt::Display for AlterTableOperation {
494501
display_separated(new_partitions, " "),
495502
ine = if *if_not_exists { " IF NOT EXISTS" } else { "" }
496503
),
497-
AlterTableOperation::AddConstraint(c) => write!(f, "ADD {c}"),
504+
AlterTableOperation::AddConstraint {
505+
not_valid,
506+
constraint,
507+
} => {
508+
write!(f, "ADD {constraint}")?;
509+
if *not_valid {
510+
write!(f, " NOT VALID")?;
511+
}
512+
Ok(())
513+
}
498514
AlterTableOperation::AddColumn {
499515
column_keyword,
500516
if_not_exists,
@@ -772,6 +788,9 @@ impl fmt::Display for AlterTableOperation {
772788
AlterTableOperation::ReplicaIdentity { identity } => {
773789
write!(f, "REPLICA IDENTITY {identity}")
774790
}
791+
AlterTableOperation::ValidateConstraint { name } => {
792+
write!(f, "VALIDATE CONSTRAINT {name}")
793+
}
775794
}
776795
}
777796
}

src/ast/spans.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1075,7 +1075,10 @@ impl Spanned for CreateTableOptions {
10751075
impl Spanned for AlterTableOperation {
10761076
fn span(&self) -> Span {
10771077
match self {
1078-
AlterTableOperation::AddConstraint(table_constraint) => table_constraint.span(),
1078+
AlterTableOperation::AddConstraint {
1079+
constraint,
1080+
not_valid: _,
1081+
} => constraint.span(),
10791082
AlterTableOperation::AddColumn {
10801083
column_keyword: _,
10811084
if_not_exists: _,
@@ -1196,6 +1199,7 @@ impl Spanned for AlterTableOperation {
11961199
AlterTableOperation::AutoIncrement { value, .. } => value.span(),
11971200
AlterTableOperation::Lock { .. } => Span::empty(),
11981201
AlterTableOperation::ReplicaIdentity { .. } => Span::empty(),
1202+
AlterTableOperation::ValidateConstraint { name } => name.span,
11991203
}
12001204
}
12011205
}

src/keywords.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -981,6 +981,7 @@ define_keywords!(
981981
UUID,
982982
VACUUM,
983983
VALID,
984+
VALIDATE,
984985
VALIDATION_MODE,
985986
VALUE,
986987
VALUES,

src/parser/mod.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8477,7 +8477,11 @@ impl<'a> Parser<'a> {
84778477
pub fn parse_alter_table_operation(&mut self) -> Result<AlterTableOperation, ParserError> {
84788478
let operation = if self.parse_keyword(Keyword::ADD) {
84798479
if let Some(constraint) = self.parse_optional_table_constraint()? {
8480-
AlterTableOperation::AddConstraint(constraint)
8480+
let not_valid = self.parse_keywords(&[Keyword::NOT, Keyword::VALID]);
8481+
AlterTableOperation::AddConstraint {
8482+
constraint,
8483+
not_valid,
8484+
}
84818485
} else if dialect_of!(self is ClickHouseDialect|GenericDialect)
84828486
&& self.parse_keyword(Keyword::PROJECTION)
84838487
{
@@ -8886,6 +8890,9 @@ impl<'a> Parser<'a> {
88868890
};
88878891

88888892
AlterTableOperation::ReplicaIdentity { identity }
8893+
} else if self.parse_keywords(&[Keyword::VALIDATE, Keyword::CONSTRAINT]) {
8894+
let name = self.parse_identifier()?;
8895+
AlterTableOperation::ValidateConstraint { name }
88898896
} else {
88908897
let options: Vec<SqlOption> =
88918898
self.parse_options_with_keywords(&[Keyword::SET, Keyword::TBLPROPERTIES])?;

src/test_utils.rs

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -479,20 +479,25 @@ pub fn index_column(stmt: Statement) -> Expr {
479479
}
480480
}
481481
Statement::AlterTable { operations, .. } => match operations.first().unwrap() {
482-
AlterTableOperation::AddConstraint(TableConstraint::Index { columns, .. }) => {
483-
columns.first().unwrap().column.expr.clone()
484-
}
485-
AlterTableOperation::AddConstraint(TableConstraint::Unique { columns, .. }) => {
486-
columns.first().unwrap().column.expr.clone()
487-
}
488-
AlterTableOperation::AddConstraint(TableConstraint::PrimaryKey { columns, .. }) => {
489-
columns.first().unwrap().column.expr.clone()
482+
AlterTableOperation::AddConstraint { constraint, .. } => {
483+
match constraint {
484+
TableConstraint::Index { columns, .. } => {
485+
columns.first().unwrap().column.expr.clone()
486+
}
487+
TableConstraint::Unique { columns, .. } => {
488+
columns.first().unwrap().column.expr.clone()
489+
}
490+
TableConstraint::PrimaryKey { columns, .. } => {
491+
columns.first().unwrap().column.expr.clone()
492+
}
493+
TableConstraint::FulltextOrSpatial {
494+
columns,
495+
..
496+
} => columns.first().unwrap().column.expr.clone(),
497+
_ => panic!("Expected an index, unique, primary, full text, or spatial constraint (foreign key does not support general key part expressions)"),
498+
}
490499
}
491-
AlterTableOperation::AddConstraint(TableConstraint::FulltextOrSpatial {
492-
columns,
493-
..
494-
}) => columns.first().unwrap().column.expr.clone(),
495-
_ => panic!("Expected an index, unique, primary, full text, or spatial constraint (foreign key does not support general key part expressions)"),
500+
_ => panic!("Expected a constraint"),
496501
},
497502
_ => panic!("Expected CREATE INDEX, ALTER TABLE, or CREATE TABLE, got: {stmt:?}"),
498503
}

tests/sqlparser_common.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4956,7 +4956,7 @@ fn parse_alter_table_constraints() {
49564956
match alter_table_op(verified_stmt(&format!(
49574957
"ALTER TABLE tab ADD {constraint_text}"
49584958
))) {
4959-
AlterTableOperation::AddConstraint(constraint) => {
4959+
AlterTableOperation::AddConstraint { constraint, .. } => {
49604960
assert_eq!(constraint_text, constraint.to_string());
49614961
}
49624962
_ => unreachable!(),

tests/sqlparser_postgres.rs

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -606,9 +606,10 @@ fn parse_alter_table_constraints_unique_nulls_distinct() {
606606
.verified_stmt("ALTER TABLE t ADD CONSTRAINT b UNIQUE NULLS NOT DISTINCT (c)")
607607
{
608608
Statement::AlterTable { operations, .. } => match &operations[0] {
609-
AlterTableOperation::AddConstraint(TableConstraint::Unique {
610-
nulls_distinct, ..
611-
}) => {
609+
AlterTableOperation::AddConstraint {
610+
constraint: TableConstraint::Unique { nulls_distinct, .. },
611+
..
612+
} => {
612613
assert_eq!(nulls_distinct, &NullsDistinctOption::NotDistinct)
613614
}
614615
_ => unreachable!(),
@@ -6229,3 +6230,43 @@ fn parse_ts_datatypes() {
62296230
_ => unreachable!(),
62306231
}
62316232
}
6233+
6234+
#[test]
6235+
fn parse_alter_table_constraint_not_valid() {
6236+
match pg_and_generic().verified_stmt(
6237+
"ALTER TABLE foo ADD CONSTRAINT bar FOREIGN KEY (baz) REFERENCES other(ref) NOT VALID",
6238+
) {
6239+
Statement::AlterTable { operations, .. } => {
6240+
assert_eq!(
6241+
operations,
6242+
vec![AlterTableOperation::AddConstraint {
6243+
constraint: TableConstraint::ForeignKey {
6244+
name: Some("bar".into()),
6245+
index_name: None,
6246+
columns: vec!["baz".into()],
6247+
foreign_table: ObjectName::from(vec!["other".into()]),
6248+
referred_columns: vec!["ref".into()],
6249+
on_delete: None,
6250+
on_update: None,
6251+
characteristics: None,
6252+
},
6253+
not_valid: true,
6254+
}]
6255+
);
6256+
}
6257+
_ => unreachable!(),
6258+
}
6259+
}
6260+
6261+
#[test]
6262+
fn parse_alter_table_validate_constraint() {
6263+
match pg_and_generic().verified_stmt("ALTER TABLE foo VALIDATE CONSTRAINT bar") {
6264+
Statement::AlterTable { operations, .. } => {
6265+
assert_eq!(
6266+
operations,
6267+
vec![AlterTableOperation::ValidateConstraint { name: "bar".into() }]
6268+
);
6269+
}
6270+
_ => unreachable!(),
6271+
}
6272+
}

0 commit comments

Comments
 (0)