PostgreSQL Source Code  git master
parse_merge.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * parse_merge.c
4  * handle merge-statement in parser
5  *
6  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/parser/parse_merge.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 
16 #include "postgres.h"
17 
18 #include "access/sysattr.h"
19 #include "miscadmin.h"
20 #include "nodes/makefuncs.h"
21 #include "parser/analyze.h"
22 #include "parser/parse_collate.h"
23 #include "parser/parsetree.h"
24 #include "parser/parser.h"
25 #include "parser/parse_clause.h"
26 #include "parser/parse_cte.h"
27 #include "parser/parse_expr.h"
28 #include "parser/parse_merge.h"
29 #include "parser/parse_relation.h"
30 #include "parser/parse_target.h"
31 #include "utils/rel.h"
32 #include "utils/relcache.h"
33 
34 static void setNamespaceForMergeWhen(ParseState *pstate,
35  MergeWhenClause *mergeWhenClause,
36  Index targetRTI,
37  Index sourceRTI);
38 static void setNamespaceVisibilityForRTE(List *namespace, RangeTblEntry *rte,
39  bool rel_visible,
40  bool cols_visible);
41 
42 /*
43  * Make appropriate changes to the namespace visibility while transforming
44  * individual action's quals and targetlist expressions. In particular, for
45  * INSERT actions we must only see the source relation (since INSERT action is
46  * invoked for NOT MATCHED tuples and hence there is no target tuple to deal
47  * with). On the other hand, UPDATE and DELETE actions can see both source and
48  * target relations.
49  *
50  * Also, since the internal join node can hide the source and target
51  * relations, we must explicitly make the respective relation as visible so
52  * that columns can be referenced unqualified from these relations.
53  */
54 static void
56  Index targetRTI, Index sourceRTI)
57 {
58  RangeTblEntry *targetRelRTE,
59  *sourceRelRTE;
60 
61  targetRelRTE = rt_fetch(targetRTI, pstate->p_rtable);
62  sourceRelRTE = rt_fetch(sourceRTI, pstate->p_rtable);
63 
64  if (mergeWhenClause->matched)
65  {
66  Assert(mergeWhenClause->commandType == CMD_UPDATE ||
67  mergeWhenClause->commandType == CMD_DELETE ||
68  mergeWhenClause->commandType == CMD_NOTHING);
69 
70  /* MATCHED actions can see both target and source relations. */
72  targetRelRTE, true, true);
74  sourceRelRTE, true, true);
75  }
76  else
77  {
78  /*
79  * NOT MATCHED actions can't see target relation, but they can see
80  * source relation.
81  */
82  Assert(mergeWhenClause->commandType == CMD_INSERT ||
83  mergeWhenClause->commandType == CMD_NOTHING);
85  targetRelRTE, false, false);
87  sourceRelRTE, true, true);
88  }
89 }
90 
91 /*
92  * transformMergeStmt -
93  * transforms a MERGE statement
94  */
95 Query *
97 {
98  Query *qry = makeNode(Query);
99  ListCell *l;
100  AclMode targetPerms = ACL_NO_RIGHTS;
101  bool is_terminal[2];
102  Index sourceRTI;
103  List *mergeActionList;
104  Node *joinExpr;
105  ParseNamespaceItem *nsitem;
106 
107  /* There can't be any outer WITH to worry about */
108  Assert(pstate->p_ctenamespace == NIL);
109 
110  qry->commandType = CMD_MERGE;
111  qry->hasRecursive = false;
112 
113  /* process the WITH clause independently of all else */
114  if (stmt->withClause)
115  {
116  if (stmt->withClause->recursive)
117  ereport(ERROR,
118  (errcode(ERRCODE_SYNTAX_ERROR),
119  errmsg("WITH RECURSIVE is not supported for MERGE statement")));
120 
121  qry->cteList = transformWithClause(pstate, stmt->withClause);
122  qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
123  }
124 
125  /*
126  * Check WHEN clauses for permissions and sanity
127  */
128  is_terminal[0] = false;
129  is_terminal[1] = false;
130  foreach(l, stmt->mergeWhenClauses)
131  {
132  MergeWhenClause *mergeWhenClause = (MergeWhenClause *) lfirst(l);
133  int when_type = (mergeWhenClause->matched ? 0 : 1);
134 
135  /*
136  * Collect action types so we can check target permissions
137  */
138  switch (mergeWhenClause->commandType)
139  {
140  case CMD_INSERT:
141  targetPerms |= ACL_INSERT;
142  break;
143  case CMD_UPDATE:
144  targetPerms |= ACL_UPDATE;
145  break;
146  case CMD_DELETE:
147  targetPerms |= ACL_DELETE;
148  break;
149  case CMD_NOTHING:
150  break;
151  default:
152  elog(ERROR, "unknown action in MERGE WHEN clause");
153  }
154 
155  /*
156  * Check for unreachable WHEN clauses
157  */
158  if (is_terminal[when_type])
159  ereport(ERROR,
160  (errcode(ERRCODE_SYNTAX_ERROR),
161  errmsg("unreachable WHEN clause specified after unconditional WHEN clause")));
162  if (mergeWhenClause->condition == NULL)
163  is_terminal[when_type] = true;
164  }
165 
166  /*
167  * Set up the MERGE target table. The target table is added to the
168  * namespace below and to joinlist in transform_MERGE_to_join, so don't
169  * do it here.
170  */
171  qry->resultRelation = setTargetTable(pstate, stmt->relation,
172  stmt->relation->inh,
173  false, targetPerms);
174 
175  /*
176  * MERGE is unsupported in various cases
177  */
178  if (pstate->p_target_relation->rd_rel->relkind != RELKIND_RELATION &&
179  pstate->p_target_relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
180  ereport(ERROR,
181  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
182  errmsg("cannot execute MERGE on relation \"%s\"",
185  if (pstate->p_target_relation->rd_rules != NULL &&
186  pstate->p_target_relation->rd_rules->numLocks > 0)
187  ereport(ERROR,
188  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
189  errmsg("cannot execute MERGE on relation \"%s\"",
191  errdetail("MERGE is not supported for relations with rules.")));
192 
193  /* Now transform the source relation to produce the source RTE. */
194  transformFromClause(pstate,
195  list_make1(stmt->sourceRelation));
196  sourceRTI = list_length(pstate->p_rtable);
197  nsitem = GetNSItemByRangeTablePosn(pstate, sourceRTI, 0);
198 
199  /*
200  * Check that the target table doesn't conflict with the source table.
201  * This would typically be a checkNameSpaceConflicts call, but we want a
202  * more specific error message.
203  */
204  if (strcmp(pstate->p_target_nsitem->p_names->aliasname,
205  nsitem->p_names->aliasname) == 0)
206  ereport(ERROR,
207  errcode(ERRCODE_DUPLICATE_ALIAS),
208  errmsg("name \"%s\" specified more than once",
209  pstate->p_target_nsitem->p_names->aliasname),
210  errdetail("The name is used both as MERGE target table and data source."));
211 
212  /*
213  * There's no need for a targetlist here; it'll be set up by
214  * preprocess_targetlist later.
215  */
216  qry->targetList = NIL;
217  qry->rtable = pstate->p_rtable;
218  qry->rteperminfos = pstate->p_rteperminfos;
219 
220  /*
221  * Transform the join condition. This includes references to the target
222  * side, so add that to the namespace.
223  */
224  addNSItemToQuery(pstate, pstate->p_target_nsitem, false, true, true);
225  joinExpr = transformExpr(pstate, stmt->joinCondition,
227 
228  /*
229  * Create the temporary query's jointree using the joinlist we built using
230  * just the source relation; the target relation is not included. The
231  * quals we use are the join conditions to the merge target. The join
232  * will be constructed fully by transform_MERGE_to_join.
233  */
234  qry->jointree = makeFromExpr(pstate->p_joinlist, joinExpr);
235 
236  /*
237  * We now have a good query shape, so now look at the WHEN conditions and
238  * action targetlists.
239  *
240  * Overall, the MERGE Query's targetlist is NIL.
241  *
242  * Each individual action has its own targetlist that needs separate
243  * transformation. These transforms don't do anything to the overall
244  * targetlist, since that is only used for resjunk columns.
245  *
246  * We can reference any column in Target or Source, which is OK because
247  * both of those already have RTEs. There is nothing like the EXCLUDED
248  * pseudo-relation for INSERT ON CONFLICT.
249  */
250  mergeActionList = NIL;
251  foreach(l, stmt->mergeWhenClauses)
252  {
253  MergeWhenClause *mergeWhenClause = lfirst_node(MergeWhenClause, l);
255 
257  action->commandType = mergeWhenClause->commandType;
258  action->matched = mergeWhenClause->matched;
259 
260  /* Use an outer join if any INSERT actions exist in the command. */
261  if (action->commandType == CMD_INSERT)
262  qry->mergeUseOuterJoin = true;
263 
264  /*
265  * Set namespace for the specific action. This must be done before
266  * analyzing the WHEN quals and the action targetlist.
267  */
268  setNamespaceForMergeWhen(pstate, mergeWhenClause,
269  qry->resultRelation,
270  sourceRTI);
271 
272  /*
273  * Transform the WHEN condition.
274  *
275  * Note that these quals are NOT added to the join quals; instead they
276  * are evaluated separately during execution to decide which of the
277  * WHEN MATCHED or WHEN NOT MATCHED actions to execute.
278  */
279  action->qual = transformWhereClause(pstate, mergeWhenClause->condition,
280  EXPR_KIND_MERGE_WHEN, "WHEN");
281 
282  /*
283  * Transform target lists for each INSERT and UPDATE action stmt
284  */
285  switch (action->commandType)
286  {
287  case CMD_INSERT:
288  {
289  List *exprList = NIL;
290  ListCell *lc;
291  RTEPermissionInfo *perminfo;
292  ListCell *icols;
293  ListCell *attnos;
294  List *icolumns;
295  List *attrnos;
296 
297  pstate->p_is_insert = true;
298 
299  icolumns = checkInsertTargets(pstate,
300  mergeWhenClause->targetList,
301  &attrnos);
302  Assert(list_length(icolumns) == list_length(attrnos));
303 
304  action->override = mergeWhenClause->override;
305 
306  /*
307  * Handle INSERT much like in transformInsertStmt
308  */
309  if (mergeWhenClause->values == NIL)
310  {
311  /*
312  * We have INSERT ... DEFAULT VALUES. We can handle
313  * this case by emitting an empty targetlist --- all
314  * columns will be defaulted when the planner expands
315  * the targetlist.
316  */
317  exprList = NIL;
318  }
319  else
320  {
321  /*
322  * Process INSERT ... VALUES with a single VALUES
323  * sublist. We treat this case separately for
324  * efficiency. The sublist is just computed directly
325  * as the Query's targetlist, with no VALUES RTE. So
326  * it works just like a SELECT without any FROM.
327  */
328 
329  /*
330  * Do basic expression transformation (same as a ROW()
331  * expr, but allow SetToDefault at top level)
332  */
333  exprList = transformExpressionList(pstate,
334  mergeWhenClause->values,
336  true);
337 
338  /* Prepare row for assignment to target table */
339  exprList = transformInsertRow(pstate, exprList,
340  mergeWhenClause->targetList,
341  icolumns, attrnos,
342  false);
343  }
344 
345  /*
346  * Generate action's target list using the computed list
347  * of expressions. Also, mark all the target columns as
348  * needing insert permissions.
349  */
350  perminfo = pstate->p_target_nsitem->p_perminfo;
351  forthree(lc, exprList, icols, icolumns, attnos, attrnos)
352  {
353  Expr *expr = (Expr *) lfirst(lc);
354  ResTarget *col = lfirst_node(ResTarget, icols);
355  AttrNumber attr_num = (AttrNumber) lfirst_int(attnos);
356  TargetEntry *tle;
357 
358  tle = makeTargetEntry(expr,
359  attr_num,
360  col->name,
361  false);
362  action->targetList = lappend(action->targetList, tle);
363 
364  perminfo->insertedCols =
365  bms_add_member(perminfo->insertedCols,
367  }
368  }
369  break;
370  case CMD_UPDATE:
371  {
372  pstate->p_is_insert = false;
373  action->targetList =
375  mergeWhenClause->targetList);
376  }
377  break;
378  case CMD_DELETE:
379  break;
380 
381  case CMD_NOTHING:
382  action->targetList = NIL;
383  break;
384  default:
385  elog(ERROR, "unknown action in MERGE WHEN clause");
386  }
387 
388  mergeActionList = lappend(mergeActionList, action);
389  }
390 
391  qry->mergeActionList = mergeActionList;
392 
393  /* RETURNING could potentially be added in the future, but not in SQL std */
394  qry->returningList = NULL;
395 
396  qry->hasTargetSRFs = false;
397  qry->hasSubLinks = pstate->p_hasSubLinks;
398 
399  assign_query_collations(pstate, qry);
400 
401  return qry;
402 }
403 
404 static void
406  bool rel_visible,
407  bool cols_visible)
408 {
409  ListCell *lc;
410 
411  foreach(lc, namespace)
412  {
413  ParseNamespaceItem *nsitem = (ParseNamespaceItem *) lfirst(lc);
414 
415  if (nsitem->p_rte == rte)
416  {
417  nsitem->p_rel_visible = rel_visible;
418  nsitem->p_cols_visible = cols_visible;
419  break;
420  }
421  }
422 }
int16 AttrNumber
Definition: attnum.h:21
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:739
unsigned int Index
Definition: c.h:598
int errdetail(const char *fmt,...)
Definition: elog.c:1202
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
Assert(fmt[strlen(fmt) - 1] !='\n')
List * lappend(List *list, void *datum)
Definition: list.c:338
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:240
FromExpr * makeFromExpr(List *fromlist, Node *quals)
Definition: makefuncs.c:287
@ CMD_MERGE
Definition: nodes.h:280
@ CMD_INSERT
Definition: nodes.h:278
@ CMD_DELETE
Definition: nodes.h:279
@ CMD_UPDATE
Definition: nodes.h:277
@ CMD_NOTHING
Definition: nodes.h:283
#define makeNode(_type_)
Definition: nodes.h:176
Node * transformWhereClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName)
void transformFromClause(ParseState *pstate, List *frmList)
Definition: parse_clause.c:116
int setTargetTable(ParseState *pstate, RangeVar *relation, bool inh, bool alsoSource, AclMode requiredPerms)
Definition: parse_clause.c:182
void assign_query_collations(ParseState *pstate, Query *query)
List * transformWithClause(ParseState *pstate, WithClause *withClause)
Definition: parse_cte.c:109
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
Definition: parse_expr.c:92
static void setNamespaceForMergeWhen(ParseState *pstate, MergeWhenClause *mergeWhenClause, Index targetRTI, Index sourceRTI)
Definition: parse_merge.c:55
Query * transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
Definition: parse_merge.c:96
static void setNamespaceVisibilityForRTE(List *namespace, RangeTblEntry *rte, bool rel_visible, bool cols_visible)
Definition: parse_merge.c:405
@ EXPR_KIND_MERGE_WHEN
Definition: parse_node.h:58
@ EXPR_KIND_JOIN_ON
Definition: parse_node.h:42
@ EXPR_KIND_VALUES_SINGLE
Definition: parse_node.h:66
void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
ParseNamespaceItem * GetNSItemByRangeTablePosn(ParseState *pstate, int varno, int sublevels_up)
List * checkInsertTargets(ParseState *pstate, List *cols, List **attrnos)
List * transformExpressionList(ParseState *pstate, List *exprlist, ParseExprKind exprKind, bool allowDefault)
Definition: parse_target.c:221
#define ACL_DELETE
Definition: parsenodes.h:86
uint64 AclMode
Definition: parsenodes.h:81
#define ACL_INSERT
Definition: parsenodes.h:83
#define ACL_NO_RIGHTS
Definition: parsenodes.h:99
#define ACL_UPDATE
Definition: parsenodes.h:85
List * transformUpdateTargetList(ParseState *pstate, List *origTlist)
Definition: analyze.c:2434
List * transformInsertRow(ParseState *pstate, List *exprlist, List *stmtcols, List *icolumns, List *attrnos, bool strip_indirection)
Definition: analyze.c:970
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
int errdetail_relkind_not_supported(char relkind)
Definition: pg_class.c:24
#define lfirst(lc)
Definition: pg_list.h:172
#define lfirst_node(type, lc)
Definition: pg_list.h:176
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
#define lfirst_int(lc)
Definition: pg_list.h:173
#define list_make1(x1)
Definition: pg_list.h:212
#define forthree(cell1, list1, cell2, list2, cell3, list3)
Definition: pg_list.h:512
#define RelationGetRelationName(relation)
Definition: rel.h:535
char * aliasname
Definition: primnodes.h:42
Definition: pg_list.h:54
Node * sourceRelation
Definition: parsenodes.h:1800
List * mergeWhenClauses
Definition: parsenodes.h:1802
RangeVar * relation
Definition: parsenodes.h:1799
Node * joinCondition
Definition: parsenodes.h:1801
WithClause * withClause
Definition: parsenodes.h:1803
OverridingKind override
Definition: parsenodes.h:1675
CmdType commandType
Definition: parsenodes.h:1674
Definition: nodes.h:129
RangeTblEntry * p_rte
Definition: parse_node.h:286
RTEPermissionInfo * p_perminfo
Definition: parse_node.h:288
List * p_ctenamespace
Definition: parse_node.h:203
ParseNamespaceItem * p_target_nsitem
Definition: parse_node.h:207
List * p_namespace
Definition: parse_node.h:200
bool p_is_insert
Definition: parse_node.h:208
bool p_hasModifyingCTE
Definition: parse_node.h:226
List * p_rteperminfos
Definition: parse_node.h:194
Relation p_target_relation
Definition: parse_node.h:206
bool p_hasSubLinks
Definition: parse_node.h:225
List * p_joinlist
Definition: parse_node.h:198
List * p_rtable
Definition: parse_node.h:193
FromExpr * jointree
Definition: parsenodes.h:182
List * returningList
Definition: parsenodes.h:196
List * cteList
Definition: parsenodes.h:173
List * rtable
Definition: parsenodes.h:175
CmdType commandType
Definition: parsenodes.h:128
List * mergeActionList
Definition: parsenodes.h:185
List * targetList
Definition: parsenodes.h:189
Bitmapset * insertedCols
Definition: parsenodes.h:1248
bool inh
Definition: primnodes.h:77
RuleLock * rd_rules
Definition: rel.h:114
Form_pg_class rd_rel
Definition: rel.h:110
char * name
Definition: parsenodes.h:515
int numLocks
Definition: prs2lock.h:42
bool recursive
Definition: parsenodes.h:1549
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27