diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 4a3e346f6..d9052916d 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -1058,9 +1058,7 @@ pub enum Statement { // Specifies the table to merge table: TableFactor, // Specifies the table or subquery to join with the target table - source: Box, - // Specifies alias to the table that is joined with target table - alias: Option, + source: TableFactor, // Specifies the expression on which to join the target table and source on: Box, // Specifies the actions to perform when values match or do not match. @@ -1772,7 +1770,6 @@ impl fmt::Display for Statement { into, table, source, - alias, on, clauses, } => { @@ -1781,9 +1778,6 @@ impl fmt::Display for Statement { "MERGE{int} {table} USING {source} ", int = if *into { " INTO" } else { "" } )?; - if let Some(a) = alias { - write!(f, "as {} ", a)?; - }; write!(f, "ON {} ", on)?; write!(f, "{}", display_separated(clauses, " ")) } diff --git a/src/parser.rs b/src/parser.rs index c4b13e91d..5ee3d5cb6 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -4288,8 +4288,7 @@ impl<'a> Parser<'a> { let table = self.parse_table_factor()?; self.expect_keyword(Keyword::USING)?; - let source = self.parse_query_body(0)?; - let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?; + let source = self.parse_table_factor()?; self.expect_keyword(Keyword::ON)?; let on = self.parse_expr()?; let clauses = self.parse_merge_clauses()?; @@ -4297,8 +4296,7 @@ impl<'a> Parser<'a> { Ok(Statement::Merge { into, table, - source: Box::new(source), - alias, + source, on: Box::new(on), clauses, }) diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index b70f592f6..bed6bbcde 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -4353,15 +4353,14 @@ fn test_revoke() { #[test] fn parse_merge() { - let sql = "MERGE INTO s.bar AS dest USING (SELECT * FROM s.foo) as stg ON dest.D = stg.D AND dest.E = stg.E WHEN NOT MATCHED THEN INSERT (A, B, C) VALUES (stg.A, stg.B, stg.C) WHEN MATCHED AND dest.A = 'a' THEN UPDATE SET dest.F = stg.F, dest.G = stg.G WHEN MATCHED THEN DELETE"; - let sql_no_into = "MERGE s.bar AS dest USING (SELECT * FROM s.foo) as stg ON dest.D = stg.D AND dest.E = stg.E WHEN NOT MATCHED THEN INSERT (A, B, C) VALUES (stg.A, stg.B, stg.C) WHEN MATCHED AND dest.A = 'a' THEN UPDATE SET dest.F = stg.F, dest.G = stg.G WHEN MATCHED THEN DELETE"; + let sql = "MERGE INTO s.bar AS dest USING (SELECT * FROM s.foo) AS stg ON dest.D = stg.D AND dest.E = stg.E WHEN NOT MATCHED THEN INSERT (A, B, C) VALUES (stg.A, stg.B, stg.C) WHEN MATCHED AND dest.A = 'a' THEN UPDATE SET dest.F = stg.F, dest.G = stg.G WHEN MATCHED THEN DELETE"; + let sql_no_into = "MERGE s.bar AS dest USING (SELECT * FROM s.foo) AS stg ON dest.D = stg.D AND dest.E = stg.E WHEN NOT MATCHED THEN INSERT (A, B, C) VALUES (stg.A, stg.B, stg.C) WHEN MATCHED AND dest.A = 'a' THEN UPDATE SET dest.F = stg.F, dest.G = stg.G WHEN MATCHED THEN DELETE"; match (verified_stmt(sql), verified_stmt(sql_no_into)) { ( Statement::Merge { into, table, source, - alias, on, clauses, }, @@ -4369,7 +4368,6 @@ fn parse_merge() { into: no_into, table: table_no_into, source: source_no_into, - alias: alias_no_into, on: on_no_into, clauses: clauses_no_into, }, @@ -4393,49 +4391,50 @@ fn parse_merge() { assert_eq!( source, - Box::new(SetExpr::Query(Box::new(Query { - with: None, - body: SetExpr::Select(Box::new(Select { - distinct: false, - top: None, - projection: vec![SelectItem::Wildcard], - into: None, - from: vec![TableWithJoins { - relation: TableFactor::Table { - name: ObjectName(vec![Ident::new("s"), Ident::new("foo")]), - alias: None, - args: vec![], - with_hints: vec![], - }, - joins: vec![] - }], - lateral_views: vec![], - selection: None, - group_by: vec![], - cluster_by: vec![], - distribute_by: vec![], - sort_by: vec![], - having: None, - qualify: None - })), - order_by: vec![], - limit: None, - offset: None, - fetch: None, - lock: None - }))) + TableFactor::Derived { + lateral: false, + subquery: Box::new(Query { + with: None, + body: SetExpr::Select(Box::new(Select { + distinct: false, + top: None, + projection: vec![SelectItem::Wildcard], + into: None, + from: vec![TableWithJoins { + relation: TableFactor::Table { + name: ObjectName(vec![Ident::new("s"), Ident::new("foo")]), + alias: None, + args: vec![], + with_hints: vec![] + }, + joins: vec![] + }], + lateral_views: vec![], + selection: None, + group_by: vec![], + 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 { + value: "stg".to_string(), + quote_style: None + }, + columns: vec![] + }) + } ); assert_eq!(source, source_no_into); - assert_eq!( - alias, - Some(TableAlias { - name: Ident::new("stg"), - columns: vec![] - }) - ); - assert_eq!(alias, alias_no_into); - assert_eq!( on, Box::new(Expr::BinaryOp { @@ -4515,6 +4514,18 @@ fn parse_merge() { } } +#[test] +fn test_merge_into_using_table() { + let sql = "MERGE INTO target_table USING source_table \ + ON target_table.id = source_table.oooid \ + WHEN MATCHED THEN \ + UPDATE SET target_table.description = source_table.description \ + WHEN NOT MATCHED THEN \ + INSERT (ID, description) VALUES (source_table.id, source_table.description)"; + + verified_stmt(sql); +} + #[test] fn test_lock() { let sql = "SELECT * FROM student WHERE id = '1' FOR UPDATE";