agent_patch
runs/2026-02-28__18-27-22__gpt-5-4/flux-pr-1908/flux-pr-1908.1-of-1.2026-02-28__18-27-22__gpt-5-4/agent-logs/agent.patch
11613 bytes
diff --git a/tmp/agent-patch-flux-pr-1908.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/ast/ddl.rs b/app/src/ast/ddl.rs
index 9134412..cfc3609 100644
--- a/tmp/agent-patch-flux-pr-1908.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/ast/ddl.rs
+++ b/app/src/ast/ddl.rs
@@ -68,7 +68,11 @@ impl fmt::Display for ReplicaIdentity {
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum AlterTableOperation {
/// `ADD <table_constraint>`
- AddConstraint(TableConstraint),
+ AddConstraint {
+ table_constraint: TableConstraint,
+ /// PostgreSQL-specific `NOT VALID` modifier.
+ not_valid: bool,
+ },
/// `ADD [COLUMN] [IF NOT EXISTS] <column_def>`
AddColumn {
/// `[COLUMN]`.
@@ -131,6 +135,12 @@ pub enum AlterTableOperation {
DisableTrigger {
name: Ident,
},
+ /// `VALIDATE CONSTRAINT <name>`
+ ///
+ /// Note: this is a PostgreSQL-specific operation.
+ ValidateConstraint {
+ name: Ident,
+ },
/// `DROP CONSTRAINT [ IF EXISTS ] <name>`
DropConstraint {
if_exists: bool,
@@ -494,7 +504,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 {
+ table_constraint,
+ not_valid,
+ } => {
+ write!(f, "ADD {table_constraint}")?;
+ if *not_valid {
+ write!(f, " NOT VALID")?;
+ }
+ Ok(())
+ }
AlterTableOperation::AddColumn {
column_keyword,
if_not_exists,
@@ -584,6 +603,9 @@ impl fmt::Display for AlterTableOperation {
AlterTableOperation::DisableTrigger { name } => {
write!(f, "DISABLE TRIGGER {name}")
}
+ AlterTableOperation::ValidateConstraint { name } => {
+ write!(f, "VALIDATE CONSTRAINT {name}")
+ }
AlterTableOperation::DropPartitions {
partitions,
if_exists,
diff --git a/tmp/agent-patch-flux-pr-1908.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/ast/spans.rs b/app/src/ast/spans.rs
index 0088260..b0a55a2 100644
--- a/tmp/agent-patch-flux-pr-1908.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/ast/spans.rs
+++ b/app/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 {
+ table_constraint,
+ not_valid: _,
+ } => table_constraint.span(),
AlterTableOperation::AddColumn {
column_keyword: _,
if_not_exists: _,
@@ -1101,6 +1104,7 @@ impl Spanned for AlterTableOperation {
AlterTableOperation::DisableRowLevelSecurity => Span::empty(),
AlterTableOperation::DisableRule { name } => name.span,
AlterTableOperation::DisableTrigger { name } => name.span,
+ AlterTableOperation::ValidateConstraint { name } => name.span,
AlterTableOperation::DropConstraint {
if_exists: _,
name,
diff --git a/tmp/agent-patch-flux-pr-1908.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/keywords.rs b/app/src/keywords.rs
index a8bbca3..49a54e8 100644
--- a/tmp/agent-patch-flux-pr-1908.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/keywords.rs
+++ b/app/src/keywords.rs
@@ -981,6 +981,7 @@ define_keywords!(
UUID,
VACUUM,
VALID,
+ VALIDATE,
VALIDATION_MODE,
VALUE,
VALUES,
diff --git a/tmp/agent-patch-flux-pr-1908.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/parser/mod.rs b/app/src/parser/mod.rs
index 6360817..75702aa 100644
--- a/tmp/agent-patch-flux-pr-1908.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/parser/mod.rs
+++ b/app/src/parser/mod.rs
@@ -8477,7 +8477,12 @@ 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 = dialect_of!(self is PostgreSqlDialect | GenericDialect)
+ && self.parse_keywords(&[Keyword::NOT, Keyword::VALID]);
+ AlterTableOperation::AddConstraint {
+ table_constraint: constraint,
+ not_valid,
+ }
} else if dialect_of!(self is ClickHouseDialect|GenericDialect)
&& self.parse_keyword(Keyword::PROJECTION)
{
@@ -8582,6 +8587,12 @@ impl<'a> Parser<'a> {
self.peek_token(),
);
}
+ } else if dialect_of!(self is PostgreSqlDialect | GenericDialect)
+ && self.parse_keyword(Keyword::VALIDATE)
+ {
+ self.expect_keyword_is(Keyword::CONSTRAINT)?;
+ let name = self.parse_identifier()?;
+ AlterTableOperation::ValidateConstraint { name }
} else if self.parse_keywords(&[Keyword::CLEAR, Keyword::PROJECTION])
&& dialect_of!(self is ClickHouseDialect|GenericDialect)
{
@@ -8895,7 +8906,7 @@ impl<'a> Parser<'a> {
}
} else {
return self.expected(
- "ADD, RENAME, PARTITION, SWAP, DROP, REPLICA IDENTITY, or SET TBLPROPERTIES after ALTER TABLE",
+ "ADD, RENAME, PARTITION, SWAP, DROP, VALIDATE CONSTRAINT, REPLICA IDENTITY, or SET TBLPROPERTIES after ALTER TABLE",
self.peek_token(),
);
}
diff --git a/tmp/agent-patch-flux-pr-1908.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/test_utils.rs b/app/src/test_utils.rs
index db7b3dd..a9c6225 100644
--- a/tmp/agent-patch-flux-pr-1908.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/src/test_utils.rs
+++ b/app/src/test_utils.rs
@@ -479,19 +479,32 @@ pub fn index_column(stmt: Statement) -> Expr {
}
}
Statement::AlterTable { operations, .. } => match operations.first().unwrap() {
- AlterTableOperation::AddConstraint(TableConstraint::Index { columns, .. }) => {
+ AlterTableOperation::AddConstraint {
+ table_constraint: TableConstraint::Index { columns, .. },
+ ..
+ } => {
columns.first().unwrap().column.expr.clone()
}
- AlterTableOperation::AddConstraint(TableConstraint::Unique { columns, .. }) => {
+ AlterTableOperation::AddConstraint {
+ table_constraint: TableConstraint::Unique { columns, .. },
+ ..
+ } => {
columns.first().unwrap().column.expr.clone()
}
- AlterTableOperation::AddConstraint(TableConstraint::PrimaryKey { columns, .. }) => {
+ AlterTableOperation::AddConstraint {
+ table_constraint: TableConstraint::PrimaryKey { columns, .. },
+ ..
+ } => {
columns.first().unwrap().column.expr.clone()
}
- AlterTableOperation::AddConstraint(TableConstraint::FulltextOrSpatial {
- columns,
+ AlterTableOperation::AddConstraint {
+ table_constraint:
+ TableConstraint::FulltextOrSpatial {
+ columns,
+ ..
+ },
..
- }) => columns.first().unwrap().column.expr.clone(),
+ } => 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:?}"),
diff --git a/tmp/agent-patch-flux-pr-1908.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/tests/sqlparser_common.rs b/app/tests/sqlparser_common.rs
index 380bd47..4632573 100644
--- a/tmp/agent-patch-flux-pr-1908.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/tests/sqlparser_common.rs
+++ b/app/tests/sqlparser_common.rs
@@ -4956,8 +4956,12 @@ fn parse_alter_table_constraints() {
match alter_table_op(verified_stmt(&format!(
"ALTER TABLE tab ADD {constraint_text}"
))) {
- AlterTableOperation::AddConstraint(constraint) => {
- assert_eq!(constraint_text, constraint.to_string());
+ AlterTableOperation::AddConstraint {
+ table_constraint,
+ not_valid,
+ } => {
+ assert!(!not_valid);
+ assert_eq!(constraint_text, table_constraint.to_string());
}
_ => unreachable!(),
}
diff --git a/tmp/agent-patch-flux-pr-1908.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/tests/sqlparser_postgres.rs b/app/tests/sqlparser_postgres.rs
index e1a49c6..35aa402 100644
--- a/tmp/agent-patch-flux-pr-1908.1-of-1.2026-02-28__18-27-22__gpt-5-4/app/tests/sqlparser_postgres.rs
+++ b/app/tests/sqlparser_postgres.rs
@@ -606,9 +606,14 @@ 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 {
+ table_constraint:
+ TableConstraint::Unique {
+ nulls_distinct, ..
+ },
+ not_valid,
+ } => {
+ assert!(!not_valid);
assert_eq!(nulls_distinct, &NullsDistinctOption::NotDistinct)
}
_ => unreachable!(),
@@ -645,6 +650,38 @@ fn parse_alter_table_enable() {
pg_and_generic().verified_stmt("ALTER TABLE tab ENABLE TRIGGER trigger_name");
}
+#[test]
+fn parse_alter_table_add_constraint_not_valid() {
+ match pg_and_generic()
+ .verified_stmt("ALTER TABLE tab ADD CONSTRAINT chk CHECK (id > 0) NOT VALID")
+ {
+ Statement::AlterTable { operations, .. } => match &operations[0] {
+ AlterTableOperation::AddConstraint {
+ table_constraint: TableConstraint::Check { name, .. },
+ not_valid,
+ } => {
+ assert_eq!(name.as_ref().map(ToString::to_string).as_deref(), Some("chk"));
+ assert!(*not_valid);
+ }
+ _ => unreachable!(),
+ },
+ _ => unreachable!(),
+ }
+}
+
+#[test]
+fn parse_alter_table_validate_constraint() {
+ match pg_and_generic().verified_stmt("ALTER TABLE tab VALIDATE CONSTRAINT chk") {
+ Statement::AlterTable { operations, .. } => {
+ assert_eq!(
+ operations,
+ vec![AlterTableOperation::ValidateConstraint { name: "chk".into() }]
+ );
+ }
+ _ => unreachable!(),
+ }
+}
+
#[test]
fn parse_truncate_table() {
pg_and_generic()