PostgreSQL Source Code  git master
preptlist.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * preptlist.c
4  * Routines to preprocess the parse tree target list
5  *
6  * For an INSERT, the targetlist must contain an entry for each attribute of
7  * the target relation in the correct order.
8  *
9  * For an UPDATE, the targetlist just contains the expressions for the new
10  * column values.
11  *
12  * For UPDATE and DELETE queries, the targetlist must also contain "junk"
13  * tlist entries needed to allow the executor to identify the rows to be
14  * updated or deleted; for example, the ctid of a heap row. (The planner
15  * adds these; they're not in what we receive from the parser/rewriter.)
16  *
17  * For all query types, there can be additional junk tlist entries, such as
18  * sort keys, Vars needed for a RETURNING list, and row ID information needed
19  * for SELECT FOR UPDATE locking and/or EvalPlanQual checking.
20  *
21  * The query rewrite phase also does preprocessing of the targetlist (see
22  * rewriteTargetListIU). The division of labor between here and there is
23  * partially historical, but it's not entirely arbitrary. The stuff done
24  * here is closely connected to physical access to tables, whereas the
25  * rewriter's work is more concerned with SQL semantics.
26  *
27  *
28  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
29  * Portions Copyright (c) 1994, Regents of the University of California
30  *
31  * IDENTIFICATION
32  * src/backend/optimizer/prep/preptlist.c
33  *
34  *-------------------------------------------------------------------------
35  */
36 
37 #include "postgres.h"
38 
39 #include "access/table.h"
40 #include "nodes/makefuncs.h"
41 #include "optimizer/appendinfo.h"
42 #include "optimizer/optimizer.h"
43 #include "optimizer/prep.h"
44 #include "optimizer/tlist.h"
45 #include "parser/parse_coerce.h"
46 #include "parser/parsetree.h"
47 #include "utils/rel.h"
48 
49 static List *expand_insert_targetlist(List *tlist, Relation rel);
50 
51 
52 /*
53  * preprocess_targetlist
54  * Driver for preprocessing the parse tree targetlist.
55  *
56  * The preprocessed targetlist is returned in root->processed_tlist.
57  * Also, if this is an UPDATE, we return a list of target column numbers
58  * in root->update_colnos. (Resnos in processed_tlist will be consecutive,
59  * so do not look at that to find out which columns are targets!)
60  */
61 void
63 {
64  Query *parse = root->parse;
65  int result_relation = parse->resultRelation;
66  List *range_table = parse->rtable;
67  CmdType command_type = parse->commandType;
68  RangeTblEntry *target_rte = NULL;
69  Relation target_relation = NULL;
70  List *tlist;
71  ListCell *lc;
72 
73  /*
74  * If there is a result relation, open it so we can look for missing
75  * columns and so on. We assume that previous code already acquired at
76  * least AccessShareLock on the relation, so we need no lock here.
77  */
78  if (result_relation)
79  {
80  target_rte = rt_fetch(result_relation, range_table);
81 
82  /*
83  * Sanity check: it'd better be a real relation not, say, a subquery.
84  * Else parser or rewriter messed up.
85  */
86  if (target_rte->rtekind != RTE_RELATION)
87  elog(ERROR, "result relation must be a regular relation");
88 
89  target_relation = table_open(target_rte->relid, NoLock);
90  }
91  else
92  Assert(command_type == CMD_SELECT);
93 
94  /*
95  * In an INSERT, the executor expects the targetlist to match the exact
96  * order of the target table's attributes, including entries for
97  * attributes not mentioned in the source query.
98  *
99  * In an UPDATE, we don't rearrange the tlist order, but we need to make a
100  * separate list of the target attribute numbers, in tlist order, and then
101  * renumber the processed_tlist entries to be consecutive.
102  */
103  tlist = parse->targetList;
104  if (command_type == CMD_INSERT)
105  tlist = expand_insert_targetlist(tlist, target_relation);
106  else if (command_type == CMD_UPDATE)
107  root->update_colnos = extract_update_targetlist_colnos(tlist);
108 
109  /*
110  * For non-inherited UPDATE/DELETE/MERGE, register any junk column(s)
111  * needed to allow the executor to identify the rows to be updated or
112  * deleted. In the inheritance case, we do nothing now, leaving this to
113  * be dealt with when expand_inherited_rtentry() makes the leaf target
114  * relations. (But there might not be any leaf target relations, in which
115  * case we must do this in distribute_row_identity_vars().)
116  */
117  if ((command_type == CMD_UPDATE || command_type == CMD_DELETE ||
118  command_type == CMD_MERGE) &&
119  !target_rte->inh)
120  {
121  /* row-identity logic expects to add stuff to processed_tlist */
122  root->processed_tlist = tlist;
123  add_row_identity_columns(root, result_relation,
124  target_rte, target_relation);
125  tlist = root->processed_tlist;
126  }
127 
128  /*
129  * For MERGE we also need to handle the target list for each INSERT and
130  * UPDATE action separately. In addition, we examine the qual of each
131  * action and add any Vars there (other than those of the target rel) to
132  * the subplan targetlist.
133  */
134  if (command_type == CMD_MERGE)
135  {
136  ListCell *l;
137 
138  /*
139  * For MERGE, handle targetlist of each MergeAction separately. Give
140  * the same treatment to MergeAction->targetList as we would have
141  * given to a regular INSERT. For UPDATE, collect the column numbers
142  * being modified.
143  */
144  foreach(l, parse->mergeActionList)
145  {
147  List *vars;
148  ListCell *l2;
149 
150  if (action->commandType == CMD_INSERT)
151  action->targetList = expand_insert_targetlist(action->targetList,
152  target_relation);
153  else if (action->commandType == CMD_UPDATE)
154  action->updateColnos =
156 
157  /*
158  * Add resjunk entries for any Vars and PlaceHolderVars used in
159  * each action's targetlist and WHEN condition that belong to
160  * relations other than the target. We don't expect to see any
161  * aggregates or window functions here.
162  */
164  list_concat_copy((List *) action->qual,
165  action->targetList),
167  foreach(l2, vars)
168  {
169  Var *var = (Var *) lfirst(l2);
170  TargetEntry *tle;
171 
172  if (IsA(var, Var) && var->varno == result_relation)
173  continue; /* don't need it */
174 
175  if (tlist_member((Expr *) var, tlist))
176  continue; /* already got it */
177 
178  tle = makeTargetEntry((Expr *) var,
179  list_length(tlist) + 1,
180  NULL, true);
181  tlist = lappend(tlist, tle);
182  }
183  list_free(vars);
184  }
185  }
186 
187  /*
188  * Add necessary junk columns for rowmarked rels. These values are needed
189  * for locking of rels selected FOR UPDATE/SHARE, and to do EvalPlanQual
190  * rechecking. See comments for PlanRowMark in plannodes.h. If you
191  * change this stanza, see also expand_inherited_rtentry(), which has to
192  * be able to add on junk columns equivalent to these.
193  *
194  * (Someday it might be useful to fold these resjunk columns into the
195  * row-identity-column management used for UPDATE/DELETE. Today is not
196  * that day, however. One notable issue is that it seems important that
197  * the whole-row Vars made here use the real table rowtype, not RECORD, so
198  * that conversion to/from child relations' rowtypes will happen. Also,
199  * since these entries don't potentially bloat with more and more child
200  * relations, there's not really much need for column sharing.)
201  */
202  foreach(lc, root->rowMarks)
203  {
204  PlanRowMark *rc = (PlanRowMark *) lfirst(lc);
205  Var *var;
206  char resname[32];
207  TargetEntry *tle;
208 
209  /* child rels use the same junk attrs as their parents */
210  if (rc->rti != rc->prti)
211  continue;
212 
213  if (rc->allMarkTypes & ~(1 << ROW_MARK_COPY))
214  {
215  /* Need to fetch TID */
216  var = makeVar(rc->rti,
218  TIDOID,
219  -1,
220  InvalidOid,
221  0);
222  snprintf(resname, sizeof(resname), "ctid%u", rc->rowmarkId);
223  tle = makeTargetEntry((Expr *) var,
224  list_length(tlist) + 1,
225  pstrdup(resname),
226  true);
227  tlist = lappend(tlist, tle);
228  }
229  if (rc->allMarkTypes & (1 << ROW_MARK_COPY))
230  {
231  /* Need the whole row as a junk var */
232  var = makeWholeRowVar(rt_fetch(rc->rti, range_table),
233  rc->rti,
234  0,
235  false);
236  snprintf(resname, sizeof(resname), "wholerow%u", rc->rowmarkId);
237  tle = makeTargetEntry((Expr *) var,
238  list_length(tlist) + 1,
239  pstrdup(resname),
240  true);
241  tlist = lappend(tlist, tle);
242  }
243 
244  /* If parent of inheritance tree, always fetch the tableoid too. */
245  if (rc->isParent)
246  {
247  var = makeVar(rc->rti,
249  OIDOID,
250  -1,
251  InvalidOid,
252  0);
253  snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId);
254  tle = makeTargetEntry((Expr *) var,
255  list_length(tlist) + 1,
256  pstrdup(resname),
257  true);
258  tlist = lappend(tlist, tle);
259  }
260  }
261 
262  /*
263  * If the query has a RETURNING list, add resjunk entries for any Vars
264  * used in RETURNING that belong to other relations. We need to do this
265  * to make these Vars available for the RETURNING calculation. Vars that
266  * belong to the result rel don't need to be added, because they will be
267  * made to refer to the actual heap tuple.
268  */
269  if (parse->returningList && list_length(parse->rtable) > 1)
270  {
271  List *vars;
272  ListCell *l;
273 
274  vars = pull_var_clause((Node *) parse->returningList,
278  foreach(l, vars)
279  {
280  Var *var = (Var *) lfirst(l);
281  TargetEntry *tle;
282 
283  if (IsA(var, Var) &&
284  var->varno == result_relation)
285  continue; /* don't need it */
286 
287  if (tlist_member((Expr *) var, tlist))
288  continue; /* already got it */
289 
290  tle = makeTargetEntry((Expr *) var,
291  list_length(tlist) + 1,
292  NULL,
293  true);
294 
295  tlist = lappend(tlist, tle);
296  }
297  list_free(vars);
298  }
299 
300  root->processed_tlist = tlist;
301 
302  if (target_relation)
303  table_close(target_relation, NoLock);
304 }
305 
306 /*
307  * extract_update_targetlist_colnos
308  * Extract a list of the target-table column numbers that
309  * an UPDATE's targetlist wants to assign to, then renumber.
310  *
311  * The convention in the parser and rewriter is that the resnos in an
312  * UPDATE's non-resjunk TLE entries are the target column numbers
313  * to assign to. Here, we extract that info into a separate list, and
314  * then convert the tlist to the sequential-numbering convention that's
315  * used by all other query types.
316  *
317  * This is also applied to the tlist associated with INSERT ... ON CONFLICT
318  * ... UPDATE, although not till much later in planning.
319  */
320 List *
322 {
323  List *update_colnos = NIL;
324  AttrNumber nextresno = 1;
325  ListCell *lc;
326 
327  foreach(lc, tlist)
328  {
329  TargetEntry *tle = (TargetEntry *) lfirst(lc);
330 
331  if (!tle->resjunk)
332  update_colnos = lappend_int(update_colnos, tle->resno);
333  tle->resno = nextresno++;
334  }
335  return update_colnos;
336 }
337 
338 
339 /*****************************************************************************
340  *
341  * TARGETLIST EXPANSION
342  *
343  *****************************************************************************/
344 
345 /*
346  * expand_insert_targetlist
347  * Given a target list as generated by the parser and a result relation,
348  * add targetlist entries for any missing attributes, and ensure the
349  * non-junk attributes appear in proper field order.
350  *
351  * Once upon a time we also did more or less this with UPDATE targetlists,
352  * but now this code is only applied to INSERT targetlists.
353  */
354 static List *
356 {
357  List *new_tlist = NIL;
358  ListCell *tlist_item;
359  int attrno,
360  numattrs;
361 
362  tlist_item = list_head(tlist);
363 
364  /*
365  * The rewriter should have already ensured that the TLEs are in correct
366  * order; but we have to insert TLEs for any missing attributes.
367  *
368  * Scan the tuple description in the relation's relcache entry to make
369  * sure we have all the user attributes in the right order.
370  */
371  numattrs = RelationGetNumberOfAttributes(rel);
372 
373  for (attrno = 1; attrno <= numattrs; attrno++)
374  {
375  Form_pg_attribute att_tup = TupleDescAttr(rel->rd_att, attrno - 1);
376  TargetEntry *new_tle = NULL;
377 
378  if (tlist_item != NULL)
379  {
380  TargetEntry *old_tle = (TargetEntry *) lfirst(tlist_item);
381 
382  if (!old_tle->resjunk && old_tle->resno == attrno)
383  {
384  new_tle = old_tle;
385  tlist_item = lnext(tlist, tlist_item);
386  }
387  }
388 
389  if (new_tle == NULL)
390  {
391  /*
392  * Didn't find a matching tlist entry, so make one.
393  *
394  * INSERTs should insert NULL in this case. (We assume the
395  * rewriter would have inserted any available non-NULL default
396  * value.) Also, if the column isn't dropped, apply any domain
397  * constraints that might exist --- this is to catch domain NOT
398  * NULL.
399  *
400  * When generating a NULL constant for a dropped column, we label
401  * it INT4 (any other guaranteed-to-exist datatype would do as
402  * well). We can't label it with the dropped column's datatype
403  * since that might not exist anymore. It does not really matter
404  * what we claim the type is, since NULL is NULL --- its
405  * representation is datatype-independent. This could perhaps
406  * confuse code comparing the finished plan to the target
407  * relation, however.
408  */
409  Oid atttype = att_tup->atttypid;
410  Oid attcollation = att_tup->attcollation;
411  Node *new_expr;
412 
413  if (!att_tup->attisdropped)
414  {
415  new_expr = (Node *) makeConst(atttype,
416  -1,
417  attcollation,
418  att_tup->attlen,
419  (Datum) 0,
420  true, /* isnull */
421  att_tup->attbyval);
422  new_expr = coerce_to_domain(new_expr,
423  InvalidOid, -1,
424  atttype,
427  -1,
428  false);
429  }
430  else
431  {
432  /* Insert NULL for dropped column */
433  new_expr = (Node *) makeConst(INT4OID,
434  -1,
435  InvalidOid,
436  sizeof(int32),
437  (Datum) 0,
438  true, /* isnull */
439  true /* byval */ );
440  }
441 
442  new_tle = makeTargetEntry((Expr *) new_expr,
443  attrno,
444  pstrdup(NameStr(att_tup->attname)),
445  false);
446  }
447 
448  new_tlist = lappend(new_tlist, new_tle);
449  }
450 
451  /*
452  * The remaining tlist entries should be resjunk; append them all to the
453  * end of the new tlist, making sure they have resnos higher than the last
454  * real attribute. (Note: although the rewriter already did such
455  * renumbering, we have to do it again here in case we added NULL entries
456  * above.)
457  */
458  while (tlist_item)
459  {
460  TargetEntry *old_tle = (TargetEntry *) lfirst(tlist_item);
461 
462  if (!old_tle->resjunk)
463  elog(ERROR, "targetlist is not sorted correctly");
464  /* Get the resno right, but don't copy unnecessarily */
465  if (old_tle->resno != attrno)
466  {
467  old_tle = flatCopyTargetEntry(old_tle);
468  old_tle->resno = attrno;
469  }
470  new_tlist = lappend(new_tlist, old_tle);
471  attrno++;
472  tlist_item = lnext(tlist, tlist_item);
473  }
474 
475  return new_tlist;
476 }
477 
478 
479 /*
480  * Locate PlanRowMark for given RT index, or return NULL if none
481  *
482  * This probably ought to be elsewhere, but there's no very good place
483  */
484 PlanRowMark *
485 get_plan_rowmark(List *rowmarks, Index rtindex)
486 {
487  ListCell *l;
488 
489  foreach(l, rowmarks)
490  {
491  PlanRowMark *rc = (PlanRowMark *) lfirst(l);
492 
493  if (rc->rti == rtindex)
494  return rc;
495  }
496  return NULL;
497 }
void add_row_identity_columns(PlannerInfo *root, Index rtindex, RangeTblEntry *target_rte, Relation target_relation)
Definition: appendinfo.c:884
int16 AttrNumber
Definition: attnum.h:21
#define NameStr(name)
Definition: c.h:733
signed int int32
Definition: c.h:481
unsigned int Index
Definition: c.h:601
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
Assert(fmt[strlen(fmt) - 1] !='\n')
List * lappend(List *list, void *datum)
Definition: list.c:339
List * lappend_int(List *list, int datum)
Definition: list.c:357
void list_free(List *list)
Definition: list.c:1546
List * list_concat_copy(const List *list1, const List *list2)
Definition: list.c:598
#define NoLock
Definition: lockdefs.h:34
Var * makeWholeRowVar(RangeTblEntry *rte, int varno, Index varlevelsup, bool allowScalar)
Definition: makefuncs.c:135
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:240
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:301
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
TargetEntry * flatCopyTargetEntry(TargetEntry *src_tle)
Definition: makefuncs.c:273
char * pstrdup(const char *in)
Definition: mcxt.c:1683
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
CmdType
Definition: nodes.h:263
@ CMD_MERGE
Definition: nodes.h:269
@ CMD_INSERT
Definition: nodes.h:267
@ CMD_DELETE
Definition: nodes.h:268
@ CMD_UPDATE
Definition: nodes.h:266
@ CMD_SELECT
Definition: nodes.h:265
#define PVC_RECURSE_AGGREGATES
Definition: optimizer.h:187
#define PVC_RECURSE_WINDOWFUNCS
Definition: optimizer.h:189
#define PVC_INCLUDE_PLACEHOLDERS
Definition: optimizer.h:190
Node * coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId, CoercionContext ccontext, CoercionForm cformat, int location, bool hideInputCoercion)
Definition: parse_coerce.c:676
@ RTE_RELATION
Definition: parsenodes.h:1011
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
static ListCell * list_head(const List *l)
Definition: pg_list.h:128
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
@ ROW_MARK_COPY
Definition: plannodes.h:1332
#define snprintf
Definition: port.h:238
uintptr_t Datum
Definition: postgres.h:64
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
PlanRowMark * get_plan_rowmark(List *rowmarks, Index rtindex)
Definition: preptlist.c:485
void preprocess_targetlist(PlannerInfo *root)
Definition: preptlist.c:62
static List * expand_insert_targetlist(List *tlist, Relation rel)
Definition: preptlist.c:355
List * extract_update_targetlist_colnos(List *tlist)
Definition: preptlist.c:321
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:692
@ COERCION_IMPLICIT
Definition: primnodes.h:670
tree ctl root
Definition: radixtree.h:1840
static struct subre * parse(struct vars *v, int stopper, int type, struct state *init, struct state *final)
Definition: regcomp.c:715
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:513
Definition: pg_list.h:54
Definition: nodes.h:129
Index prti
Definition: plannodes.h:1381
bool isParent
Definition: plannodes.h:1387
Index rowmarkId
Definition: plannodes.h:1382
int allMarkTypes
Definition: plannodes.h:1384
RTEKind rtekind
Definition: parsenodes.h:1040
TupleDesc rd_att
Definition: rel.h:112
AttrNumber resno
Definition: primnodes.h:2067
Definition: primnodes.h:234
int varno
Definition: primnodes.h:241
Definition: regcomp.c:281
#define TableOidAttributeNumber
Definition: sysattr.h:26
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
TargetEntry * tlist_member(Expr *node, List *targetlist)
Definition: tlist.c:79
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
List * pull_var_clause(Node *node, int flags)
Definition: var.c:607