mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-07-24 08:43:43 +00:00
Support multiple-table DELETE syntax (#855)
This commit is contained in:
parent
5ecf633e31
commit
f72e2ec382
3 changed files with 131 additions and 26 deletions
|
@ -1229,10 +1229,12 @@ pub enum Statement {
|
||||||
},
|
},
|
||||||
/// DELETE
|
/// DELETE
|
||||||
Delete {
|
Delete {
|
||||||
|
/// Multi tables delete are supported in mysql
|
||||||
|
tables: Vec<ObjectName>,
|
||||||
/// FROM
|
/// FROM
|
||||||
table_name: TableFactor,
|
from: Vec<TableWithJoins>,
|
||||||
/// USING (Snowflake, Postgres)
|
/// USING (Snowflake, Postgres, MySQL)
|
||||||
using: Option<TableFactor>,
|
using: Option<Vec<TableWithJoins>>,
|
||||||
/// WHERE
|
/// WHERE
|
||||||
selection: Option<Expr>,
|
selection: Option<Expr>,
|
||||||
/// RETURNING
|
/// RETURNING
|
||||||
|
@ -1982,14 +1984,19 @@ impl fmt::Display for Statement {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Statement::Delete {
|
Statement::Delete {
|
||||||
table_name,
|
tables,
|
||||||
|
from,
|
||||||
using,
|
using,
|
||||||
selection,
|
selection,
|
||||||
returning,
|
returning,
|
||||||
} => {
|
} => {
|
||||||
write!(f, "DELETE FROM {table_name}")?;
|
write!(f, "DELETE ")?;
|
||||||
|
if !tables.is_empty() {
|
||||||
|
write!(f, "{} ", display_comma_separated(tables))?;
|
||||||
|
}
|
||||||
|
write!(f, "FROM {}", display_comma_separated(from))?;
|
||||||
if let Some(using) = using {
|
if let Some(using) = using {
|
||||||
write!(f, " USING {using}")?;
|
write!(f, " USING {}", display_comma_separated(using))?;
|
||||||
}
|
}
|
||||||
if let Some(selection) = selection {
|
if let Some(selection) = selection {
|
||||||
write!(f, " WHERE {selection}")?;
|
write!(f, " WHERE {selection}")?;
|
||||||
|
|
|
@ -4813,10 +4813,17 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_delete(&mut self) -> Result<Statement, ParserError> {
|
pub fn parse_delete(&mut self) -> Result<Statement, ParserError> {
|
||||||
self.expect_keyword(Keyword::FROM)?;
|
let tables = if !self.parse_keyword(Keyword::FROM) {
|
||||||
let table_name = self.parse_table_factor()?;
|
let tables = self.parse_comma_separated(Parser::parse_object_name)?;
|
||||||
|
self.expect_keyword(Keyword::FROM)?;
|
||||||
|
tables
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
};
|
||||||
|
|
||||||
|
let from = self.parse_comma_separated(Parser::parse_table_and_joins)?;
|
||||||
let using = if self.parse_keyword(Keyword::USING) {
|
let using = if self.parse_keyword(Keyword::USING) {
|
||||||
Some(self.parse_table_factor()?)
|
Some(self.parse_comma_separated(Parser::parse_table_and_joins)?)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
@ -4833,7 +4840,8 @@ impl<'a> Parser<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Statement::Delete {
|
Ok(Statement::Delete {
|
||||||
table_name,
|
tables,
|
||||||
|
from,
|
||||||
using,
|
using,
|
||||||
selection,
|
selection,
|
||||||
returning,
|
returning,
|
||||||
|
|
|
@ -385,7 +385,7 @@ fn parse_no_table_name() {
|
||||||
fn parse_delete_statement() {
|
fn parse_delete_statement() {
|
||||||
let sql = "DELETE FROM \"table\"";
|
let sql = "DELETE FROM \"table\"";
|
||||||
match verified_stmt(sql) {
|
match verified_stmt(sql) {
|
||||||
Statement::Delete { table_name, .. } => {
|
Statement::Delete { from, .. } => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
TableFactor::Table {
|
TableFactor::Table {
|
||||||
name: ObjectName(vec![Ident::with_quote('"', "table")]),
|
name: ObjectName(vec![Ident::with_quote('"', "table")]),
|
||||||
|
@ -393,7 +393,93 @@ fn parse_delete_statement() {
|
||||||
args: None,
|
args: None,
|
||||||
with_hints: vec![],
|
with_hints: vec![],
|
||||||
},
|
},
|
||||||
table_name
|
from[0].relation
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_delete_statement_for_multi_tables() {
|
||||||
|
let sql = "DELETE schema1.table1, schema2.table2 FROM schema1.table1 JOIN schema2.table2 ON schema2.table2.col1 = schema1.table1.col1 WHERE schema2.table2.col2 = 1";
|
||||||
|
match verified_stmt(sql) {
|
||||||
|
Statement::Delete { tables, from, .. } => {
|
||||||
|
assert_eq!(
|
||||||
|
ObjectName(vec![Ident::new("schema1"), Ident::new("table1")]),
|
||||||
|
tables[0]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
ObjectName(vec![Ident::new("schema2"), Ident::new("table2")]),
|
||||||
|
tables[1]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
TableFactor::Table {
|
||||||
|
name: ObjectName(vec![Ident::new("schema1"), Ident::new("table1")]),
|
||||||
|
alias: None,
|
||||||
|
args: None,
|
||||||
|
with_hints: vec![],
|
||||||
|
},
|
||||||
|
from[0].relation
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
TableFactor::Table {
|
||||||
|
name: ObjectName(vec![Ident::new("schema2"), Ident::new("table2")]),
|
||||||
|
alias: None,
|
||||||
|
args: None,
|
||||||
|
with_hints: vec![],
|
||||||
|
},
|
||||||
|
from[0].joins[0].relation
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_delete_statement_for_multi_tables_with_using() {
|
||||||
|
let sql = "DELETE FROM schema1.table1, schema2.table2 USING schema1.table1 JOIN schema2.table2 ON schema2.table2.pk = schema1.table1.col1 WHERE schema2.table2.col2 = 1";
|
||||||
|
match verified_stmt(sql) {
|
||||||
|
Statement::Delete {
|
||||||
|
from,
|
||||||
|
using: Some(using),
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
assert_eq!(
|
||||||
|
TableFactor::Table {
|
||||||
|
name: ObjectName(vec![Ident::new("schema1"), Ident::new("table1")]),
|
||||||
|
alias: None,
|
||||||
|
args: None,
|
||||||
|
with_hints: vec![],
|
||||||
|
},
|
||||||
|
from[0].relation
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
TableFactor::Table {
|
||||||
|
name: ObjectName(vec![Ident::new("schema2"), Ident::new("table2")]),
|
||||||
|
alias: None,
|
||||||
|
args: None,
|
||||||
|
with_hints: vec![],
|
||||||
|
},
|
||||||
|
from[1].relation
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
TableFactor::Table {
|
||||||
|
name: ObjectName(vec![Ident::new("schema1"), Ident::new("table1")]),
|
||||||
|
alias: None,
|
||||||
|
args: None,
|
||||||
|
with_hints: vec![],
|
||||||
|
},
|
||||||
|
using[0].relation
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
TableFactor::Table {
|
||||||
|
name: ObjectName(vec![Ident::new("schema2"), Ident::new("table2")]),
|
||||||
|
alias: None,
|
||||||
|
args: None,
|
||||||
|
with_hints: vec![],
|
||||||
|
},
|
||||||
|
using[0].joins[0].relation
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
@ -407,7 +493,8 @@ fn parse_where_delete_statement() {
|
||||||
let sql = "DELETE FROM foo WHERE name = 5";
|
let sql = "DELETE FROM foo WHERE name = 5";
|
||||||
match verified_stmt(sql) {
|
match verified_stmt(sql) {
|
||||||
Statement::Delete {
|
Statement::Delete {
|
||||||
table_name,
|
tables: _,
|
||||||
|
from,
|
||||||
using,
|
using,
|
||||||
selection,
|
selection,
|
||||||
returning,
|
returning,
|
||||||
|
@ -419,7 +506,7 @@ fn parse_where_delete_statement() {
|
||||||
args: None,
|
args: None,
|
||||||
with_hints: vec![],
|
with_hints: vec![],
|
||||||
},
|
},
|
||||||
table_name,
|
from[0].relation,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(None, using);
|
assert_eq!(None, using);
|
||||||
|
@ -444,7 +531,8 @@ fn parse_where_delete_with_alias_statement() {
|
||||||
let sql = "DELETE FROM basket AS a USING basket AS b WHERE a.id < b.id";
|
let sql = "DELETE FROM basket AS a USING basket AS b WHERE a.id < b.id";
|
||||||
match verified_stmt(sql) {
|
match verified_stmt(sql) {
|
||||||
Statement::Delete {
|
Statement::Delete {
|
||||||
table_name,
|
tables: _,
|
||||||
|
from,
|
||||||
using,
|
using,
|
||||||
selection,
|
selection,
|
||||||
returning,
|
returning,
|
||||||
|
@ -459,19 +547,21 @@ fn parse_where_delete_with_alias_statement() {
|
||||||
args: None,
|
args: None,
|
||||||
with_hints: vec![],
|
with_hints: vec![],
|
||||||
},
|
},
|
||||||
table_name,
|
from[0].relation,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Some(TableFactor::Table {
|
Some(vec![TableWithJoins {
|
||||||
name: ObjectName(vec![Ident::new("basket")]),
|
relation: TableFactor::Table {
|
||||||
alias: Some(TableAlias {
|
name: ObjectName(vec![Ident::new("basket")]),
|
||||||
name: Ident::new("b"),
|
alias: Some(TableAlias {
|
||||||
columns: vec![],
|
name: Ident::new("b"),
|
||||||
}),
|
columns: vec![],
|
||||||
args: None,
|
}),
|
||||||
with_hints: vec![],
|
args: None,
|
||||||
}),
|
with_hints: vec![],
|
||||||
|
},
|
||||||
|
joins: vec![],
|
||||||
|
}]),
|
||||||
using
|
using
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue