From d443595a0f867d17d416767704aa214e8fa47390 Mon Sep 17 00:00:00 2001 From: unvalley Date: Fri, 28 Oct 2022 23:25:55 +0900 Subject: [PATCH 1/3] Apply UPDATE SET FROM statement for some dialects --- src/parser.rs | 4 +- tests/sqlparser_common.rs | 89 ++++++++++++++++++++++++++++++++++++- tests/sqlparser_postgres.rs | 79 -------------------------------- 3 files changed, 91 insertions(+), 81 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index 108427889..cae4236f3 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -5075,7 +5075,9 @@ impl<'a> Parser<'a> { let table = self.parse_table_and_joins()?; self.expect_keyword(Keyword::SET)?; let assignments = self.parse_comma_separated(Parser::parse_assignment)?; - let from = if self.parse_keyword(Keyword::FROM) && dialect_of!(self is PostgreSqlDialect) { + let from = if self.parse_keyword(Keyword::FROM) + && dialect_of!(self is PostgreSqlDialect | BigQueryDialect | SnowflakeDialect | RedshiftSqlDialect | MsSqlDialect) + { Some(self.parse_table_and_joins()?) } else { None diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index bae310ef0..338ec8bee 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -26,7 +26,7 @@ use sqlparser::ast::SelectItem::UnnamedExpr; use sqlparser::ast::*; use sqlparser::dialect::{ AnsiDialect, BigQueryDialect, ClickHouseDialect, GenericDialect, HiveDialect, MsSqlDialect, - PostgreSqlDialect, SQLiteDialect, SnowflakeDialect, + PostgreSqlDialect, RedshiftSqlDialect, SQLiteDialect, SnowflakeDialect, }; use sqlparser::keywords::ALL_KEYWORDS; use sqlparser::parser::{Parser, ParserError}; @@ -186,6 +186,93 @@ fn parse_update() { ); } +#[test] +fn parse_update_set_from() { + let sql = "UPDATE t1 SET name = t2.name FROM (SELECT name, id FROM t1 GROUP BY id) AS t2 WHERE t1.id = t2.id"; + let dialects = TestedDialects { + dialects: vec![ + Box::new(PostgreSqlDialect {}), + Box::new(BigQueryDialect {}), + Box::new(RedshiftSqlDialect {}), + Box::new(MsSqlDialect {}), + ], + }; + let stmt = dialects.verified_stmt(sql); + assert_eq!( + stmt, + Statement::Update { + table: TableWithJoins { + relation: TableFactor::Table { + name: ObjectName(vec![Ident::new("t1")]), + alias: None, + args: None, + with_hints: vec![], + }, + joins: vec![], + }, + assignments: vec![Assignment { + id: vec![Ident::new("name")], + value: Expr::CompoundIdentifier(vec![Ident::new("t2"), Ident::new("name")]) + }], + from: Some(TableWithJoins { + relation: TableFactor::Derived { + lateral: false, + subquery: Box::new(Query { + with: None, + body: Box::new(SetExpr::Select(Box::new(Select { + distinct: false, + top: None, + projection: vec![ + SelectItem::UnnamedExpr(Expr::Identifier(Ident::new("name"))), + SelectItem::UnnamedExpr(Expr::Identifier(Ident::new("id"))), + ], + into: None, + from: vec![TableWithJoins { + relation: TableFactor::Table { + name: ObjectName(vec![Ident::new("t1")]), + alias: None, + args: None, + with_hints: vec![], + }, + joins: vec![], + }], + lateral_views: vec![], + selection: None, + group_by: vec![Expr::Identifier(Ident::new("id"))], + cluster_by: vec![], + distribute_by: vec![], + sort_by: vec![], + having: None, + qualify: None + }))), + order_by: vec![], + limit: None, + offset: None, + fetch: None, + lock: None, + }), + alias: Some(TableAlias { + name: Ident::new("t2"), + columns: vec![], + }) + }, + joins: vec![], + }), + selection: Some(Expr::BinaryOp { + left: Box::new(Expr::CompoundIdentifier(vec![ + Ident::new("t1"), + Ident::new("id") + ])), + op: BinaryOperator::Eq, + right: Box::new(Expr::CompoundIdentifier(vec![ + Ident::new("t2"), + Ident::new("id") + ])), + }), + } + ); +} + #[test] fn parse_update_with_table_alias() { let sql = "UPDATE users AS u SET u.username = 'new_user' WHERE u.username = 'old_user'"; diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index c5d4bd0fc..ee94c6a12 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -446,85 +446,6 @@ PHP ₱ USD $ //assert_eq!(sql, ast.to_string()); } -#[test] -fn parse_update_set_from() { - let sql = "UPDATE t1 SET name = t2.name FROM (SELECT name, id FROM t1 GROUP BY id) AS t2 WHERE t1.id = t2.id"; - let stmt = pg().verified_stmt(sql); - assert_eq!( - stmt, - Statement::Update { - table: TableWithJoins { - relation: TableFactor::Table { - name: ObjectName(vec![Ident::new("t1")]), - alias: None, - args: None, - with_hints: vec![], - }, - joins: vec![], - }, - assignments: vec![Assignment { - id: vec![Ident::new("name")], - value: Expr::CompoundIdentifier(vec![Ident::new("t2"), Ident::new("name")]) - }], - from: Some(TableWithJoins { - relation: TableFactor::Derived { - lateral: false, - subquery: Box::new(Query { - with: None, - body: Box::new(SetExpr::Select(Box::new(Select { - distinct: false, - top: None, - projection: vec![ - SelectItem::UnnamedExpr(Expr::Identifier(Ident::new("name"))), - SelectItem::UnnamedExpr(Expr::Identifier(Ident::new("id"))), - ], - into: None, - from: vec![TableWithJoins { - relation: TableFactor::Table { - name: ObjectName(vec![Ident::new("t1")]), - alias: None, - args: None, - with_hints: vec![], - }, - joins: vec![], - }], - lateral_views: vec![], - selection: None, - group_by: vec![Expr::Identifier(Ident::new("id"))], - cluster_by: vec![], - distribute_by: vec![], - sort_by: vec![], - having: None, - qualify: None - }))), - order_by: vec![], - limit: None, - offset: None, - fetch: None, - lock: None, - }), - alias: Some(TableAlias { - name: Ident::new("t2"), - columns: vec![], - }) - }, - joins: vec![], - }), - selection: Some(Expr::BinaryOp { - left: Box::new(Expr::CompoundIdentifier(vec![ - Ident::new("t1"), - Ident::new("id") - ])), - op: BinaryOperator::Eq, - right: Box::new(Expr::CompoundIdentifier(vec![ - Ident::new("t2"), - Ident::new("id") - ])), - }), - } - ); -} - #[test] fn test_copy_from() { let stmt = pg().verified_stmt("COPY users FROM 'data.csv'"); From d38e3be68a1941c244ba222da527b23affeca9de Mon Sep 17 00:00:00 2001 From: unvalley Date: Sun, 30 Oct 2022 13:53:03 +0900 Subject: [PATCH 2/3] Add GenericDialect to support --- src/parser.rs | 2 +- tests/sqlparser_common.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/parser.rs b/src/parser.rs index cae4236f3..eb46a74f2 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -5076,7 +5076,7 @@ impl<'a> Parser<'a> { self.expect_keyword(Keyword::SET)?; let assignments = self.parse_comma_separated(Parser::parse_assignment)?; let from = if self.parse_keyword(Keyword::FROM) - && dialect_of!(self is PostgreSqlDialect | BigQueryDialect | SnowflakeDialect | RedshiftSqlDialect | MsSqlDialect) + && dialect_of!(self is GenericDialect | PostgreSqlDialect | BigQueryDialect | SnowflakeDialect | RedshiftSqlDialect | MsSqlDialect) { Some(self.parse_table_and_joins()?) } else { diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 338ec8bee..bbfa87a0c 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -191,6 +191,7 @@ fn parse_update_set_from() { let sql = "UPDATE t1 SET name = t2.name FROM (SELECT name, id FROM t1 GROUP BY id) AS t2 WHERE t1.id = t2.id"; let dialects = TestedDialects { dialects: vec![ + Box::new(GenericDialect {}), Box::new(PostgreSqlDialect {}), Box::new(BigQueryDialect {}), Box::new(RedshiftSqlDialect {}), From 413195b74a81ba664a88a71a228ea53455f8028f Mon Sep 17 00:00:00 2001 From: unvalley Date: Mon, 31 Oct 2022 00:27:01 +0900 Subject: [PATCH 3/3] Test SnowflakeDialect --- tests/sqlparser_common.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index bbfa87a0c..3e6f5831e 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -194,6 +194,7 @@ fn parse_update_set_from() { Box::new(GenericDialect {}), Box::new(PostgreSqlDialect {}), Box::new(BigQueryDialect {}), + Box::new(SnowflakeDialect {}), Box::new(RedshiftSqlDialect {}), Box::new(MsSqlDialect {}), ],