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 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,
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:703
int32_t int32
Definition: c.h:484
#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:242
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:303
TargetEntry * flatCopyTargetEntry(TargetEntry *src_tle)
Definition: makefuncs.c:275
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:200
#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:69
#define InvalidOid
Definition: postgres_ext.h:37
unsigned int Oid
Definition: postgres_ext.h:32
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:752
@ COERCION_IMPLICIT
Definition: primnodes.h:730
#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:2247
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:153

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 }
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,
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,
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 }
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:904
#define Assert(condition)
Definition: c.h:815
List * list_concat_copy(const List *list1, const List *list2)
Definition: list.c:598
void list_free(List *list)
Definition: list.c:1546
#define NoLock
Definition: lockdefs.h:34
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
Var * makeWholeRowVar(RangeTblEntry *rte, int varno, Index varlevelsup, bool allowScalar)
Definition: makefuncs.c:137
#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:1026
#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:1334
#define snprintf
Definition: port.h:238
List * extract_update_targetlist_colnos(List *tlist)
Definition: preptlist.c:345
static List * expand_insert_targetlist(List *tlist, Relation rel)
Definition: preptlist.c:379
tree ctl root
Definition: radixtree.h:1857
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:1383
bool isParent
Definition: plannodes.h:1389
Index rowmarkId
Definition: plannodes.h:1384
int allMarkTypes
Definition: plannodes.h:1386
RTEKind rtekind
Definition: parsenodes.h:1056
Definition: primnodes.h:261
int varno
Definition: primnodes.h:268
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:653

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