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

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

322 {
323  List *update_colnos = NIL;
324  AttrNumber nextresno = 1;
325  ListCell *lc;
326 
327  foreach(lc, tlist)
328  {
329  TargetEntry *tle = (TargetEntry *) lfirst(lc);
330 
331  if (!tle->resjunk)
332  update_colnos = lappend_int(update_colnos, tle->resno);
333  tle->resno = nextresno++;
334  }
335  return update_colnos;
336 }
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 485 of file preptlist.c.

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

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 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  /*
188  * Add necessary junk columns for rowmarked rels. These values are needed
189  * for locking of rels selected FOR UPDATE/SHARE, and to do EvalPlanQual
190  * rechecking. See comments for PlanRowMark in plannodes.h. If you
191  * change this stanza, see also expand_inherited_rtentry(), which has to
192  * be able to add on junk columns equivalent to these.
193  *
194  * (Someday it might be useful to fold these resjunk columns into the
195  * row-identity-column management used for UPDATE/DELETE. Today is not
196  * that day, however. One notable issue is that it seems important that
197  * the whole-row Vars made here use the real table rowtype, not RECORD, so
198  * that conversion to/from child relations' rowtypes will happen. Also,
199  * since these entries don't potentially bloat with more and more child
200  * relations, there's not really much need for column sharing.)
201  */
202  foreach(lc, root->rowMarks)
203  {
204  PlanRowMark *rc = (PlanRowMark *) lfirst(lc);
205  Var *var;
206  char resname[32];
207  TargetEntry *tle;
208 
209  /* child rels use the same junk attrs as their parents */
210  if (rc->rti != rc->prti)
211  continue;
212 
213  if (rc->allMarkTypes & ~(1 << ROW_MARK_COPY))
214  {
215  /* Need to fetch TID */
216  var = makeVar(rc->rti,
218  TIDOID,
219  -1,
220  InvalidOid,
221  0);
222  snprintf(resname, sizeof(resname), "ctid%u", rc->rowmarkId);
223  tle = makeTargetEntry((Expr *) var,
224  list_length(tlist) + 1,
225  pstrdup(resname),
226  true);
227  tlist = lappend(tlist, tle);
228  }
229  if (rc->allMarkTypes & (1 << ROW_MARK_COPY))
230  {
231  /* Need the whole row as a junk var */
232  var = makeWholeRowVar(rt_fetch(rc->rti, range_table),
233  rc->rti,
234  0,
235  false);
236  snprintf(resname, sizeof(resname), "wholerow%u", rc->rowmarkId);
237  tle = makeTargetEntry((Expr *) var,
238  list_length(tlist) + 1,
239  pstrdup(resname),
240  true);
241  tlist = lappend(tlist, tle);
242  }
243 
244  /* If parent of inheritance tree, always fetch the tableoid too. */
245  if (rc->isParent)
246  {
247  var = makeVar(rc->rti,
249  OIDOID,
250  -1,
251  InvalidOid,
252  0);
253  snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId);
254  tle = makeTargetEntry((Expr *) var,
255  list_length(tlist) + 1,
256  pstrdup(resname),
257  true);
258  tlist = lappend(tlist, tle);
259  }
260  }
261 
262  /*
263  * If the query has a RETURNING list, add resjunk entries for any Vars
264  * used in RETURNING that belong to other relations. We need to do this
265  * to make these Vars available for the RETURNING calculation. Vars that
266  * belong to the result rel don't need to be added, because they will be
267  * made to refer to the actual heap tuple.
268  */
269  if (parse->returningList && list_length(parse->rtable) > 1)
270  {
271  List *vars;
272  ListCell *l;
273 
274  vars = pull_var_clause((Node *) parse->returningList,
278  foreach(l, vars)
279  {
280  Var *var = (Var *) lfirst(l);
281  TargetEntry *tle;
282 
283  if (IsA(var, Var) &&
284  var->varno == result_relation)
285  continue; /* don't need it */
286 
287  if (tlist_member((Expr *) var, tlist))
288  continue; /* already got it */
289 
290  tle = makeTargetEntry((Expr *) var,
291  list_length(tlist) + 1,
292  NULL,
293  true);
294 
295  tlist = lappend(tlist, tle);
296  }
297  list_free(vars);
298  }
299 
300  root->processed_tlist = tlist;
301 
302  if (target_relation)
303  table_close(target_relation, NoLock);
304 }
void add_row_identity_columns(PlannerInfo *root, Index rtindex, RangeTblEntry *target_rte, Relation target_relation)
Definition: appendinfo.c:884
Assert(fmt[strlen(fmt) - 1] !='\n')
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:136
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:158
CmdType
Definition: nodes.h:253
@ CMD_MERGE
Definition: nodes.h:259
@ CMD_INSERT
Definition: nodes.h:257
@ CMD_DELETE
Definition: nodes.h:258
@ CMD_UPDATE
Definition: nodes.h:256
@ CMD_SELECT
Definition: nodes.h:255
#define PVC_RECURSE_AGGREGATES
Definition: optimizer.h:187
#define PVC_RECURSE_WINDOWFUNCS
Definition: optimizer.h:189
#define PVC_INCLUDE_PLACEHOLDERS
Definition: optimizer.h:190
@ RTE_RELATION
Definition: parsenodes.h:1006
#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:1332
#define snprintf
Definition: port.h:238
static List * expand_insert_targetlist(List *tlist, Relation rel)
Definition: preptlist.c:355
List * extract_update_targetlist_colnos(List *tlist)
Definition: preptlist.c:321
static struct subre * parse(struct vars *v, int stopper, int type, struct state *init, struct state *final)
Definition: regcomp.c:715
Index prti
Definition: plannodes.h:1381
bool isParent
Definition: plannodes.h:1387
Index rowmarkId
Definition: plannodes.h:1382
int allMarkTypes
Definition: plannodes.h:1384
List * processed_tlist
Definition: pathnodes.h:453
Query * parse
Definition: pathnodes.h:199
List * rowMarks
Definition: pathnodes.h:368
List * update_colnos
Definition: pathnodes.h:461
RTEKind rtekind
Definition: parsenodes.h:1025
Definition: primnodes.h:234
int varno
Definition: primnodes.h:241
Definition: regcomp.c:281
#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:607

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().