PostgreSQL Source Code  git master
preptlist.c File Reference
#include "postgres.h"
#include "access/heapam.h"
#include "access/sysattr.h"
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "optimizer/prep.h"
#include "optimizer/tlist.h"
#include "optimizer/var.h"
#include "parser/parsetree.h"
#include "parser/parse_coerce.h"
#include "rewrite/rewriteHandler.h"
#include "utils/rel.h"
Include dependency graph for preptlist.c:

Go to the source code of this file.

Functions

static Listexpand_targetlist (List *tlist, int command_type, Index result_relation, Relation rel)
 
Listpreprocess_targetlist (PlannerInfo *root)
 
PlanRowMarkget_plan_rowmark (List *rowmarks, Index rtindex)
 

Function Documentation

◆ expand_targetlist()

static List * expand_targetlist ( List tlist,
int  command_type,
Index  result_relation,
Relation  rel 
)
static

Definition at line 255 of file preptlist.c.

References CMD_INSERT, CMD_UPDATE, COERCE_IMPLICIT_CAST, coerce_to_domain(), COERCION_IMPLICIT, elog, ERROR, flatCopyTargetEntry(), INT4OID, InvalidOid, lappend(), lfirst, list_head(), lnext, makeConst(), makeTargetEntry(), makeVar(), NameStr, NIL, pstrdup(), RelationData::rd_att, RelationGetNumberOfAttributes, TargetEntry::resjunk, TargetEntry::resno, and TupleDescAttr.

Referenced by preprocess_targetlist().

257 {
258  List *new_tlist = NIL;
259  ListCell *tlist_item;
260  int attrno,
261  numattrs;
262 
263  tlist_item = list_head(tlist);
264 
265  /*
266  * The rewriter should have already ensured that the TLEs are in correct
267  * order; but we have to insert TLEs for any missing attributes.
268  *
269  * Scan the tuple description in the relation's relcache entry to make
270  * sure we have all the user attributes in the right order.
271  */
272  numattrs = RelationGetNumberOfAttributes(rel);
273 
274  for (attrno = 1; attrno <= numattrs; attrno++)
275  {
276  Form_pg_attribute att_tup = TupleDescAttr(rel->rd_att, attrno - 1);
277  TargetEntry *new_tle = NULL;
278 
279  if (tlist_item != NULL)
280  {
281  TargetEntry *old_tle = (TargetEntry *) lfirst(tlist_item);
282 
283  if (!old_tle->resjunk && old_tle->resno == attrno)
284  {
285  new_tle = old_tle;
286  tlist_item = lnext(tlist_item);
287  }
288  }
289 
290  if (new_tle == NULL)
291  {
292  /*
293  * Didn't find a matching tlist entry, so make one.
294  *
295  * For INSERT, generate a NULL constant. (We assume the rewriter
296  * would have inserted any available default value.) Also, if the
297  * column isn't dropped, apply any domain constraints that might
298  * exist --- this is to catch domain NOT NULL.
299  *
300  * For UPDATE, generate a Var reference to the existing value of
301  * the attribute, so that it gets copied to the new tuple. But
302  * generate a NULL for dropped columns (we want to drop any old
303  * values).
304  *
305  * When generating a NULL constant for a dropped column, we label
306  * it INT4 (any other guaranteed-to-exist datatype would do as
307  * well). We can't label it with the dropped column's datatype
308  * since that might not exist anymore. It does not really matter
309  * what we claim the type is, since NULL is NULL --- its
310  * representation is datatype-independent. This could perhaps
311  * confuse code comparing the finished plan to the target
312  * relation, however.
313  */
314  Oid atttype = att_tup->atttypid;
315  int32 atttypmod = att_tup->atttypmod;
316  Oid attcollation = att_tup->attcollation;
317  Node *new_expr;
318 
319  switch (command_type)
320  {
321  case CMD_INSERT:
322  if (!att_tup->attisdropped)
323  {
324  new_expr = (Node *) makeConst(atttype,
325  -1,
326  attcollation,
327  att_tup->attlen,
328  (Datum) 0,
329  true, /* isnull */
330  att_tup->attbyval);
331  new_expr = coerce_to_domain(new_expr,
332  InvalidOid, -1,
333  atttype,
336  -1,
337  false);
338  }
339  else
340  {
341  /* Insert NULL for dropped column */
342  new_expr = (Node *) makeConst(INT4OID,
343  -1,
344  InvalidOid,
345  sizeof(int32),
346  (Datum) 0,
347  true, /* isnull */
348  true /* byval */ );
349  }
350  break;
351  case CMD_UPDATE:
352  if (!att_tup->attisdropped)
353  {
354  new_expr = (Node *) makeVar(result_relation,
355  attrno,
356  atttype,
357  atttypmod,
358  attcollation,
359  0);
360  }
361  else
362  {
363  /* Insert NULL for dropped column */
364  new_expr = (Node *) makeConst(INT4OID,
365  -1,
366  InvalidOid,
367  sizeof(int32),
368  (Datum) 0,
369  true, /* isnull */
370  true /* byval */ );
371  }
372  break;
373  default:
374  elog(ERROR, "unrecognized command_type: %d",
375  (int) command_type);
376  new_expr = NULL; /* keep compiler quiet */
377  break;
378  }
379 
380  new_tle = makeTargetEntry((Expr *) new_expr,
381  attrno,
382  pstrdup(NameStr(att_tup->attname)),
383  false);
384  }
385 
386  new_tlist = lappend(new_tlist, new_tle);
387  }
388 
389  /*
390  * The remaining tlist entries should be resjunk; append them all to the
391  * end of the new tlist, making sure they have resnos higher than the last
392  * real attribute. (Note: although the rewriter already did such
393  * renumbering, we have to do it again here in case we are doing an UPDATE
394  * in a table with dropped columns, or an inheritance child table with
395  * extra columns.)
396  */
397  while (tlist_item)
398  {
399  TargetEntry *old_tle = (TargetEntry *) lfirst(tlist_item);
400 
401  if (!old_tle->resjunk)
402  elog(ERROR, "targetlist is not sorted correctly");
403  /* Get the resno right, but don't copy unnecessarily */
404  if (old_tle->resno != attrno)
405  {
406  old_tle = flatCopyTargetEntry(old_tle);
407  old_tle->resno = attrno;
408  }
409  new_tlist = lappend(new_tlist, old_tle);
410  attrno++;
411  tlist_item = lnext(tlist_item);
412  }
413 
414  return new_tlist;
415 }
#define NIL
Definition: pg_list.h:69
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:431
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:90
char * pstrdup(const char *in)
Definition: mcxt.c:1076
#define INT4OID
Definition: pg_type.h:316
Definition: nodes.h:512
unsigned int Oid
Definition: postgres_ext.h:31
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:298
signed int int32
Definition: c.h:284
bool resjunk
Definition: primnodes.h:1382
#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:663
AttrNumber resno
Definition: primnodes.h:1376
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
TargetEntry * flatCopyTargetEntry(TargetEntry *src_tle)
Definition: makefuncs.c:270
#define lnext(lc)
Definition: pg_list.h:105
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:237
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
uintptr_t Datum
Definition: postgres.h:372
TupleDesc rd_att
Definition: rel.h:115
#define InvalidOid
Definition: postgres_ext.h:36
#define lfirst(lc)
Definition: pg_list.h:106
#define NameStr(name)
Definition: c.h:547
#define elog
Definition: elog.h:219
Definition: pg_list.h:45

◆ get_plan_rowmark()

PlanRowMark* get_plan_rowmark ( List rowmarks,
Index  rtindex 
)

Definition at line 424 of file preptlist.c.

References lfirst, and PlanRowMark::rti.

Referenced by AcquireExecutorLocks(), check_index_predicates(), deparseLockingClause(), and expand_inherited_rtentry().

425 {
426  ListCell *l;
427 
428  foreach(l, rowmarks)
429  {
430  PlanRowMark *rc = (PlanRowMark *) lfirst(l);
431 
432  if (rc->rti == rtindex)
433  return rc;
434  }
435  return NULL;
436 }
#define lfirst(lc)
Definition: pg_list.h:106

◆ preprocess_targetlist()

List* preprocess_targetlist ( PlannerInfo root)

Definition at line 70 of file preptlist.c.

References PlanRowMark::allMarkTypes, Assert, CMD_DELETE, CMD_INSERT, CMD_SELECT, CMD_UPDATE, Query::commandType, elog, ERROR, expand_targetlist(), heap_close, heap_open(), InvalidOid, IsA, PlanRowMark::isParent, lappend(), lfirst, list_free(), list_length(), makeTargetEntry(), makeVar(), makeWholeRowVar(), NoLock, OIDOID, Query::onConflict, OnConflictExpr::onConflictSet, parse(), PlannerInfo::parse, PlanRowMark::prti, pstrdup(), pull_var_clause(), PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_AGGREGATES, PVC_RECURSE_WINDOWFUNCS, RangeTblEntry::relid, Query::resultRelation, Query::returningList, rewriteTargetListUD(), ROW_MARK_COPY, PlanRowMark::rowmarkId, PlannerInfo::rowMarks, rt_fetch, Query::rtable, RTE_RELATION, RangeTblEntry::rtekind, PlanRowMark::rti, SelfItemPointerAttributeNumber, snprintf(), TableOidAttributeNumber, Query::targetList, TIDOID, tlist_member(), and Var::varno.

Referenced by grouping_planner().

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 = heap_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.
125  */
126  foreach(lc, root->rowMarks)
127  {
128  PlanRowMark *rc = (PlanRowMark *) lfirst(lc);
129  Var *var;
130  char resname[32];
131  TargetEntry *tle;
132 
133  /* child rels use the same junk attrs as their parents */
134  if (rc->rti != rc->prti)
135  continue;
136 
137  if (rc->allMarkTypes & ~(1 << ROW_MARK_COPY))
138  {
139  /* Need to fetch TID */
140  var = makeVar(rc->rti,
142  TIDOID,
143  -1,
144  InvalidOid,
145  0);
146  snprintf(resname, sizeof(resname), "ctid%u", rc->rowmarkId);
147  tle = makeTargetEntry((Expr *) var,
148  list_length(tlist) + 1,
149  pstrdup(resname),
150  true);
151  tlist = lappend(tlist, tle);
152  }
153  if (rc->allMarkTypes & (1 << ROW_MARK_COPY))
154  {
155  /* Need the whole row as a junk var */
156  var = makeWholeRowVar(rt_fetch(rc->rti, range_table),
157  rc->rti,
158  0,
159  false);
160  snprintf(resname, sizeof(resname), "wholerow%u", rc->rowmarkId);
161  tle = makeTargetEntry((Expr *) var,
162  list_length(tlist) + 1,
163  pstrdup(resname),
164  true);
165  tlist = lappend(tlist, tle);
166  }
167 
168  /* If parent of inheritance tree, always fetch the tableoid too. */
169  if (rc->isParent)
170  {
171  var = makeVar(rc->rti,
173  OIDOID,
174  -1,
175  InvalidOid,
176  0);
177  snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId);
178  tle = makeTargetEntry((Expr *) var,
179  list_length(tlist) + 1,
180  pstrdup(resname),
181  true);
182  tlist = lappend(tlist, tle);
183  }
184  }
185 
186  /*
187  * If the query has a RETURNING list, add resjunk entries for any Vars
188  * used in RETURNING that belong to other relations. We need to do this
189  * to make these Vars available for the RETURNING calculation. Vars that
190  * belong to the result rel don't need to be added, because they will be
191  * made to refer to the actual heap tuple.
192  */
193  if (parse->returningList && list_length(parse->rtable) > 1)
194  {
195  List *vars;
196  ListCell *l;
197 
198  vars = pull_var_clause((Node *) parse->returningList,
202  foreach(l, vars)
203  {
204  Var *var = (Var *) lfirst(l);
205  TargetEntry *tle;
206 
207  if (IsA(var, Var) &&
208  var->varno == result_relation)
209  continue; /* don't need it */
210 
211  if (tlist_member((Expr *) var, tlist))
212  continue; /* already got it */
213 
214  tle = makeTargetEntry((Expr *) var,
215  list_length(tlist) + 1,
216  NULL,
217  true);
218 
219  tlist = lappend(tlist, tle);
220  }
221  list_free(vars);
222  }
223 
224  /*
225  * If there's an ON CONFLICT UPDATE clause, preprocess its targetlist too
226  * while we have the relation open.
227  */
228  if (parse->onConflict)
229  parse->onConflict->onConflictSet =
231  CMD_UPDATE,
232  result_relation,
233  target_relation);
234 
235  if (target_relation)
236  heap_close(target_relation, NoLock);
237 
238  return tlist;
239 }
List * rowMarks
Definition: relation.h:256
#define IsA(nodeptr, _type_)
Definition: nodes.h:563
Query * parse
Definition: relation.h:155
#define PVC_RECURSE_AGGREGATES
Definition: var.h:21
OnConflictExpr * onConflict
Definition: parsenodes.h:142
#define OIDOID
Definition: pg_type.h:328
char * pstrdup(const char *in)
Definition: mcxt.c:1076
int resultRelation
Definition: parsenodes.h:120
Definition: nodes.h:512
Var * makeWholeRowVar(RangeTblEntry *rte, Index varno, Index varlevelsup, bool allowScalar)
Definition: makefuncs.c:134
Index prti
Definition: plannodes.h:1019
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
Definition: primnodes.h:163
Index rowmarkId
Definition: plannodes.h:1020
List * targetList
Definition: parsenodes.h:138
#define PVC_INCLUDE_PLACEHOLDERS
Definition: var.h:24
#define TIDOID
Definition: pg_type.h:332
List * rtable
Definition: parsenodes.h:135
#define ERROR
Definition: elog.h:43
#define NoLock
Definition: lockdefs.h:34
#define TableOidAttributeNumber
Definition: sysattr.h:27
int allMarkTypes
Definition: plannodes.h:1022
#define PVC_RECURSE_WINDOWFUNCS
Definition: var.h:23
List * returningList
Definition: parsenodes.h:144
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:237
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
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
TargetEntry * tlist_member(Expr *node, List *targetlist)
Definition: tlist.c:54
static List * expand_targetlist(List *tlist, int command_type, Index result_relation, Relation rel)
Definition: preptlist.c:255
#define InvalidOid
Definition: postgres_ext.h:36
CmdType commandType
Definition: parsenodes.h:110
#define Assert(condition)
Definition: c.h:670
#define lfirst(lc)
Definition: pg_list.h:106
static int list_length(const List *l)
Definition: pg_list.h:89
RTEKind rtekind
Definition: parsenodes.h:951
void list_free(List *list)
Definition: list.c:1133
List * onConflictSet
Definition: primnodes.h:1503
bool isParent
Definition: plannodes.h:1025
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21
#define elog
Definition: elog.h:219
Definition: regcomp.c:224
Definition: pg_list.h:45
void rewriteTargetListUD(Query *parsetree, RangeTblEntry *target_rte, Relation target_relation)
CmdType
Definition: nodes.h:652
static struct subre * parse(struct vars *, int, int, struct state *, struct state *)
Definition: regcomp.c:649