PostgreSQL Source Code git master
Loading...
Searching...
No Matches
preptlist.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * preptlist.c
4 * Routines to preprocess the parse tree target list
5 *
6 * For an INSERT, the targetlist must contain an entry for each attribute of
7 * the target relation in the correct order.
8 *
9 * For an UPDATE, the targetlist just contains the expressions for the new
10 * column values.
11 *
12 * For UPDATE and DELETE queries, the targetlist must also contain "junk"
13 * tlist entries needed to allow the executor to identify the rows to be
14 * updated or deleted; for example, the ctid of a heap row. (The planner
15 * adds these; they're not in what we receive from the parser/rewriter.)
16 *
17 * For all query types, there can be additional junk tlist entries, such as
18 * sort keys, Vars needed for a RETURNING list, and row ID information needed
19 * for SELECT FOR UPDATE locking and/or EvalPlanQual checking.
20 *
21 * The query rewrite phase also does preprocessing of the targetlist (see
22 * rewriteTargetListIU). The division of labor between here and there is
23 * partially historical, but it's not entirely arbitrary. The stuff done
24 * here is closely connected to physical access to tables, whereas the
25 * rewriter's work is more concerned with SQL semantics.
26 *
27 *
28 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
29 * Portions Copyright (c) 1994, Regents of the University of California
30 *
31 * IDENTIFICATION
32 * src/backend/optimizer/prep/preptlist.c
33 *
34 *-------------------------------------------------------------------------
35 */
36
37#include "postgres.h"
38
39#include "access/sysattr.h"
40#include "access/table.h"
41#include "catalog/pg_type_d.h"
42#include "nodes/makefuncs.h"
44#include "optimizer/optimizer.h"
45#include "optimizer/prep.h"
46#include "optimizer/tlist.h"
47#include "parser/parse_coerce.h"
48#include "parser/parsetree.h"
49#include "utils/lsyscache.h"
50#include "utils/rel.h"
51
53 Relation rel);
54
55
56/*
57 * preprocess_targetlist
58 * Driver for preprocessing the parse tree targetlist.
59 *
60 * The preprocessed targetlist is returned in root->processed_tlist.
61 * Also, if this is an UPDATE, we return a list of target column numbers
62 * in root->update_colnos. (Resnos in processed_tlist will be consecutive,
63 * so do not look at that to find out which columns are targets!)
64 */
65void
67{
68 Query *parse = root->parse;
69 int result_relation = parse->resultRelation;
70 List *range_table = parse->rtable;
71 CmdType command_type = parse->commandType;
72 RangeTblEntry *target_rte = NULL;
74 List *tlist;
75 ListCell *lc;
76
77 /*
78 * If there is a result relation, open it so we can look for missing
79 * columns and so on. We assume that previous code already acquired at
80 * least AccessShareLock on the relation, so we need no lock here.
81 */
82 if (result_relation)
83 {
84 target_rte = rt_fetch(result_relation, range_table);
85
86 /*
87 * Sanity check: it'd better be a real relation not, say, a subquery.
88 * Else parser or rewriter messed up.
89 */
90 if (target_rte->rtekind != RTE_RELATION)
91 elog(ERROR, "result relation must be a regular relation");
92
93 target_relation = table_open(target_rte->relid, NoLock);
94 }
95 else
97
98 /*
99 * In an INSERT, the executor expects the targetlist to match the exact
100 * order of the target table's attributes, including entries for
101 * attributes not mentioned in the source query.
102 *
103 * In an UPDATE, we don't rearrange the tlist order, but we need to make a
104 * separate list of the target attribute numbers, in tlist order, and then
105 * renumber the processed_tlist entries to be consecutive.
106 */
107 tlist = parse->targetList;
110 else if (command_type == CMD_UPDATE)
111 root->update_colnos = extract_update_targetlist_colnos(tlist);
112
113 /*
114 * For non-inherited UPDATE/DELETE/MERGE, register any junk column(s)
115 * needed to allow the executor to identify the rows to be updated or
116 * deleted. In the inheritance case, we do nothing now, leaving this to
117 * be dealt with when expand_inherited_rtentry() makes the leaf target
118 * relations. (But there might not be any leaf target relations, in which
119 * case we must do this in distribute_row_identity_vars().)
120 */
123 !target_rte->inh)
124 {
125 /* row-identity logic expects to add stuff to processed_tlist */
126 root->processed_tlist = tlist;
127 add_row_identity_columns(root, result_relation,
128 target_rte, target_relation);
129 tlist = root->processed_tlist;
130 }
131
132 /*
133 * For MERGE we also need to handle the target list for each INSERT and
134 * UPDATE action separately. In addition, we examine the qual of each
135 * action and add any Vars there (other than those of the target rel) to
136 * the subplan targetlist.
137 */
138 if (command_type == CMD_MERGE)
139 {
140 ListCell *l;
141 List *vars;
142
143 /*
144 * For MERGE, handle targetlist of each MergeAction separately. Give
145 * the same treatment to MergeAction->targetList as we would have
146 * given to a regular INSERT. For UPDATE, collect the column numbers
147 * being modified.
148 */
149 foreach(l, parse->mergeActionList)
150 {
151 MergeAction *action = (MergeAction *) lfirst(l);
152 ListCell *l2;
153
154 if (action->commandType == CMD_INSERT)
155 action->targetList = expand_insert_targetlist(root,
156 action->targetList,
158 else if (action->commandType == CMD_UPDATE)
159 action->updateColnos =
160 extract_update_targetlist_colnos(action->targetList);
161
162 /*
163 * Add resjunk entries for any Vars and PlaceHolderVars used in
164 * each action's targetlist and WHEN condition that belong to
165 * relations other than the target. We don't expect to see any
166 * aggregates or window functions here.
167 */
169 list_concat_copy((List *) action->qual,
170 action->targetList),
172 foreach(l2, vars)
173 {
174 Var *var = (Var *) lfirst(l2);
176
177 if (IsA(var, Var) && var->varno == result_relation)
178 continue; /* don't need it */
179
180 if (tlist_member((Expr *) var, tlist))
181 continue; /* already got it */
182
183 tle = makeTargetEntry((Expr *) var,
184 list_length(tlist) + 1,
185 NULL, true);
186 tlist = lappend(tlist, tle);
187 }
189 }
190
191 /*
192 * Add resjunk entries for any Vars and PlaceHolderVars used in the
193 * join condition that belong to relations other than the target. We
194 * don't expect to see any aggregates or window functions here.
195 */
196 vars = pull_var_clause(parse->mergeJoinCondition,
198 foreach(l, vars)
199 {
200 Var *var = (Var *) lfirst(l);
202
203 if (IsA(var, Var) && var->varno == result_relation)
204 continue; /* don't need it */
205
206 if (tlist_member((Expr *) var, tlist))
207 continue; /* already got it */
208
209 tle = makeTargetEntry((Expr *) var,
210 list_length(tlist) + 1,
211 NULL, true);
212 tlist = lappend(tlist, tle);
213 }
214 }
215
216 /*
217 * Add necessary junk columns for rowmarked rels. These values are needed
218 * for locking of rels selected FOR UPDATE/SHARE, and to do EvalPlanQual
219 * rechecking. See comments for PlanRowMark in plannodes.h. If you
220 * change this stanza, see also expand_inherited_rtentry(), which has to
221 * be able to add on junk columns equivalent to these.
222 *
223 * (Someday it might be useful to fold these resjunk columns into the
224 * row-identity-column management used for UPDATE/DELETE. Today is not
225 * that day, however. One notable issue is that it seems important that
226 * the whole-row Vars made here use the real table rowtype, not RECORD, so
227 * that conversion to/from child relations' rowtypes will happen. Also,
228 * since these entries don't potentially bloat with more and more child
229 * relations, there's not really much need for column sharing.)
230 */
231 foreach(lc, root->rowMarks)
232 {
233 PlanRowMark *rc = (PlanRowMark *) lfirst(lc);
234 Var *var;
235 char resname[32];
237
238 /* child rels use the same junk attrs as their parents */
239 if (rc->rti != rc->prti)
240 continue;
241
242 if (rc->allMarkTypes & ~(1 << ROW_MARK_COPY))
243 {
244 /* Need to fetch TID */
245 var = makeVar(rc->rti,
247 TIDOID,
248 -1,
250 0);
251 snprintf(resname, sizeof(resname), "ctid%u", rc->rowmarkId);
252 tle = makeTargetEntry((Expr *) var,
253 list_length(tlist) + 1,
255 true);
256 tlist = lappend(tlist, tle);
257 }
258 if (rc->allMarkTypes & (1 << ROW_MARK_COPY))
259 {
260 /* Need the whole row as a junk var */
261 var = makeWholeRowVar(rt_fetch(rc->rti, range_table),
262 rc->rti,
263 0,
264 false);
265 snprintf(resname, sizeof(resname), "wholerow%u", rc->rowmarkId);
266 tle = makeTargetEntry((Expr *) var,
267 list_length(tlist) + 1,
269 true);
270 tlist = lappend(tlist, tle);
271 }
272
273 /* If parent of inheritance tree, always fetch the tableoid too. */
274 if (rc->isParent)
275 {
276 var = makeVar(rc->rti,
278 OIDOID,
279 -1,
281 0);
282 snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId);
283 tle = makeTargetEntry((Expr *) var,
284 list_length(tlist) + 1,
286 true);
287 tlist = lappend(tlist, tle);
288 }
289 }
290
291 /*
292 * If the query has a RETURNING list, add resjunk entries for any Vars
293 * used in RETURNING that belong to other relations. We need to do this
294 * to make these Vars available for the RETURNING calculation. Vars that
295 * belong to the result rel don't need to be added, because they will be
296 * made to refer to the actual heap tuple.
297 */
298 if (parse->returningList && list_length(parse->rtable) > 1)
299 {
300 List *vars;
301 ListCell *l;
302
303 vars = pull_var_clause((Node *) parse->returningList,
307 foreach(l, vars)
308 {
309 Var *var = (Var *) lfirst(l);
311
312 if (IsA(var, Var) &&
313 var->varno == result_relation)
314 continue; /* don't need it */
315
316 if (tlist_member((Expr *) var, tlist))
317 continue; /* already got it */
318
319 tle = makeTargetEntry((Expr *) var,
320 list_length(tlist) + 1,
321 NULL,
322 true);
323
324 tlist = lappend(tlist, tle);
325 }
327 }
328
329 root->processed_tlist = tlist;
330
331 if (target_relation)
333}
334
335/*
336 * extract_update_targetlist_colnos
337 * Extract a list of the target-table column numbers that
338 * an UPDATE's targetlist wants to assign to, then renumber.
339 *
340 * The convention in the parser and rewriter is that the resnos in an
341 * UPDATE's non-resjunk TLE entries are the target column numbers
342 * to assign to. Here, we extract that info into a separate list, and
343 * then convert the tlist to the sequential-numbering convention that's
344 * used by all other query types.
345 *
346 * This is also applied to the tlist associated with INSERT ... ON CONFLICT
347 * ... UPDATE, although not till much later in planning.
348 */
349List *
351{
352 List *update_colnos = NIL;
354 ListCell *lc;
355
356 foreach(lc, tlist)
357 {
359
360 if (!tle->resjunk)
361 update_colnos = lappend_int(update_colnos, tle->resno);
362 tle->resno = nextresno++;
363 }
364 return update_colnos;
365}
366
367
368/*****************************************************************************
369 *
370 * TARGETLIST EXPANSION
371 *
372 *****************************************************************************/
373
374/*
375 * expand_insert_targetlist
376 * Given a target list as generated by the parser and a result relation,
377 * add targetlist entries for any missing attributes, and ensure the
378 * non-junk attributes appear in proper field order.
379 *
380 * Once upon a time we also did more or less this with UPDATE targetlists,
381 * but now this code is only applied to INSERT targetlists.
382 */
383static List *
385{
386 List *new_tlist = NIL;
388 int attrno,
389 numattrs;
390
391 tlist_item = list_head(tlist);
392
393 /*
394 * The rewriter should have already ensured that the TLEs are in correct
395 * order; but we have to insert TLEs for any missing attributes.
396 *
397 * Scan the tuple description in the relation's relcache entry to make
398 * sure we have all the user attributes in the right order.
399 */
401
402 for (attrno = 1; attrno <= numattrs; attrno++)
403 {
406
407 if (tlist_item != NULL)
408 {
410
411 if (!old_tle->resjunk && old_tle->resno == attrno)
412 {
414 tlist_item = lnext(tlist, tlist_item);
415 }
416 }
417
418 if (new_tle == NULL)
419 {
420 /*
421 * Didn't find a matching tlist entry, so make one.
422 *
423 * INSERTs should insert NULL in this case. (We assume the
424 * rewriter would have inserted any available non-NULL default
425 * value.) Also, normally we must apply any domain constraints
426 * that might exist --- this is to catch domain NOT NULL.
427 *
428 * When generating a NULL constant for a dropped column, we label
429 * it INT4 (any other guaranteed-to-exist datatype would do as
430 * well). We can't label it with the dropped column's datatype
431 * since that might not exist anymore. It does not really matter
432 * what we claim the type is, since NULL is NULL --- its
433 * representation is datatype-independent. This could perhaps
434 * confuse code comparing the finished plan to the target
435 * relation, however.
436 *
437 * Another exception is that if the column is generated, the value
438 * we produce here will be ignored, and we don't want to risk
439 * throwing an error. So in that case we *don't* want to apply
440 * domain constraints, so we must produce a NULL of the base type.
441 * Again, code comparing the finished plan to the target relation
442 * must account for this.
443 */
444 Node *new_expr;
445
446 if (att_tup->attisdropped)
447 {
448 /* Insert NULL for dropped column */
450 -1,
452 sizeof(int32),
453 (Datum) 0,
454 true, /* isnull */
455 true /* byval */ );
456 }
457 else if (att_tup->attgenerated)
458 {
459 /* Generated column, insert a NULL of the base type */
460 Oid baseTypeId = att_tup->atttypid;
461 int32 baseTypeMod = att_tup->atttypmod;
462
466 att_tup->attcollation,
467 att_tup->attlen,
468 (Datum) 0,
469 true, /* isnull */
470 att_tup->attbyval);
471 }
472 else
473 {
474 /* Normal column, insert a NULL of the column datatype */
476 att_tup->atttypmod,
477 att_tup->attcollation,
478 att_tup->attlen,
479 att_tup->attbyval);
480 /* Must run expression preprocessing on any non-const nodes */
481 if (!IsA(new_expr, Const))
483 }
484
486 attrno,
487 pstrdup(NameStr(att_tup->attname)),
488 false);
489 }
490
492 }
493
494 /*
495 * The remaining tlist entries should be resjunk; append them all to the
496 * end of the new tlist, making sure they have resnos higher than the last
497 * real attribute. (Note: although the rewriter already did such
498 * renumbering, we have to do it again here in case we added NULL entries
499 * above.)
500 */
501 while (tlist_item)
502 {
504
505 if (!old_tle->resjunk)
506 elog(ERROR, "targetlist is not sorted correctly");
507 /* Get the resno right, but don't copy unnecessarily */
508 if (old_tle->resno != attrno)
509 {
511 old_tle->resno = attrno;
512 }
514 attrno++;
515 tlist_item = lnext(tlist, tlist_item);
516 }
517
518 return new_tlist;
519}
520
521
522/*
523 * Locate PlanRowMark for given RT index, or return NULL if none
524 *
525 * This probably ought to be elsewhere, but there's no very good place
526 */
529{
530 ListCell *l;
531
532 foreach(l, rowmarks)
533 {
534 PlanRowMark *rc = (PlanRowMark *) lfirst(l);
535
536 if (rc->rti == rtindex)
537 return rc;
538 }
539 return NULL;
540}
void add_row_identity_columns(PlannerInfo *root, Index rtindex, RangeTblEntry *target_rte, Relation target_relation)
Definition appendinfo.c:959
int16 AttrNumber
Definition attnum.h:21
#define NameStr(name)
Definition c.h:837
#define Assert(condition)
Definition c.h:945
int32_t int32
Definition c.h:614
unsigned int Index
Definition c.h:700
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition clauses.c:2498
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
void parse(int)
Definition parse.c:49
List * lappend(List *list, void *datum)
Definition list.c:339
List * list_concat_copy(const List *list1, const List *list2)
Definition list.c:598
List * lappend_int(List *list, int datum)
Definition list.c:357
void list_free(List *list)
Definition list.c:1546
#define NoLock
Definition lockdefs.h:34
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
Definition lsyscache.c:2760
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
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition makefuncs.c:289
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition makefuncs.c:350
TargetEntry * flatCopyTargetEntry(TargetEntry *src_tle)
Definition makefuncs.c:322
char * pstrdup(const char *in)
Definition mcxt.c:1781
#define IsA(nodeptr, _type_)
Definition nodes.h:164
CmdType
Definition nodes.h:273
@ CMD_MERGE
Definition nodes.h:279
@ CMD_INSERT
Definition nodes.h:277
@ CMD_DELETE
Definition nodes.h:278
@ CMD_UPDATE
Definition nodes.h:276
@ CMD_SELECT
Definition nodes.h:275
#define PVC_RECURSE_AGGREGATES
Definition optimizer.h:198
#define PVC_RECURSE_WINDOWFUNCS
Definition optimizer.h:200
#define PVC_INCLUDE_PLACEHOLDERS
Definition optimizer.h:201
Node * coerce_null_to_domain(Oid typid, int32 typmod, Oid collation, int typlen, bool typbyval)
@ RTE_RELATION
#define rt_fetch(rangetable_index, rangetable)
Definition parsetree.h:31
FormData_pg_attribute * Form_pg_attribute
#define lfirst(lc)
Definition pg_list.h:172
static int list_length(const List *l)
Definition pg_list.h:152
#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
@ ROW_MARK_COPY
Definition plannodes.h:1558
#define snprintf
Definition port.h:260
uint64_t Datum
Definition postgres.h:70
#define InvalidOid
unsigned int Oid
static int fb(int x)
List * extract_update_targetlist_colnos(List *tlist)
Definition preptlist.c:350
void preprocess_targetlist(PlannerInfo *root)
Definition preptlist.c:66
PlanRowMark * get_plan_rowmark(List *rowmarks, Index rtindex)
Definition preptlist.c:528
static List * expand_insert_targetlist(PlannerInfo *root, List *tlist, Relation rel)
Definition preptlist.c:384
tree ctl root
Definition radixtree.h:1857
#define RelationGetNumberOfAttributes(relation)
Definition rel.h:520
Definition pg_list.h:54
Definition nodes.h:135
Index rowmarkId
Definition plannodes.h:1611
RTEKind rtekind
TupleDesc rd_att
Definition rel.h:112
int varno
Definition primnodes.h:270
#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:88
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:178
List * pull_var_clause(Node *node, int flags)
Definition var.c:653