PostgreSQL Source Code  git master
preptlist.c File Reference
#include "postgres.h"
#include "access/sysattr.h"
#include "access/table.h"
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "optimizer/optimizer.h"
#include "optimizer/prep.h"
#include "optimizer/tlist.h"
#include "parser/parse_coerce.h"
#include "parser/parsetree.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 256 of file preptlist.c.

References attcollation, CMD_INSERT, CMD_UPDATE, COERCE_IMPLICIT_CAST, coerce_to_domain(), COERCION_IMPLICIT, elog, ERROR, flatCopyTargetEntry(), 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().

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

◆ get_plan_rowmark()

PlanRowMark* get_plan_rowmark ( List rowmarks,
Index  rtindex 
)

Definition at line 425 of file preptlist.c.

References lfirst, and PlanRowMark::rti.

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

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

◆ preprocess_targetlist()

List* preprocess_targetlist ( PlannerInfo root)

Definition at line 69 of file preptlist.c.

References PlanRowMark::allMarkTypes, Assert, CMD_DELETE, CMD_INSERT, CMD_SELECT, CMD_UPDATE, Query::commandType, elog, ERROR, expand_targetlist(), InvalidOid, IsA, PlanRowMark::isParent, lappend(), lfirst, list_free(), list_length(), makeTargetEntry(), makeVar(), makeWholeRowVar(), NoLock, 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, table_close(), table_open(), TableOidAttributeNumber, Query::targetList, tlist_member(), and Var::varno.

Referenced by grouping_planner(), and inheritance_planner().

70 {
71  Query *parse = root->parse;
72  int result_relation = parse->resultRelation;
73  List *range_table = parse->rtable;
74  CmdType command_type = parse->commandType;
75  RangeTblEntry *target_rte = NULL;
76  Relation target_relation = NULL;
77  List *tlist;
78  ListCell *lc;
79 
80  /*
81  * If there is a result relation, open it so we can look for missing
82  * columns and so on. We assume that previous code already acquired at
83  * least AccessShareLock on the relation, so we need no lock here.
84  */
85  if (result_relation)
86  {
87  target_rte = rt_fetch(result_relation, range_table);
88 
89  /*
90  * Sanity check: it'd better be a real relation not, say, a subquery.
91  * Else parser or rewriter messed up.
92  */
93  if (target_rte->rtekind != RTE_RELATION)
94  elog(ERROR, "result relation must be a regular relation");
95 
96  target_relation = table_open(target_rte->relid, NoLock);
97  }
98  else
99  Assert(command_type == CMD_SELECT);
100 
101  /*
102  * For UPDATE/DELETE, add any junk column(s) needed to allow the executor
103  * to identify the rows to be updated or deleted. Note that this step
104  * scribbles on parse->targetList, which is not very desirable, but we
105  * keep it that way to avoid changing APIs used by FDWs.
106  */
107  if (command_type == CMD_UPDATE || command_type == CMD_DELETE)
108  rewriteTargetListUD(parse, target_rte, target_relation);
109 
110  /*
111  * for heap_form_tuple to work, the targetlist must match the exact order
112  * of the attributes. We also need to fill in any missing attributes. -ay
113  * 10/94
114  */
115  tlist = parse->targetList;
116  if (command_type == CMD_INSERT || command_type == CMD_UPDATE)
117  tlist = expand_targetlist(tlist, command_type,
118  result_relation, target_relation);
119 
120  /*
121  * Add necessary junk columns for rowmarked rels. These values are needed
122  * for locking of rels selected FOR UPDATE/SHARE, and to do EvalPlanQual
123  * rechecking. See comments for PlanRowMark in plannodes.h. If you
124  * change this stanza, see also expand_inherited_rtentry(), which has to
125  * be able to add on junk columns equivalent to these.
126  */
127  foreach(lc, root->rowMarks)
128  {
129  PlanRowMark *rc = (PlanRowMark *) lfirst(lc);
130  Var *var;
131  char resname[32];
132  TargetEntry *tle;
133 
134  /* child rels use the same junk attrs as their parents */
135  if (rc->rti != rc->prti)
136  continue;
137 
138  if (rc->allMarkTypes & ~(1 << ROW_MARK_COPY))
139  {
140  /* Need to fetch TID */
141  var = makeVar(rc->rti,
143  TIDOID,
144  -1,
145  InvalidOid,
146  0);
147  snprintf(resname, sizeof(resname), "ctid%u", rc->rowmarkId);
148  tle = makeTargetEntry((Expr *) var,
149  list_length(tlist) + 1,
150  pstrdup(resname),
151  true);
152  tlist = lappend(tlist, tle);
153  }
154  if (rc->allMarkTypes & (1 << ROW_MARK_COPY))
155  {
156  /* Need the whole row as a junk var */
157  var = makeWholeRowVar(rt_fetch(rc->rti, range_table),
158  rc->rti,
159  0,
160  false);
161  snprintf(resname, sizeof(resname), "wholerow%u", rc->rowmarkId);
162  tle = makeTargetEntry((Expr *) var,
163  list_length(tlist) + 1,
164  pstrdup(resname),
165  true);
166  tlist = lappend(tlist, tle);
167  }
168 
169  /* If parent of inheritance tree, always fetch the tableoid too. */
170  if (rc->isParent)
171  {
172  var = makeVar(rc->rti,
174  OIDOID,
175  -1,
176  InvalidOid,
177  0);
178  snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId);
179  tle = makeTargetEntry((Expr *) var,
180  list_length(tlist) + 1,
181  pstrdup(resname),
182  true);
183  tlist = lappend(tlist, tle);
184  }
185  }
186 
187  /*
188  * If the query has a RETURNING list, add resjunk entries for any Vars
189  * used in RETURNING that belong to other relations. We need to do this
190  * to make these Vars available for the RETURNING calculation. Vars that
191  * belong to the result rel don't need to be added, because they will be
192  * made to refer to the actual heap tuple.
193  */
194  if (parse->returningList && list_length(parse->rtable) > 1)
195  {
196  List *vars;
197  ListCell *l;
198 
199  vars = pull_var_clause((Node *) parse->returningList,
203  foreach(l, vars)
204  {
205  Var *var = (Var *) lfirst(l);
206  TargetEntry *tle;
207 
208  if (IsA(var, Var) &&
209  var->varno == result_relation)
210  continue; /* don't need it */
211 
212  if (tlist_member((Expr *) var, tlist))
213  continue; /* already got it */
214 
215  tle = makeTargetEntry((Expr *) var,
216  list_length(tlist) + 1,
217  NULL,
218  true);
219 
220  tlist = lappend(tlist, tle);
221  }
222  list_free(vars);
223  }
224 
225  /*
226  * If there's an ON CONFLICT UPDATE clause, preprocess its targetlist too
227  * while we have the relation open.
228  */
229  if (parse->onConflict)
230  parse->onConflict->onConflictSet =
232  CMD_UPDATE,
233  result_relation,
234  target_relation);
235 
236  if (target_relation)
237  table_close(target_relation, NoLock);
238 
239  return tlist;
240 }
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
OnConflictExpr * onConflict
Definition: parsenodes.h:144
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
Definition: primnodes.h:167
Index rowmarkId
Definition: plannodes.h:1059
List * targetList
Definition: parsenodes.h:140
List * rtable
Definition: parsenodes.h:137
#define ERROR
Definition: elog.h:43
#define NoLock
Definition: lockdefs.h:34
#define TableOidAttributeNumber
Definition: sysattr.h:26
int allMarkTypes
Definition: plannodes.h:1061
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
TargetEntry * tlist_member(Expr *node, List *targetlist)
Definition: tlist.c:73
static List * expand_targetlist(List *tlist, int command_type, Index result_relation, Relation rel)
Definition: preptlist.c:256
#define InvalidOid
Definition: postgres_ext.h:36
CmdType commandType
Definition: parsenodes.h:112
#define Assert(condition)
Definition: c.h:739
#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:228
List * onConflictSet
Definition: primnodes.h:1521
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