sql_parse/
delete.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License at
4//
5// http://www.apache.org/licenses/LICENSE-2.0
6//
7// Unless required by applicable law or agreed to in writing, software
8// distributed under the License is distributed on an "AS IS" BASIS,
9// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10// See the License for the specific language governing permissions and
11// limitations under the License.
12
13use alloc::vec::Vec;
14
15use crate::{
16    expression::{parse_expression, Expression},
17    keywords::Keyword,
18    lexer::Token,
19    parser::{ParseError, Parser},
20    qualified_name::parse_qualified_name,
21    select::{parse_select_expr, parse_table_reference},
22    QualifiedName, SelectExpr, Span, Spanned, TableReference,
23};
24
25/// Flags for deletion
26#[derive(Clone, Debug)]
27pub enum DeleteFlag {
28    LowPriority(Span),
29    Quick(Span),
30    Ignore(Span),
31}
32
33impl Spanned for DeleteFlag {
34    fn span(&self) -> Span {
35        match &self {
36            DeleteFlag::LowPriority(v) => v.span(),
37            DeleteFlag::Quick(v) => v.span(),
38            DeleteFlag::Ignore(v) => v.span(),
39        }
40    }
41}
42
43/// Represent a delete statement
44/// ```
45/// # use sql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, Delete, Statement, Issues};
46/// # let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
47/// #
48/// let sql = "DELETE FROM t1 WHERE c1 IN (SELECT b.c1 FROM t1 b WHERE b.c2=0);";
49/// let mut issues = Issues::new(sql);
50/// let mut stmts = parse_statements(sql, &mut issues, &options);
51///
52/// # assert!(issues.is_ok());
53/// let delete: Delete = match stmts.pop() {
54///     Some(Statement::Delete(d)) => d,
55///     _ => panic!("We should get a delete statement")
56/// };
57///
58/// assert!(delete.tables[0].identifier.as_str() == "t1");
59/// println!("{:#?}", delete.where_);
60///
61/// let sql = "DELETE `t1` FROM `t1` LEFT JOIN `t2` ON `t1`.`t2_id`=`t2`.`id` WHERE `t2`.`key`='my_key';";
62///
63/// let mut stmts = parse_statements(sql, &mut issues, &options);
64///
65/// # assert!(issues.is_ok());
66/// ```
67#[derive(Clone, Debug)]
68pub struct Delete<'a> {
69    /// Span of "DELETE"
70    pub delete_span: Span,
71    /// Flags following "DELETE"
72    pub flags: Vec<DeleteFlag>,
73    /// Span of "FROM"
74    pub from_span: Span,
75    /// Tables to do deletes on
76    pub tables: Vec<QualifiedName<'a>>,
77    /// Table to use in where clause in multi table delete
78    pub using: Vec<TableReference<'a>>,
79    /// Where expression and Span of "WHERE" if specified
80    pub where_: Option<(Expression<'a>, Span)>,
81    /// Span of "RETURNING" and select expressions after "RETURNING", if "RETURNING" is present
82    pub returning: Option<(Span, Vec<SelectExpr<'a>>)>,
83}
84
85impl<'a> Spanned for Delete<'a> {
86    fn span(&self) -> Span {
87        self.delete_span
88            .join_span(&self.flags)
89            .join_span(&self.from_span)
90            .join_span(&self.tables)
91            .join_span(&self.using)
92            .join_span(&self.where_)
93            .join_span(&self.returning)
94    }
95}
96
97pub(crate) fn parse_delete<'a>(parser: &mut Parser<'a, '_>) -> Result<Delete<'a>, ParseError> {
98    let delete_span = parser.consume_keyword(Keyword::DELETE)?;
99    let mut flags = Vec::new();
100
101    loop {
102        match &parser.token {
103            Token::Ident(_, Keyword::LOW_PRIORITY) => flags.push(DeleteFlag::LowPriority(
104                parser.consume_keyword(Keyword::LOW_PRIORITY)?,
105            )),
106            Token::Ident(_, Keyword::QUICK) => {
107                flags.push(DeleteFlag::Quick(parser.consume_keyword(Keyword::QUICK)?))
108            }
109            Token::Ident(_, Keyword::IGNORE) => {
110                flags.push(DeleteFlag::Ignore(parser.consume_keyword(Keyword::IGNORE)?))
111            }
112            _ => break,
113        }
114    }
115
116    let mut tables = Vec::new();
117    let mut using = Vec::new();
118    let from_span = if let Some(from_span) = parser.skip_keyword(Keyword::FROM) {
119        loop {
120            tables.push(parse_qualified_name(parser)?);
121            if parser.skip_token(Token::Comma).is_none() {
122                break;
123            }
124        }
125        from_span
126    } else {
127        loop {
128            tables.push(parse_qualified_name(parser)?);
129            if parser.skip_token(Token::Comma).is_none() {
130                break;
131            }
132        }
133        let from_span = parser.consume_keyword(Keyword::FROM)?;
134        loop {
135            using.push(parse_table_reference(parser)?);
136            if parser.skip_token(Token::Comma).is_none() {
137                break;
138            }
139        }
140        from_span
141    };
142
143    //TODO [PARTITION (partition_list)]
144    //TODO [FOR PORTION OF period FROM expr1 TO expr2]
145
146    if let Some(using_span) = parser.skip_keyword(Keyword::USING) {
147        if !using.is_empty() {
148            parser.err(
149                "Using not allowed in delete with table names before FROM",
150                &using_span,
151            );
152        }
153        loop {
154            using.push(parse_table_reference(parser)?);
155            if parser.skip_token(Token::Comma).is_none() {
156                break;
157            }
158        }
159    }
160
161    let where_ = if let Some(span) = parser.skip_keyword(Keyword::WHERE) {
162        Some((parse_expression(parser, false)?, span))
163    } else {
164        None
165    };
166    //TODO [ORDER BY ...]
167    //TODO LIMIT row_count]
168
169    let returning = if let Some(returning_span) = parser.skip_keyword(Keyword::RETURNING) {
170        let mut returning_exprs = Vec::new();
171        loop {
172            returning_exprs.push(parse_select_expr(parser)?);
173            if parser.skip_token(Token::Comma).is_none() {
174                break;
175            }
176        }
177        Some((returning_span, returning_exprs))
178    } else {
179        None
180    };
181
182    Ok(Delete {
183        flags,
184        delete_span,
185        tables,
186        using,
187        from_span,
188        where_,
189        returning,
190    })
191}