PostgreSQL Source Code  git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 379 of file preptlist.c.

380 {
381  List *new_tlist = NIL;
382  ListCell *tlist_item;
383  int attrno,
384  numattrs;
385 
386  tlist_item = list_head(tlist);
387 
388  /*
389  * The rewriter should have already ensured that the TLEs are in correct
390  * order; but we have to insert TLEs for any missing attributes.
391  *
392  * Scan the tuple description in the relation's relcache entry to make
393  * sure we have all the user attributes in the right order.
394  */
395  numattrs = RelationGetNumberOfAttributes(rel);
396 
397  for (attrno = 1; attrno <= numattrs; attrno++)
398  {
399  Form_pg_attribute att_tup = TupleDescAttr(rel->rd_att, attrno - 1);
400  TargetEntry *new_tle = NULL;
401 
402  if (tlist_item != NULL)
403  {
404  TargetEntry *old_tle = (TargetEntry *) lfirst(tlist_item);
405 
406  if (!old_tle->resjunk && old_tle->resno == attrno)
407  {
408  new_tle = old_tle;
409  tlist_item = lnext(tlist, tlist_item);
410  }
411  }
412 
413  if (new_tle == NULL)
414  {
415  /*
416  * Didn't find a matching tlist entry, so make one.
417  *
418  * INSERTs should insert NULL in this case. (We assume the
419  * rewriter would have inserted any available non-NULL default
420  * value.) Also, if the column isn't dropped, apply any domain
421  * constraints that might exist --- this is to catch domain NOT
422  * NULL.
423  *
424  * When generating a NULL constant for a dropped column, we label
425  * it INT4 (any other guaranteed-to-exist datatype would do as
426  * well). We can't label it with the dropped column's datatype
427  * since that might not exist anymore. It does not really matter
428  * what we claim the type is, since NULL is NULL --- its
429  * representation is datatype-independent. This could perhaps
430  * confuse code comparing the finished plan to the target
431  * relation, however.
432  */
433  Oid atttype = att_tup->atttypid;
434  Oid attcollation = att_tup->attcollation;
435  Node *new_expr;
436 
437  if (!att_tup->attisdropped)
438  {
439  new_expr = (Node *) makeConst(atttype,
440  -1,
441  attcollation,
442  att_tup->attlen,
443  (Datum) 0,
444  true, /* isnull */
445  att_tup->attbyval);
446  new_expr = coerce_to_domain(new_expr,
447  InvalidOid, -1,
448  atttype,
451  -1,
452  false);
453  }
454  else
455  {
456  /* Insert NULL for dropped column */
457  new_expr = (Node *) makeConst(INT4OID,
458  -1,
459  InvalidOid,
460  sizeof(int32),
461  (Datum) 0,
462  true, /* isnull */
463  true /* byval */ );
464  }
465 
466  new_tle = makeTargetEntry((Expr *) new_expr,
467  attrno,
468  pstrdup(NameStr(att_tup->attname)),
469  false);
470  }
471 
472  new_tlist = lappend(new_tlist, new_tle);
473  }
474 
475  /*
476  * The remaining tlist entries should be resjunk; append them all to the
477  * end of the new tlist, making sure they have resnos higher than the last
478  * real attribute. (Note: although the rewriter already did such
479  * renumbering, we have to do it again here in case we added NULL entries
480  * above.)
481  */
482  while (tlist_item)
483  {
484  TargetEntry *old_tle = (TargetEntry *) lfirst(tlist_item);
485 
486  if (!old_tle->resjunk)
487  elog(ERROR, "targetlist is not sorted correctly");
488  /* Get the resno right, but don't copy unnecessarily */
489  if (old_tle->resno != attrno)
490  {
491  old_tle = flatCopyTargetEntry(old_tle);
492  old_tle->resno = attrno;
493  }
494  new_tlist = lappend(new_tlist, old_tle);
495  attrno++;
496  tlist_item = lnext(tlist, tlist_item);
497  }
498 
499  return new_tlist;
500 }
#define NameStr(name)
Definition: c.h:725
signed int int32
Definition: c.h:482
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
List * lappend(List *list, void *datum)
Definition: list.c:339
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:240
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:301
TargetEntry * flatCopyTargetEntry(TargetEntry *src_tle)
Definition: makefuncs.c:273
char * pstrdup(const char *in)
Definition: mcxt.c:1696
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
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
#define lfirst(lc)
Definition: pg_list.h:172
#define NIL
Definition: pg_list.h:68
static ListCell * list_head(const List *l)
Definition: pg_list.h:128
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
uintptr_t Datum
Definition: postgres.h:64
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:736
@ COERCION_IMPLICIT
Definition: primnodes.h:714
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:511
Definition: pg_list.h:54
Definition: nodes.h:129
TupleDesc rd_att
Definition: rel.h:112
AttrNumber resno
Definition: primnodes.h:2192
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

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::resno, and TupleDescAttr.

Referenced by preprocess_targetlist().

◆ extract_update_targetlist_colnos()

List* extract_update_targetlist_colnos ( List tlist)

Definition at line 345 of file preptlist.c.

346 {
347  List *update_colnos = NIL;
348  AttrNumber nextresno = 1;
349  ListCell *lc;
350 
351  foreach(lc, tlist)
352  {
353  TargetEntry *tle = (TargetEntry *) lfirst(lc);
354 
355  if (!tle->resjunk)
356  update_colnos = lappend_int(update_colnos, tle->resno);
357  tle->resno = nextresno++;
358  }
359  return update_colnos;
360 }
int16 AttrNumber
Definition: attnum.h:21
List * lappend_int(List *list, int datum)
Definition: list.c:357

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

Referenced by make_modifytable(), and preprocess_targetlist().

◆ get_plan_rowmark()

PlanRowMark* get_plan_rowmark ( List rowmarks,
Index  rtindex 
)

Definition at line 509 of file preptlist.c.

510 {
511  ListCell *l;
512 
513  foreach(l, rowmarks)
514  {
515  PlanRowMark *rc = (PlanRowMark *) lfirst(l);
516 
517  if (rc->rti == rtindex)
518  return rc;
519  }
520  return NULL;
521 }

References lfirst, and PlanRowMark::rti.

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

◆ preprocess_targetlist()

void preprocess_targetlist ( PlannerInfo root)

Definition at line 62 of file preptlist.c.

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)
107  root->update_colnos = extract_update_targetlist_colnos(tlist);
108 
109  /*
110  * For non-inherited UPDATE/DELETE/MERGE, register any junk column(s)
111  * needed to allow the executor to identify the rows to be updated or
112  * deleted. In the inheritance case, we do nothing now, leaving this to
113  * be dealt with when expand_inherited_rtentry() makes the leaf target
114  * relations. (But there might not be any leaf target relations, in which
115  * case we must do this in distribute_row_identity_vars().)
116  */
117  if ((command_type == CMD_UPDATE || command_type == CMD_DELETE ||
118  command_type == CMD_MERGE) &&
119  !target_rte->inh)
120  {
121  /* row-identity logic expects to add stuff to processed_tlist */
122  root->processed_tlist = tlist;
123  add_row_identity_columns(root, result_relation,
124  target_rte, target_relation);
125  tlist = root->processed_tlist;
126  }
127 
128  /*
129  * For MERGE we also need to handle the target list for each INSERT and
130  * UPDATE action separately. In addition, we examine the qual of each
131  * action and add any Vars there (other than those of the target rel) to
132  * the subplan targetlist.
133  */
134  if (command_type == CMD_MERGE)
135  {
136  ListCell *l;
137  List *vars;
138 
139  /*
140  * For MERGE, handle targetlist of each MergeAction separately. Give
141  * the same treatment to MergeAction->targetList as we would have
142  * given to a regular INSERT. For UPDATE, collect the column numbers
143  * being modified.
144  */
145  foreach(l, parse->mergeActionList)
146  {
148  ListCell *l2;
149 
150  if (action->commandType == CMD_INSERT)
151  action->targetList = expand_insert_targetlist(action->targetList,
152  target_relation);
153  else if (action->commandType == CMD_UPDATE)
154  action->updateColnos =
156 
157  /*
158  * Add resjunk entries for any Vars and PlaceHolderVars used in
159  * each action's targetlist and WHEN condition that belong to
160  * relations other than the target. We don't expect to see any
161  * aggregates or window functions here.
162  */
164  list_concat_copy((List *) action->qual,
165  action->targetList),
167  foreach(l2, vars)
168  {
169  Var *var = (Var *) lfirst(l2);
170  TargetEntry *tle;
171 
172  if (IsA(var, Var) && var->varno == result_relation)
173  continue; /* don't need it */
174 
175  if (tlist_member((Expr *) var, tlist))
176  continue; /* already got it */
177 
178  tle = makeTargetEntry((Expr *) var,
179  list_length(tlist) + 1,
180  NULL, true);
181  tlist = lappend(tlist, tle);
182  }
183  list_free(vars);
184  }
185 
186  /*
187  * Add resjunk entries for any Vars and PlaceHolderVars used in the
188  * join condition that belong to relations other than the target. We
189  * don't expect to see any aggregates or window functions here.
190  */
191  vars = pull_var_clause(parse->mergeJoinCondition,
193  foreach(l, vars)
194  {
195  Var *var = (Var *) lfirst(l);
196  TargetEntry *tle;
197 
198  if (IsA(var, Var) && var->varno == result_relation)
199  continue; /* don't need it */
200 
201  if (tlist_member((Expr *) var, tlist))
202  continue; /* already got it */
203 
204  tle = makeTargetEntry((Expr *) var,
205  list_length(tlist) + 1,
206  NULL, true);
207  tlist = lappend(tlist, tle);
208  }
209  }
210 
211  /*
212  * Add necessary junk columns for rowmarked rels. These values are needed
213  * for locking of rels selected FOR UPDATE/SHARE, and to do EvalPlanQual
214  * rechecking. See comments for PlanRowMark in plannodes.h. If you
215  * change this stanza, see also expand_inherited_rtentry(), which has to
216  * be able to add on junk columns equivalent to these.
217  *
218  * (Someday it might be useful to fold these resjunk columns into the
219  * row-identity-column management used for UPDATE/DELETE. Today is not
220  * that day, however. One notable issue is that it seems important that
221  * the whole-row Vars made here use the real table rowtype, not RECORD, so
222  * that conversion to/from child relations' rowtypes will happen. Also,
223  * since these entries don't potentially bloat with more and more child
224  * relations, there's not really much need for column sharing.)
225  */
226  foreach(lc, root->rowMarks)
227  {
228  PlanRowMark *rc = (PlanRowMark *) lfirst(lc);
229  Var *var;
230  char resname[32];
231  TargetEntry *tle;
232 
233  /* child rels use the same junk attrs as their parents */
234  if (rc->rti != rc->prti)
235  continue;
236 
237  if (rc->allMarkTypes & ~(1 << ROW_MARK_COPY))
238  {
239  /* Need to fetch TID */
240  var = makeVar(rc->rti,
242  TIDOID,
243  -1,
244  InvalidOid,
245  0);
246  snprintf(resname, sizeof(resname), "ctid%u", rc->rowmarkId);
247  tle = makeTargetEntry((Expr *) var,
248  list_length(tlist) + 1,
249  pstrdup(resname),
250  true);
251  tlist = lappend(tlist, tle);
252  }
253  if (rc->allMarkTypes & (1 << ROW_MARK_COPY))
254  {
255  /* Need the whole row as a junk var */
256  var = makeWholeRowVar(rt_fetch(rc->rti, range_table),
257  rc->rti,
258  0,
259  false);
260  snprintf(resname, sizeof(resname), "wholerow%u", rc->rowmarkId);
261  tle = makeTargetEntry((Expr *) var,
262  list_length(tlist) + 1,
263  pstrdup(resname),
264  true);
265  tlist = lappend(tlist, tle);
266  }
267 
268  /* If parent of inheritance tree, always fetch the tableoid too. */
269  if (rc->isParent)
270  {
271  var = makeVar(rc->rti,
273  OIDOID,
274  -1,
275  InvalidOid,
276  0);
277  snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId);
278  tle = makeTargetEntry((Expr *) var,
279  list_length(tlist) + 1,
280  pstrdup(resname),
281  true);
282  tlist = lappend(tlist, tle);
283  }
284  }
285 
286  /*
287  * If the query has a RETURNING list, add resjunk entries for any Vars
288  * used in RETURNING that belong to other relations. We need to do this
289  * to make these Vars available for the RETURNING calculation. Vars that
290  * belong to the result rel don't need to be added, because they will be
291  * made to refer to the actual heap tuple.
292  */
293  if (parse->returningList && list_length(parse->rtable) > 1)
294  {
295  List *vars;
296  ListCell *l;
297 
298  vars = pull_var_clause((Node *) parse->returningList,
302  foreach(l, vars)
303  {
304  Var *var = (Var *) lfirst(l);
305  TargetEntry *tle;
306 
307  if (IsA(var, Var) &&
308  var->varno == result_relation)
309  continue; /* don't need it */
310 
311  if (tlist_member((Expr *) var, tlist))
312  continue; /* already got it */
313 
314  tle = makeTargetEntry((Expr *) var,
315  list_length(tlist) + 1,
316  NULL,
317  true);
318 
319  tlist = lappend(tlist, tle);
320  }
321  list_free(vars);
322  }
323 
324  root->processed_tlist = tlist;
325 
326  if (target_relation)
327  table_close(target_relation, NoLock);
328 }
void add_row_identity_columns(PlannerInfo *root, Index rtindex, RangeTblEntry *target_rte, Relation target_relation)
Definition: appendinfo.c:887
#define Assert(condition)
Definition: c.h:837
void list_free(List *list)
Definition: list.c:1546
List * list_concat_copy(const List *list1, const List *list2)
Definition: list.c:598
#define NoLock
Definition: lockdefs.h:34
Var * makeWholeRowVar(RangeTblEntry *rte, int varno, Index varlevelsup, bool allowScalar)
Definition: makefuncs.c:135
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
CmdType
Definition: nodes.h:263
@ CMD_MERGE
Definition: nodes.h:269
@ CMD_INSERT
Definition: nodes.h:267
@ CMD_DELETE
Definition: nodes.h:268
@ CMD_UPDATE
Definition: nodes.h:266
@ CMD_SELECT
Definition: nodes.h:265
#define PVC_RECURSE_AGGREGATES
Definition: optimizer.h:188
#define PVC_RECURSE_WINDOWFUNCS
Definition: optimizer.h:190
#define PVC_INCLUDE_PLACEHOLDERS
Definition: optimizer.h:191
@ RTE_RELATION
Definition: parsenodes.h:1017
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
static int list_length(const List *l)
Definition: pg_list.h:152
@ ROW_MARK_COPY
Definition: plannodes.h:1335
#define snprintf
Definition: port.h:238
static List * expand_insert_targetlist(List *tlist, Relation rel)
Definition: preptlist.c:379
List * extract_update_targetlist_colnos(List *tlist)
Definition: preptlist.c:345
tree ctl root
Definition: radixtree.h:1886
static struct subre * parse(struct vars *v, int stopper, int type, struct state *init, struct state *final)
Definition: regcomp.c:717
Index prti
Definition: plannodes.h:1384
bool isParent
Definition: plannodes.h:1390
Index rowmarkId
Definition: plannodes.h:1385
int allMarkTypes
Definition: plannodes.h:1387
RTEKind rtekind
Definition: parsenodes.h:1047
Definition: primnodes.h:248
int varno
Definition: primnodes.h:255
Definition: regcomp.c:282
#define TableOidAttributeNumber
Definition: sysattr.h:26
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
TargetEntry * tlist_member(Expr *node, List *targetlist)
Definition: tlist.c:79
List * pull_var_clause(Node *node, int flags)
Definition: var.c:609

References generate_unaccent_rules::action, add_row_identity_columns(), PlanRowMark::allMarkTypes, Assert, CMD_DELETE, CMD_INSERT, CMD_MERGE, CMD_SELECT, CMD_UPDATE, elog, ERROR, expand_insert_targetlist(), extract_update_targetlist_colnos(), RangeTblEntry::inh, InvalidOid, IsA, PlanRowMark::isParent, lappend(), lfirst, list_concat_copy(), list_free(), list_length(), makeTargetEntry(), makeVar(), makeWholeRowVar(), NoLock, parse(), PlanRowMark::prti, pstrdup(), pull_var_clause(), PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_AGGREGATES, PVC_RECURSE_WINDOWFUNCS, RangeTblEntry::relid, root, ROW_MARK_COPY, PlanRowMark::rowmarkId, rt_fetch, RTE_RELATION, RangeTblEntry::rtekind, PlanRowMark::rti, SelfItemPointerAttributeNumber, snprintf, table_close(), table_open(), TableOidAttributeNumber, tlist_member(), and Var::varno.

Referenced by grouping_planner().