Skip to content

Commit 4b1dc1a

Browse files
unvalleyalamb
andauthored
Support UPDATE ... FROM ( subquery ) in some dialects (apache#694)
* Apply UPDATE SET FROM statement for some dialects * Add GenericDialect to support * Test SnowflakeDialect Co-authored-by: Andrew Lamb <[email protected]>
1 parent 0d91662 commit 4b1dc1a

File tree

3 files changed

+94
-82
lines changed

3 files changed

+94
-82
lines changed

Diff for: src/parser.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -5254,7 +5254,9 @@ impl<'a> Parser<'a> {
52545254
let table = self.parse_table_and_joins()?;
52555255
self.expect_keyword(Keyword::SET)?;
52565256
let assignments = self.parse_comma_separated(Parser::parse_assignment)?;
5257-
let from = if self.parse_keyword(Keyword::FROM) && dialect_of!(self is PostgreSqlDialect) {
5257+
let from = if self.parse_keyword(Keyword::FROM)
5258+
&& dialect_of!(self is GenericDialect | PostgreSqlDialect | BigQueryDialect | SnowflakeDialect | RedshiftSqlDialect | MsSqlDialect)
5259+
{
52585260
Some(self.parse_table_and_joins()?)
52595261
} else {
52605262
None

Diff for: tests/sqlparser_common.rs

+91-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use sqlparser::ast::SelectItem::UnnamedExpr;
2424
use sqlparser::ast::*;
2525
use sqlparser::dialect::{
2626
AnsiDialect, BigQueryDialect, ClickHouseDialect, GenericDialect, HiveDialect, MsSqlDialect,
27-
MySqlDialect, PostgreSqlDialect, SQLiteDialect, SnowflakeDialect,
27+
MySqlDialect, PostgreSqlDialect, RedshiftSqlDialect, SQLiteDialect, SnowflakeDialect,
2828
};
2929
use sqlparser::keywords::ALL_KEYWORDS;
3030
use sqlparser::parser::{Parser, ParserError};
@@ -186,6 +186,96 @@ fn parse_update() {
186186
);
187187
}
188188

189+
#[test]
190+
fn parse_update_set_from() {
191+
let sql = "UPDATE t1 SET name = t2.name FROM (SELECT name, id FROM t1 GROUP BY id) AS t2 WHERE t1.id = t2.id";
192+
let dialects = TestedDialects {
193+
dialects: vec![
194+
Box::new(GenericDialect {}),
195+
Box::new(PostgreSqlDialect {}),
196+
Box::new(BigQueryDialect {}),
197+
Box::new(SnowflakeDialect {}),
198+
Box::new(RedshiftSqlDialect {}),
199+
Box::new(MsSqlDialect {}),
200+
],
201+
};
202+
let stmt = dialects.verified_stmt(sql);
203+
assert_eq!(
204+
stmt,
205+
Statement::Update {
206+
table: TableWithJoins {
207+
relation: TableFactor::Table {
208+
name: ObjectName(vec![Ident::new("t1")]),
209+
alias: None,
210+
args: None,
211+
with_hints: vec![],
212+
},
213+
joins: vec![],
214+
},
215+
assignments: vec![Assignment {
216+
id: vec![Ident::new("name")],
217+
value: Expr::CompoundIdentifier(vec![Ident::new("t2"), Ident::new("name")])
218+
}],
219+
from: Some(TableWithJoins {
220+
relation: TableFactor::Derived {
221+
lateral: false,
222+
subquery: Box::new(Query {
223+
with: None,
224+
body: Box::new(SetExpr::Select(Box::new(Select {
225+
distinct: false,
226+
top: None,
227+
projection: vec![
228+
SelectItem::UnnamedExpr(Expr::Identifier(Ident::new("name"))),
229+
SelectItem::UnnamedExpr(Expr::Identifier(Ident::new("id"))),
230+
],
231+
into: None,
232+
from: vec![TableWithJoins {
233+
relation: TableFactor::Table {
234+
name: ObjectName(vec![Ident::new("t1")]),
235+
alias: None,
236+
args: None,
237+
with_hints: vec![],
238+
},
239+
joins: vec![],
240+
}],
241+
lateral_views: vec![],
242+
selection: None,
243+
group_by: vec![Expr::Identifier(Ident::new("id"))],
244+
cluster_by: vec![],
245+
distribute_by: vec![],
246+
sort_by: vec![],
247+
having: None,
248+
qualify: None
249+
}))),
250+
order_by: vec![],
251+
limit: None,
252+
offset: None,
253+
fetch: None,
254+
lock: None,
255+
}),
256+
alias: Some(TableAlias {
257+
name: Ident::new("t2"),
258+
columns: vec![],
259+
})
260+
},
261+
joins: vec![],
262+
}),
263+
selection: Some(Expr::BinaryOp {
264+
left: Box::new(Expr::CompoundIdentifier(vec![
265+
Ident::new("t1"),
266+
Ident::new("id")
267+
])),
268+
op: BinaryOperator::Eq,
269+
right: Box::new(Expr::CompoundIdentifier(vec![
270+
Ident::new("t2"),
271+
Ident::new("id")
272+
])),
273+
}),
274+
returning: None,
275+
}
276+
);
277+
}
278+
189279
#[test]
190280
fn parse_update_with_table_alias() {
191281
let sql = "UPDATE users AS u SET u.username = 'new_user' WHERE u.username = 'old_user'";

Diff for: tests/sqlparser_postgres.rs

-80
Original file line numberDiff line numberDiff line change
@@ -489,86 +489,6 @@ PHP ₱ USD $
489489
//assert_eq!(sql, ast.to_string());
490490
}
491491

492-
#[test]
493-
fn parse_update_set_from() {
494-
let sql = "UPDATE t1 SET name = t2.name FROM (SELECT name, id FROM t1 GROUP BY id) AS t2 WHERE t1.id = t2.id";
495-
let stmt = pg().verified_stmt(sql);
496-
assert_eq!(
497-
stmt,
498-
Statement::Update {
499-
table: TableWithJoins {
500-
relation: TableFactor::Table {
501-
name: ObjectName(vec![Ident::new("t1")]),
502-
alias: None,
503-
args: None,
504-
with_hints: vec![],
505-
},
506-
joins: vec![],
507-
},
508-
assignments: vec![Assignment {
509-
id: vec![Ident::new("name")],
510-
value: Expr::CompoundIdentifier(vec![Ident::new("t2"), Ident::new("name")])
511-
}],
512-
from: Some(TableWithJoins {
513-
relation: TableFactor::Derived {
514-
lateral: false,
515-
subquery: Box::new(Query {
516-
with: None,
517-
body: Box::new(SetExpr::Select(Box::new(Select {
518-
distinct: false,
519-
top: None,
520-
projection: vec![
521-
SelectItem::UnnamedExpr(Expr::Identifier(Ident::new("name"))),
522-
SelectItem::UnnamedExpr(Expr::Identifier(Ident::new("id"))),
523-
],
524-
into: None,
525-
from: vec![TableWithJoins {
526-
relation: TableFactor::Table {
527-
name: ObjectName(vec![Ident::new("t1")]),
528-
alias: None,
529-
args: None,
530-
with_hints: vec![],
531-
},
532-
joins: vec![],
533-
}],
534-
lateral_views: vec![],
535-
selection: None,
536-
group_by: vec![Expr::Identifier(Ident::new("id"))],
537-
cluster_by: vec![],
538-
distribute_by: vec![],
539-
sort_by: vec![],
540-
having: None,
541-
qualify: None
542-
}))),
543-
order_by: vec![],
544-
limit: None,
545-
offset: None,
546-
fetch: None,
547-
lock: None,
548-
}),
549-
alias: Some(TableAlias {
550-
name: Ident::new("t2"),
551-
columns: vec![],
552-
})
553-
},
554-
joins: vec![],
555-
}),
556-
selection: Some(Expr::BinaryOp {
557-
left: Box::new(Expr::CompoundIdentifier(vec![
558-
Ident::new("t1"),
559-
Ident::new("id")
560-
])),
561-
op: BinaryOperator::Eq,
562-
right: Box::new(Expr::CompoundIdentifier(vec![
563-
Ident::new("t2"),
564-
Ident::new("id")
565-
])),
566-
}),
567-
returning: None,
568-
}
569-
);
570-
}
571-
572492
#[test]
573493
fn test_copy_from() {
574494
let stmt = pg().verified_stmt("COPY users FROM 'data.csv'");

0 commit comments

Comments
 (0)