1use rupg_common::{Error, Result, SqlState};
8use rupg_sql::nodes::{
9 CmdType, List, MergeMatchKind, MergeStmt, MergeSupportFunc, MergeWhenClause, Node, RangeVar,
10};
11use rupg_types::{Value, oid};
12
13use crate::Analyzer;
14use crate::agg::Kind;
15use crate::coerce::AtOpt;
16use crate::expr::{Expr, ExprKind, Var};
17use crate::from::{Column, FromItem, Join, JoinKind, Relation};
18use crate::insert::{Foreign, Write, WriteKind, targets, with_checks};
19use crate::modify::{carried_targets, old_row, set_columns, table_oid_target, tid_target};
20use crate::perm::{ACL_DELETE, ACL_INSERT, ACL_SELECT, ACL_UPDATE};
21use crate::returning::rewrite;
22use crate::select::{Query, Target};
23use crate::typename::place;
24
25#[derive(Clone, Copy, Debug, PartialEq, Eq)]
27pub enum MatchKind {
28 Matched,
30 NotMatchedBySource,
32 NotMatchedByTarget,
34}
35
36#[derive(Clone, Copy, Debug, PartialEq, Eq)]
38pub enum MergeCommand {
39 Insert,
40 Update,
41 Delete,
42 Nothing,
44}
45
46#[derive(Clone, Debug, PartialEq)]
48pub struct MergeClause {
49 pub kind: MatchKind,
50 pub command: MergeCommand,
51 pub query: Box<Query>,
53}
54
55#[derive(Clone, Debug, PartialEq)]
57pub struct Merge {
58 pub clauses: Vec<MergeClause>,
60 pub carried: usize,
62 pub insert_foreign: Vec<Foreign>,
64 pub update_foreign: Vec<Foreign>,
66 pub delete_foreign: Vec<Foreign>,
68}
69
70struct Parts {
72 kind: MatchKind,
73 command: MergeCommand,
74 condition: Option<Expr>,
75 row: Vec<Expr>,
76}
77
78fn command(kind: CmdType) -> MergeCommand {
80 match kind {
81 CmdType::CMD_INSERT => MergeCommand::Insert,
82 CmdType::CMD_UPDATE => MergeCommand::Update,
83 CmdType::CMD_DELETE => MergeCommand::Delete,
84 _ => MergeCommand::Nothing,
85 }
86}
87
88fn match_kind(clause: &MergeWhenClause) -> MatchKind {
90 match clause.matchKind {
91 MergeMatchKind::MERGE_WHEN_MATCHED => MatchKind::Matched,
92 MergeMatchKind::MERGE_WHEN_NOT_MATCHED_BY_SOURCE => MatchKind::NotMatchedBySource,
93 _ => MatchKind::NotMatchedByTarget,
94 }
95}
96
97pub(crate) fn carry(carried: &mut Vec<Expr>, relation: usize, attnum: i16, expr: &Expr) -> usize {
99 let found = carried.iter().position(
100 |c| matches!(c.kind, ExprKind::Var(v) if v.relation == relation && v.attnum == attnum),
101 );
102 found.unwrap_or_else(|| {
103 let mut value = Expr::new(ExprKind::Var(Var { relation, attnum, levels_up: 0 }), expr.ty);
104 value.typmod = expr.typmod;
105 carried.push(value);
106 carried.len() - 1
107 })
108}
109
110impl Analyzer<'_> {
111 pub(crate) fn merge(&mut self, s: &MergeStmt) -> Result<Query> {
113 self.write_with(s.withClause.as_deref())?;
114 let mut clauses = Vec::with_capacity(s.mergeWhenClauses.len());
115 for node in &s.mergeWhenClauses {
116 let Some(Node::MergeWhenClause(clause)) = node else {
117 return Err(Error::internal("a WHEN clause that is not MergeWhenClause"));
118 };
119 clauses.push(&**clause);
120 }
121 let mut unconditional: Vec<MatchKind> = Vec::new();
123 for clause in &clauses {
124 let kind = match_kind(clause);
125 if unconditional.contains(&kind) {
126 return Err(Error::new(
127 SqlState::SYNTAX_ERROR,
128 "unreachable WHEN clause specified after unconditional WHEN clause",
129 ));
130 }
131 if clause.condition.is_none() {
132 unconditional.push(kind);
133 }
134 }
135 let rv = s.relation.as_deref().ok_or_else(|| Error::internal("a MERGE with no table"))?;
136 self.merge_actions = clauses.iter().map(|c| command(c.commandType)).collect();
137 let (table, name, columns) = self.target_table(rv, WriteKind::Merge)?;
138 let required = clauses.iter().fold(0, |bits, clause| {
140 bits | match clause.commandType {
141 CmdType::CMD_INSERT => ACL_INSERT,
142 CmdType::CMD_UPDATE => ACL_UPDATE,
143 CmdType::CMD_DELETE => ACL_DELETE,
144 _ => ACL_SELECT,
145 }
146 });
147 if let Some(perm) = self.target_perm_mut() {
148 perm.required |= required;
149 }
150 let source =
151 s.sourceRelation.as_ref().ok_or_else(|| Error::internal("a MERGE with no source"))?;
152 let source = self.merge_from(rv, source)?;
153 let on = self.with_kind(Kind::JoinOn, |a| a.transform(s.joinCondition.as_ref()))?;
154 let on = self.coerce_to_boolean(on, "JOIN/ON")?;
155 let (returning, mut carried) = match s.returningClause.as_deref() {
156 None => (None, Vec::new()),
157 Some(clause) => {
158 let (query, carried) = self.returning(clause, WriteKind::Merge)?;
159 (Some(Box::new(query)), carried)
160 }
161 };
162 let mut parts = Vec::with_capacity(clauses.len());
163 let mut updated = Vec::new();
164 for clause in &clauses {
165 let kind = match_kind(clause);
166 let update = matches!(clause.commandType, CmdType::CMD_UPDATE);
167 let set =
169 if update { self.auto_view_set(rv, &clause.targetList, &columns) } else { None };
170 let (renamed, error) = match set {
171 Some((list, unknown, fixed)) => (Some(list), unknown.or(fixed)),
172 None => (None, None),
173 };
174 let list = renamed.as_ref().unwrap_or(&clause.targetList);
175 if update {
176 for column in set_columns(list, &columns) {
177 if !updated.contains(&column) {
178 updated.push(column);
179 }
180 }
181 }
182 let full = self.merge_namespace(
183 kind != MatchKind::NotMatchedByTarget,
184 kind != MatchKind::NotMatchedBySource,
185 );
186 let part = match error {
187 Some(error) => self.set_items(list).and(Err(error)),
188 None => self.merge_clause(clause, list, kind, rv, (table, &name, &columns)),
189 };
190 self.set_namespace(full);
191 let mut part = part?;
192 let mut change = |expr: &mut Expr, depth: usize| {
194 let ExprKind::Var(var) = expr.kind else { return };
195 if var.levels_up != depth || var.relation == 0 {
196 return;
197 }
198 let at = carry(&mut carried, var.relation, var.attnum, expr);
199 let attnum = i16::try_from(at + 1).unwrap_or(i16::MAX);
200 expr.kind = ExprKind::Var(Var { relation: 1, attnum, levels_up: depth });
201 };
202 for expr in part.row.iter_mut().chain(part.condition.as_mut()) {
203 rewrite(expr, 0, &mut change);
204 }
205 parts.push(part);
206 }
207 let inherit = self.inherits_target(WriteKind::Merge);
209 let partitioned = self.is_partitioned(table) || inherit;
210 let checks = if partitioned { Vec::new() } else { self.checks(table)? };
211 let names = checks.iter().map(|(n, _)| n.clone()).collect();
212 let generated = if partitioned { Vec::new() } else { self.generated_columns(table)? };
213 let carried_columns: Vec<Column> = carried
214 .iter()
215 .map(|expr| Column {
216 name: String::new(),
217 ty: expr.ty,
218 typmod: expr.typmod,
219 not_null: false,
220 })
221 .collect();
222 let mut target = self
223 .scope
224 .relations
225 .first()
226 .cloned()
227 .ok_or_else(|| Error::internal("a MERGE with no table"))?;
228 target.subquery = None;
230 let mut merge_clauses = Vec::with_capacity(parts.len());
231 for part in parts {
232 let writes = matches!(part.command, MergeCommand::Insert | MergeCommand::Update);
233 let row = if writes {
234 targets(&columns, part.row)
235 } else {
236 let expr = Expr::new(ExprKind::Const(Value::Bool(true)), oid::BOOL);
237 vec![Target { name: String::new(), expr, origin: None, junk: false }]
238 };
239 let mut query = Query {
240 relations: vec![
241 target.clone(),
242 Relation::new(0, carried_columns.clone(), None, None, None),
243 ],
244 from: vec![FromItem::Relation(0), FromItem::Relation(1)],
245 targets: row,
246 filter: part.condition,
247 ..Query::default()
248 };
249 if writes && (!checks.is_empty() || !generated.is_empty()) {
250 query = with_checks(&name, &columns, query, checks.clone(), &generated, &[]);
251 }
252 merge_clauses.push(MergeClause {
253 kind: part.kind,
254 command: part.command,
255 query: Box::new(query),
256 });
257 }
258 let has = |kind: MatchKind| merge_clauses.iter().any(|c| c.kind == kind);
259 let (by_source, by_target) =
260 (has(MatchKind::NotMatchedBySource), has(MatchKind::NotMatchedByTarget));
261 let (source, marker) = if by_source {
263 let index = self.scope.relations.len();
264 let column =
265 Column { name: "marker".to_string(), ty: oid::BOOL, typmod: -1, not_null: false };
266 let value = Expr::new(ExprKind::Const(Value::Bool(true)), oid::BOOL);
267 let mut relation = Relation::new(0, vec![column], None, None, Some(vec![vec![value]]));
268 relation.name = "*VALUES*".to_string();
269 self.scope.relations.push(relation);
270 let var = Var { relation: index, attnum: 1, levels_up: 0 };
271 (join(JoinKind::Inner, source, FromItem::Relation(index), None), ExprKind::Var(var))
272 } else {
273 (source, ExprKind::Const(Value::Bool(true)))
274 };
275 let kind = match (by_source, by_target) {
276 (true, true) => JoinKind::Full,
277 (true, false) => JoinKind::Right,
278 (false, true) => JoinKind::Left,
279 (false, false) => JoinKind::Inner,
280 };
281 let target_item = match self.auto_view_quals() {
283 None => FromItem::Relation(0),
284 Some(quals) => {
285 let index = self.scope.relations.len();
286 let column =
287 Column { name: "one".to_string(), ty: oid::BOOL, typmod: -1, not_null: false };
288 let value = Expr::new(ExprKind::Const(Value::Bool(true)), oid::BOOL);
289 let mut relation =
290 Relation::new(0, vec![column], None, None, Some(vec![vec![value]]));
291 relation.name = "*VALUES*".to_string();
292 self.scope.relations.push(relation);
293 join(JoinKind::Inner, FromItem::Relation(0), FromItem::Relation(index), Some(quals))
294 }
295 };
296 let instead = self.is_view(table);
298 let mut tid = tid_target();
299 let target_item = if instead {
300 let index = self.scope.relations.len();
301 let column =
302 Column { name: "ctid".to_string(), ty: oid::INT8, typmod: -1, not_null: false };
303 let value = Expr::new(ExprKind::Const(Value::Int8(0)), oid::INT8);
304 let mut relation = Relation::new(0, vec![column], None, None, Some(vec![vec![value]]));
305 relation.name = "*VALUES*".to_string();
306 self.scope.relations.push(relation);
307 let var = Var { relation: index, attnum: 1, levels_up: 0 };
308 tid.expr = Expr::new(ExprKind::Var(var), oid::INT8);
309 join(JoinKind::Inner, target_item, FromItem::Relation(index), None)
310 } else {
311 target_item
312 };
313 let from = join(kind, source, target_item, Some(on));
314 let mut query_targets = old_row(&columns);
315 if partitioned {
316 query_targets.push(table_oid_target());
317 }
318 query_targets.push(tid);
319 query_targets.push(Target {
320 name: String::new(),
321 expr: Expr::new(marker, oid::BOOL),
322 origin: None,
323 junk: false,
324 });
325 let count = carried.len();
326 query_targets.extend(carried_targets(carried));
327 let uses = |command: MergeCommand| merge_clauses.iter().any(|c| c.command == command);
328 if !updated.is_empty() {
329 self.mark_updated(&updated);
330 }
331 let foreign = |a: &Self, command: MergeCommand, kind: WriteKind| {
332 if uses(command) { a.foreign_keys(table, kind, &columns) } else { Ok(Vec::new()) }
333 };
334 let insert_foreign = foreign(self, MergeCommand::Insert, WriteKind::Insert)?;
335 let update_foreign = foreign(self, MergeCommand::Update, WriteKind::Update)?;
336 let delete_foreign = foreign(self, MergeCommand::Delete, WriteKind::Delete)?;
337 let unique = self.unique_keys(table, &columns)?;
338 let recheck =
340 [(MergeCommand::Insert, WriteKind::Insert), (MergeCommand::Update, WriteKind::Update)]
341 .into_iter()
342 .filter(|&(command, _)| uses(command))
343 .find_map(|(_, kind)| {
344 self.recheck(table, kind, &name, &columns, &checks, &generated)
345 });
346 let mut query = Query {
347 relations: std::mem::take(&mut self.scope.relations),
348 from: vec![from],
349 targets: query_targets,
350 write: Some(Write {
351 kind: WriteKind::Merge,
352 table,
353 name,
354 alias: None,
355 width: columns.len(),
356 checks: names,
357 unique,
358 returning,
359 foreign: Vec::new(),
360 on_conflict: None,
361 merge: Some(Merge {
362 clauses: merge_clauses,
363 carried: count,
364 insert_foreign,
365 update_foreign,
366 delete_foreign,
367 }),
368 recheck,
369 updated: crate::modify::with_extra_updated(updated, &generated),
370 instead,
371 inherit,
372 view_check: None,
373 views: 0,
374 }),
375 ..Query::default()
376 };
377 self.end_write_with(&mut query, s.withClause.as_deref())?;
378 Ok(query)
379 }
380
381 fn merge_clause(
383 &mut self,
384 clause: &MergeWhenClause,
385 list: &List,
386 kind: MatchKind,
387 rv: &RangeVar,
388 (table, name, columns): (u32, &str, &[Column]),
389 ) -> Result<Parts> {
390 let condition = match &clause.condition {
391 None => None,
392 Some(node) => {
393 let expr = self.with_kind(Kind::MergeWhen, |a| a.transform(Some(node)))?;
394 Some(self.coerce_to_boolean(expr, "WHEN")?)
395 }
396 };
397 let (command, row) = match clause.commandType {
398 CmdType::CMD_INSERT => {
399 self.swap_auto_view_defaults();
400 let row = self.merge_insert(clause, table, name, columns);
401 self.swap_auto_view_defaults();
402 (MergeCommand::Insert, row?)
403 }
404 CmdType::CMD_UPDATE => {
405 (MergeCommand::Update, self.update_row(rv, table, name, columns, list)?)
406 }
407 CmdType::CMD_DELETE => (MergeCommand::Delete, Vec::new()),
408 _ => (MergeCommand::Nothing, Vec::new()),
409 };
410 Ok(Parts { kind, command, condition, row })
411 }
412
413 fn merge_insert(
415 &mut self,
416 clause: &MergeWhenClause,
417 table: u32,
418 name: &str,
419 columns: &[Column],
420 ) -> Result<Vec<Expr>> {
421 let given = match self.auto_view_targets(&clause.targetList, columns.len())? {
422 Some(given) => given,
423 None => self.insert_targets(&clause.targetList, name, columns)?,
424 };
425 let exprs = if clause.values.is_empty() {
426 Vec::new()
428 } else {
429 self.mark_inserted(&given);
430 let items = self.value_items(&clause.values, Kind::ValuesSingle)?;
431 let explicit = !clause.targetList.is_empty();
432 self.insert_row(items, table, columns, &given, explicit, clause.r#override)?
433 };
434 self.full_row(table, columns, &given, exprs)
435 }
436
437 pub(crate) fn merge_support_func(&mut self, f: &MergeSupportFunc) -> Result<Expr> {
443 let count = self.outer_kinds.len();
444 for (level, scope) in self.levels() {
445 let kind = match level {
446 0 => Some(self.kind),
447 _ => count.checked_sub(level).and_then(|i| self.outer_kinds.get(i)?.0),
448 };
449 if kind == Some(Kind::Returning)
450 && let Some(relation) = scope.merge_action
451 {
452 let var = Var { relation, attnum: 1, levels_up: level };
453 return Ok(Expr::new(ExprKind::Var(var), oid::TEXT).at(place(f.location)));
454 }
455 }
456 Err(Error::new(
457 SqlState::SYNTAX_ERROR,
458 "MERGE_ACTION() can only be used in the RETURNING list of a MERGE command",
459 )
460 .at_opt(place(f.location)))
461 }
462}
463
464fn join(kind: JoinKind, left: FromItem, right: FromItem, on: Option<Expr>) -> FromItem {
466 FromItem::Join(Box::new(Join {
467 kind,
468 left,
469 right,
470 on,
471 using: Vec::new(),
472 plain_using: true,
473 alias: None,
474 using_alias: None,
475 merged: Vec::new(),
476 columns: Vec::new(),
477 aliases: Vec::new(),
478 sources: Vec::new(),
479 }))
480}