1 /*-------------------------------------------------------------------------
2  *
3  * preptlist.c
4  *	  Routines to preprocess the parse tree target list
5  *
6  * For INSERT and UPDATE queries, the targetlist must contain an entry for
7  * each attribute of the target relation in the correct order.  For UPDATE and
8  * DELETE queries, it must also contain junk tlist entries needed to allow the
9  * executor to identify the rows to be updated or deleted.  For all query
10  * types, we may need to add junk tlist entries for Vars used in the RETURNING
11  * list and row ID information needed for SELECT FOR UPDATE locking and/or
12  * EvalPlanQual checking.
13  *
14  * The query rewrite phase also does preprocessing of the targetlist (see
15  * rewriteTargetListIU).  The division of labor between here and there is
16  * partially historical, but it's not entirely arbitrary.  In particular,
17  * consider an UPDATE across an inheritance tree.  What rewriteTargetListIU
18  * does need be done only once (because it depends only on the properties of
19  * the parent relation).  What's done here has to be done over again for each
20  * child relation, because it depends on the properties of the child, which
21  * might be of a different relation type, or have more columns and/or a
22  * different column order than the parent.
23  *
24  * The fact that rewriteTargetListIU sorts non-resjunk tlist entries by column
25  * position, which expand_targetlist depends on, violates the above comment
26  * because the sorting is only valid for the parent relation.  In inherited
27  * UPDATE cases, adjust_inherited_tlist runs in between to take care of fixing
28  * the tlists for child tables to keep expand_targetlist happy.  We do it like
29  * that because it's faster in typical non-inherited cases.
30  *
31  *
32  * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
33  * Portions Copyright (c) 1994, Regents of the University of California
34  *
35  * IDENTIFICATION
36  *	  src/backend/optimizer/prep/preptlist.c
37  *
38  *-------------------------------------------------------------------------
39  */
40 
41 #include "postgres.h"
42 
43 #include "access/heapam.h"
44 #include "access/sysattr.h"
45 #include "catalog/pg_type.h"
46 #include "nodes/makefuncs.h"
47 #include "optimizer/prep.h"
48 #include "optimizer/tlist.h"
49 #include "optimizer/var.h"
50 #include "parser/parsetree.h"
51 #include "parser/parse_coerce.h"
52 #include "rewrite/rewriteHandler.h"
53 #include "utils/rel.h"
54 
55 
56 static List *expand_targetlist(List *tlist, int command_type,
57 				  Index result_relation, Relation rel);
58 
59 
60 /*
61  * preprocess_targetlist
62  *	  Driver for preprocessing the parse tree targetlist.
63  *
64  *	  Returns the new targetlist.
65  *
66  * As a side effect, if there's an ON CONFLICT UPDATE clause, its targetlist
67  * is also preprocessed (and updated in-place).
68  */
69 List *
preprocess_targetlist(PlannerInfo * root)70 preprocess_targetlist(PlannerInfo *root)
71 {
72 	Query	   *parse = root->parse;
73 	int			result_relation = parse->resultRelation;
74 	List	   *range_table = parse->rtable;
75 	CmdType		command_type = parse->commandType;
76 	RangeTblEntry *target_rte = NULL;
77 	Relation	target_relation = NULL;
78 	List	   *tlist;
79 	ListCell   *lc;
80 
81 	/*
82 	 * If there is a result relation, open it so we can look for missing
83 	 * columns and so on.  We assume that previous code already acquired at
84 	 * least AccessShareLock on the relation, so we need no lock here.
85 	 */
86 	if (result_relation)
87 	{
88 		target_rte = rt_fetch(result_relation, range_table);
89 
90 		/*
91 		 * Sanity check: it'd better be a real relation not, say, a subquery.
92 		 * Else parser or rewriter messed up.
93 		 */
94 		if (target_rte->rtekind != RTE_RELATION)
95 			elog(ERROR, "result relation must be a regular relation");
96 
97 		target_relation = heap_open(target_rte->relid, NoLock);
98 	}
99 	else
100 		Assert(command_type == CMD_SELECT);
101 
102 	/*
103 	 * For UPDATE/DELETE, add any junk column(s) needed to allow the executor
104 	 * to identify the rows to be updated or deleted.  Note that this step
105 	 * scribbles on parse->targetList, which is not very desirable, but we
106 	 * keep it that way to avoid changing APIs used by FDWs.
107 	 */
108 	if (command_type == CMD_UPDATE || command_type == CMD_DELETE)
109 		rewriteTargetListUD(parse, target_rte, target_relation);
110 
111 	/*
112 	 * for heap_form_tuple to work, the targetlist must match the exact order
113 	 * of the attributes. We also need to fill in any missing attributes. -ay
114 	 * 10/94
115 	 */
116 	tlist = parse->targetList;
117 	if (command_type == CMD_INSERT || command_type == CMD_UPDATE)
118 		tlist = expand_targetlist(tlist, command_type,
119 								  result_relation, target_relation);
120 
121 	/*
122 	 * Add necessary junk columns for rowmarked rels.  These values are needed
123 	 * for locking of rels selected FOR UPDATE/SHARE, and to do EvalPlanQual
124 	 * rechecking.  See comments for PlanRowMark in plannodes.h.
125 	 */
126 	foreach(lc, root->rowMarks)
127 	{
128 		PlanRowMark *rc = (PlanRowMark *) lfirst(lc);
129 		Var		   *var;
130 		char		resname[32];
131 		TargetEntry *tle;
132 
133 		/* child rels use the same junk attrs as their parents */
134 		if (rc->rti != rc->prti)
135 			continue;
136 
137 		if (rc->allMarkTypes & ~(1 << ROW_MARK_COPY))
138 		{
139 			/* Need to fetch TID */
140 			var = makeVar(rc->rti,
141 						  SelfItemPointerAttributeNumber,
142 						  TIDOID,
143 						  -1,
144 						  InvalidOid,
145 						  0);
146 			snprintf(resname, sizeof(resname), "ctid%u", rc->rowmarkId);
147 			tle = makeTargetEntry((Expr *) var,
148 								  list_length(tlist) + 1,
149 								  pstrdup(resname),
150 								  true);
151 			tlist = lappend(tlist, tle);
152 		}
153 		if (rc->allMarkTypes & (1 << ROW_MARK_COPY))
154 		{
155 			/* Need the whole row as a junk var */
156 			var = makeWholeRowVar(rt_fetch(rc->rti, range_table),
157 								  rc->rti,
158 								  0,
159 								  false);
160 			snprintf(resname, sizeof(resname), "wholerow%u", rc->rowmarkId);
161 			tle = makeTargetEntry((Expr *) var,
162 								  list_length(tlist) + 1,
163 								  pstrdup(resname),
164 								  true);
165 			tlist = lappend(tlist, tle);
166 		}
167 
168 		/* If parent of inheritance tree, always fetch the tableoid too. */
169 		if (rc->isParent)
170 		{
171 			var = makeVar(rc->rti,
172 						  TableOidAttributeNumber,
173 						  OIDOID,
174 						  -1,
175 						  InvalidOid,
176 						  0);
177 			snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId);
178 			tle = makeTargetEntry((Expr *) var,
179 								  list_length(tlist) + 1,
180 								  pstrdup(resname),
181 								  true);
182 			tlist = lappend(tlist, tle);
183 		}
184 	}
185 
186 	/*
187 	 * If the query has a RETURNING list, add resjunk entries for any Vars
188 	 * used in RETURNING that belong to other relations.  We need to do this
189 	 * to make these Vars available for the RETURNING calculation.  Vars that
190 	 * belong to the result rel don't need to be added, because they will be
191 	 * made to refer to the actual heap tuple.
192 	 */
193 	if (parse->returningList && list_length(parse->rtable) > 1)
194 	{
195 		List	   *vars;
196 		ListCell   *l;
197 
198 		vars = pull_var_clause((Node *) parse->returningList,
199 							   PVC_RECURSE_AGGREGATES |
200 							   PVC_RECURSE_WINDOWFUNCS |
201 							   PVC_INCLUDE_PLACEHOLDERS);
202 		foreach(l, vars)
203 		{
204 			Var		   *var = (Var *) lfirst(l);
205 			TargetEntry *tle;
206 
207 			if (IsA(var, Var) &&
208 				var->varno == result_relation)
209 				continue;		/* don't need it */
210 
211 			if (tlist_member((Node *) var, tlist))
212 				continue;		/* already got it */
213 
214 			tle = makeTargetEntry((Expr *) var,
215 								  list_length(tlist) + 1,
216 								  NULL,
217 								  true);
218 
219 			tlist = lappend(tlist, tle);
220 		}
221 		list_free(vars);
222 	}
223 
224 	/*
225 	 * If there's an ON CONFLICT UPDATE clause, preprocess its targetlist too
226 	 * while we have the relation open.
227 	 */
228 	if (parse->onConflict)
229 		parse->onConflict->onConflictSet =
230 			expand_targetlist(parse->onConflict->onConflictSet,
231 							  CMD_UPDATE,
232 							  result_relation,
233 							  target_relation);
234 
235 	if (target_relation)
236 		heap_close(target_relation, NoLock);
237 
238 	return tlist;
239 }
240 
241 
242 /*****************************************************************************
243  *
244  *		TARGETLIST EXPANSION
245  *
246  *****************************************************************************/
247 
248 /*
249  * expand_targetlist
250  *	  Given a target list as generated by the parser and a result relation,
251  *	  add targetlist entries for any missing attributes, and ensure the
252  *	  non-junk attributes appear in proper field order.
253  */
254 static List *
expand_targetlist(List * tlist,int command_type,Index result_relation,Relation rel)255 expand_targetlist(List *tlist, int command_type,
256 				  Index result_relation, Relation rel)
257 {
258 	List	   *new_tlist = NIL;
259 	ListCell   *tlist_item;
260 	int			attrno,
261 				numattrs;
262 
263 	tlist_item = list_head(tlist);
264 
265 	/*
266 	 * The rewriter should have already ensured that the TLEs are in correct
267 	 * order; but we have to insert TLEs for any missing attributes.
268 	 *
269 	 * Scan the tuple description in the relation's relcache entry to make
270 	 * sure we have all the user attributes in the right order.
271 	 */
272 	numattrs = RelationGetNumberOfAttributes(rel);
273 
274 	for (attrno = 1; attrno <= numattrs; attrno++)
275 	{
276 		Form_pg_attribute att_tup = rel->rd_att->attrs[attrno - 1];
277 		TargetEntry *new_tle = NULL;
278 
279 		if (tlist_item != NULL)
280 		{
281 			TargetEntry *old_tle = (TargetEntry *) lfirst(tlist_item);
282 
283 			if (!old_tle->resjunk && old_tle->resno == attrno)
284 			{
285 				new_tle = old_tle;
286 				tlist_item = lnext(tlist_item);
287 			}
288 		}
289 
290 		if (new_tle == NULL)
291 		{
292 			/*
293 			 * Didn't find a matching tlist entry, so make one.
294 			 *
295 			 * For INSERT, generate a NULL constant.  (We assume the rewriter
296 			 * would have inserted any available default value.) Also, if the
297 			 * column isn't dropped, apply any domain constraints that might
298 			 * exist --- this is to catch domain NOT NULL.
299 			 *
300 			 * For UPDATE, generate a Var reference to the existing value of
301 			 * the attribute, so that it gets copied to the new tuple. But
302 			 * generate a NULL for dropped columns (we want to drop any old
303 			 * values).
304 			 *
305 			 * When generating a NULL constant for a dropped column, we label
306 			 * it INT4 (any other guaranteed-to-exist datatype would do as
307 			 * well). We can't label it with the dropped column's datatype
308 			 * since that might not exist anymore.  It does not really matter
309 			 * what we claim the type is, since NULL is NULL --- its
310 			 * representation is datatype-independent.  This could perhaps
311 			 * confuse code comparing the finished plan to the target
312 			 * relation, however.
313 			 */
314 			Oid			atttype = att_tup->atttypid;
315 			int32		atttypmod = att_tup->atttypmod;
316 			Oid			attcollation = att_tup->attcollation;
317 			Node	   *new_expr;
318 
319 			switch (command_type)
320 			{
321 				case CMD_INSERT:
322 					if (!att_tup->attisdropped)
323 					{
324 						new_expr = (Node *) makeConst(atttype,
325 													  -1,
326 													  attcollation,
327 													  att_tup->attlen,
328 													  (Datum) 0,
329 													  true,		/* isnull */
330 													  att_tup->attbyval);
331 						new_expr = coerce_to_domain(new_expr,
332 													InvalidOid, -1,
333 													atttype,
334 													COERCE_IMPLICIT_CAST,
335 													-1,
336 													false,
337 													false);
338 					}
339 					else
340 					{
341 						/* Insert NULL for dropped column */
342 						new_expr = (Node *) makeConst(INT4OID,
343 													  -1,
344 													  InvalidOid,
345 													  sizeof(int32),
346 													  (Datum) 0,
347 													  true,		/* isnull */
348 													  true /* byval */ );
349 					}
350 					break;
351 				case CMD_UPDATE:
352 					if (!att_tup->attisdropped)
353 					{
354 						new_expr = (Node *) makeVar(result_relation,
355 													attrno,
356 													atttype,
357 													atttypmod,
358 													attcollation,
359 													0);
360 					}
361 					else
362 					{
363 						/* Insert NULL for dropped column */
364 						new_expr = (Node *) makeConst(INT4OID,
365 													  -1,
366 													  InvalidOid,
367 													  sizeof(int32),
368 													  (Datum) 0,
369 													  true,		/* isnull */
370 													  true /* byval */ );
371 					}
372 					break;
373 				default:
374 					elog(ERROR, "unrecognized command_type: %d",
375 						 (int) command_type);
376 					new_expr = NULL;	/* keep compiler quiet */
377 					break;
378 			}
379 
380 			new_tle = makeTargetEntry((Expr *) new_expr,
381 									  attrno,
382 									  pstrdup(NameStr(att_tup->attname)),
383 									  false);
384 		}
385 
386 		new_tlist = lappend(new_tlist, new_tle);
387 	}
388 
389 	/*
390 	 * The remaining tlist entries should be resjunk; append them all to the
391 	 * end of the new tlist, making sure they have resnos higher than the last
392 	 * real attribute.  (Note: although the rewriter already did such
393 	 * renumbering, we have to do it again here in case we are doing an UPDATE
394 	 * in a table with dropped columns, or an inheritance child table with
395 	 * extra columns.)
396 	 */
397 	while (tlist_item)
398 	{
399 		TargetEntry *old_tle = (TargetEntry *) lfirst(tlist_item);
400 
401 		if (!old_tle->resjunk)
402 			elog(ERROR, "targetlist is not sorted correctly");
403 		/* Get the resno right, but don't copy unnecessarily */
404 		if (old_tle->resno != attrno)
405 		{
406 			old_tle = flatCopyTargetEntry(old_tle);
407 			old_tle->resno = attrno;
408 		}
409 		new_tlist = lappend(new_tlist, old_tle);
410 		attrno++;
411 		tlist_item = lnext(tlist_item);
412 	}
413 
414 	return new_tlist;
415 }
416 
417 
418 /*
419  * Locate PlanRowMark for given RT index, or return NULL if none
420  *
421  * This probably ought to be elsewhere, but there's no very good place
422  */
423 PlanRowMark *
get_plan_rowmark(List * rowmarks,Index rtindex)424 get_plan_rowmark(List *rowmarks, Index rtindex)
425 {
426 	ListCell   *l;
427 
428 	foreach(l, rowmarks)
429 	{
430 		PlanRowMark *rc = (PlanRowMark *) lfirst(l);
431 
432 		if (rc->rti == rtindex)
433 			return rc;
434 	}
435 	return NULL;
436 }
437