PostgreSQL Source Code  git master
preptlist.c File Reference
#include "postgres.h"
#include "access/table.h"
#include "nodes/makefuncs.h"
#include "optimizer/appendinfo.h"
#include "optimizer/optimizer.h"
#include "optimizer/prep.h"
#include "optimizer/tlist.h"
#include "parser/parse_coerce.h"
#include "parser/parsetree.h"
#include "utils/rel.h"
Include dependency graph for preptlist.c:

Go to the source code of this file.

Functions

static Listexpand_insert_targetlist (List *tlist, Relation rel)
 
void preprocess_targetlist (PlannerInfo *root)
 
Listextract_update_targetlist_colnos (List *tlist)
 
PlanRowMarkget_plan_rowmark (List *rowmarks, Index rtindex)
 

Function Documentation

◆ expand_insert_targetlist()

static List * expand_insert_targetlist ( List tlist,
Relation  rel 
)
static

Definition at line 295 of file preptlist.c.

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

Referenced by preprocess_targetlist().

296 {
297  List *new_tlist = NIL;
298  ListCell *tlist_item;
299  int attrno,
300  numattrs;
301 
302  tlist_item = list_head(tlist);
303 
304  /*
305  * The rewriter should have already ensured that the TLEs are in correct
306  * order; but we have to insert TLEs for any missing attributes.
307  *
308  * Scan the tuple description in the relation's relcache entry to make
309  * sure we have all the user attributes in the right order.
310  */
311  numattrs = RelationGetNumberOfAttributes(rel);
312 
313  for (attrno = 1; attrno <= numattrs; attrno++)
314  {
315  Form_pg_attribute att_tup = TupleDescAttr(rel->rd_att, attrno - 1);
316  TargetEntry *new_tle = NULL;
317 
318  if (tlist_item != NULL)
319  {
320  TargetEntry *old_tle = (TargetEntry *) lfirst(tlist_item);
321 
322  if (!old_tle->resjunk && old_tle->resno == attrno)
323  {
324  new_tle = old_tle;
325  tlist_item = lnext(tlist, tlist_item);
326  }
327  }
328 
329  if (new_tle == NULL)
330  {
331  /*
332  * Didn't find a matching tlist entry, so make one.
333  *
334  * INSERTs should insert NULL in this case. (We assume the
335  * rewriter would have inserted any available non-NULL default
336  * value.) Also, if the column isn't dropped, apply any domain
337  * constraints that might exist --- this is to catch domain NOT
338  * NULL.
339  *
340  * When generating a NULL constant for a dropped column, we label
341  * it INT4 (any other guaranteed-to-exist datatype would do as
342  * well). We can't label it with the dropped column's datatype
343  * since that might not exist anymore. It does not really matter
344  * what we claim the type is, since NULL is NULL --- its
345  * representation is datatype-independent. This could perhaps
346  * confuse code comparing the finished plan to the target
347  * relation, however.
348  */
349  Oid atttype = att_tup->atttypid;
350  Oid attcollation = att_tup->attcollation;
351  Node *new_expr;
352 
353  if (!att_tup->attisdropped)
354  {
355  new_expr = (Node *) makeConst(atttype,
356  -1,
357  attcollation,
358  att_tup->attlen,
359  (Datum) 0,
360  true, /* isnull */
361  att_tup->attbyval);
362  new_expr = coerce_to_domain(new_expr,
363  InvalidOid, -1,
364  atttype,
367  -1,
368  false);
369  }
370  else
371  {
372  /* Insert NULL for dropped column */
373  new_expr = (Node *) makeConst(INT4OID,
374  -1,
375  InvalidOid,
376  sizeof(int32),
377  (Datum) 0,
378  true, /* isnull */
379  true /* byval */ );
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 added NULL entries
396  * above.)
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:322
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:483
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
char * pstrdup(const char *in)
Definition: mcxt.c:1299
Definition: nodes.h:536
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:299
signed int int32
Definition: c.h:429
bool resjunk
Definition: primnodes.h:1462
#define ERROR
Definition: elog.h:46
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
AttrNumber resno
Definition: primnodes.h:1456
static ListCell * list_head(const List *l)
Definition: pg_list.h:125
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
TargetEntry * flatCopyTargetEntry(TargetEntry *src_tle)
Definition: makefuncs.c:271
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:238
List * lappend(List *list, void *datum)
Definition: list.c:336
uintptr_t Datum
Definition: postgres.h:411
TupleDesc rd_att
Definition: rel.h:110
#define InvalidOid
Definition: postgres_ext.h:36
#define lfirst(lc)
Definition: pg_list.h:169
#define elog(elevel,...)
Definition: elog.h:232
#define NameStr(name)
Definition: c.h:681
Definition: pg_list.h:50

◆ extract_update_targetlist_colnos()

List* extract_update_targetlist_colnos ( List tlist)

Definition at line 261 of file preptlist.c.

References lappend_int(), lfirst, NIL, TargetEntry::resjunk, and TargetEntry::resno.

Referenced by make_modifytable(), and preprocess_targetlist().

262 {
263  List *update_colnos = NIL;
264  AttrNumber nextresno = 1;
265  ListCell *lc;
266 
267  foreach(lc, tlist)
268  {
269  TargetEntry *tle = (TargetEntry *) lfirst(lc);
270 
271  if (!tle->resjunk)
272  update_colnos = lappend_int(update_colnos, tle->resno);
273  tle->resno = nextresno++;
274  }
275  return update_colnos;
276 }
#define NIL
Definition: pg_list.h:65
bool resjunk
Definition: primnodes.h:1462
AttrNumber resno
Definition: primnodes.h:1456
List * lappend_int(List *list, int datum)
Definition: list.c:354
#define lfirst(lc)
Definition: pg_list.h:169
Definition: pg_list.h:50
int16 AttrNumber
Definition: attnum.h:21

◆ 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:169

◆ preprocess_targetlist()

void preprocess_targetlist ( PlannerInfo root)

Definition at line 62 of file preptlist.c.

References add_row_identity_columns(), PlanRowMark::allMarkTypes, Assert, CMD_DELETE, CMD_INSERT, CMD_SELECT, CMD_UPDATE, Query::commandType, elog, ERROR, expand_insert_targetlist(), extract_update_targetlist_colnos(), RangeTblEntry::inh, InvalidOid, IsA, PlanRowMark::isParent, lappend(), lfirst, list_free(), list_length(), makeTargetEntry(), makeVar(), makeWholeRowVar(), NoLock, parse(), PlannerInfo::parse, PlannerInfo::processed_tlist, PlanRowMark::prti, pstrdup(), pull_var_clause(), PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_AGGREGATES, PVC_RECURSE_WINDOWFUNCS, RangeTblEntry::relid, Query::resultRelation, Query::returningList, 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(), PlannerInfo::update_colnos, and Var::varno.

Referenced by grouping_planner().

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)
108 
109  /*
110  * For non-inherited UPDATE/DELETE, register any junk column(s) needed to
111  * allow the executor to identify the rows to be updated or deleted. In
112  * the inheritance case, we do nothing now, leaving this to be dealt with
113  * when expand_inherited_rtentry() makes the leaf target relations. (But
114  * there might not be any leaf target relations, in which case we must do
115  * this in distribute_row_identity_vars().)
116  */
117  if ((command_type == CMD_UPDATE || command_type == CMD_DELETE) &&
118  !target_rte->inh)
119  {
120  /* row-identity logic expects to add stuff to processed_tlist */
121  root->processed_tlist = tlist;
122  add_row_identity_columns(root, result_relation,
123  target_rte, target_relation);
124  tlist = root->processed_tlist;
125  }
126 
127  /*
128  * Add necessary junk columns for rowmarked rels. These values are needed
129  * for locking of rels selected FOR UPDATE/SHARE, and to do EvalPlanQual
130  * rechecking. See comments for PlanRowMark in plannodes.h. If you
131  * change this stanza, see also expand_inherited_rtentry(), which has to
132  * be able to add on junk columns equivalent to these.
133  *
134  * (Someday it might be useful to fold these resjunk columns into the
135  * row-identity-column management used for UPDATE/DELETE. Today is not
136  * that day, however. One notable issue is that it seems important that
137  * the whole-row Vars made here use the real table rowtype, not RECORD, so
138  * that conversion to/from child relations' rowtypes will happen. Also,
139  * since these entries don't potentially bloat with more and more child
140  * relations, there's not really much need for column sharing.)
141  */
142  foreach(lc, root->rowMarks)
143  {
144  PlanRowMark *rc = (PlanRowMark *) lfirst(lc);
145  Var *var;
146  char resname[32];
147  TargetEntry *tle;
148 
149  /* child rels use the same junk attrs as their parents */
150  if (rc->rti != rc->prti)
151  continue;
152 
153  if (rc->allMarkTypes & ~(1 << ROW_MARK_COPY))
154  {
155  /* Need to fetch TID */
156  var = makeVar(rc->rti,
158  TIDOID,
159  -1,
160  InvalidOid,
161  0);
162  snprintf(resname, sizeof(resname), "ctid%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  if (rc->allMarkTypes & (1 << ROW_MARK_COPY))
170  {
171  /* Need the whole row as a junk var */
172  var = makeWholeRowVar(rt_fetch(rc->rti, range_table),
173  rc->rti,
174  0,
175  false);
176  snprintf(resname, sizeof(resname), "wholerow%u", rc->rowmarkId);
177  tle = makeTargetEntry((Expr *) var,
178  list_length(tlist) + 1,
179  pstrdup(resname),
180  true);
181  tlist = lappend(tlist, tle);
182  }
183 
184  /* If parent of inheritance tree, always fetch the tableoid too. */
185  if (rc->isParent)
186  {
187  var = makeVar(rc->rti,
189  OIDOID,
190  -1,
191  InvalidOid,
192  0);
193  snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId);
194  tle = makeTargetEntry((Expr *) var,
195  list_length(tlist) + 1,
196  pstrdup(resname),
197  true);
198  tlist = lappend(tlist, tle);
199  }
200  }
201 
202  /*
203  * If the query has a RETURNING list, add resjunk entries for any Vars
204  * used in RETURNING that belong to other relations. We need to do this
205  * to make these Vars available for the RETURNING calculation. Vars that
206  * belong to the result rel don't need to be added, because they will be
207  * made to refer to the actual heap tuple.
208  */
209  if (parse->returningList && list_length(parse->rtable) > 1)
210  {
211  List *vars;
212  ListCell *l;
213 
214  vars = pull_var_clause((Node *) parse->returningList,
218  foreach(l, vars)
219  {
220  Var *var = (Var *) lfirst(l);
221  TargetEntry *tle;
222 
223  if (IsA(var, Var) &&
224  var->varno == result_relation)
225  continue; /* don't need it */
226 
227  if (tlist_member((Expr *) var, tlist))
228  continue; /* already got it */
229 
230  tle = makeTargetEntry((Expr *) var,
231  list_length(tlist) + 1,
232  NULL,
233  true);
234 
235  tlist = lappend(tlist, tle);
236  }
237  list_free(vars);
238  }
239 
240  root->processed_tlist = tlist;
241 
242  if (target_relation)
243  table_close(target_relation, NoLock);
244 }
int varno
Definition: primnodes.h:189
List * rowMarks
Definition: pathnodes.h:288
List * extract_update_targetlist_colnos(List *tlist)
Definition: preptlist.c:261
#define IsA(nodeptr, _type_)
Definition: nodes.h:587
Query * parse
Definition: pathnodes.h:162
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
char * pstrdup(const char *in)
Definition: mcxt.c:1299
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
int resultRelation
Definition: parsenodes.h:130
Definition: nodes.h:536
Index prti
Definition: plannodes.h:1121
List * pull_var_clause(Node *node, int flags)
Definition: var.c:597
Definition: primnodes.h:186
Index rowmarkId
Definition: plannodes.h:1122
List * targetList
Definition: parsenodes.h:150
List * rtable
Definition: parsenodes.h:147
#define ERROR
Definition: elog.h:46
static List * expand_insert_targetlist(List *tlist, Relation rel)
Definition: preptlist.c:295
#define NoLock
Definition: lockdefs.h:34
Var * makeWholeRowVar(RangeTblEntry *rte, int varno, Index varlevelsup, bool allowScalar)
Definition: makefuncs.c:133
#define TableOidAttributeNumber
Definition: sysattr.h:26
int allMarkTypes
Definition: plannodes.h:1124
List * returningList
Definition: parsenodes.h:156
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:238
List * lappend(List *list, void *datum)
Definition: list.c:336
#define PVC_INCLUDE_PLACEHOLDERS
Definition: optimizer.h:190
TargetEntry * tlist_member(Expr *node, List *targetlist)
Definition: tlist.c:68
#define InvalidOid
Definition: postgres_ext.h:36
CmdType commandType
Definition: parsenodes.h:120
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
static int list_length(const List *l)
Definition: pg_list.h:149
RTEKind rtekind
Definition: parsenodes.h:1007
#define PVC_RECURSE_WINDOWFUNCS
Definition: optimizer.h:189
void list_free(List *list)
Definition: list.c:1391
#define elog(elevel,...)
Definition: elog.h:232
bool isParent
Definition: plannodes.h:1127
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21
List * processed_tlist
Definition: pathnodes.h:321
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: regcomp.c:237
Definition: pg_list.h:50
#define snprintf
Definition: port.h:216
#define PVC_RECURSE_AGGREGATES
Definition: optimizer.h:187
CmdType
Definition: nodes.h:680
void add_row_identity_columns(PlannerInfo *root, Index rtindex, RangeTblEntry *target_rte, Relation target_relation)
Definition: appendinfo.c:857
List * update_colnos
Definition: pathnodes.h:329
static struct subre * parse(struct vars *, int, int, struct state *, struct state *)
Definition: regcomp.c:673