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