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 INSERT and UPDATE queries, the targetlist must contain an entry for
7  * each attribute of the target relation in the correct order. For UPDATE and
8  * DELETE queries, it must also contain junk tlist entries needed to allow the
9  * executor to identify the rows to be updated or deleted. For all query
10  * types, we may need to add junk tlist entries for Vars used in the RETURNING
11  * list and row ID information needed for SELECT FOR UPDATE locking and/or
12  * EvalPlanQual checking.
13  *
14  * The query rewrite phase also does preprocessing of the targetlist (see
15  * rewriteTargetListIU). The division of labor between here and there is
16  * partially historical, but it's not entirely arbitrary. In particular,
17  * consider an UPDATE across an inheritance tree. What rewriteTargetListIU
18  * does need be done only once (because it depends only on the properties of
19  * the parent relation). What's done here has to be done over again for each
20  * child relation, because it depends on the properties of the child, which
21  * might be of a different relation type, or have more columns and/or a
22  * different column order than the parent.
23  *
24  * The fact that rewriteTargetListIU sorts non-resjunk tlist entries by column
25  * position, which expand_targetlist depends on, violates the above comment
26  * because the sorting is only valid for the parent relation. In inherited
27  * UPDATE cases, adjust_inherited_tlist runs in between to take care of fixing
28  * the tlists for child tables to keep expand_targetlist happy. We do it like
29  * that because it's faster in typical non-inherited cases.
30  *
31  *
32  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
33  * Portions Copyright (c) 1994, Regents of the University of California
34  *
35  * IDENTIFICATION
36  * src/backend/optimizer/prep/preptlist.c
37  *
38  *-------------------------------------------------------------------------
39  */
40 
41 #include "postgres.h"
42 
43 #include "access/sysattr.h"
44 #include "access/table.h"
45 #include "catalog/pg_type.h"
46 #include "nodes/makefuncs.h"
47 #include "optimizer/optimizer.h"
48 #include "optimizer/prep.h"
49 #include "optimizer/tlist.h"
50 #include "parser/parsetree.h"
51 #include "parser/parse_coerce.h"
52 #include "rewrite/rewriteHandler.h"
53 #include "utils/rel.h"
54 
55 
56 static List *expand_targetlist(List *tlist, int command_type,
57  Index result_relation, Relation rel);
58 
59 
60 /*
61  * preprocess_targetlist
62  * Driver for preprocessing the parse tree targetlist.
63  *
64  * Returns the new targetlist.
65  *
66  * As a side effect, if there's an ON CONFLICT UPDATE clause, its targetlist
67  * is also preprocessed (and updated in-place).
68  */
69 List *
71 {
72  Query *parse = root->parse;
73  int result_relation = parse->resultRelation;
74  List *range_table = parse->rtable;
75  CmdType command_type = parse->commandType;
76  RangeTblEntry *target_rte = NULL;
77  Relation target_relation = NULL;
78  List *tlist;
79  ListCell *lc;
80 
81  /*
82  * If there is a result relation, open it so we can look for missing
83  * columns and so on. We assume that previous code already acquired at
84  * least AccessShareLock on the relation, so we need no lock here.
85  */
86  if (result_relation)
87  {
88  target_rte = rt_fetch(result_relation, range_table);
89 
90  /*
91  * Sanity check: it'd better be a real relation not, say, a subquery.
92  * Else parser or rewriter messed up.
93  */
94  if (target_rte->rtekind != RTE_RELATION)
95  elog(ERROR, "result relation must be a regular relation");
96 
97  target_relation = table_open(target_rte->relid, NoLock);
98  }
99  else
100  Assert(command_type == CMD_SELECT);
101 
102  /*
103  * For UPDATE/DELETE, add any junk column(s) needed to allow the executor
104  * to identify the rows to be updated or deleted. Note that this step
105  * scribbles on parse->targetList, which is not very desirable, but we
106  * keep it that way to avoid changing APIs used by FDWs.
107  */
108  if (command_type == CMD_UPDATE || command_type == CMD_DELETE)
109  rewriteTargetListUD(parse, target_rte, target_relation);
110 
111  /*
112  * for heap_form_tuple to work, the targetlist must match the exact order
113  * of the attributes. We also need to fill in any missing attributes. -ay
114  * 10/94
115  */
116  tlist = parse->targetList;
117  if (command_type == CMD_INSERT || command_type == CMD_UPDATE)
118  tlist = expand_targetlist(tlist, command_type,
119  result_relation, target_relation);
120 
121  /*
122  * Add necessary junk columns for rowmarked rels. These values are needed
123  * for locking of rels selected FOR UPDATE/SHARE, and to do EvalPlanQual
124  * rechecking. See comments for PlanRowMark in plannodes.h. If you
125  * change this stanza, see also expand_inherited_rtentry(), which has to
126  * be able to add on junk columns equivalent to these.
127  */
128  foreach(lc, root->rowMarks)
129  {
130  PlanRowMark *rc = (PlanRowMark *) lfirst(lc);
131  Var *var;
132  char resname[32];
133  TargetEntry *tle;
134 
135  /* child rels use the same junk attrs as their parents */
136  if (rc->rti != rc->prti)
137  continue;
138 
139  if (rc->allMarkTypes & ~(1 << ROW_MARK_COPY))
140  {
141  /* Need to fetch TID */
142  var = makeVar(rc->rti,
144  TIDOID,
145  -1,
146  InvalidOid,
147  0);
148  snprintf(resname, sizeof(resname), "ctid%u", rc->rowmarkId);
149  tle = makeTargetEntry((Expr *) var,
150  list_length(tlist) + 1,
151  pstrdup(resname),
152  true);
153  tlist = lappend(tlist, tle);
154  }
155  if (rc->allMarkTypes & (1 << ROW_MARK_COPY))
156  {
157  /* Need the whole row as a junk var */
158  var = makeWholeRowVar(rt_fetch(rc->rti, range_table),
159  rc->rti,
160  0,
161  false);
162  snprintf(resname, sizeof(resname), "wholerow%u", rc->rowmarkId);
163  tle = makeTargetEntry((Expr *) var,
164  list_length(tlist) + 1,
165  pstrdup(resname),
166  true);
167  tlist = lappend(tlist, tle);
168  }
169 
170  /* If parent of inheritance tree, always fetch the tableoid too. */
171  if (rc->isParent)
172  {
173  var = makeVar(rc->rti,
175  OIDOID,
176  -1,
177  InvalidOid,
178  0);
179  snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId);
180  tle = makeTargetEntry((Expr *) var,
181  list_length(tlist) + 1,
182  pstrdup(resname),
183  true);
184  tlist = lappend(tlist, tle);
185  }
186  }
187 
188  /*
189  * If the query has a RETURNING list, add resjunk entries for any Vars
190  * used in RETURNING that belong to other relations. We need to do this
191  * to make these Vars available for the RETURNING calculation. Vars that
192  * belong to the result rel don't need to be added, because they will be
193  * made to refer to the actual heap tuple.
194  */
195  if (parse->returningList && list_length(parse->rtable) > 1)
196  {
197  List *vars;
198  ListCell *l;
199 
200  vars = pull_var_clause((Node *) parse->returningList,
204  foreach(l, vars)
205  {
206  Var *var = (Var *) lfirst(l);
207  TargetEntry *tle;
208 
209  if (IsA(var, Var) &&
210  var->varno == result_relation)
211  continue; /* don't need it */
212 
213  if (tlist_member((Expr *) var, tlist))
214  continue; /* already got it */
215 
216  tle = makeTargetEntry((Expr *) var,
217  list_length(tlist) + 1,
218  NULL,
219  true);
220 
221  tlist = lappend(tlist, tle);
222  }
223  list_free(vars);
224  }
225 
226  /*
227  * If there's an ON CONFLICT UPDATE clause, preprocess its targetlist too
228  * while we have the relation open.
229  */
230  if (parse->onConflict)
231  parse->onConflict->onConflictSet =
233  CMD_UPDATE,
234  result_relation,
235  target_relation);
236 
237  if (target_relation)
238  table_close(target_relation, NoLock);
239 
240  return tlist;
241 }
242 
243 
244 /*****************************************************************************
245  *
246  * TARGETLIST EXPANSION
247  *
248  *****************************************************************************/
249 
250 /*
251  * expand_targetlist
252  * Given a target list as generated by the parser and a result relation,
253  * add targetlist entries for any missing attributes, and ensure the
254  * non-junk attributes appear in proper field order.
255  */
256 static List *
257 expand_targetlist(List *tlist, int command_type,
258  Index result_relation, Relation rel)
259 {
260  List *new_tlist = NIL;
261  ListCell *tlist_item;
262  int attrno,
263  numattrs;
264 
265  tlist_item = list_head(tlist);
266 
267  /*
268  * The rewriter should have already ensured that the TLEs are in correct
269  * order; but we have to insert TLEs for any missing attributes.
270  *
271  * Scan the tuple description in the relation's relcache entry to make
272  * sure we have all the user attributes in the right order.
273  */
274  numattrs = RelationGetNumberOfAttributes(rel);
275 
276  for (attrno = 1; attrno <= numattrs; attrno++)
277  {
278  Form_pg_attribute att_tup = TupleDescAttr(rel->rd_att, attrno - 1);
279  TargetEntry *new_tle = NULL;
280 
281  if (tlist_item != NULL)
282  {
283  TargetEntry *old_tle = (TargetEntry *) lfirst(tlist_item);
284 
285  if (!old_tle->resjunk && old_tle->resno == attrno)
286  {
287  new_tle = old_tle;
288  tlist_item = lnext(tlist, tlist_item);
289  }
290  }
291 
292  if (new_tle == NULL)
293  {
294  /*
295  * Didn't find a matching tlist entry, so make one.
296  *
297  * For INSERT, generate a NULL constant. (We assume the rewriter
298  * would have inserted any available default value.) Also, if the
299  * column isn't dropped, apply any domain constraints that might
300  * exist --- this is to catch domain NOT NULL.
301  *
302  * For UPDATE, generate a Var reference to the existing value of
303  * the attribute, so that it gets copied to the new tuple. But
304  * generate a NULL for dropped columns (we want to drop any old
305  * values).
306  *
307  * When generating a NULL constant for a dropped column, we label
308  * it INT4 (any other guaranteed-to-exist datatype would do as
309  * well). We can't label it with the dropped column's datatype
310  * since that might not exist anymore. It does not really matter
311  * what we claim the type is, since NULL is NULL --- its
312  * representation is datatype-independent. This could perhaps
313  * confuse code comparing the finished plan to the target
314  * relation, however.
315  */
316  Oid atttype = att_tup->atttypid;
317  int32 atttypmod = att_tup->atttypmod;
318  Oid attcollation = att_tup->attcollation;
319  Node *new_expr;
320 
321  switch (command_type)
322  {
323  case CMD_INSERT:
324  if (!att_tup->attisdropped)
325  {
326  new_expr = (Node *) makeConst(atttype,
327  -1,
328  attcollation,
329  att_tup->attlen,
330  (Datum) 0,
331  true, /* isnull */
332  att_tup->attbyval);
333  new_expr = coerce_to_domain(new_expr,
334  InvalidOid, -1,
335  atttype,
338  -1,
339  false);
340  }
341  else
342  {
343  /* Insert NULL for dropped column */
344  new_expr = (Node *) makeConst(INT4OID,
345  -1,
346  InvalidOid,
347  sizeof(int32),
348  (Datum) 0,
349  true, /* isnull */
350  true /* byval */ );
351  }
352  break;
353  case CMD_UPDATE:
354  if (!att_tup->attisdropped)
355  {
356  new_expr = (Node *) makeVar(result_relation,
357  attrno,
358  atttype,
359  atttypmod,
360  attcollation,
361  0);
362  }
363  else
364  {
365  /* Insert NULL for dropped column */
366  new_expr = (Node *) makeConst(INT4OID,
367  -1,
368  InvalidOid,
369  sizeof(int32),
370  (Datum) 0,
371  true, /* isnull */
372  true /* byval */ );
373  }
374  break;
375  default:
376  elog(ERROR, "unrecognized command_type: %d",
377  (int) command_type);
378  new_expr = NULL; /* keep compiler quiet */
379  break;
380  }
381 
382  new_tle = makeTargetEntry((Expr *) new_expr,
383  attrno,
384  pstrdup(NameStr(att_tup->attname)),
385  false);
386  }
387 
388  new_tlist = lappend(new_tlist, new_tle);
389  }
390 
391  /*
392  * The remaining tlist entries should be resjunk; append them all to the
393  * end of the new tlist, making sure they have resnos higher than the last
394  * real attribute. (Note: although the rewriter already did such
395  * renumbering, we have to do it again here in case we are doing an UPDATE
396  * in a table with dropped columns, or an inheritance child table with
397  * extra columns.)
398  */
399  while (tlist_item)
400  {
401  TargetEntry *old_tle = (TargetEntry *) lfirst(tlist_item);
402 
403  if (!old_tle->resjunk)
404  elog(ERROR, "targetlist is not sorted correctly");
405  /* Get the resno right, but don't copy unnecessarily */
406  if (old_tle->resno != attrno)
407  {
408  old_tle = flatCopyTargetEntry(old_tle);
409  old_tle->resno = attrno;
410  }
411  new_tlist = lappend(new_tlist, old_tle);
412  attrno++;
413  tlist_item = lnext(tlist, tlist_item);
414  }
415 
416  return new_tlist;
417 }
418 
419 
420 /*
421  * Locate PlanRowMark for given RT index, or return NULL if none
422  *
423  * This probably ought to be elsewhere, but there's no very good place
424  */
425 PlanRowMark *
426 get_plan_rowmark(List *rowmarks, Index rtindex)
427 {
428  ListCell *l;
429 
430  foreach(l, rowmarks)
431  {
432  PlanRowMark *rc = (PlanRowMark *) lfirst(l);
433 
434  if (rc->rti == rtindex)
435  return rc;
436  }
437  return NULL;
438 }
#define NIL
Definition: pg_list.h:65
List * rowMarks
Definition: pathnodes.h:290
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
Query * parse
Definition: pathnodes.h:177
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:321
OnConflictExpr * onConflict
Definition: parsenodes.h:144
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:425
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
char * pstrdup(const char *in)
Definition: mcxt.c:1186
int resultRelation
Definition: parsenodes.h:122
Definition: nodes.h:525
Var * makeWholeRowVar(RangeTblEntry *rte, Index varno, Index varlevelsup, bool allowScalar)
Definition: makefuncs.c:133
Index prti
Definition: plannodes.h:1058
List * pull_var_clause(Node *node, int flags)
Definition: var.c:535
unsigned int Oid
Definition: postgres_ext.h:31
Definition: primnodes.h:167
Index rowmarkId
Definition: plannodes.h:1059
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:297
signed int int32
Definition: c.h:346
List * targetList
Definition: parsenodes.h:140
bool resjunk
Definition: primnodes.h:1400
List * rtable
Definition: parsenodes.h:137
#define ERROR
Definition: elog.h:43
List * preprocess_targetlist(PlannerInfo *root)
Definition: preptlist.c:70
Node * coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId, CoercionContext ccontext, CoercionForm cformat, int location, bool hideInputCoercion)
Definition: parse_coerce.c:663
Oid attcollation
Definition: pg_attribute.h:164
#define NoLock
Definition: lockdefs.h:34
AttrNumber resno
Definition: primnodes.h:1394
static ListCell * list_head(const List *l)
Definition: pg_list.h:125
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
#define TableOidAttributeNumber
Definition: sysattr.h:26
int allMarkTypes
Definition: plannodes.h:1061
TargetEntry * flatCopyTargetEntry(TargetEntry *src_tle)
Definition: makefuncs.c:269
List * returningList
Definition: parsenodes.h:146
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:236
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
List * lappend(List *list, void *datum)
Definition: list.c:322
Index varno
Definition: primnodes.h:170
#define PVC_INCLUDE_PLACEHOLDERS
Definition: optimizer.h:174
uintptr_t Datum
Definition: postgres.h:367
unsigned int Index
Definition: c.h:475
TargetEntry * tlist_member(Expr *node, List *targetlist)
Definition: tlist.c:73
TupleDesc rd_att
Definition: rel.h:84
static List * expand_targetlist(List *tlist, int command_type, Index result_relation, Relation rel)
Definition: preptlist.c:257
#define InvalidOid
Definition: postgres_ext.h:36
CmdType commandType
Definition: parsenodes.h:112
#define Assert(condition)
Definition: c.h:732
#define lfirst(lc)
Definition: pg_list.h:190
static int list_length(const List *l)
Definition: pg_list.h:169
RTEKind rtekind
Definition: parsenodes.h:974
#define PVC_RECURSE_WINDOWFUNCS
Definition: optimizer.h:173
void list_free(List *list)
Definition: list.c:1377
#define elog(elevel,...)
Definition: elog.h:226
PlanRowMark * get_plan_rowmark(List *rowmarks, Index rtindex)
Definition: preptlist.c:426
List * onConflictSet
Definition: primnodes.h:1521
#define NameStr(name)
Definition: c.h:609
bool isParent
Definition: plannodes.h:1064
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: regcomp.c:224
Definition: pg_list.h:50
#define snprintf
Definition: port.h:192
void rewriteTargetListUD(Query *parsetree, RangeTblEntry *target_rte, Relation target_relation)
#define PVC_RECURSE_AGGREGATES
Definition: optimizer.h:171
CmdType
Definition: nodes.h:668
static struct subre * parse(struct vars *, int, int, struct state *, struct state *)
Definition: regcomp.c:648