1#[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 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 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}