diff --git a/src/ast/mod.rs b/src/ast/mod.rs index c316aa6b3..6f5c4b84e 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -828,7 +828,9 @@ pub enum Statement { /// DELETE Delete { /// FROM - table_name: ObjectName, + table_name: TableFactor, + /// USING (Snowflake, Postgres) + using: Option, /// WHERE selection: Option, }, @@ -1395,9 +1397,13 @@ impl fmt::Display for Statement { } Statement::Delete { table_name, + using, selection, } => { write!(f, "DELETE FROM {}", table_name)?; + if let Some(using) = using { + write!(f, " USING {}", using)?; + } if let Some(selection) = selection { write!(f, " WHERE {}", selection)?; } diff --git a/src/parser.rs b/src/parser.rs index 325d90c47..31ada3fc8 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -3132,7 +3132,12 @@ impl<'a> Parser<'a> { pub fn parse_delete(&mut self) -> Result { self.expect_keyword(Keyword::FROM)?; - let table_name = self.parse_object_name()?; + let table_name = self.parse_table_factor()?; + let using = if self.parse_keyword(Keyword::USING) { + Some(self.parse_table_factor()?) + } else { + None + }; let selection = if self.parse_keyword(Keyword::WHERE) { Some(self.parse_expr()?) } else { @@ -3141,6 +3146,7 @@ impl<'a> Parser<'a> { Ok(Statement::Delete { table_name, + using, selection, }) } diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index bb2c4d018..18f3ce15d 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -253,7 +253,12 @@ fn parse_delete_statement() { match verified_stmt(sql) { Statement::Delete { table_name, .. } => { assert_eq!( - ObjectName(vec![Ident::with_quote('"', "table")]), + TableFactor::Table { + name: ObjectName(vec![Ident::with_quote('"', "table")]), + alias: None, + args: None, + with_hints: vec![] + }, table_name ); } @@ -269,11 +274,20 @@ fn parse_where_delete_statement() { match verified_stmt(sql) { Statement::Delete { table_name, + using, selection, - .. } => { - assert_eq!(ObjectName(vec![Ident::new("foo")]), table_name); + assert_eq!( + TableFactor::Table { + name: ObjectName(vec![Ident::new("foo")]), + alias: None, + args: None, + with_hints: vec![] + }, + table_name, + ); + assert_eq!(None, using); assert_eq!( Expr::BinaryOp { left: Box::new(Expr::Identifier(Ident::new("name"))), @@ -287,6 +301,61 @@ fn parse_where_delete_statement() { } } +#[test] +fn parse_where_delete_with_alias_statement() { + use self::BinaryOperator::*; + + let sql = "DELETE FROM basket AS a USING basket AS b WHERE a.id < b.id"; + match verified_stmt(sql) { + Statement::Delete { + table_name, + using, + selection, + } => { + assert_eq!( + TableFactor::Table { + name: ObjectName(vec![Ident::new("basket")]), + alias: Some(TableAlias { + name: Ident::new("a"), + columns: vec![] + }), + args: None, + with_hints: vec![] + }, + table_name, + ); + + assert_eq!( + Some(TableFactor::Table { + name: ObjectName(vec![Ident::new("basket")]), + alias: Some(TableAlias { + name: Ident::new("b"), + columns: vec![] + }), + args: None, + with_hints: vec![] + }), + using + ); + assert_eq!( + Expr::BinaryOp { + left: Box::new(Expr::CompoundIdentifier(vec![ + Ident::new("a"), + Ident::new("id") + ])), + op: Lt, + right: Box::new(Expr::CompoundIdentifier(vec![ + Ident::new("b"), + Ident::new("id") + ])), + }, + selection.unwrap(), + ); + } + _ => unreachable!(), + } +} + #[test] fn parse_top_level() { verified_stmt("SELECT 1");