sql_parse/
insert_replace.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.
12use alloc::vec::Vec;
13
14use crate::{
15    expression::{parse_expression, Expression},
16    keywords::Keyword,
17    lexer::Token,
18    parser::{ParseError, Parser},
19    qualified_name::parse_qualified_name,
20    select::{parse_select, parse_select_expr, Select, SelectExpr},
21    Identifier, OptSpanned, QualifiedName, Span, Spanned,
22};
23
24/// Flags for insert
25#[derive(Clone, Debug)]
26pub enum InsertReplaceFlag {
27    LowPriority(Span),
28    HighPriority(Span),
29    Delayed(Span),
30    Ignore(Span),
31}
32
33impl Spanned for InsertReplaceFlag {
34    fn span(&self) -> Span {
35        match &self {
36            InsertReplaceFlag::LowPriority(v) => v.span(),
37            InsertReplaceFlag::HighPriority(v) => v.span(),
38            InsertReplaceFlag::Delayed(v) => v.span(),
39            InsertReplaceFlag::Ignore(v) => v.span(),
40        }
41    }
42}
43
44#[derive(Clone, Debug)]
45pub enum InsertReplaceType {
46    Insert(Span),
47    Replace(Span),
48}
49
50impl Spanned for InsertReplaceType {
51    fn span(&self) -> Span {
52        match self {
53            InsertReplaceType::Insert(a) => a.clone(),
54            InsertReplaceType::Replace(a) => a.clone(),
55        }
56    }
57}
58
59#[derive(Clone, Debug)]
60pub enum OnConflictTarget<'a> {
61    Column {
62        name: Identifier<'a>,
63    },
64    OnConstraint {
65        on_constraint_span: Span,
66        name: Identifier<'a>,
67    },
68    None,
69}
70
71impl<'a> OptSpanned for OnConflictTarget<'a> {
72    fn opt_span(&self) -> Option<Span> {
73        match self {
74            OnConflictTarget::Column { name } => Some(name.span()),
75            OnConflictTarget::OnConstraint {
76                on_constraint_span: token,
77                name,
78            } => Some(token.join_span(name)),
79            OnConflictTarget::None => None,
80        }
81    }
82}
83
84#[derive(Clone, Debug)]
85pub enum OnConflictAction<'a> {
86    DoNothing(Span),
87    DoUpdateSet {
88        do_update_set_span: Span,
89        sets: Vec<(Identifier<'a>, Expression<'a>)>,
90        where_: Option<(Span, alloc::boxed::Box<Expression<'a>>)>,
91    },
92}
93
94impl<'a> Spanned for OnConflictAction<'a> {
95    fn span(&self) -> Span {
96        match self {
97            OnConflictAction::DoNothing(span) => span.span(),
98            OnConflictAction::DoUpdateSet {
99                do_update_set_span,
100                sets,
101                where_,
102            } => do_update_set_span.join_span(sets).join_span(where_),
103        }
104    }
105}
106
107#[derive(Clone, Debug)]
108pub struct OnConflict<'a> {
109    pub on_conflict_span: Span,
110    pub target: OnConflictTarget<'a>,
111    pub action: OnConflictAction<'a>,
112}
113
114impl<'a> Spanned for OnConflict<'a> {
115    fn span(&self) -> Span {
116        self.on_conflict_span
117            .join_span(&self.target)
118            .join_span(&self.action)
119    }
120}
121
122#[derive(Clone, Debug)]
123pub struct InsertReplaceSetPair<'a> {
124    pub column: Identifier<'a>,
125    pub equal_span: Span,
126    pub value: Expression<'a>,
127}
128
129impl<'a> Spanned for InsertReplaceSetPair<'a> {
130    fn span(&self) -> Span {
131        self.column
132            .join_span(&self.equal_span)
133            .join_span(&self.value)
134    }
135}
136
137#[derive(Clone, Debug)]
138pub struct InsertReplaceSet<'a> {
139    pub set_span: Span,
140    pub pairs: Vec<InsertReplaceSetPair<'a>>,
141}
142
143impl<'a> Spanned for InsertReplaceSet<'a> {
144    fn span(&self) -> Span {
145        self.set_span.join_span(&self.pairs)
146    }
147}
148
149#[derive(Clone, Debug)]
150pub struct InsertReplaceOnDuplicateKeyUpdate<'a> {
151    pub on_duplicate_key_update_span: Span,
152    pub pairs: Vec<InsertReplaceSetPair<'a>>,
153}
154
155impl<'a> Spanned for InsertReplaceOnDuplicateKeyUpdate<'a> {
156    fn span(&self) -> Span {
157        self.on_duplicate_key_update_span.join_span(&self.pairs)
158    }
159}
160
161/// Representation of Insert or Replace Statement
162///
163/// ```
164/// # use sql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statement, InsertReplace, InsertReplaceType, Statement, Issues};
165/// # let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
166/// #
167/// let sql1 = "INSERT INTO person (first_name, last_name) VALUES ('John', 'Doe')";
168/// # let mut issues = Issues::new(sql1);
169/// let stmt1 = parse_statement(sql1, &mut issues, &options);
170/// # assert!(issues.is_ok());/// #
171/// let sql2 = "INSERT INTO contractor SELECT * FROM person WHERE status = 'c'";
172/// # let mut issues = Issues::new(sql2);
173/// let stmt2 = parse_statement(sql2, &mut issues, &options);
174/// # assert!(issues.is_ok());/// #
175/// let sql3 = "INSERT INTO account (`key`, `value`) VALUES ('foo', 42)
176///             ON DUPLICATE KEY UPDATE `value`=`value`+42";
177/// # let mut issues = Issues::new(sql3);
178/// let stmt3 = parse_statement(sql3, &mut issues, &options);
179/// # assert!(issues.is_ok());
180///
181/// let i: InsertReplace = match stmt1 {
182///     Some(Statement::InsertReplace(
183///         i @ InsertReplace{type_: InsertReplaceType::Insert(_), ..})) => i,
184///     _ => panic!("We should get an insert statement")
185/// };
186///
187/// assert!(i.table.identifier.as_str() == "person");
188/// println!("{:#?}", i.values.unwrap());
189///
190///
191/// let sql = "REPLACE INTO t2 VALUES (1,'Leopard'),(2,'Dog')";
192/// # let mut issues = Issues::new(sql);
193/// let stmt = parse_statement(sql, &mut issues, &options);
194/// # assert!(issues.is_ok());
195/// #
196/// let r: InsertReplace = match stmt {
197///     Some(Statement::InsertReplace(
198///         r @ InsertReplace{type_: InsertReplaceType::Replace(_), ..})) => r,
199///     _ => panic!("We should get an replace statement")
200/// };
201///
202/// assert!(r.table.identifier.as_str() == "t2");
203/// println!("{:#?}", r.values.unwrap());
204/// ```
205///
206/// PostgreSQL
207/// ```
208/// # use sql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statement, InsertReplace, InsertReplaceType, Statement, Issues};
209/// # let options = ParseOptions::new().dialect(SQLDialect::PostgreSQL).arguments(SQLArguments::Dollar);
210/// #
211///
212/// let sql4 = "INSERT INTO contractor SELECT * FROM person WHERE status = $1 ON CONFLICT (name) DO NOTHING";
213/// # let mut issues = Issues::new(sql4);
214/// let stmt4 = parse_statement(sql4, &mut issues, &options);
215///
216/// println!("{}", issues);
217/// # assert!(issues.is_ok());
218/// ```
219#[derive(Clone, Debug)]
220pub struct InsertReplace<'a> {
221    /// Span of "INSERT" or "REPLACE"
222    pub type_: InsertReplaceType,
223    /// Flags specified after "INSERT"
224    pub flags: Vec<InsertReplaceFlag>,
225    /// Span of "INTO" if specified
226    pub into_span: Option<Span>,
227    /// Table to insert into
228    pub table: QualifiedName<'a>,
229    /// List of columns to set
230    pub columns: Vec<Identifier<'a>>,
231    /// Span of values "VALUES" and list of tuples to insert if specified
232    pub values: Option<(Span, Vec<Vec<Expression<'a>>>)>,
233    /// Select statement to insert if specified
234    pub select: Option<Select<'a>>,
235    /// Span of "SET" and list of key, value pairs to set if specified
236    pub set: Option<InsertReplaceSet<'a>>,
237    /// Updates to execute on duplicate key (mysql)
238    pub on_duplicate_key_update: Option<InsertReplaceOnDuplicateKeyUpdate<'a>>,
239    /// Action to take on duplicate keys (postgresql)
240    pub on_conflict: Option<OnConflict<'a>>,
241    /// Span of "RETURNING" and select expressions after "RETURNING", if "RETURNING" is present
242    pub returning: Option<(Span, Vec<SelectExpr<'a>>)>,
243}
244
245impl<'a> Spanned for InsertReplace<'a> {
246    fn span(&self) -> Span {
247        self.type_
248            .join_span(&self.flags)
249            .join_span(&self.into_span)
250            .join_span(&self.table)
251            .join_span(&self.values)
252            .join_span(&self.select)
253            .join_span(&self.set)
254            .join_span(&self.on_duplicate_key_update)
255            .join_span(&self.on_conflict)
256            .join_span(&self.returning)
257    }
258}
259
260pub(crate) fn parse_insert_replace<'a>(
261    parser: &mut Parser<'a, '_>,
262) -> Result<InsertReplace<'a>, ParseError> {
263    let type_ = match &parser.token {
264        Token::Ident(_, Keyword::INSERT) => InsertReplaceType::Insert(parser.consume()),
265        Token::Ident(_, Keyword::REPLACE) => InsertReplaceType::Replace(parser.consume()),
266        _ => parser.expected_failure("INSERT or REPLACE")?,
267    };
268
269    let insert = matches!(type_, InsertReplaceType::Insert(_));
270
271    let mut flags = Vec::new();
272    loop {
273        match &parser.token {
274            Token::Ident(_, Keyword::LOW_PRIORITY) => flags.push(InsertReplaceFlag::LowPriority(
275                parser.consume_keyword(Keyword::LOW_PRIORITY)?,
276            )),
277            Token::Ident(_, Keyword::HIGH_PRIORITY) => flags.push(InsertReplaceFlag::HighPriority(
278                parser.consume_keyword(Keyword::HIGH_PRIORITY)?,
279            )),
280            Token::Ident(_, Keyword::DELAYED) => flags.push(InsertReplaceFlag::Delayed(
281                parser.consume_keyword(Keyword::DELAYED)?,
282            )),
283            Token::Ident(_, Keyword::IGNORE) => flags.push(InsertReplaceFlag::Ignore(
284                parser.consume_keyword(Keyword::IGNORE)?,
285            )),
286            _ => break,
287        }
288    }
289
290    for flag in &flags {
291        match flag {
292            InsertReplaceFlag::LowPriority(_) => {}
293            InsertReplaceFlag::HighPriority(s) => {
294                if !insert {
295                    parser.err("Not supported for replace", s);
296                }
297            }
298            InsertReplaceFlag::Delayed(_) => {}
299            InsertReplaceFlag::Ignore(s) => {
300                if !insert {
301                    parser.err("Not supported for replace", s);
302                }
303            }
304        }
305    }
306
307    let into_span = parser.skip_keyword(Keyword::INTO);
308    let table = parse_qualified_name(parser)?;
309    // [PARTITION (partition_list)]
310
311    let mut columns = Vec::new();
312    if parser.skip_token(Token::LParen).is_some() {
313        parser.recovered(")", &|t| t == &Token::RParen, |parser| {
314            loop {
315                columns.push(parser.consume_plain_identifier()?);
316                if parser.skip_token(Token::Comma).is_none() {
317                    break;
318                }
319            }
320            Ok(())
321        })?;
322        parser.consume_token(Token::RParen)?;
323    }
324
325    let mut select = None;
326    let mut values = None;
327    let mut set = None;
328    match &parser.token {
329        Token::Ident(_, Keyword::SELECT) => {
330            select = Some(parse_select(parser)?);
331        }
332        Token::Ident(_, Keyword::VALUE | Keyword::VALUES) => {
333            let values_span = parser.consume();
334            let mut values_items = Vec::new();
335            loop {
336                let mut vals = Vec::new();
337                parser.consume_token(Token::LParen)?;
338                parser.recovered(")", &|t| t == &Token::RParen, |parser| {
339                    loop {
340                        vals.push(parse_expression(parser, false)?);
341                        if parser.skip_token(Token::Comma).is_none() {
342                            break;
343                        }
344                    }
345                    Ok(())
346                })?;
347                parser.consume_token(Token::RParen)?;
348                values_items.push(vals);
349                if parser.skip_token(Token::Comma).is_none() {
350                    break;
351                }
352            }
353            values = Some((values_span, values_items));
354        }
355        Token::Ident(_, Keyword::SET) => {
356            let set_span = parser.consume_keyword(Keyword::SET)?;
357            let mut pairs = Vec::new();
358            loop {
359                let column = parser.consume_plain_identifier()?;
360                let equal_span = parser.consume_token(Token::Eq)?;
361                let value: Expression<'_> = parse_expression(parser, false)?;
362                pairs.push(InsertReplaceSetPair {
363                    column,
364                    equal_span,
365                    value,
366                });
367                if parser.skip_token(Token::Comma).is_none() {
368                    break;
369                }
370            }
371            if let Some(cs) = columns.opt_span() {
372                parser
373                    .err("Columns may not be used here", &cs)
374                    .frag("Together with SET", &set_span);
375            }
376            set = Some(InsertReplaceSet { set_span, pairs });
377        }
378        _ => {
379            parser.expected_error("VALUE, VALUES, SELECT or SET");
380        }
381    }
382
383    let (on_duplicate_key_update, on_conflict) =
384        if matches!(parser.token, Token::Ident(_, Keyword::ON)) {
385            let on = parser.consume_keyword(Keyword::ON)?;
386            match &parser.token {
387                Token::Ident(_, Keyword::DUPLICATE) => {
388                    let on_duplicate_key_update_span =
389                        on.join_span(&parser.consume_keywords(&[
390                            Keyword::DUPLICATE,
391                            Keyword::KEY,
392                            Keyword::UPDATE,
393                        ])?);
394                    let mut pairs = Vec::new();
395                    loop {
396                        let column = parser.consume_plain_identifier()?;
397                        let equal_span = parser.consume_token(Token::Eq)?;
398                        let value = parse_expression(parser, false)?;
399                        pairs.push(InsertReplaceSetPair {
400                            column,
401                            equal_span,
402                            value,
403                        });
404                        if parser.skip_token(Token::Comma).is_none() {
405                            break;
406                        }
407                    }
408                    if !parser.options.dialect.is_maria() {
409                        parser.err(
410                            "Only support by mariadb",
411                            &on_duplicate_key_update_span.join_span(&pairs),
412                        );
413                    }
414                    (
415                        Some(InsertReplaceOnDuplicateKeyUpdate {
416                            on_duplicate_key_update_span,
417                            pairs,
418                        }),
419                        None,
420                    )
421                }
422                Token::Ident(_, Keyword::CONFLICT) => {
423                    let on_conflict_span =
424                        on.join_span(&parser.consume_keyword(Keyword::CONFLICT)?);
425
426                    let target = match &parser.token {
427                        Token::LParen => {
428                            parser.consume_token(Token::LParen)?;
429                            let name = parser.consume_plain_identifier()?;
430                            parser.consume_token(Token::RParen)?;
431                            OnConflictTarget::Column { name }
432                        }
433                        Token::Ident(_, Keyword::ON) => {
434                            let on_constraint =
435                                parser.consume_keywords(&[Keyword::ON, Keyword::CONSTRAINT])?;
436                            let name = parser.consume_plain_identifier()?;
437                            OnConflictTarget::OnConstraint {
438                                on_constraint_span: on_constraint,
439                                name,
440                            }
441                        }
442                        _ => OnConflictTarget::None,
443                    };
444
445                    let do_ = parser.consume_keyword(Keyword::DO)?;
446                    let action = match &parser.token {
447                        Token::Ident(_, Keyword::NOTHING) => OnConflictAction::DoNothing(
448                            do_.join_span(&parser.consume_keyword(Keyword::NOTHING)?),
449                        ),
450                        Token::Ident(_, Keyword::UPDATE) => {
451                            let do_update_set_span = do_.join_span(
452                                &parser.consume_keywords(&[Keyword::UPDATE, Keyword::SET])?,
453                            );
454                            let mut sets = Vec::new();
455                            loop {
456                                let name = parser.consume_plain_identifier()?;
457                                parser.consume_token(Token::Eq)?;
458                                let expr = parse_expression(parser, false)?;
459                                sets.push((name, expr));
460                                if parser.skip_token(Token::Comma).is_none() {
461                                    break;
462                                }
463                            }
464                            let where_ = if matches!(parser.token, Token::Ident(_, Keyword::WHERE))
465                            {
466                                let where_span = parser.consume_keyword(Keyword::WHERE)?;
467                                let where_expr =
468                                    alloc::boxed::Box::new(parse_expression(parser, false)?);
469                                Some((where_span, where_expr))
470                            } else {
471                                None
472                            };
473                            OnConflictAction::DoUpdateSet {
474                                do_update_set_span,
475                                sets,
476                                where_,
477                            }
478                        }
479                        _ => parser.expected_failure("'NOTHING' or 'UPDATE'")?,
480                    };
481
482                    let on_conflict = OnConflict {
483                        on_conflict_span,
484                        target,
485                        action,
486                    };
487
488                    if !parser.options.dialect.is_postgresql() {
489                        parser.err("Only support by postgesql", &on_conflict);
490                    }
491
492                    (None, Some(on_conflict))
493                }
494                _ => parser.expected_failure("'DUPLICATE' OR 'CONFLICT'")?,
495            }
496        } else {
497            (None, None)
498        };
499
500    let returning = if let Some(returning_span) = parser.skip_keyword(Keyword::RETURNING) {
501        let mut returning_exprs = Vec::new();
502        loop {
503            returning_exprs.push(parse_select_expr(parser)?);
504            if parser.skip_token(Token::Comma).is_none() {
505                break;
506            }
507        }
508        Some((returning_span, returning_exprs))
509    } else {
510        None
511    };
512
513    Ok(InsertReplace {
514        type_,
515        flags,
516        table,
517        columns,
518        into_span,
519        values,
520        select,
521        set,
522        on_duplicate_key_update,
523        on_conflict,
524        returning,
525    })
526}