Skip to main content

sqlparser/parser/
merge.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
13//! SQL Parser for a `MERGE` statement
14
15#[cfg(not(feature = "std"))]
16use alloc::{boxed::Box, format, vec, vec::Vec};
17
18use crate::{
19    ast::{
20        Merge, MergeAction, MergeClause, MergeClauseKind, MergeInsertExpr, MergeInsertKind,
21        MergeUpdateExpr, MergeUpdateKind, ObjectName, OutputClause, SetExpr,
22    },
23    dialect::{BigQueryDialect, GenericDialect, MySqlDialect},
24    keywords::Keyword,
25    parser::IsOptional,
26    tokenizer::Token,
27    tokenizer::TokenWithSpan,
28};
29
30use super::{Parser, ParserError};
31
32impl Parser<'_> {
33    /// Parse a `MERGE` statement, returning a `Box`ed SetExpr
34    ///
35    /// This is used to reduce the size of the stack frames in debug builds
36    pub(super) fn parse_merge_setexpr_boxed(
37        &mut self,
38        merge_token: TokenWithSpan,
39    ) -> Result<Box<SetExpr>, ParserError> {
40        Ok(Box::new(SetExpr::Merge(
41            self.parse_merge(merge_token)?.into(),
42        )))
43    }
44
45    /// Parse a `MERGE` statement
46    pub fn parse_merge(&mut self, merge_token: TokenWithSpan) -> Result<Merge, ParserError> {
47        let optimizer_hints = self.maybe_parse_optimizer_hints()?;
48        let into = self.parse_keyword(Keyword::INTO);
49
50        let table = self.parse_table_factor()?;
51
52        self.expect_keyword_is(Keyword::USING)?;
53        let source = self.parse_table_factor()?;
54        self.expect_keyword_is(Keyword::ON)?;
55        let on = self.parse_expr()?;
56        let clauses = self.parse_merge_clauses()?;
57        let output = match self.parse_one_of_keywords(&[Keyword::OUTPUT, Keyword::RETURNING]) {
58            Some(keyword) => Some(self.parse_output(keyword, self.get_current_token().clone())?),
59            None => None,
60        };
61
62        Ok(Merge {
63            merge_token: merge_token.into(),
64            optimizer_hints,
65            into,
66            table,
67            source,
68            on: Box::new(on),
69            clauses,
70            output,
71        })
72    }
73
74    fn parse_merge_clauses(&mut self) -> Result<Vec<MergeClause>, ParserError> {
75        let mut clauses = vec![];
76        loop {
77            if !(self.parse_keyword(Keyword::WHEN)) {
78                break;
79            }
80            let when_token = self.get_current_token().clone();
81
82            let mut clause_kind = MergeClauseKind::Matched;
83            if self.parse_keyword(Keyword::NOT) {
84                clause_kind = MergeClauseKind::NotMatched;
85            }
86            self.expect_keyword_is(Keyword::MATCHED)?;
87
88            if matches!(clause_kind, MergeClauseKind::NotMatched)
89                && self.parse_keywords(&[Keyword::BY, Keyword::SOURCE])
90            {
91                clause_kind = MergeClauseKind::NotMatchedBySource;
92            } else if matches!(clause_kind, MergeClauseKind::NotMatched)
93                && self.parse_keywords(&[Keyword::BY, Keyword::TARGET])
94            {
95                clause_kind = MergeClauseKind::NotMatchedByTarget;
96            }
97
98            let predicate = if self.parse_keyword(Keyword::AND) {
99                Some(self.parse_expr()?)
100            } else {
101                None
102            };
103
104            self.expect_keyword_is(Keyword::THEN)?;
105
106            let merge_clause = match self.parse_one_of_keywords(&[
107                Keyword::UPDATE,
108                Keyword::INSERT,
109                Keyword::DELETE,
110                Keyword::DO,
111            ]) {
112                Some(Keyword::DO) => {
113                    let do_token = self.get_current_token().clone();
114                    let nothing_token = self.expect_keyword(Keyword::NOTHING)?;
115                    MergeAction::DoNothing {
116                        do_token: do_token.into(),
117                        nothing_token: nothing_token.into(),
118                    }
119                }
120                Some(Keyword::UPDATE) => {
121                    if matches!(
122                        clause_kind,
123                        MergeClauseKind::NotMatched | MergeClauseKind::NotMatchedByTarget
124                    ) {
125                        return parser_err!(
126                            format_args!("UPDATE is not allowed in a {clause_kind} merge clause"),
127                            self.get_current_token().span.start
128                        );
129                    }
130
131                    let update_token = self.get_current_token().clone();
132                    self.expect_keyword_is(Keyword::SET)?;
133                    let kind = if self.consume_token(&Token::Mul) {
134                        MergeUpdateKind::Wildcard
135                    } else {
136                        MergeUpdateKind::Set(self.parse_comma_separated(Parser::parse_assignment)?)
137                    };
138                    let update_predicate = if self.parse_keyword(Keyword::WHERE) {
139                        Some(self.parse_expr()?)
140                    } else {
141                        None
142                    };
143                    let delete_predicate = if self.parse_keyword(Keyword::DELETE) {
144                        let _ = self.expect_keyword(Keyword::WHERE)?;
145                        Some(self.parse_expr()?)
146                    } else {
147                        None
148                    };
149                    MergeAction::Update(MergeUpdateExpr {
150                        update_token: update_token.into(),
151                        kind,
152                        update_predicate,
153                        delete_predicate,
154                    })
155                }
156                Some(Keyword::DELETE) => {
157                    if matches!(
158                        clause_kind,
159                        MergeClauseKind::NotMatched | MergeClauseKind::NotMatchedByTarget
160                    ) {
161                        return parser_err!(
162                            format_args!("DELETE is not allowed in a {clause_kind} merge clause"),
163                            self.get_current_token().span.start
164                        );
165                    };
166
167                    let delete_token = self.get_current_token().clone();
168                    MergeAction::Delete {
169                        delete_token: delete_token.into(),
170                    }
171                }
172                Some(Keyword::INSERT) => {
173                    if !matches!(
174                        clause_kind,
175                        MergeClauseKind::NotMatched | MergeClauseKind::NotMatchedByTarget
176                    ) {
177                        return parser_err!(
178                            format_args!("INSERT is not allowed in a {clause_kind} merge clause"),
179                            self.get_current_token().span.start
180                        );
181                    };
182
183                    let insert_token = self.get_current_token().clone();
184
185                    if self.consume_token(&Token::Mul) {
186                        let star_token = self.get_current_token().clone();
187                        MergeAction::Insert(MergeInsertExpr {
188                            insert_token: insert_token.into(),
189                            columns: vec![],
190                            kind_token: star_token.into(),
191                            kind: MergeInsertKind::Wildcard,
192                            insert_predicate: None,
193                        })
194                    } else {
195                        let is_mysql = dialect_of!(self is MySqlDialect);
196                        let columns = self.parse_merge_clause_insert_columns(is_mysql)?;
197                        let (kind, kind_token) = if dialect_of!(self is BigQueryDialect | GenericDialect)
198                            && self.parse_keyword(Keyword::ROW)
199                        {
200                            (MergeInsertKind::Row, self.get_current_token().clone())
201                        } else {
202                            self.expect_keyword_is(Keyword::VALUES)?;
203                            let values_token = self.get_current_token().clone();
204                            let values = self.parse_values(is_mysql, false)?;
205                            (MergeInsertKind::Values(values), values_token)
206                        };
207                        let insert_predicate = if self.parse_keyword(Keyword::WHERE) {
208                            Some(self.parse_expr()?)
209                        } else {
210                            None
211                        };
212
213                        MergeAction::Insert(MergeInsertExpr {
214                            insert_token: insert_token.into(),
215                            columns,
216                            kind_token: kind_token.into(),
217                            kind,
218                            insert_predicate,
219                        })
220                    }
221                }
222                _ => {
223                    return parser_err!(
224                        "expected UPDATE, DELETE, INSERT or DO NOTHING in merge clause",
225                        self.peek_token_ref().span.start
226                    );
227                }
228            };
229            clauses.push(MergeClause {
230                when_token: when_token.into(),
231                clause_kind,
232                predicate,
233                action: merge_clause,
234            });
235        }
236        Ok(clauses)
237    }
238
239    fn parse_merge_clause_insert_columns(
240        &mut self,
241        allow_empty: bool,
242    ) -> Result<Vec<ObjectName>, ParserError> {
243        self.parse_parenthesized_qualified_column_list(IsOptional::Optional, allow_empty)
244    }
245
246    /// Parses an `OUTPUT` clause if present (MSSQL).
247    pub(super) fn maybe_parse_output_clause(
248        &mut self,
249    ) -> Result<Option<OutputClause>, ParserError> {
250        if self.parse_keyword(Keyword::OUTPUT) {
251            Ok(Some(self.parse_output(
252                Keyword::OUTPUT,
253                self.get_current_token().clone(),
254            )?))
255        } else {
256            Ok(None)
257        }
258    }
259
260    pub(super) fn parse_output(
261        &mut self,
262        start_keyword: Keyword,
263        start_token: TokenWithSpan,
264    ) -> Result<OutputClause, ParserError> {
265        let select_items = self.parse_projection()?;
266        let into_table = if start_keyword == Keyword::OUTPUT && self.peek_keyword(Keyword::INTO) {
267            self.expect_keyword_is(Keyword::INTO)?;
268            Some(self.parse_select_into()?)
269        } else {
270            None
271        };
272
273        Ok(if start_keyword == Keyword::OUTPUT {
274            OutputClause::Output {
275                output_token: start_token.into(),
276                select_items,
277                into_table,
278            }
279        } else {
280            OutputClause::Returning {
281                returning_token: start_token.into(),
282                select_items,
283            }
284        })
285    }
286}