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-2022, 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 (mergeWhenClause->condition == NULL)
159  is_terminal[when_type] = true;
160  else if (is_terminal[when_type])
161  ereport(ERROR,
162  (errcode(ERRCODE_SYNTAX_ERROR),
163  errmsg("unreachable WHEN clause specified after unconditional WHEN clause")));
164  }
165 
166  /* Set up the MERGE target table. */
167  qry->resultRelation = setTargetTable(pstate, stmt->relation,
168  stmt->relation->inh,
169  false, targetPerms);
170 
171  /*
172  * MERGE is unsupported in various cases
173  */
174  if (pstate->p_target_relation->rd_rel->relkind != RELKIND_RELATION &&
175  pstate->p_target_relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
176  ereport(ERROR,
177  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
178  errmsg("cannot execute MERGE on relation \"%s\"",
181  if (pstate->p_target_relation->rd_rel->relhasrules)
182  ereport(ERROR,
183  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
184  errmsg("cannot execute MERGE on relation \"%s\"",
186  errdetail("MERGE is not supported for relations with rules.")));
187 
188  /* Now transform the source relation to produce the source RTE. */
189  transformFromClause(pstate,
190  list_make1(stmt->sourceRelation));
191  sourceRTI = list_length(pstate->p_rtable);
192  nsitem = GetNSItemByRangeTablePosn(pstate, sourceRTI, 0);
193 
194  /*
195  * Check that the target table doesn't conflict with the source table.
196  * This would typically be a checkNameSpaceConflicts call, but we want a
197  * more specific error message.
198  */
199  if (strcmp(pstate->p_target_nsitem->p_names->aliasname,
200  nsitem->p_names->aliasname) == 0)
201  ereport(ERROR,
202  errcode(ERRCODE_DUPLICATE_ALIAS),
203  errmsg("name \"%s\" specified more than once",
204  pstate->p_target_nsitem->p_names->aliasname),
205  errdetail("The name is used both as MERGE target table and data source."));
206 
207  /*
208  * There's no need for a targetlist here; it'll be set up by
209  * preprocess_targetlist later.
210  */
211  qry->targetList = NIL;
212  qry->rtable = pstate->p_rtable;
213 
214  /*
215  * Transform the join condition. This includes references to the target
216  * side, so add that to the namespace.
217  */
218  addNSItemToQuery(pstate, pstate->p_target_nsitem, false, true, true);
219  joinExpr = transformExpr(pstate, stmt->joinCondition,
221 
222  /*
223  * Create the temporary query's jointree using the joinlist we built using
224  * just the source relation; the target relation is not included. The
225  * quals we use are the join conditions to the merge target. The join
226  * will be constructed fully by transform_MERGE_to_join.
227  */
228  qry->jointree = makeFromExpr(pstate->p_joinlist, joinExpr);
229 
230  /*
231  * We now have a good query shape, so now look at the WHEN conditions and
232  * action targetlists.
233  *
234  * Overall, the MERGE Query's targetlist is NIL.
235  *
236  * Each individual action has its own targetlist that needs separate
237  * transformation. These transforms don't do anything to the overall
238  * targetlist, since that is only used for resjunk columns.
239  *
240  * We can reference any column in Target or Source, which is OK because
241  * both of those already have RTEs. There is nothing like the EXCLUDED
242  * pseudo-relation for INSERT ON CONFLICT.
243  */
244  mergeActionList = NIL;
245  foreach(l, stmt->mergeWhenClauses)
246  {
247  MergeWhenClause *mergeWhenClause = lfirst_node(MergeWhenClause, l);
249 
251  action->commandType = mergeWhenClause->commandType;
252  action->matched = mergeWhenClause->matched;
253 
254  /* Use an outer join if any INSERT actions exist in the command. */
255  if (action->commandType == CMD_INSERT)
256  qry->mergeUseOuterJoin = true;
257 
258  /*
259  * Set namespace for the specific action. This must be done before
260  * analyzing the WHEN quals and the action targetlist.
261  */
262  setNamespaceForMergeWhen(pstate, mergeWhenClause,
263  qry->resultRelation,
264  sourceRTI);
265 
266  /*
267  * Transform the WHEN condition.
268  *
269  * Note that these quals are NOT added to the join quals; instead they
270  * are evaluated separately during execution to decide which of the
271  * WHEN MATCHED or WHEN NOT MATCHED actions to execute.
272  */
273  action->qual = transformWhereClause(pstate, mergeWhenClause->condition,
274  EXPR_KIND_MERGE_WHEN, "WHEN");
275 
276  /*
277  * Transform target lists for each INSERT and UPDATE action stmt
278  */
279  switch (action->commandType)
280  {
281  case CMD_INSERT:
282  {
283  List *exprList = NIL;
284  ListCell *lc;
285  RangeTblEntry *rte;
286  ListCell *icols;
287  ListCell *attnos;
288  List *icolumns;
289  List *attrnos;
290 
291  pstate->p_is_insert = true;
292 
293  icolumns = checkInsertTargets(pstate,
294  mergeWhenClause->targetList,
295  &attrnos);
296  Assert(list_length(icolumns) == list_length(attrnos));
297 
298  action->override = mergeWhenClause->override;
299 
300  /*
301  * Handle INSERT much like in transformInsertStmt
302  */
303  if (mergeWhenClause->values == NIL)
304  {
305  /*
306  * We have INSERT ... DEFAULT VALUES. We can handle
307  * this case by emitting an empty targetlist --- all
308  * columns will be defaulted when the planner expands
309  * the targetlist.
310  */
311  exprList = NIL;
312  }
313  else
314  {
315  /*
316  * Process INSERT ... VALUES with a single VALUES
317  * sublist. We treat this case separately for
318  * efficiency. The sublist is just computed directly
319  * as the Query's targetlist, with no VALUES RTE. So
320  * it works just like a SELECT without any FROM.
321  */
322 
323  /*
324  * Do basic expression transformation (same as a ROW()
325  * expr, but allow SetToDefault at top level)
326  */
327  exprList = transformExpressionList(pstate,
328  mergeWhenClause->values,
330  true);
331 
332  /* Prepare row for assignment to target table */
333  exprList = transformInsertRow(pstate, exprList,
334  mergeWhenClause->targetList,
335  icolumns, attrnos,
336  false);
337  }
338 
339  /*
340  * Generate action's target list using the computed list
341  * of expressions. Also, mark all the target columns as
342  * needing insert permissions.
343  */
344  rte = pstate->p_target_nsitem->p_rte;
345  forthree(lc, exprList, icols, icolumns, attnos, attrnos)
346  {
347  Expr *expr = (Expr *) lfirst(lc);
348  ResTarget *col = lfirst_node(ResTarget, icols);
349  AttrNumber attr_num = (AttrNumber) lfirst_int(attnos);
350  TargetEntry *tle;
351 
352  tle = makeTargetEntry(expr,
353  attr_num,
354  col->name,
355  false);
356  action->targetList = lappend(action->targetList, tle);
357 
358  rte->insertedCols =
361  }
362  }
363  break;
364  case CMD_UPDATE:
365  {
366  pstate->p_is_insert = false;
367  action->targetList =
369  mergeWhenClause->targetList);
370  }
371  break;
372  case CMD_DELETE:
373  break;
374 
375  case CMD_NOTHING:
376  action->targetList = NIL;
377  break;
378  default:
379  elog(ERROR, "unknown action in MERGE WHEN clause");
380  }
381 
382  mergeActionList = lappend(mergeActionList, action);
383  }
384 
385  qry->mergeActionList = mergeActionList;
386 
387  /* RETURNING could potentially be added in the future, but not in SQL std */
388  qry->returningList = NULL;
389 
390  qry->hasTargetSRFs = false;
391  qry->hasSubLinks = pstate->p_hasSubLinks;
392 
393  assign_query_collations(pstate, qry);
394 
395  return qry;
396 }
397 
398 static void
400  bool rel_visible,
401  bool cols_visible)
402 {
403  ListCell *lc;
404 
405  foreach(lc, namespace)
406  {
407  ParseNamespaceItem *nsitem = (ParseNamespaceItem *) lfirst(lc);
408 
409  if (nsitem->p_rte == rte)
410  {
411  nsitem->p_rel_visible = rel_visible;
412  nsitem->p_cols_visible = cols_visible;
413  break;
414  }
415  }
416 }
int16 AttrNumber
Definition: attnum.h:21
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:738
unsigned int Index
Definition: c.h:549
int errdetail(const char *fmt,...)
Definition: elog.c:1037
int errcode(int sqlerrcode)
Definition: elog.c:693
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define ERROR
Definition: elog.h:33
#define elog(elevel,...)
Definition: elog.h:218
#define ereport(elevel,...)
Definition: elog.h:143
Assert(fmt[strlen(fmt) - 1] !='\n')
List * lappend(List *list, void *datum)
Definition: list.c:336
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:239
FromExpr * makeFromExpr(List *fromlist, Node *quals)
Definition: makefuncs.c:286
@ CMD_MERGE
Definition: nodes.h:725
@ CMD_INSERT
Definition: nodes.h:723
@ CMD_DELETE
Definition: nodes.h:724
@ CMD_UPDATE
Definition: nodes.h:722
@ CMD_NOTHING
Definition: nodes.h:728
#define makeNode(_type_)
Definition: nodes.h:621
Node * transformWhereClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName)
void transformFromClause(ParseState *pstate, List *frmList)
Definition: parse_clause.c:113
int setTargetTable(ParseState *pstate, RangeVar *relation, bool inh, bool alsoSource, AclMode requiredPerms)
Definition: parse_clause.c:177
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:112
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:399
@ 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:222
#define ACL_DELETE
Definition: parsenodes.h:85
#define ACL_INSERT
Definition: parsenodes.h:82
#define ACL_NO_RIGHTS
Definition: parsenodes.h:97
#define ACL_UPDATE
Definition: parsenodes.h:84
uint32 AclMode
Definition: parsenodes.h:80
List * transformUpdateTargetList(ParseState *pstate, List *origTlist)
Definition: analyze.c:2423
List * transformInsertRow(ParseState *pstate, List *exprlist, List *stmtcols, List *icolumns, List *attrnos, bool strip_indirection)
Definition: analyze.c:962
#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:169
#define lfirst_node(type, lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:149
#define NIL
Definition: pg_list.h:65
#define lfirst_int(lc)
Definition: pg_list.h:170
#define list_make1(x1)
Definition: pg_list.h:206
#define forthree(cell1, list1, cell2, list2, cell3, list3)
Definition: pg_list.h:491
#define RelationGetRelationName(relation)
Definition: rel.h:522
char * aliasname
Definition: primnodes.h:42
Definition: pg_list.h:51
Node * sourceRelation
Definition: parsenodes.h:1969
List * mergeWhenClauses
Definition: parsenodes.h:1971
RangeVar * relation
Definition: parsenodes.h:1968
Node * joinCondition
Definition: parsenodes.h:1970
WithClause * withClause
Definition: parsenodes.h:1972
OverridingKind override
Definition: parsenodes.h:1559
CmdType commandType
Definition: parsenodes.h:1558
Definition: nodes.h:574
RangeTblEntry * p_rte
Definition: parse_node.h:269
List * p_ctenamespace
Definition: parse_node.h:190
ParseNamespaceItem * p_target_nsitem
Definition: parse_node.h:194
List * p_namespace
Definition: parse_node.h:187
bool p_is_insert
Definition: parse_node.h:195
bool p_hasModifyingCTE
Definition: parse_node.h:213
Relation p_target_relation
Definition: parse_node.h:193
bool p_hasSubLinks
Definition: parse_node.h:212
List * p_joinlist
Definition: parse_node.h:185
List * p_rtable
Definition: parse_node.h:183
FromExpr * jointree
Definition: parsenodes.h:149
List * returningList
Definition: parsenodes.h:161
List * cteList
Definition: parsenodes.h:146
bool hasTargetSRFs
Definition: parsenodes.h:136
List * rtable
Definition: parsenodes.h:148
int resultRelation
Definition: parsenodes.h:131
CmdType commandType
Definition: parsenodes.h:121
bool hasRecursive
Definition: parsenodes.h:139
bool hasModifyingCTE
Definition: parsenodes.h:140
List * mergeActionList
Definition: parsenodes.h:152
List * targetList
Definition: parsenodes.h:155
bool mergeUseOuterJoin
Definition: parsenodes.h:153
bool hasSubLinks
Definition: parsenodes.h:137
Bitmapset * insertedCols
Definition: parsenodes.h:1168
bool inh
Definition: primnodes.h:69
Form_pg_class rd_rel
Definition: rel.h:109
char * name
Definition: parsenodes.h:471
bool recursive
Definition: parsenodes.h:1448
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27