agent_patch
runs/2026-02-28__18-27-22__gpt-5-3-codex/flux-pr-1604/flux-pr-1604.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/agent-logs/agent.patch
6974 bytes
diff --git a/tmp/agent-patch-flux-pr-1604.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/src/ast/mod.rs b/app/src/ast/mod.rs
index 9fb2bb9..b844e5f 100644
--- a/tmp/agent-patch-flux-pr-1604.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/src/ast/mod.rs
+++ b/app/src/ast/mod.rs
@@ -2470,9 +2470,11 @@ pub enum Statement {
Update {
/// TABLE
table: TableWithJoins,
+ /// Table which provide value to be set (Snowflake-style, before `SET`)
+ from_before_set: Option<TableWithJoins>,
/// Column assignments
assignments: Vec<Assignment>,
- /// Table which provide value to be set
+ /// Table which provide value to be set (standard, after `SET`)
from: Option<TableWithJoins>,
/// WHERE
selection: Option<Expr>,
@@ -3734,6 +3736,7 @@ impl fmt::Display for Statement {
}
Statement::Update {
table,
+ from_before_set,
assignments,
from,
selection,
@@ -3745,6 +3748,9 @@ impl fmt::Display for Statement {
write!(f, "{or} ")?;
}
write!(f, "{table}")?;
+ if let Some(from_before_set) = from_before_set {
+ write!(f, " FROM {from_before_set}")?;
+ }
if !assignments.is_empty() {
write!(f, " SET {}", display_comma_separated(assignments))?;
}
diff --git a/tmp/agent-patch-flux-pr-1604.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/src/ast/spans.rs b/app/src/ast/spans.rs
index 9ba3bdd..c64b7b9 100644
--- a/tmp/agent-patch-flux-pr-1604.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/src/ast/spans.rs
+++ b/app/src/ast/spans.rs
@@ -347,6 +347,7 @@ impl Spanned for Statement {
},
Statement::Update {
table,
+ from_before_set,
assignments,
from,
selection,
@@ -354,6 +355,7 @@ impl Spanned for Statement {
or: _,
} => union_spans(
core::iter::once(table.span())
+ .chain(from_before_set.iter().map(|i| i.span()))
.chain(assignments.iter().map(|i| i.span()))
.chain(from.iter().map(|i| i.span()))
.chain(selection.iter().map(|i| i.span()))
diff --git a/tmp/agent-patch-flux-pr-1604.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/src/parser/mod.rs b/app/src/parser/mod.rs
index cc0a57e..4df5188 100644
--- a/tmp/agent-patch-flux-pr-1604.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/src/parser/mod.rs
+++ b/app/src/parser/mod.rs
@@ -11791,6 +11791,13 @@ impl<'a> Parser<'a> {
pub fn parse_update(&mut self) -> Result<Statement, ParserError> {
let or = self.parse_conflict_clause();
let table = self.parse_table_and_joins()?;
+ let from_before_set = if self.parse_keyword(Keyword::FROM)
+ && dialect_of!(self is GenericDialect | SnowflakeDialect)
+ {
+ Some(self.parse_table_and_joins()?)
+ } else {
+ None
+ };
self.expect_keyword(Keyword::SET)?;
let assignments = self.parse_comma_separated(Parser::parse_assignment)?;
let from = if self.parse_keyword(Keyword::FROM)
@@ -11812,6 +11819,7 @@ impl<'a> Parser<'a> {
};
Ok(Statement::Update {
table,
+ from_before_set,
assignments,
from,
selection,
diff --git a/tmp/agent-patch-flux-pr-1604.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/tests/sqlparser_common.rs b/app/tests/sqlparser_common.rs
index 79f5c8d..d7cfbf0 100644
--- a/tmp/agent-patch-flux-pr-1604.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/tests/sqlparser_common.rs
+++ b/app/tests/sqlparser_common.rs
@@ -362,6 +362,7 @@ fn parse_update_set_from() {
relation: table_from_name(ObjectName(vec![Ident::new("t1")])),
joins: vec![],
},
+ from_before_set: None,
assignments: vec![Assignment {
target: AssignmentTarget::ColumnName(ObjectName(vec![Ident::new("name")])),
value: Expr::CompoundIdentifier(vec![Ident::new("t2"), Ident::new("name")])
@@ -444,6 +445,7 @@ fn parse_update_with_table_alias() {
table,
assignments,
from: _from,
+ from_before_set: _from_before_set,
selection,
returning,
or: None,
diff --git a/tmp/agent-patch-flux-pr-1604.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/tests/sqlparser_mysql.rs b/app/tests/sqlparser_mysql.rs
index 4a4e796..325d574 100644
--- a/tmp/agent-patch-flux-pr-1604.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/tests/sqlparser_mysql.rs
+++ b/app/tests/sqlparser_mysql.rs
@@ -1988,6 +1988,7 @@ fn parse_update_with_joins() {
table,
assignments,
from: _from,
+ from_before_set: _from_before_set,
selection,
returning,
or: None,
diff --git a/tmp/agent-patch-flux-pr-1604.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/tests/sqlparser_snowflake.rs b/app/tests/sqlparser_snowflake.rs
index 9fe1478..3f1d019 100644
--- a/tmp/agent-patch-flux-pr-1604.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/tests/sqlparser_snowflake.rs
+++ b/app/tests/sqlparser_snowflake.rs
@@ -1246,6 +1246,29 @@ fn parse_delimited_identifiers() {
//TODO verified_stmt(r#"UPDATE foo SET "bar" = 5"#);
}
+#[test]
+fn parse_update_from_before_set() {
+ let sql = "UPDATE t1 FROM t2 SET t1.col = t2.col WHERE t1.id = t2.id";
+ match snowflake().verified_stmt(sql) {
+ Statement::Update {
+ table,
+ from_before_set,
+ assignments,
+ from,
+ selection,
+ ..
+ } => {
+ assert_eq!(table.to_string(), "t1");
+ assert_eq!(from_before_set.unwrap().to_string(), "t2");
+ assert_eq!(assignments.len(), 1);
+ assert_eq!(from, None);
+ assert!(selection.is_some());
+ }
+ _ => unreachable!(),
+ }
+ assert_eq!(snowflake().verified_stmt(sql).to_string(), sql);
+}
+
#[test]
fn test_array_agg_func() {
for sql in [
diff --git a/tmp/agent-patch-flux-pr-1604.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/tests/sqlparser_sqlite.rs b/app/tests/sqlparser_sqlite.rs
index ff0b54e..2c9da92 100644
--- a/tmp/agent-patch-flux-pr-1604.1-of-1.2026-02-28__18-27-22__gpt-5-3-codex/app/tests/sqlparser_sqlite.rs
+++ b/app/tests/sqlparser_sqlite.rs
@@ -482,6 +482,7 @@ fn parse_update_tuple_row_values() {
relation: table_from_name(ObjectName(vec![Ident::new("x")])),
joins: vec![],
},
+ from_before_set: None,
from: None,
returning: None
}