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 357 of file preptlist.c.

358 {
359  List *new_tlist = NIL;
360  ListCell *tlist_item;
361  int attrno,
362  numattrs;
363 
364  tlist_item = list_head(tlist);
365 
366  /*
367  * The rewriter should have already ensured that the TLEs are in correct
368  * order; but we have to insert TLEs for any missing attributes.
369  *
370  * Scan the tuple description in the relation's relcache entry to make
371  * sure we have all the user attributes in the right order.
372  */
373  numattrs = RelationGetNumberOfAttributes(rel);
374 
375  for (attrno = 1; attrno <= numattrs; attrno++)
376  {
377  Form_pg_attribute att_tup = TupleDescAttr(rel->rd_att, attrno - 1);
378  TargetEntry *new_tle = NULL;
379 
380  if (tlist_item != NULL)
381  {
382  TargetEntry *old_tle = (TargetEntry *) lfirst(tlist_item);
383 
384  if (!old_tle->resjunk && old_tle->resno == attrno)
385  {
386  new_tle = old_tle;
387  tlist_item = lnext(tlist, tlist_item);
388  }
389  }
390 
391  if (new_tle == NULL)
392  {
393  /*
394  * Didn't find a matching tlist entry, so make one.
395  *
396  * INSERTs should insert NULL in this case. (We assume the
397  * rewriter would have inserted any available non-NULL default
398  * value.) Also, if the column isn't dropped, apply any domain
399  * constraints that might exist --- this is to catch domain NOT
400  * NULL.
401  *
402  * When generating a NULL constant for a dropped column, we label
403  * it INT4 (any other guaranteed-to-exist datatype would do as
404  * well). We can't label it with the dropped column's datatype
405  * since that might not exist anymore. It does not really matter
406  * what we claim the type is, since NULL is NULL --- its
407  * representation is datatype-independent. This could perhaps
408  * confuse code comparing the finished plan to the target
409  * relation, however.
410  */
411  Oid atttype = att_tup->atttypid;
412  Oid attcollation = att_tup->attcollation;
413  Node *new_expr;
414 
415  if (!att_tup->attisdropped)
416  {
417  new_expr = (Node *) makeConst(atttype,
418  -1,
419  attcollation,
420  att_tup->attlen,
421  (Datum) 0,
422  true, /* isnull */
423  att_tup->attbyval);
424  new_expr = coerce_to_domain(new_expr,
425  InvalidOid, -1,
426  atttype,
429  -1,
430  false);
431  }
432  else
433  {
434  /* Insert NULL for dropped column */
435  new_expr = (Node *) makeConst(INT4OID,
436  -1,
437  InvalidOid,
438  sizeof(int32),
439  (Datum) 0,
440  true, /* isnull */
441  true /* byval */ );
442  }
443 
444  new_tle = makeTargetEntry((Expr *) new_expr,
445  attrno,
446  pstrdup(NameStr(att_tup->attname)),
447  false);
448  }
449 
450  new_tlist = lappend(new_tlist, new_tle);
451  }
452 
453  /*
454  * The remaining tlist entries should be resjunk; append them all to the
455  * end of the new tlist, making sure they have resnos higher than the last
456  * real attribute. (Note: although the rewriter already did such
457  * renumbering, we have to do it again here in case we added NULL entries
458  * above.)
459  */
460  while (tlist_item)
461  {
462  TargetEntry *old_tle = (TargetEntry *) lfirst(tlist_item);
463 
464  if (!old_tle->resjunk)
465  elog(ERROR, "targetlist is not sorted correctly");
466  /* Get the resno right, but don't copy unnecessarily */
467  if (old_tle->resno != attrno)
468  {
469  old_tle = flatCopyTargetEntry(old_tle);
470  old_tle->resno = attrno;
471  }
472  new_tlist = lappend(new_tlist, old_tle);
473  attrno++;
474  tlist_item = lnext(tlist, tlist_item);
475  }
476 
477  return new_tlist;
478 }
#define NameStr(name)
Definition: c.h:692
signed int int32
Definition: c.h:440
#define ERROR
Definition: elog.h:33
List * lappend(List *list, void *datum)
Definition: list.c:338
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:239
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:300
TargetEntry * flatCopyTargetEntry(TargetEntry *src_tle)
Definition: makefuncs.c:272
char * pstrdup(const char *in)
Definition: mcxt.c:1305
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:207
#define lfirst(lc)
Definition: pg_list.h:170
#define NIL
Definition: pg_list.h:66
static ListCell * list_head(const List *l)
Definition: pg_list.h:126
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:341
uintptr_t Datum
Definition: postgres.h:411
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:575
@ COERCION_IMPLICIT
Definition: primnodes.h:553
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:494
Definition: pg_list.h:52
Definition: nodes.h:575
TupleDesc rd_att
Definition: rel.h:110
AttrNumber resno
Definition: primnodes.h:1829
bool resjunk
Definition: primnodes.h:1835
#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::resjunk, TargetEntry::resno, and TupleDescAttr.

Referenced by preprocess_targetlist().

◆ extract_update_targetlist_colnos()

List* extract_update_targetlist_colnos ( List tlist)

Definition at line 323 of file preptlist.c.

324 {
325  List *update_colnos = NIL;
326  AttrNumber nextresno = 1;
327  ListCell *lc;
328 
329  foreach(lc, tlist)
330  {
331  TargetEntry *tle = (TargetEntry *) lfirst(lc);
332 
333  if (!tle->resjunk)
334  update_colnos = lappend_int(update_colnos, tle->resno);
335  tle->resno = nextresno++;
336  }
337  return update_colnos;
338 }
int16 AttrNumber
Definition: attnum.h:21
List * lappend_int(List *list, int datum)
Definition: list.c:356

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

Referenced by make_modifytable(), and preprocess_targetlist().

◆ get_plan_rowmark()

PlanRowMark* get_plan_rowmark ( List rowmarks,
Index  rtindex 
)

Definition at line 487 of file preptlist.c.

488 {
489  ListCell *l;
490 
491  foreach(l, rowmarks)
492  {
493  PlanRowMark *rc = (PlanRowMark *) lfirst(l);
494 
495  if (rc->rti == rtindex)
496  return rc;
497  }
498  return NULL;
499 }

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)
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 
138  /*
139  * For MERGE, handle targetlist of each MergeAction separately. Give
140  * the same treatment to MergeAction->targetList as we would have
141  * given to a regular INSERT. For UPDATE, collect the column numbers
142  * being modified.
143  */
144  foreach(l, parse->mergeActionList)
145  {
147  List *vars;
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 used in each action's
159  * targetlist and WHEN condition that belong to relations other
160  * than target. Note that aggregates, window functions and
161  * placeholder vars are not possible anywhere in MERGE's WHEN
162  * clauses. (PHVs may be added later, but they don't concern us
163  * here.)
164  */
166  list_concat_copy((List *) action->qual,
167  action->targetList),
168  0);
169  foreach(l2, vars)
170  {
171  Var *var = (Var *) lfirst(l2);
172  TargetEntry *tle;
173 
174  if (IsA(var, Var) && var->varno == result_relation)
175  continue; /* don't need it */
176 
177  if (tlist_member((Expr *) var, tlist))
178  continue; /* already got it */
179 
180  tle = makeTargetEntry((Expr *) var,
181  list_length(tlist) + 1,
182  NULL, true);
183  tlist = lappend(tlist, tle);
184  }
185  list_free(vars);
186  }
187  }
188 
189  /*
190  * Add necessary junk columns for rowmarked rels. These values are needed
191  * for locking of rels selected FOR UPDATE/SHARE, and to do EvalPlanQual
192  * rechecking. See comments for PlanRowMark in plannodes.h. If you
193  * change this stanza, see also expand_inherited_rtentry(), which has to
194  * be able to add on junk columns equivalent to these.
195  *
196  * (Someday it might be useful to fold these resjunk columns into the
197  * row-identity-column management used for UPDATE/DELETE. Today is not
198  * that day, however. One notable issue is that it seems important that
199  * the whole-row Vars made here use the real table rowtype, not RECORD, so
200  * that conversion to/from child relations' rowtypes will happen. Also,
201  * since these entries don't potentially bloat with more and more child
202  * relations, there's not really much need for column sharing.)
203  */
204  foreach(lc, root->rowMarks)
205  {
206  PlanRowMark *rc = (PlanRowMark *) lfirst(lc);
207  Var *var;
208  char resname[32];
209  TargetEntry *tle;
210 
211  /* child rels use the same junk attrs as their parents */
212  if (rc->rti != rc->prti)
213  continue;
214 
215  if (rc->allMarkTypes & ~(1 << ROW_MARK_COPY))
216  {
217  /* Need to fetch TID */
218  var = makeVar(rc->rti,
220  TIDOID,
221  -1,
222  InvalidOid,
223  0);
224  snprintf(resname, sizeof(resname), "ctid%u", rc->rowmarkId);
225  tle = makeTargetEntry((Expr *) var,
226  list_length(tlist) + 1,
227  pstrdup(resname),
228  true);
229  tlist = lappend(tlist, tle);
230  }
231  if (rc->allMarkTypes & (1 << ROW_MARK_COPY))
232  {
233  /* Need the whole row as a junk var */
234  var = makeWholeRowVar(rt_fetch(rc->rti, range_table),
235  rc->rti,
236  0,
237  false);
238  snprintf(resname, sizeof(resname), "wholerow%u", rc->rowmarkId);
239  tle = makeTargetEntry((Expr *) var,
240  list_length(tlist) + 1,
241  pstrdup(resname),
242  true);
243  tlist = lappend(tlist, tle);
244  }
245 
246  /* If parent of inheritance tree, always fetch the tableoid too. */
247  if (rc->isParent)
248  {
249  var = makeVar(rc->rti,
251  OIDOID,
252  -1,
253  InvalidOid,
254  0);
255  snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId);
256  tle = makeTargetEntry((Expr *) var,
257  list_length(tlist) + 1,
258  pstrdup(resname),
259  true);
260  tlist = lappend(tlist, tle);
261  }
262  }
263 
264  /*
265  * If the query has a RETURNING list, add resjunk entries for any Vars
266  * used in RETURNING that belong to other relations. We need to do this
267  * to make these Vars available for the RETURNING calculation. Vars that
268  * belong to the result rel don't need to be added, because they will be
269  * made to refer to the actual heap tuple.
270  */
271  if (parse->returningList && list_length(parse->rtable) > 1)
272  {
273  List *vars;
274  ListCell *l;
275 
276  vars = pull_var_clause((Node *) parse->returningList,
280  foreach(l, vars)
281  {
282  Var *var = (Var *) lfirst(l);
283  TargetEntry *tle;
284 
285  if (IsA(var, Var) &&
286  var->varno == result_relation)
287  continue; /* don't need it */
288 
289  if (tlist_member((Expr *) var, tlist))
290  continue; /* already got it */
291 
292  tle = makeTargetEntry((Expr *) var,
293  list_length(tlist) + 1,
294  NULL,
295  true);
296 
297  tlist = lappend(tlist, tle);
298  }
299  list_free(vars);
300  }
301 
302  root->processed_tlist = tlist;
303 
304  if (target_relation)
305  table_close(target_relation, NoLock);
306 }
void add_row_identity_columns(PlannerInfo *root, Index rtindex, RangeTblEntry *target_rte, Relation target_relation)
Definition: appendinfo.c:857
Assert(fmt[strlen(fmt) - 1] !='\n')
void list_free(List *list)
Definition: list.c:1545
List * list_concat_copy(const List *list1, const List *list2)
Definition: list.c:597
#define NoLock
Definition: lockdefs.h:34
Var * makeWholeRowVar(RangeTblEntry *rte, int varno, Index varlevelsup, bool allowScalar)
Definition: makefuncs.c:134
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:67
#define IsA(nodeptr, _type_)
Definition: nodes.h:625
CmdType
Definition: nodes.h:720
@ CMD_MERGE
Definition: nodes.h:726
@ CMD_INSERT
Definition: nodes.h:724
@ CMD_DELETE
Definition: nodes.h:725
@ CMD_UPDATE
Definition: nodes.h:723
@ CMD_SELECT
Definition: nodes.h:722
#define PVC_RECURSE_AGGREGATES
Definition: optimizer.h:189
#define PVC_RECURSE_WINDOWFUNCS
Definition: optimizer.h:191
#define PVC_INCLUDE_PLACEHOLDERS
Definition: optimizer.h:192
@ RTE_RELATION
Definition: parsenodes.h:999
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
static int list_length(const List *l)
Definition: pg_list.h:150
@ ROW_MARK_COPY
Definition: plannodes.h:1303
#define snprintf
Definition: port.h:225
static List * expand_insert_targetlist(List *tlist, Relation rel)
Definition: preptlist.c:357
List * extract_update_targetlist_colnos(List *tlist)
Definition: preptlist.c:323
static struct subre * parse(struct vars *, int, int, struct state *, struct state *)
Definition: regcomp.c:673
Index prti
Definition: plannodes.h:1350
bool isParent
Definition: plannodes.h:1356
Index rowmarkId
Definition: plannodes.h:1351
int allMarkTypes
Definition: plannodes.h:1353
List * processed_tlist
Definition: pathnodes.h:322
Query * parse
Definition: pathnodes.h:162
List * rowMarks
Definition: pathnodes.h:289
List * update_colnos
Definition: pathnodes.h:330
RTEKind rtekind
Definition: parsenodes.h:1016
Definition: primnodes.h:209
int varno
Definition: primnodes.h:216
Definition: regcomp.c:238
#define TableOidAttributeNumber
Definition: sysattr.h:26
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
TargetEntry * tlist_member(Expr *node, List *targetlist)
Definition: tlist.c:68
List * pull_var_clause(Node *node, int flags)
Definition: var.c:604

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(), PlannerInfo::parse, PlannerInfo::processed_tlist, PlanRowMark::prti, pstrdup(), pull_var_clause(), PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_AGGREGATES, PVC_RECURSE_WINDOWFUNCS, RangeTblEntry::relid, ROW_MARK_COPY, PlanRowMark::rowmarkId, PlannerInfo::rowMarks, rt_fetch, RTE_RELATION, RangeTblEntry::rtekind, PlanRowMark::rti, SelfItemPointerAttributeNumber, snprintf, table_close(), table_open(), TableOidAttributeNumber, tlist_member(), PlannerInfo::update_colnos, and Var::varno.

Referenced by grouping_planner().