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