This is an automated email from the ASF dual-hosted git repository.
iffyio pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
The following commit(s) were added to refs/heads/main by this push:
new 418b9422 Postgres: support `ADD CONSTRAINT NOT VALID` and `VALIDATE
CONSTRAINT` (#1908)
418b9422 is described below
commit 418b94227a5cf6ae721629f95a279c40b6a196ad
Author: carl <[email protected]>
AuthorDate: Thu Jul 3 12:19:26 2025 -0400
Postgres: support `ADD CONSTRAINT NOT VALID` and `VALIDATE CONSTRAINT`
(#1908)
---
src/ast/ddl.rs | 25 +++++++++++++++++++++---
src/ast/spans.rs | 6 +++++-
src/keywords.rs | 1 +
src/parser/mod.rs | 9 ++++++++-
src/test_utils.rs | 31 +++++++++++++++++-------------
tests/sqlparser_common.rs | 2 +-
tests/sqlparser_postgres.rs | 47 ++++++++++++++++++++++++++++++++++++++++++---
7 files changed, 99 insertions(+), 22 deletions(-)
diff --git a/src/ast/ddl.rs b/src/ast/ddl.rs
index 9134412c..9d500203 100644
--- a/src/ast/ddl.rs
+++ b/src/ast/ddl.rs
@@ -67,8 +67,11 @@ impl fmt::Display for ReplicaIdentity {
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum AlterTableOperation {
- /// `ADD <table_constraint>`
- AddConstraint(TableConstraint),
+ /// `ADD <table_constraint> [NOT VALID]`
+ AddConstraint {
+ constraint: TableConstraint,
+ not_valid: bool,
+ },
/// `ADD [COLUMN] [IF NOT EXISTS] <column_def>`
AddColumn {
/// `[COLUMN]`.
@@ -344,6 +347,10 @@ pub enum AlterTableOperation {
equals: bool,
value: ValueWithSpan,
},
+ /// `VALIDATE CONSTRAINT <name>`
+ ValidateConstraint {
+ name: Ident,
+ },
}
/// An `ALTER Policy` (`Statement::AlterPolicy`) operation
@@ -494,7 +501,16 @@ impl fmt::Display for AlterTableOperation {
display_separated(new_partitions, " "),
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 {
column_keyword,
if_not_exists,
@@ -772,6 +788,9 @@ impl fmt::Display for AlterTableOperation {
AlterTableOperation::ReplicaIdentity { identity } => {
write!(f, "REPLICA IDENTITY {identity}")
}
+ AlterTableOperation::ValidateConstraint { name } => {
+ write!(f, "VALIDATE CONSTRAINT {name}")
+ }
}
}
}
diff --git a/src/ast/spans.rs b/src/ast/spans.rs
index 00882602..26205496 100644
--- a/src/ast/spans.rs
+++ b/src/ast/spans.rs
@@ -1075,7 +1075,10 @@ impl Spanned for CreateTableOptions {
impl Spanned for AlterTableOperation {
fn span(&self) -> Span {
match self {
- AlterTableOperation::AddConstraint(table_constraint) =>
table_constraint.span(),
+ AlterTableOperation::AddConstraint {
+ constraint,
+ not_valid: _,
+ } => constraint.span(),
AlterTableOperation::AddColumn {
column_keyword: _,
if_not_exists: _,
@@ -1196,6 +1199,7 @@ impl Spanned for AlterTableOperation {
AlterTableOperation::AutoIncrement { value, .. } => value.span(),
AlterTableOperation::Lock { .. } => Span::empty(),
AlterTableOperation::ReplicaIdentity { .. } => Span::empty(),
+ AlterTableOperation::ValidateConstraint { name } => name.span,
}
}
}
diff --git a/src/keywords.rs b/src/keywords.rs
index a8bbca3d..49a54e8a 100644
--- a/src/keywords.rs
+++ b/src/keywords.rs
@@ -981,6 +981,7 @@ define_keywords!(
UUID,
VACUUM,
VALID,
+ VALIDATE,
VALIDATION_MODE,
VALUE,
VALUES,
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index 6360817f..1c40a964 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -8477,7 +8477,11 @@ impl<'a> Parser<'a> {
pub fn parse_alter_table_operation(&mut self) ->
Result<AlterTableOperation, ParserError> {
let operation = if self.parse_keyword(Keyword::ADD) {
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)
&& self.parse_keyword(Keyword::PROJECTION)
{
@@ -8886,6 +8890,9 @@ impl<'a> Parser<'a> {
};
AlterTableOperation::ReplicaIdentity { identity }
+ } else if self.parse_keywords(&[Keyword::VALIDATE,
Keyword::CONSTRAINT]) {
+ let name = self.parse_identifier()?;
+ AlterTableOperation::ValidateConstraint { name }
} else {
let options: Vec<SqlOption> =
self.parse_options_with_keywords(&[Keyword::SET,
Keyword::TBLPROPERTIES])?;
diff --git a/src/test_utils.rs b/src/test_utils.rs
index db7b3dd6..544ceaef 100644
--- a/src/test_utils.rs
+++ b/src/test_utils.rs
@@ -479,20 +479,25 @@ pub fn index_column(stmt: Statement) -> Expr {
}
}
Statement::AlterTable { operations, .. } => match
operations.first().unwrap() {
- AlterTableOperation::AddConstraint(TableConstraint::Index {
columns, .. }) => {
- columns.first().unwrap().column.expr.clone()
- }
- AlterTableOperation::AddConstraint(TableConstraint::Unique {
columns, .. }) => {
- columns.first().unwrap().column.expr.clone()
- }
- AlterTableOperation::AddConstraint(TableConstraint::PrimaryKey {
columns, .. }) => {
- columns.first().unwrap().column.expr.clone()
+ AlterTableOperation::AddConstraint { constraint, .. } => {
+ 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::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 a constraint"),
},
_ => panic!("Expected CREATE INDEX, ALTER TABLE, or CREATE TABLE, got:
{stmt:?}"),
}
diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs
index 380bd475..9ca985b3 100644
--- a/tests/sqlparser_common.rs
+++ b/tests/sqlparser_common.rs
@@ -4956,7 +4956,7 @@ fn parse_alter_table_constraints() {
match alter_table_op(verified_stmt(&format!(
"ALTER TABLE tab ADD {constraint_text}"
))) {
- AlterTableOperation::AddConstraint(constraint) => {
+ AlterTableOperation::AddConstraint { constraint, .. } => {
assert_eq!(constraint_text, constraint.to_string());
}
_ => unreachable!(),
diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs
index e1a49c69..16ba5f23 100644
--- a/tests/sqlparser_postgres.rs
+++ b/tests/sqlparser_postgres.rs
@@ -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)")
{
Statement::AlterTable { operations, .. } => match &operations[0] {
- AlterTableOperation::AddConstraint(TableConstraint::Unique {
- nulls_distinct, ..
- }) => {
+ AlterTableOperation::AddConstraint {
+ constraint: TableConstraint::Unique { nulls_distinct, .. },
+ ..
+ } => {
assert_eq!(nulls_distinct, &NullsDistinctOption::NotDistinct)
}
_ => unreachable!(),
@@ -6229,3 +6230,43 @@ fn parse_ts_datatypes() {
_ => 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!(),
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]