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, 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 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 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 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}