Skip to content

Commit cd2108b

Browse files
lovasoaayman-sigma
authored andcommitted
add support for with clauses (CTEs) in delete statements (apache#1764)
1 parent dfabc56 commit cd2108b

File tree

4 files changed

+52
-0
lines changed

4 files changed

+52
-0
lines changed

src/ast/query.rs

+2
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ pub enum SetExpr {
156156
Values(Values),
157157
Insert(Statement),
158158
Update(Statement),
159+
Delete(Statement),
159160
Table(Box<Table>),
160161
}
161162

@@ -178,6 +179,7 @@ impl fmt::Display for SetExpr {
178179
SetExpr::Values(v) => write!(f, "{v}"),
179180
SetExpr::Insert(v) => write!(f, "{v}"),
180181
SetExpr::Update(v) => write!(f, "{v}"),
182+
SetExpr::Delete(v) => write!(f, "{v}"),
181183
SetExpr::Table(t) => write!(f, "{t}"),
182184
SetExpr::SetOperation {
183185
left,

src/ast/spans.rs

+1
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ impl Spanned for SetExpr {
191191
SetExpr::Insert(statement) => statement.span(),
192192
SetExpr::Table(_) => Span::empty(),
193193
SetExpr::Update(statement) => statement.span(),
194+
SetExpr::Delete(statement) => statement.span(),
194195
}
195196
}
196197
}

src/parser/mod.rs

+22
Original file line numberDiff line numberDiff line change
@@ -10060,6 +10060,13 @@ impl<'a> Parser<'a> {
1006010060
Ok(parent_type(inside_type.into()))
1006110061
}
1006210062

10063+
/// Parse a DELETE statement, returning a `Box`ed SetExpr
10064+
///
10065+
/// This is used to reduce the size of the stack frames in debug builds
10066+
fn parse_delete_setexpr_boxed(&mut self) -> Result<Box<SetExpr>, ParserError> {
10067+
Ok(Box::new(SetExpr::Delete(self.parse_delete()?)))
10068+
}
10069+
1006310070
pub fn parse_delete(&mut self) -> Result<Statement, ParserError> {
1006410071
let (tables, with_from_keyword) = if !self.parse_keyword(Keyword::FROM) {
1006510072
// `FROM` keyword is optional in BigQuery SQL.
@@ -10259,6 +10266,21 @@ impl<'a> Parser<'a> {
1025910266
format_clause: None,
1026010267
}
1026110268
.into())
10269+
} else if self.parse_keyword(Keyword::DELETE) {
10270+
Ok(Query {
10271+
with,
10272+
body: self.parse_delete_setexpr_boxed()?,
10273+
limit: None,
10274+
limit_by: vec![],
10275+
order_by: None,
10276+
offset: None,
10277+
fetch: None,
10278+
locks: vec![],
10279+
for_clause: None,
10280+
settings: None,
10281+
format_clause: None,
10282+
}
10283+
.into())
1026210284
} else {
1026310285
let body = self.parse_query_body(self.dialect.prec_unknown())?;
1026410286

tests/sqlparser_common.rs

+27
Original file line numberDiff line numberDiff line change
@@ -7384,6 +7384,33 @@ fn parse_recursive_cte() {
73847384
assert_eq!(with.cte_tables.first().unwrap(), &expected);
73857385
}
73867386

7387+
#[test]
7388+
fn parse_cte_in_data_modification_statements() {
7389+
match verified_stmt("WITH x AS (SELECT 1) UPDATE t SET bar = (SELECT * FROM x)") {
7390+
Statement::Query(query) => {
7391+
assert_eq!(query.with.unwrap().to_string(), "WITH x AS (SELECT 1)");
7392+
assert!(matches!(*query.body, SetExpr::Update(_)));
7393+
}
7394+
other => panic!("Expected: UPDATE, got: {:?}", other),
7395+
}
7396+
7397+
match verified_stmt("WITH t (x) AS (SELECT 9) DELETE FROM q WHERE id IN (SELECT x FROM t)") {
7398+
Statement::Query(query) => {
7399+
assert_eq!(query.with.unwrap().to_string(), "WITH t (x) AS (SELECT 9)");
7400+
assert!(matches!(*query.body, SetExpr::Delete(_)));
7401+
}
7402+
other => panic!("Expected: DELETE, got: {:?}", other),
7403+
}
7404+
7405+
match verified_stmt("WITH x AS (SELECT 42) INSERT INTO t SELECT foo FROM x") {
7406+
Statement::Query(query) => {
7407+
assert_eq!(query.with.unwrap().to_string(), "WITH x AS (SELECT 42)");
7408+
assert!(matches!(*query.body, SetExpr::Insert(_)));
7409+
}
7410+
other => panic!("Expected: INSERT, got: {:?}", other),
7411+
}
7412+
}
7413+
73877414
#[test]
73887415
fn parse_derived_tables() {
73897416
let sql = "SELECT a.x, b.y FROM (SELECT x FROM foo) AS a CROSS JOIN (SELECT y FROM bar) AS b";

0 commit comments

Comments
 (0)