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 planner/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-2021, 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/table.h"
40 #include "nodes/makefuncs.h"
41 #include "optimizer/appendinfo.h"
42 #include "optimizer/optimizer.h"
43 #include "optimizer/prep.h"
44 #include "optimizer/tlist.h"
45 #include "parser/parse_coerce.h"
46 #include "parser/parsetree.h"
47 #include "utils/rel.h"
48
49 static List *expand_insert_targetlist(List *tlist, Relation rel);
50
51
52 /*
53 * preprocess_targetlist
54 * Driver for preprocessing the parse tree targetlist.
55 *
56 * The preprocessed targetlist is returned in root->processed_tlist.
57 * Also, if this is an UPDATE, we return a list of target column numbers
58 * in root->update_colnos. (Resnos in processed_tlist will be consecutive,
59 * so do not look at that to find out which columns are targets!)
60 */
61 void
preprocess_targetlist(PlannerInfo * root)62 preprocess_targetlist(PlannerInfo *root)
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, register any junk column(s) needed to
111 * allow the executor to identify the rows to be updated or deleted. In
112 * the inheritance case, we do nothing now, leaving this to be dealt with
113 * when expand_inherited_rtentry() makes the leaf target relations. (But
114 * there might not be any leaf target relations, in which case we must do
115 * this in distribute_row_identity_vars().)
116 */
117 if ((command_type == CMD_UPDATE || command_type == CMD_DELETE) &&
118 !target_rte->inh)
119 {
120 /* row-identity logic expects to add stuff to processed_tlist */
121 root->processed_tlist = tlist;
122 add_row_identity_columns(root, result_relation,
123 target_rte, target_relation);
124 tlist = root->processed_tlist;
125 }
126
127 /*
128 * Add necessary junk columns for rowmarked rels. These values are needed
129 * for locking of rels selected FOR UPDATE/SHARE, and to do EvalPlanQual
130 * rechecking. See comments for PlanRowMark in plannodes.h. If you
131 * change this stanza, see also expand_inherited_rtentry(), which has to
132 * be able to add on junk columns equivalent to these.
133 *
134 * (Someday it might be useful to fold these resjunk columns into the
135 * row-identity-column management used for UPDATE/DELETE. Today is not
136 * that day, however. One notable issue is that it seems important that
137 * the whole-row Vars made here use the real table rowtype, not RECORD, so
138 * that conversion to/from child relations' rowtypes will happen. Also,
139 * since these entries don't potentially bloat with more and more child
140 * relations, there's not really much need for column sharing.)
141 */
142 foreach(lc, root->rowMarks)
143 {
144 PlanRowMark *rc = (PlanRowMark *) lfirst(lc);
145 Var *var;
146 char resname[32];
147 TargetEntry *tle;
148
149 /* child rels use the same junk attrs as their parents */
150 if (rc->rti != rc->prti)
151 continue;
152
153 if (rc->allMarkTypes & ~(1 << ROW_MARK_COPY))
154 {
155 /* Need to fetch TID */
156 var = makeVar(rc->rti,
157 SelfItemPointerAttributeNumber,
158 TIDOID,
159 -1,
160 InvalidOid,
161 0);
162 snprintf(resname, sizeof(resname), "ctid%u", rc->rowmarkId);
163 tle = makeTargetEntry((Expr *) var,
164 list_length(tlist) + 1,
165 pstrdup(resname),
166 true);
167 tlist = lappend(tlist, tle);
168 }
169 if (rc->allMarkTypes & (1 << ROW_MARK_COPY))
170 {
171 /* Need the whole row as a junk var */
172 var = makeWholeRowVar(rt_fetch(rc->rti, range_table),
173 rc->rti,
174 0,
175 false);
176 snprintf(resname, sizeof(resname), "wholerow%u", rc->rowmarkId);
177 tle = makeTargetEntry((Expr *) var,
178 list_length(tlist) + 1,
179 pstrdup(resname),
180 true);
181 tlist = lappend(tlist, tle);
182 }
183
184 /* If parent of inheritance tree, always fetch the tableoid too. */
185 if (rc->isParent)
186 {
187 var = makeVar(rc->rti,
188 TableOidAttributeNumber,
189 OIDOID,
190 -1,
191 InvalidOid,
192 0);
193 snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId);
194 tle = makeTargetEntry((Expr *) var,
195 list_length(tlist) + 1,
196 pstrdup(resname),
197 true);
198 tlist = lappend(tlist, tle);
199 }
200 }
201
202 /*
203 * If the query has a RETURNING list, add resjunk entries for any Vars
204 * used in RETURNING that belong to other relations. We need to do this
205 * to make these Vars available for the RETURNING calculation. Vars that
206 * belong to the result rel don't need to be added, because they will be
207 * made to refer to the actual heap tuple.
208 */
209 if (parse->returningList && list_length(parse->rtable) > 1)
210 {
211 List *vars;
212 ListCell *l;
213
214 vars = pull_var_clause((Node *) parse->returningList,
215 PVC_RECURSE_AGGREGATES |
216 PVC_RECURSE_WINDOWFUNCS |
217 PVC_INCLUDE_PLACEHOLDERS);
218 foreach(l, vars)
219 {
220 Var *var = (Var *) lfirst(l);
221 TargetEntry *tle;
222
223 if (IsA(var, Var) &&
224 var->varno == result_relation)
225 continue; /* don't need it */
226
227 if (tlist_member((Expr *) var, tlist))
228 continue; /* already got it */
229
230 tle = makeTargetEntry((Expr *) var,
231 list_length(tlist) + 1,
232 NULL,
233 true);
234
235 tlist = lappend(tlist, tle);
236 }
237 list_free(vars);
238 }
239
240 root->processed_tlist = tlist;
241
242 if (target_relation)
243 table_close(target_relation, NoLock);
244 }
245
246 /*
247 * extract_update_targetlist_colnos
248 * Extract a list of the target-table column numbers that
249 * an UPDATE's targetlist wants to assign to, then renumber.
250 *
251 * The convention in the parser and rewriter is that the resnos in an
252 * UPDATE's non-resjunk TLE entries are the target column numbers
253 * to assign to. Here, we extract that info into a separate list, and
254 * then convert the tlist to the sequential-numbering convention that's
255 * used by all other query types.
256 *
257 * This is also applied to the tlist associated with INSERT ... ON CONFLICT
258 * ... UPDATE, although not till much later in planning.
259 */
260 List *
extract_update_targetlist_colnos(List * tlist)261 extract_update_targetlist_colnos(List *tlist)
262 {
263 List *update_colnos = NIL;
264 AttrNumber nextresno = 1;
265 ListCell *lc;
266
267 foreach(lc, tlist)
268 {
269 TargetEntry *tle = (TargetEntry *) lfirst(lc);
270
271 if (!tle->resjunk)
272 update_colnos = lappend_int(update_colnos, tle->resno);
273 tle->resno = nextresno++;
274 }
275 return update_colnos;
276 }
277
278
279 /*****************************************************************************
280 *
281 * TARGETLIST EXPANSION
282 *
283 *****************************************************************************/
284
285 /*
286 * expand_insert_targetlist
287 * Given a target list as generated by the parser and a result relation,
288 * add targetlist entries for any missing attributes, and ensure the
289 * non-junk attributes appear in proper field order.
290 *
291 * Once upon a time we also did more or less this with UPDATE targetlists,
292 * but now this code is only applied to INSERT targetlists.
293 */
294 static List *
expand_insert_targetlist(List * tlist,Relation rel)295 expand_insert_targetlist(List *tlist, Relation rel)
296 {
297 List *new_tlist = NIL;
298 ListCell *tlist_item;
299 int attrno,
300 numattrs;
301
302 tlist_item = list_head(tlist);
303
304 /*
305 * The rewriter should have already ensured that the TLEs are in correct
306 * order; but we have to insert TLEs for any missing attributes.
307 *
308 * Scan the tuple description in the relation's relcache entry to make
309 * sure we have all the user attributes in the right order.
310 */
311 numattrs = RelationGetNumberOfAttributes(rel);
312
313 for (attrno = 1; attrno <= numattrs; attrno++)
314 {
315 Form_pg_attribute att_tup = TupleDescAttr(rel->rd_att, attrno - 1);
316 TargetEntry *new_tle = NULL;
317
318 if (tlist_item != NULL)
319 {
320 TargetEntry *old_tle = (TargetEntry *) lfirst(tlist_item);
321
322 if (!old_tle->resjunk && old_tle->resno == attrno)
323 {
324 new_tle = old_tle;
325 tlist_item = lnext(tlist, tlist_item);
326 }
327 }
328
329 if (new_tle == NULL)
330 {
331 /*
332 * Didn't find a matching tlist entry, so make one.
333 *
334 * INSERTs should insert NULL in this case. (We assume the
335 * rewriter would have inserted any available non-NULL default
336 * value.) Also, if the column isn't dropped, apply any domain
337 * constraints that might exist --- this is to catch domain NOT
338 * NULL.
339 *
340 * When generating a NULL constant for a dropped column, we label
341 * it INT4 (any other guaranteed-to-exist datatype would do as
342 * well). We can't label it with the dropped column's datatype
343 * since that might not exist anymore. It does not really matter
344 * what we claim the type is, since NULL is NULL --- its
345 * representation is datatype-independent. This could perhaps
346 * confuse code comparing the finished plan to the target
347 * relation, however.
348 */
349 Oid atttype = att_tup->atttypid;
350 Oid attcollation = att_tup->attcollation;
351 Node *new_expr;
352
353 if (!att_tup->attisdropped)
354 {
355 new_expr = (Node *) makeConst(atttype,
356 -1,
357 attcollation,
358 att_tup->attlen,
359 (Datum) 0,
360 true, /* isnull */
361 att_tup->attbyval);
362 new_expr = coerce_to_domain(new_expr,
363 InvalidOid, -1,
364 atttype,
365 COERCION_IMPLICIT,
366 COERCE_IMPLICIT_CAST,
367 -1,
368 false);
369 }
370 else
371 {
372 /* Insert NULL for dropped column */
373 new_expr = (Node *) makeConst(INT4OID,
374 -1,
375 InvalidOid,
376 sizeof(int32),
377 (Datum) 0,
378 true, /* isnull */
379 true /* byval */ );
380 }
381
382 new_tle = makeTargetEntry((Expr *) new_expr,
383 attrno,
384 pstrdup(NameStr(att_tup->attname)),
385 false);
386 }
387
388 new_tlist = lappend(new_tlist, new_tle);
389 }
390
391 /*
392 * The remaining tlist entries should be resjunk; append them all to the
393 * end of the new tlist, making sure they have resnos higher than the last
394 * real attribute. (Note: although the rewriter already did such
395 * renumbering, we have to do it again here in case we added NULL entries
396 * above.)
397 */
398 while (tlist_item)
399 {
400 TargetEntry *old_tle = (TargetEntry *) lfirst(tlist_item);
401
402 if (!old_tle->resjunk)
403 elog(ERROR, "targetlist is not sorted correctly");
404 /* Get the resno right, but don't copy unnecessarily */
405 if (old_tle->resno != attrno)
406 {
407 old_tle = flatCopyTargetEntry(old_tle);
408 old_tle->resno = attrno;
409 }
410 new_tlist = lappend(new_tlist, old_tle);
411 attrno++;
412 tlist_item = lnext(tlist, tlist_item);
413 }
414
415 return new_tlist;
416 }
417
418
419 /*
420 * Locate PlanRowMark for given RT index, or return NULL if none
421 *
422 * This probably ought to be elsewhere, but there's no very good place
423 */
424 PlanRowMark *
get_plan_rowmark(List * rowmarks,Index rtindex)425 get_plan_rowmark(List *rowmarks, Index rtindex)
426 {
427 ListCell *l;
428
429 foreach(l, rowmarks)
430 {
431 PlanRowMark *rc = (PlanRowMark *) lfirst(l);
432
433 if (rc->rti == rtindex)
434 return rc;
435 }
436 return NULL;
437 }
438