Support multiple tables in UPDATE FROM clause (#1681)

This commit is contained in:
Ifeanyi Ubah 2025-01-28 08:45:14 +01:00 committed by GitHub
parent 74163b148e
commit fdbe864d0d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 20 additions and 14 deletions

View file

@ -3872,13 +3872,13 @@ impl fmt::Display for Statement {
} }
write!(f, "{table}")?; write!(f, "{table}")?;
if let Some(UpdateTableFromKind::BeforeSet(from)) = from { if let Some(UpdateTableFromKind::BeforeSet(from)) = from {
write!(f, " FROM {from}")?; write!(f, " FROM {}", display_comma_separated(from))?;
} }
if !assignments.is_empty() { if !assignments.is_empty() {
write!(f, " SET {}", display_comma_separated(assignments))?; write!(f, " SET {}", display_comma_separated(assignments))?;
} }
if let Some(UpdateTableFromKind::AfterSet(from)) = from { if let Some(UpdateTableFromKind::AfterSet(from)) = from {
write!(f, " FROM {from}")?; write!(f, " FROM {}", display_comma_separated(from))?;
} }
if let Some(selection) = selection { if let Some(selection) = selection {
write!(f, " WHERE {selection}")?; write!(f, " WHERE {selection}")?;

View file

@ -2829,8 +2829,8 @@ impl fmt::Display for ValueTableMode {
pub enum UpdateTableFromKind { pub enum UpdateTableFromKind {
/// Update Statement where the 'FROM' clause is before the 'SET' keyword (Supported by Snowflake) /// Update Statement where the 'FROM' clause is before the 'SET' keyword (Supported by Snowflake)
/// For Example: `UPDATE FROM t1 SET t1.name='aaa'` /// For Example: `UPDATE FROM t1 SET t1.name='aaa'`
BeforeSet(TableWithJoins), BeforeSet(Vec<TableWithJoins>),
/// Update Statement where the 'FROM' clause is after the 'SET' keyword (Which is the standard way) /// Update Statement where the 'FROM' clause is after the 'SET' keyword (Which is the standard way)
/// For Example: `UPDATE SET t1.name='aaa' FROM t1` /// For Example: `UPDATE SET t1.name='aaa' FROM t1`
AfterSet(TableWithJoins), AfterSet(Vec<TableWithJoins>),
} }

View file

@ -2138,10 +2138,11 @@ impl Spanned for SelectInto {
impl Spanned for UpdateTableFromKind { impl Spanned for UpdateTableFromKind {
fn span(&self) -> Span { fn span(&self) -> Span {
match self { let from = match self {
UpdateTableFromKind::BeforeSet(from) => from.span(), UpdateTableFromKind::BeforeSet(from) => from,
UpdateTableFromKind::AfterSet(from) => from.span(), UpdateTableFromKind::AfterSet(from) => from,
} };
union_spans(from.iter().map(|t| t.span()))
} }
} }

View file

@ -12617,7 +12617,7 @@ impl<'a> Parser<'a> {
let table = self.parse_table_and_joins()?; let table = self.parse_table_and_joins()?;
let from_before_set = if self.parse_keyword(Keyword::FROM) { let from_before_set = if self.parse_keyword(Keyword::FROM) {
Some(UpdateTableFromKind::BeforeSet( Some(UpdateTableFromKind::BeforeSet(
self.parse_table_and_joins()?, self.parse_table_with_joins()?,
)) ))
} else { } else {
None None
@ -12625,7 +12625,9 @@ impl<'a> Parser<'a> {
self.expect_keyword(Keyword::SET)?; self.expect_keyword(Keyword::SET)?;
let assignments = self.parse_comma_separated(Parser::parse_assignment)?; let assignments = self.parse_comma_separated(Parser::parse_assignment)?;
let from = if from_before_set.is_none() && self.parse_keyword(Keyword::FROM) { let from = if from_before_set.is_none() && self.parse_keyword(Keyword::FROM) {
Some(UpdateTableFromKind::AfterSet(self.parse_table_and_joins()?)) Some(UpdateTableFromKind::AfterSet(
self.parse_table_with_joins()?,
))
} else { } else {
from_before_set from_before_set
}; };

View file

@ -403,7 +403,7 @@ fn parse_update_set_from() {
target: AssignmentTarget::ColumnName(ObjectName::from(vec![Ident::new("name")])), target: AssignmentTarget::ColumnName(ObjectName::from(vec![Ident::new("name")])),
value: Expr::CompoundIdentifier(vec![Ident::new("t2"), Ident::new("name")]) value: Expr::CompoundIdentifier(vec![Ident::new("t2"), Ident::new("name")])
}], }],
from: Some(UpdateTableFromKind::AfterSet(TableWithJoins { from: Some(UpdateTableFromKind::AfterSet(vec![TableWithJoins {
relation: TableFactor::Derived { relation: TableFactor::Derived {
lateral: false, lateral: false,
subquery: Box::new(Query { subquery: Box::new(Query {
@ -455,7 +455,7 @@ fn parse_update_set_from() {
}) })
}, },
joins: vec![] joins: vec![]
})), }])),
selection: Some(Expr::BinaryOp { selection: Some(Expr::BinaryOp {
left: Box::new(Expr::CompoundIdentifier(vec![ left: Box::new(Expr::CompoundIdentifier(vec![
Ident::new("t1"), Ident::new("t1"),
@ -471,6 +471,9 @@ fn parse_update_set_from() {
or: None, or: None,
} }
); );
let sql = "UPDATE T SET a = b FROM U, (SELECT foo FROM V) AS W WHERE 1 = 1";
dialects.verified_stmt(sql);
} }
#[test] #[test]
@ -13051,8 +13054,8 @@ fn parse_select_without_projection() {
#[test] #[test]
fn parse_update_from_before_select() { fn parse_update_from_before_select() {
all_dialects() verified_stmt("UPDATE t1 FROM (SELECT name, id FROM t1 GROUP BY id) AS t2 SET name = t2.name WHERE t1.id = t2.id");
.verified_stmt("UPDATE t1 FROM (SELECT name, id FROM t1 GROUP BY id) AS t2 SET name = t2.name WHERE t1.id = t2.id"); verified_stmt("UPDATE t1 FROM U, (SELECT id FROM V) AS W SET a = b WHERE 1 = 1");
let query = let query =
"UPDATE t1 FROM (SELECT name, id FROM t1 GROUP BY id) AS t2 SET name = t2.name FROM (SELECT name from t2) AS t2"; "UPDATE t1 FROM (SELECT name, id FROM t1 GROUP BY id) AS t2 SET name = t2.name FROM (SELECT name from t2) AS t2";