1 /*-------------------------------------------------------------------------
2  *
3  * setrefs.c
4  *	  Post-processing of a completed plan tree: fix references to subplan
5  *	  vars, compute regproc values for operators, etc
6  *
7  * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  *
11  * IDENTIFICATION
12  *	  src/backend/optimizer/plan/setrefs.c
13  *
14  *-------------------------------------------------------------------------
15  */
16 #include "postgres.h"
17 
18 #include "access/transam.h"
19 #include "catalog/pg_type.h"
20 #include "nodes/makefuncs.h"
21 #include "nodes/nodeFuncs.h"
22 #include "optimizer/pathnode.h"
23 #include "optimizer/planmain.h"
24 #include "optimizer/planner.h"
25 #include "optimizer/tlist.h"
26 #include "tcop/utility.h"
27 #include "utils/lsyscache.h"
28 #include "utils/syscache.h"
29 
30 
31 typedef struct
32 {
33 	Index		varno;			/* RT index of Var */
34 	AttrNumber	varattno;		/* attr number of Var */
35 	AttrNumber	resno;			/* TLE position of Var */
36 } tlist_vinfo;
37 
38 typedef struct
39 {
40 	List	   *tlist;			/* underlying target list */
41 	int			num_vars;		/* number of plain Var tlist entries */
42 	bool		has_ph_vars;	/* are there PlaceHolderVar entries? */
43 	bool		has_non_vars;	/* are there other entries? */
44 	tlist_vinfo vars[FLEXIBLE_ARRAY_MEMBER];	/* has num_vars entries */
45 } indexed_tlist;
46 
47 typedef struct
48 {
49 	PlannerInfo *root;
50 	int			rtoffset;
51 } fix_scan_expr_context;
52 
53 typedef struct
54 {
55 	PlannerInfo *root;
56 	indexed_tlist *outer_itlist;
57 	indexed_tlist *inner_itlist;
58 	Index		acceptable_rel;
59 	int			rtoffset;
60 } fix_join_expr_context;
61 
62 typedef struct
63 {
64 	PlannerInfo *root;
65 	indexed_tlist *subplan_itlist;
66 	Index		newvarno;
67 	int			rtoffset;
68 } fix_upper_expr_context;
69 
70 /*
71  * Check if a Const node is a regclass value.  We accept plain OID too,
72  * since a regclass Const will get folded to that type if it's an argument
73  * to oideq or similar operators.  (This might result in some extraneous
74  * values in a plan's list of relation dependencies, but the worst result
75  * would be occasional useless replans.)
76  */
77 #define ISREGCLASSCONST(con) \
78 	(((con)->consttype == REGCLASSOID || (con)->consttype == OIDOID) && \
79 	 !(con)->constisnull)
80 
81 #define fix_scan_list(root, lst, rtoffset) \
82 	((List *) fix_scan_expr(root, (Node *) (lst), rtoffset))
83 
84 static void add_rtes_to_flat_rtable(PlannerInfo *root, bool recursing);
85 static void flatten_unplanned_rtes(PlannerGlobal *glob, RangeTblEntry *rte);
86 static bool flatten_rtes_walker(Node *node, PlannerGlobal *glob);
87 static void add_rte_to_flat_rtable(PlannerGlobal *glob, RangeTblEntry *rte);
88 static Plan *set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset);
89 static Plan *set_indexonlyscan_references(PlannerInfo *root,
90 							 IndexOnlyScan *plan,
91 							 int rtoffset);
92 static Plan *set_subqueryscan_references(PlannerInfo *root,
93 							SubqueryScan *plan,
94 							int rtoffset);
95 static bool trivial_subqueryscan(SubqueryScan *plan);
96 static void set_foreignscan_references(PlannerInfo *root,
97 						   ForeignScan *fscan,
98 						   int rtoffset);
99 static void set_customscan_references(PlannerInfo *root,
100 						  CustomScan *cscan,
101 						  int rtoffset);
102 static Node *fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset);
103 static Node *fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context);
104 static bool fix_scan_expr_walker(Node *node, fix_scan_expr_context *context);
105 static void set_join_references(PlannerInfo *root, Join *join, int rtoffset);
106 static void set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset);
107 static void set_param_references(PlannerInfo *root, Plan *plan);
108 static Node *convert_combining_aggrefs(Node *node, void *context);
109 static void set_dummy_tlist_references(Plan *plan, int rtoffset);
110 static indexed_tlist *build_tlist_index(List *tlist);
111 static Var *search_indexed_tlist_for_var(Var *var,
112 							 indexed_tlist *itlist,
113 							 Index newvarno,
114 							 int rtoffset);
115 static Var *search_indexed_tlist_for_non_var(Expr *node,
116 								 indexed_tlist *itlist,
117 								 Index newvarno);
118 static Var *search_indexed_tlist_for_sortgroupref(Expr *node,
119 									  Index sortgroupref,
120 									  indexed_tlist *itlist,
121 									  Index newvarno);
122 static List *fix_join_expr(PlannerInfo *root,
123 			  List *clauses,
124 			  indexed_tlist *outer_itlist,
125 			  indexed_tlist *inner_itlist,
126 			  Index acceptable_rel, int rtoffset);
127 static Node *fix_join_expr_mutator(Node *node,
128 					  fix_join_expr_context *context);
129 static Node *fix_upper_expr(PlannerInfo *root,
130 			   Node *node,
131 			   indexed_tlist *subplan_itlist,
132 			   Index newvarno,
133 			   int rtoffset);
134 static Node *fix_upper_expr_mutator(Node *node,
135 					   fix_upper_expr_context *context);
136 static List *set_returning_clause_references(PlannerInfo *root,
137 								List *rlist,
138 								Plan *topplan,
139 								Index resultRelation,
140 								int rtoffset);
141 static bool extract_query_dependencies_walker(Node *node,
142 								  PlannerInfo *context);
143 
144 /*****************************************************************************
145  *
146  *		SUBPLAN REFERENCES
147  *
148  *****************************************************************************/
149 
150 /*
151  * set_plan_references
152  *
153  * This is the final processing pass of the planner/optimizer.  The plan
154  * tree is complete; we just have to adjust some representational details
155  * for the convenience of the executor:
156  *
157  * 1. We flatten the various subquery rangetables into a single list, and
158  * zero out RangeTblEntry fields that are not useful to the executor.
159  *
160  * 2. We adjust Vars in scan nodes to be consistent with the flat rangetable.
161  *
162  * 3. We adjust Vars in upper plan nodes to refer to the outputs of their
163  * subplans.
164  *
165  * 4. Aggrefs in Agg plan nodes need to be adjusted in some cases involving
166  * partial aggregation or minmax aggregate optimization.
167  *
168  * 5. PARAM_MULTIEXPR Params are replaced by regular PARAM_EXEC Params,
169  * now that we have finished planning all MULTIEXPR subplans.
170  *
171  * 6. We compute regproc OIDs for operators (ie, we look up the function
172  * that implements each op).
173  *
174  * 7. We create lists of specific objects that the plan depends on.
175  * This will be used by plancache.c to drive invalidation of cached plans.
176  * Relation dependencies are represented by OIDs, and everything else by
177  * PlanInvalItems (this distinction is motivated by the shared-inval APIs).
178  * Currently, relations and user-defined functions are the only types of
179  * objects that are explicitly tracked this way.
180  *
181  * 8. We assign every plan node in the tree a unique ID.
182  *
183  * We also perform one final optimization step, which is to delete
184  * SubqueryScan plan nodes that aren't doing anything useful (ie, have
185  * no qual and a no-op targetlist).  The reason for doing this last is that
186  * it can't readily be done before set_plan_references, because it would
187  * break set_upper_references: the Vars in the subquery's top tlist
188  * wouldn't match up with the Vars in the outer plan tree.  The SubqueryScan
189  * serves a necessary function as a buffer between outer query and subquery
190  * variable numbering ... but after we've flattened the rangetable this is
191  * no longer a problem, since then there's only one rtindex namespace.
192  *
193  * set_plan_references recursively traverses the whole plan tree.
194  *
195  * The return value is normally the same Plan node passed in, but can be
196  * different when the passed-in Plan is a SubqueryScan we decide isn't needed.
197  *
198  * The flattened rangetable entries are appended to root->glob->finalrtable.
199  * Also, rowmarks entries are appended to root->glob->finalrowmarks, and the
200  * RT indexes of ModifyTable result relations to root->glob->resultRelations.
201  * Plan dependencies are appended to root->glob->relationOids (for relations)
202  * and root->glob->invalItems (for everything else).
203  *
204  * Notice that we modify Plan nodes in-place, but use expression_tree_mutator
205  * to process targetlist and qual expressions.  We can assume that the Plan
206  * nodes were just built by the planner and are not multiply referenced, but
207  * it's not so safe to assume that for expression tree nodes.
208  */
209 Plan *
set_plan_references(PlannerInfo * root,Plan * plan)210 set_plan_references(PlannerInfo *root, Plan *plan)
211 {
212 	PlannerGlobal *glob = root->glob;
213 	int			rtoffset = list_length(glob->finalrtable);
214 	ListCell   *lc;
215 
216 	/*
217 	 * Add all the query's RTEs to the flattened rangetable.  The live ones
218 	 * will have their rangetable indexes increased by rtoffset.  (Additional
219 	 * RTEs, not referenced by the Plan tree, might get added after those.)
220 	 */
221 	add_rtes_to_flat_rtable(root, false);
222 
223 	/*
224 	 * Adjust RT indexes of PlanRowMarks and add to final rowmarks list
225 	 */
226 	foreach(lc, root->rowMarks)
227 	{
228 		PlanRowMark *rc = lfirst_node(PlanRowMark, lc);
229 		PlanRowMark *newrc;
230 
231 		/* flat copy is enough since all fields are scalars */
232 		newrc = (PlanRowMark *) palloc(sizeof(PlanRowMark));
233 		memcpy(newrc, rc, sizeof(PlanRowMark));
234 
235 		/* adjust indexes ... but *not* the rowmarkId */
236 		newrc->rti += rtoffset;
237 		newrc->prti += rtoffset;
238 
239 		glob->finalrowmarks = lappend(glob->finalrowmarks, newrc);
240 	}
241 
242 	/* Now fix the Plan tree */
243 	return set_plan_refs(root, plan, rtoffset);
244 }
245 
246 /*
247  * Extract RangeTblEntries from the plan's rangetable, and add to flat rtable
248  *
249  * This can recurse into subquery plans; "recursing" is true if so.
250  */
251 static void
add_rtes_to_flat_rtable(PlannerInfo * root,bool recursing)252 add_rtes_to_flat_rtable(PlannerInfo *root, bool recursing)
253 {
254 	PlannerGlobal *glob = root->glob;
255 	Index		rti;
256 	ListCell   *lc;
257 
258 	/*
259 	 * Add the query's own RTEs to the flattened rangetable.
260 	 *
261 	 * At top level, we must add all RTEs so that their indexes in the
262 	 * flattened rangetable match up with their original indexes.  When
263 	 * recursing, we only care about extracting relation RTEs.
264 	 */
265 	foreach(lc, root->parse->rtable)
266 	{
267 		RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
268 
269 		if (!recursing || rte->rtekind == RTE_RELATION)
270 			add_rte_to_flat_rtable(glob, rte);
271 	}
272 
273 	/*
274 	 * If there are any dead subqueries, they are not referenced in the Plan
275 	 * tree, so we must add RTEs contained in them to the flattened rtable
276 	 * separately.  (If we failed to do this, the executor would not perform
277 	 * expected permission checks for tables mentioned in such subqueries.)
278 	 *
279 	 * Note: this pass over the rangetable can't be combined with the previous
280 	 * one, because that would mess up the numbering of the live RTEs in the
281 	 * flattened rangetable.
282 	 */
283 	rti = 1;
284 	foreach(lc, root->parse->rtable)
285 	{
286 		RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
287 
288 		/*
289 		 * We should ignore inheritance-parent RTEs: their contents have been
290 		 * pulled up into our rangetable already.  Also ignore any subquery
291 		 * RTEs without matching RelOptInfos, as they likewise have been
292 		 * pulled up.
293 		 */
294 		if (rte->rtekind == RTE_SUBQUERY && !rte->inh &&
295 			rti < root->simple_rel_array_size)
296 		{
297 			RelOptInfo *rel = root->simple_rel_array[rti];
298 
299 			if (rel != NULL)
300 			{
301 				Assert(rel->relid == rti);	/* sanity check on array */
302 
303 				/*
304 				 * The subquery might never have been planned at all, if it
305 				 * was excluded on the basis of self-contradictory constraints
306 				 * in our query level.  In this case apply
307 				 * flatten_unplanned_rtes.
308 				 *
309 				 * If it was planned but the result rel is dummy, we assume
310 				 * that it has been omitted from our plan tree (see
311 				 * set_subquery_pathlist), and recurse to pull up its RTEs.
312 				 *
313 				 * Otherwise, it should be represented by a SubqueryScan node
314 				 * somewhere in our plan tree, and we'll pull up its RTEs when
315 				 * we process that plan node.
316 				 *
317 				 * However, if we're recursing, then we should pull up RTEs
318 				 * whether the subquery is dummy or not, because we've found
319 				 * that some upper query level is treating this one as dummy,
320 				 * and so we won't scan this level's plan tree at all.
321 				 */
322 				if (rel->subroot == NULL)
323 					flatten_unplanned_rtes(glob, rte);
324 				else if (recursing ||
325 						 IS_DUMMY_REL(fetch_upper_rel(rel->subroot,
326 													  UPPERREL_FINAL, NULL)))
327 					add_rtes_to_flat_rtable(rel->subroot, true);
328 			}
329 		}
330 		rti++;
331 	}
332 }
333 
334 /*
335  * Extract RangeTblEntries from a subquery that was never planned at all
336  */
337 static void
flatten_unplanned_rtes(PlannerGlobal * glob,RangeTblEntry * rte)338 flatten_unplanned_rtes(PlannerGlobal *glob, RangeTblEntry *rte)
339 {
340 	/* Use query_tree_walker to find all RTEs in the parse tree */
341 	(void) query_tree_walker(rte->subquery,
342 							 flatten_rtes_walker,
343 							 (void *) glob,
344 							 QTW_EXAMINE_RTES);
345 }
346 
347 static bool
flatten_rtes_walker(Node * node,PlannerGlobal * glob)348 flatten_rtes_walker(Node *node, PlannerGlobal *glob)
349 {
350 	if (node == NULL)
351 		return false;
352 	if (IsA(node, RangeTblEntry))
353 	{
354 		RangeTblEntry *rte = (RangeTblEntry *) node;
355 
356 		/* As above, we need only save relation RTEs */
357 		if (rte->rtekind == RTE_RELATION)
358 			add_rte_to_flat_rtable(glob, rte);
359 		return false;
360 	}
361 	if (IsA(node, Query))
362 	{
363 		/* Recurse into subselects */
364 		return query_tree_walker((Query *) node,
365 								 flatten_rtes_walker,
366 								 (void *) glob,
367 								 QTW_EXAMINE_RTES);
368 	}
369 	return expression_tree_walker(node, flatten_rtes_walker,
370 								  (void *) glob);
371 }
372 
373 /*
374  * Add (a copy of) the given RTE to the final rangetable
375  *
376  * In the flat rangetable, we zero out substructure pointers that are not
377  * needed by the executor; this reduces the storage space and copying cost
378  * for cached plans.  We keep only the ctename, alias and eref Alias fields,
379  * which are needed by EXPLAIN, and the selectedCols, insertedCols and
380  * updatedCols bitmaps, which are needed for executor-startup permissions
381  * checking and for trigger event checking.
382  */
383 static void
add_rte_to_flat_rtable(PlannerGlobal * glob,RangeTblEntry * rte)384 add_rte_to_flat_rtable(PlannerGlobal *glob, RangeTblEntry *rte)
385 {
386 	RangeTblEntry *newrte;
387 
388 	/* flat copy to duplicate all the scalar fields */
389 	newrte = (RangeTblEntry *) palloc(sizeof(RangeTblEntry));
390 	memcpy(newrte, rte, sizeof(RangeTblEntry));
391 
392 	/* zap unneeded sub-structure */
393 	newrte->tablesample = NULL;
394 	newrte->subquery = NULL;
395 	newrte->joinaliasvars = NIL;
396 	newrte->functions = NIL;
397 	newrte->tablefunc = NULL;
398 	newrte->values_lists = NIL;
399 	newrte->coltypes = NIL;
400 	newrte->coltypmods = NIL;
401 	newrte->colcollations = NIL;
402 	newrte->securityQuals = NIL;
403 
404 	glob->finalrtable = lappend(glob->finalrtable, newrte);
405 
406 	/*
407 	 * Check for RT index overflow; it's very unlikely, but if it did happen,
408 	 * the executor would get confused by varnos that match the special varno
409 	 * values.
410 	 */
411 	if (IS_SPECIAL_VARNO(list_length(glob->finalrtable)))
412 		ereport(ERROR,
413 				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
414 				 errmsg("too many range table entries")));
415 
416 	/*
417 	 * If it's a plain relation RTE, add the table to relationOids.
418 	 *
419 	 * We do this even though the RTE might be unreferenced in the plan tree;
420 	 * this would correspond to cases such as views that were expanded, child
421 	 * tables that were eliminated by constraint exclusion, etc. Schema
422 	 * invalidation on such a rel must still force rebuilding of the plan.
423 	 *
424 	 * Note we don't bother to avoid making duplicate list entries.  We could,
425 	 * but it would probably cost more cycles than it would save.
426 	 */
427 	if (newrte->rtekind == RTE_RELATION)
428 		glob->relationOids = lappend_oid(glob->relationOids, newrte->relid);
429 }
430 
431 /*
432  * set_plan_refs: recurse through the Plan nodes of a single subquery level
433  */
434 static Plan *
set_plan_refs(PlannerInfo * root,Plan * plan,int rtoffset)435 set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
436 {
437 	ListCell   *l;
438 
439 	if (plan == NULL)
440 		return NULL;
441 
442 	/* Assign this node a unique ID. */
443 	plan->plan_node_id = root->glob->lastPlanNodeId++;
444 
445 	/*
446 	 * Plan-type-specific fixes
447 	 */
448 	switch (nodeTag(plan))
449 	{
450 		case T_SeqScan:
451 			{
452 				SeqScan    *splan = (SeqScan *) plan;
453 
454 				splan->scanrelid += rtoffset;
455 				splan->plan.targetlist =
456 					fix_scan_list(root, splan->plan.targetlist, rtoffset);
457 				splan->plan.qual =
458 					fix_scan_list(root, splan->plan.qual, rtoffset);
459 			}
460 			break;
461 		case T_SampleScan:
462 			{
463 				SampleScan *splan = (SampleScan *) plan;
464 
465 				splan->scan.scanrelid += rtoffset;
466 				splan->scan.plan.targetlist =
467 					fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
468 				splan->scan.plan.qual =
469 					fix_scan_list(root, splan->scan.plan.qual, rtoffset);
470 				splan->tablesample = (TableSampleClause *)
471 					fix_scan_expr(root, (Node *) splan->tablesample, rtoffset);
472 			}
473 			break;
474 		case T_IndexScan:
475 			{
476 				IndexScan  *splan = (IndexScan *) plan;
477 
478 				splan->scan.scanrelid += rtoffset;
479 				splan->scan.plan.targetlist =
480 					fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
481 				splan->scan.plan.qual =
482 					fix_scan_list(root, splan->scan.plan.qual, rtoffset);
483 				splan->indexqual =
484 					fix_scan_list(root, splan->indexqual, rtoffset);
485 				splan->indexqualorig =
486 					fix_scan_list(root, splan->indexqualorig, rtoffset);
487 				splan->indexorderby =
488 					fix_scan_list(root, splan->indexorderby, rtoffset);
489 				splan->indexorderbyorig =
490 					fix_scan_list(root, splan->indexorderbyorig, rtoffset);
491 			}
492 			break;
493 		case T_IndexOnlyScan:
494 			{
495 				IndexOnlyScan *splan = (IndexOnlyScan *) plan;
496 
497 				return set_indexonlyscan_references(root, splan, rtoffset);
498 			}
499 			break;
500 		case T_BitmapIndexScan:
501 			{
502 				BitmapIndexScan *splan = (BitmapIndexScan *) plan;
503 
504 				splan->scan.scanrelid += rtoffset;
505 				/* no need to fix targetlist and qual */
506 				Assert(splan->scan.plan.targetlist == NIL);
507 				Assert(splan->scan.plan.qual == NIL);
508 				splan->indexqual =
509 					fix_scan_list(root, splan->indexqual, rtoffset);
510 				splan->indexqualorig =
511 					fix_scan_list(root, splan->indexqualorig, rtoffset);
512 			}
513 			break;
514 		case T_BitmapHeapScan:
515 			{
516 				BitmapHeapScan *splan = (BitmapHeapScan *) plan;
517 
518 				splan->scan.scanrelid += rtoffset;
519 				splan->scan.plan.targetlist =
520 					fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
521 				splan->scan.plan.qual =
522 					fix_scan_list(root, splan->scan.plan.qual, rtoffset);
523 				splan->bitmapqualorig =
524 					fix_scan_list(root, splan->bitmapqualorig, rtoffset);
525 			}
526 			break;
527 		case T_TidScan:
528 			{
529 				TidScan    *splan = (TidScan *) plan;
530 
531 				splan->scan.scanrelid += rtoffset;
532 				splan->scan.plan.targetlist =
533 					fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
534 				splan->scan.plan.qual =
535 					fix_scan_list(root, splan->scan.plan.qual, rtoffset);
536 				splan->tidquals =
537 					fix_scan_list(root, splan->tidquals, rtoffset);
538 			}
539 			break;
540 		case T_SubqueryScan:
541 			/* Needs special treatment, see comments below */
542 			return set_subqueryscan_references(root,
543 											   (SubqueryScan *) plan,
544 											   rtoffset);
545 		case T_FunctionScan:
546 			{
547 				FunctionScan *splan = (FunctionScan *) plan;
548 
549 				splan->scan.scanrelid += rtoffset;
550 				splan->scan.plan.targetlist =
551 					fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
552 				splan->scan.plan.qual =
553 					fix_scan_list(root, splan->scan.plan.qual, rtoffset);
554 				splan->functions =
555 					fix_scan_list(root, splan->functions, rtoffset);
556 			}
557 			break;
558 		case T_TableFuncScan:
559 			{
560 				TableFuncScan *splan = (TableFuncScan *) plan;
561 
562 				splan->scan.scanrelid += rtoffset;
563 				splan->scan.plan.targetlist =
564 					fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
565 				splan->scan.plan.qual =
566 					fix_scan_list(root, splan->scan.plan.qual, rtoffset);
567 				splan->tablefunc = (TableFunc *)
568 					fix_scan_expr(root, (Node *) splan->tablefunc, rtoffset);
569 			}
570 			break;
571 		case T_ValuesScan:
572 			{
573 				ValuesScan *splan = (ValuesScan *) plan;
574 
575 				splan->scan.scanrelid += rtoffset;
576 				splan->scan.plan.targetlist =
577 					fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
578 				splan->scan.plan.qual =
579 					fix_scan_list(root, splan->scan.plan.qual, rtoffset);
580 				splan->values_lists =
581 					fix_scan_list(root, splan->values_lists, rtoffset);
582 			}
583 			break;
584 		case T_CteScan:
585 			{
586 				CteScan    *splan = (CteScan *) plan;
587 
588 				splan->scan.scanrelid += rtoffset;
589 				splan->scan.plan.targetlist =
590 					fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
591 				splan->scan.plan.qual =
592 					fix_scan_list(root, splan->scan.plan.qual, rtoffset);
593 			}
594 			break;
595 		case T_NamedTuplestoreScan:
596 			{
597 				NamedTuplestoreScan *splan = (NamedTuplestoreScan *) plan;
598 
599 				splan->scan.scanrelid += rtoffset;
600 				splan->scan.plan.targetlist =
601 					fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
602 				splan->scan.plan.qual =
603 					fix_scan_list(root, splan->scan.plan.qual, rtoffset);
604 			}
605 			break;
606 		case T_WorkTableScan:
607 			{
608 				WorkTableScan *splan = (WorkTableScan *) plan;
609 
610 				splan->scan.scanrelid += rtoffset;
611 				splan->scan.plan.targetlist =
612 					fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
613 				splan->scan.plan.qual =
614 					fix_scan_list(root, splan->scan.plan.qual, rtoffset);
615 			}
616 			break;
617 		case T_ForeignScan:
618 			set_foreignscan_references(root, (ForeignScan *) plan, rtoffset);
619 			break;
620 		case T_CustomScan:
621 			set_customscan_references(root, (CustomScan *) plan, rtoffset);
622 			break;
623 
624 		case T_NestLoop:
625 		case T_MergeJoin:
626 		case T_HashJoin:
627 			set_join_references(root, (Join *) plan, rtoffset);
628 			break;
629 
630 		case T_Gather:
631 		case T_GatherMerge:
632 			{
633 				set_upper_references(root, plan, rtoffset);
634 				set_param_references(root, plan);
635 			}
636 			break;
637 
638 		case T_Hash:
639 		case T_Material:
640 		case T_Sort:
641 		case T_Unique:
642 		case T_SetOp:
643 
644 			/*
645 			 * These plan types don't actually bother to evaluate their
646 			 * targetlists, because they just return their unmodified input
647 			 * tuples.  Even though the targetlist won't be used by the
648 			 * executor, we fix it up for possible use by EXPLAIN (not to
649 			 * mention ease of debugging --- wrong varnos are very confusing).
650 			 */
651 			set_dummy_tlist_references(plan, rtoffset);
652 
653 			/*
654 			 * Since these plan types don't check quals either, we should not
655 			 * find any qual expression attached to them.
656 			 */
657 			Assert(plan->qual == NIL);
658 			break;
659 		case T_LockRows:
660 			{
661 				LockRows   *splan = (LockRows *) plan;
662 
663 				/*
664 				 * Like the plan types above, LockRows doesn't evaluate its
665 				 * tlist or quals.  But we have to fix up the RT indexes in
666 				 * its rowmarks.
667 				 */
668 				set_dummy_tlist_references(plan, rtoffset);
669 				Assert(splan->plan.qual == NIL);
670 
671 				foreach(l, splan->rowMarks)
672 				{
673 					PlanRowMark *rc = (PlanRowMark *) lfirst(l);
674 
675 					rc->rti += rtoffset;
676 					rc->prti += rtoffset;
677 				}
678 			}
679 			break;
680 		case T_Limit:
681 			{
682 				Limit	   *splan = (Limit *) plan;
683 
684 				/*
685 				 * Like the plan types above, Limit doesn't evaluate its tlist
686 				 * or quals.  It does have live expressions for limit/offset,
687 				 * however; and those cannot contain subplan variable refs, so
688 				 * fix_scan_expr works for them.
689 				 */
690 				set_dummy_tlist_references(plan, rtoffset);
691 				Assert(splan->plan.qual == NIL);
692 
693 				splan->limitOffset =
694 					fix_scan_expr(root, splan->limitOffset, rtoffset);
695 				splan->limitCount =
696 					fix_scan_expr(root, splan->limitCount, rtoffset);
697 			}
698 			break;
699 		case T_Agg:
700 			{
701 				Agg		   *agg = (Agg *) plan;
702 
703 				/*
704 				 * If this node is combining partial-aggregation results, we
705 				 * must convert its Aggrefs to contain references to the
706 				 * partial-aggregate subexpressions that will be available
707 				 * from the child plan node.
708 				 */
709 				if (DO_AGGSPLIT_COMBINE(agg->aggsplit))
710 				{
711 					plan->targetlist = (List *)
712 						convert_combining_aggrefs((Node *) plan->targetlist,
713 												  NULL);
714 					plan->qual = (List *)
715 						convert_combining_aggrefs((Node *) plan->qual,
716 												  NULL);
717 				}
718 
719 				set_upper_references(root, plan, rtoffset);
720 			}
721 			break;
722 		case T_Group:
723 			set_upper_references(root, plan, rtoffset);
724 			break;
725 		case T_WindowAgg:
726 			{
727 				WindowAgg  *wplan = (WindowAgg *) plan;
728 
729 				set_upper_references(root, plan, rtoffset);
730 
731 				/*
732 				 * Like Limit node limit/offset expressions, WindowAgg has
733 				 * frame offset expressions, which cannot contain subplan
734 				 * variable refs, so fix_scan_expr works for them.
735 				 */
736 				wplan->startOffset =
737 					fix_scan_expr(root, wplan->startOffset, rtoffset);
738 				wplan->endOffset =
739 					fix_scan_expr(root, wplan->endOffset, rtoffset);
740 			}
741 			break;
742 		case T_Result:
743 			{
744 				Result	   *splan = (Result *) plan;
745 
746 				/*
747 				 * Result may or may not have a subplan; if not, it's more
748 				 * like a scan node than an upper node.
749 				 */
750 				if (splan->plan.lefttree != NULL)
751 					set_upper_references(root, plan, rtoffset);
752 				else
753 				{
754 					splan->plan.targetlist =
755 						fix_scan_list(root, splan->plan.targetlist, rtoffset);
756 					splan->plan.qual =
757 						fix_scan_list(root, splan->plan.qual, rtoffset);
758 				}
759 				/* resconstantqual can't contain any subplan variable refs */
760 				splan->resconstantqual =
761 					fix_scan_expr(root, splan->resconstantqual, rtoffset);
762 			}
763 			break;
764 		case T_ProjectSet:
765 			set_upper_references(root, plan, rtoffset);
766 			break;
767 		case T_ModifyTable:
768 			{
769 				ModifyTable *splan = (ModifyTable *) plan;
770 
771 				Assert(splan->plan.targetlist == NIL);
772 				Assert(splan->plan.qual == NIL);
773 
774 				splan->withCheckOptionLists =
775 					fix_scan_list(root, splan->withCheckOptionLists, rtoffset);
776 
777 				if (splan->returningLists)
778 				{
779 					List	   *newRL = NIL;
780 					ListCell   *lcrl,
781 							   *lcrr,
782 							   *lcp;
783 
784 					/*
785 					 * Pass each per-subplan returningList through
786 					 * set_returning_clause_references().
787 					 */
788 					Assert(list_length(splan->returningLists) == list_length(splan->resultRelations));
789 					Assert(list_length(splan->returningLists) == list_length(splan->plans));
790 					forthree(lcrl, splan->returningLists,
791 							 lcrr, splan->resultRelations,
792 							 lcp, splan->plans)
793 					{
794 						List	   *rlist = (List *) lfirst(lcrl);
795 						Index		resultrel = lfirst_int(lcrr);
796 						Plan	   *subplan = (Plan *) lfirst(lcp);
797 
798 						rlist = set_returning_clause_references(root,
799 																rlist,
800 																subplan,
801 																resultrel,
802 																rtoffset);
803 						newRL = lappend(newRL, rlist);
804 					}
805 					splan->returningLists = newRL;
806 
807 					/*
808 					 * Set up the visible plan targetlist as being the same as
809 					 * the first RETURNING list. This is for the use of
810 					 * EXPLAIN; the executor won't pay any attention to the
811 					 * targetlist.  We postpone this step until here so that
812 					 * we don't have to do set_returning_clause_references()
813 					 * twice on identical targetlists.
814 					 */
815 					splan->plan.targetlist = copyObject(linitial(newRL));
816 				}
817 
818 				/*
819 				 * We treat ModifyTable with ON CONFLICT as a form of 'pseudo
820 				 * join', where the inner side is the EXCLUDED tuple.
821 				 * Therefore use fix_join_expr to setup the relevant variables
822 				 * to INNER_VAR. We explicitly don't create any OUTER_VARs as
823 				 * those are already used by RETURNING and it seems better to
824 				 * be non-conflicting.
825 				 */
826 				if (splan->onConflictSet)
827 				{
828 					indexed_tlist *itlist;
829 
830 					itlist = build_tlist_index(splan->exclRelTlist);
831 
832 					splan->onConflictSet =
833 						fix_join_expr(root, splan->onConflictSet,
834 									  NULL, itlist,
835 									  linitial_int(splan->resultRelations),
836 									  rtoffset);
837 
838 					splan->onConflictWhere = (Node *)
839 						fix_join_expr(root, (List *) splan->onConflictWhere,
840 									  NULL, itlist,
841 									  linitial_int(splan->resultRelations),
842 									  rtoffset);
843 
844 					pfree(itlist);
845 
846 					splan->exclRelTlist =
847 						fix_scan_list(root, splan->exclRelTlist, rtoffset);
848 				}
849 
850 				splan->nominalRelation += rtoffset;
851 				splan->exclRelRTI += rtoffset;
852 
853 				foreach(l, splan->partitioned_rels)
854 				{
855 					lfirst_int(l) += rtoffset;
856 				}
857 				foreach(l, splan->resultRelations)
858 				{
859 					lfirst_int(l) += rtoffset;
860 				}
861 				foreach(l, splan->rowMarks)
862 				{
863 					PlanRowMark *rc = (PlanRowMark *) lfirst(l);
864 
865 					rc->rti += rtoffset;
866 					rc->prti += rtoffset;
867 				}
868 				foreach(l, splan->plans)
869 				{
870 					lfirst(l) = set_plan_refs(root,
871 											  (Plan *) lfirst(l),
872 											  rtoffset);
873 				}
874 
875 				/*
876 				 * Append this ModifyTable node's final result relation RT
877 				 * index(es) to the global list for the plan, and set its
878 				 * resultRelIndex to reflect their starting position in the
879 				 * global list.
880 				 */
881 				splan->resultRelIndex = list_length(root->glob->resultRelations);
882 				root->glob->resultRelations =
883 					list_concat(root->glob->resultRelations,
884 								list_copy(splan->resultRelations));
885 
886 				/*
887 				 * If the main target relation is a partitioned table, the
888 				 * following list contains the RT indexes of partitioned child
889 				 * relations including the root, which are not included in the
890 				 * above list.  We also keep RT indexes of the roots
891 				 * separately to be identified as such during the executor
892 				 * initialization.
893 				 */
894 				if (splan->partitioned_rels != NIL)
895 				{
896 					root->glob->nonleafResultRelations =
897 						list_concat(root->glob->nonleafResultRelations,
898 									list_copy(splan->partitioned_rels));
899 					/* Remember where this root will be in the global list. */
900 					splan->rootResultRelIndex =
901 						list_length(root->glob->rootResultRelations);
902 					root->glob->rootResultRelations =
903 						lappend_int(root->glob->rootResultRelations,
904 									linitial_int(splan->partitioned_rels));
905 				}
906 			}
907 			break;
908 		case T_Append:
909 			{
910 				Append	   *splan = (Append *) plan;
911 
912 				/*
913 				 * Append, like Sort et al, doesn't actually evaluate its
914 				 * targetlist or check quals.
915 				 */
916 				set_dummy_tlist_references(plan, rtoffset);
917 				Assert(splan->plan.qual == NIL);
918 				foreach(l, splan->partitioned_rels)
919 				{
920 					lfirst_int(l) += rtoffset;
921 				}
922 				foreach(l, splan->appendplans)
923 				{
924 					lfirst(l) = set_plan_refs(root,
925 											  (Plan *) lfirst(l),
926 											  rtoffset);
927 				}
928 			}
929 			break;
930 		case T_MergeAppend:
931 			{
932 				MergeAppend *splan = (MergeAppend *) plan;
933 
934 				/*
935 				 * MergeAppend, like Sort et al, doesn't actually evaluate its
936 				 * targetlist or check quals.
937 				 */
938 				set_dummy_tlist_references(plan, rtoffset);
939 				Assert(splan->plan.qual == NIL);
940 				foreach(l, splan->partitioned_rels)
941 				{
942 					lfirst_int(l) += rtoffset;
943 				}
944 				foreach(l, splan->mergeplans)
945 				{
946 					lfirst(l) = set_plan_refs(root,
947 											  (Plan *) lfirst(l),
948 											  rtoffset);
949 				}
950 			}
951 			break;
952 		case T_RecursiveUnion:
953 			/* This doesn't evaluate targetlist or check quals either */
954 			set_dummy_tlist_references(plan, rtoffset);
955 			Assert(plan->qual == NIL);
956 			break;
957 		case T_BitmapAnd:
958 			{
959 				BitmapAnd  *splan = (BitmapAnd *) plan;
960 
961 				/* BitmapAnd works like Append, but has no tlist */
962 				Assert(splan->plan.targetlist == NIL);
963 				Assert(splan->plan.qual == NIL);
964 				foreach(l, splan->bitmapplans)
965 				{
966 					lfirst(l) = set_plan_refs(root,
967 											  (Plan *) lfirst(l),
968 											  rtoffset);
969 				}
970 			}
971 			break;
972 		case T_BitmapOr:
973 			{
974 				BitmapOr   *splan = (BitmapOr *) plan;
975 
976 				/* BitmapOr works like Append, but has no tlist */
977 				Assert(splan->plan.targetlist == NIL);
978 				Assert(splan->plan.qual == NIL);
979 				foreach(l, splan->bitmapplans)
980 				{
981 					lfirst(l) = set_plan_refs(root,
982 											  (Plan *) lfirst(l),
983 											  rtoffset);
984 				}
985 			}
986 			break;
987 		default:
988 			elog(ERROR, "unrecognized node type: %d",
989 				 (int) nodeTag(plan));
990 			break;
991 	}
992 
993 	/*
994 	 * Now recurse into child plans, if any
995 	 *
996 	 * NOTE: it is essential that we recurse into child plans AFTER we set
997 	 * subplan references in this plan's tlist and quals.  If we did the
998 	 * reference-adjustments bottom-up, then we would fail to match this
999 	 * plan's var nodes against the already-modified nodes of the children.
1000 	 */
1001 	plan->lefttree = set_plan_refs(root, plan->lefttree, rtoffset);
1002 	plan->righttree = set_plan_refs(root, plan->righttree, rtoffset);
1003 
1004 	return plan;
1005 }
1006 
1007 /*
1008  * set_indexonlyscan_references
1009  *		Do set_plan_references processing on an IndexOnlyScan
1010  *
1011  * This is unlike the handling of a plain IndexScan because we have to
1012  * convert Vars referencing the heap into Vars referencing the index.
1013  * We can use the fix_upper_expr machinery for that, by working from a
1014  * targetlist describing the index columns.
1015  */
1016 static Plan *
set_indexonlyscan_references(PlannerInfo * root,IndexOnlyScan * plan,int rtoffset)1017 set_indexonlyscan_references(PlannerInfo *root,
1018 							 IndexOnlyScan *plan,
1019 							 int rtoffset)
1020 {
1021 	indexed_tlist *index_itlist;
1022 
1023 	index_itlist = build_tlist_index(plan->indextlist);
1024 
1025 	plan->scan.scanrelid += rtoffset;
1026 	plan->scan.plan.targetlist = (List *)
1027 		fix_upper_expr(root,
1028 					   (Node *) plan->scan.plan.targetlist,
1029 					   index_itlist,
1030 					   INDEX_VAR,
1031 					   rtoffset);
1032 	plan->scan.plan.qual = (List *)
1033 		fix_upper_expr(root,
1034 					   (Node *) plan->scan.plan.qual,
1035 					   index_itlist,
1036 					   INDEX_VAR,
1037 					   rtoffset);
1038 	/* indexqual is already transformed to reference index columns */
1039 	plan->indexqual = fix_scan_list(root, plan->indexqual, rtoffset);
1040 	/* indexorderby is already transformed to reference index columns */
1041 	plan->indexorderby = fix_scan_list(root, plan->indexorderby, rtoffset);
1042 	/* indextlist must NOT be transformed to reference index columns */
1043 	plan->indextlist = fix_scan_list(root, plan->indextlist, rtoffset);
1044 
1045 	pfree(index_itlist);
1046 
1047 	return (Plan *) plan;
1048 }
1049 
1050 /*
1051  * set_subqueryscan_references
1052  *		Do set_plan_references processing on a SubqueryScan
1053  *
1054  * We try to strip out the SubqueryScan entirely; if we can't, we have
1055  * to do the normal processing on it.
1056  */
1057 static Plan *
set_subqueryscan_references(PlannerInfo * root,SubqueryScan * plan,int rtoffset)1058 set_subqueryscan_references(PlannerInfo *root,
1059 							SubqueryScan *plan,
1060 							int rtoffset)
1061 {
1062 	RelOptInfo *rel;
1063 	Plan	   *result;
1064 
1065 	/* Need to look up the subquery's RelOptInfo, since we need its subroot */
1066 	rel = find_base_rel(root, plan->scan.scanrelid);
1067 
1068 	/* Recursively process the subplan */
1069 	plan->subplan = set_plan_references(rel->subroot, plan->subplan);
1070 
1071 	if (trivial_subqueryscan(plan))
1072 	{
1073 		/*
1074 		 * We can omit the SubqueryScan node and just pull up the subplan.
1075 		 */
1076 		ListCell   *lp,
1077 				   *lc;
1078 
1079 		result = plan->subplan;
1080 
1081 		/* We have to be sure we don't lose any initplans */
1082 		result->initPlan = list_concat(plan->scan.plan.initPlan,
1083 									   result->initPlan);
1084 
1085 		/*
1086 		 * We also have to transfer the SubqueryScan's result-column names
1087 		 * into the subplan, else columns sent to client will be improperly
1088 		 * labeled if this is the topmost plan level.  Copy the "source
1089 		 * column" information too.
1090 		 */
1091 		forboth(lp, plan->scan.plan.targetlist, lc, result->targetlist)
1092 		{
1093 			TargetEntry *ptle = (TargetEntry *) lfirst(lp);
1094 			TargetEntry *ctle = (TargetEntry *) lfirst(lc);
1095 
1096 			ctle->resname = ptle->resname;
1097 			ctle->resorigtbl = ptle->resorigtbl;
1098 			ctle->resorigcol = ptle->resorigcol;
1099 		}
1100 	}
1101 	else
1102 	{
1103 		/*
1104 		 * Keep the SubqueryScan node.  We have to do the processing that
1105 		 * set_plan_references would otherwise have done on it.  Notice we do
1106 		 * not do set_upper_references() here, because a SubqueryScan will
1107 		 * always have been created with correct references to its subplan's
1108 		 * outputs to begin with.
1109 		 */
1110 		plan->scan.scanrelid += rtoffset;
1111 		plan->scan.plan.targetlist =
1112 			fix_scan_list(root, plan->scan.plan.targetlist, rtoffset);
1113 		plan->scan.plan.qual =
1114 			fix_scan_list(root, plan->scan.plan.qual, rtoffset);
1115 
1116 		result = (Plan *) plan;
1117 	}
1118 
1119 	return result;
1120 }
1121 
1122 /*
1123  * trivial_subqueryscan
1124  *		Detect whether a SubqueryScan can be deleted from the plan tree.
1125  *
1126  * We can delete it if it has no qual to check and the targetlist just
1127  * regurgitates the output of the child plan.
1128  */
1129 static bool
trivial_subqueryscan(SubqueryScan * plan)1130 trivial_subqueryscan(SubqueryScan *plan)
1131 {
1132 	int			attrno;
1133 	ListCell   *lp,
1134 			   *lc;
1135 
1136 	if (plan->scan.plan.qual != NIL)
1137 		return false;
1138 
1139 	if (list_length(plan->scan.plan.targetlist) !=
1140 		list_length(plan->subplan->targetlist))
1141 		return false;			/* tlists not same length */
1142 
1143 	attrno = 1;
1144 	forboth(lp, plan->scan.plan.targetlist, lc, plan->subplan->targetlist)
1145 	{
1146 		TargetEntry *ptle = (TargetEntry *) lfirst(lp);
1147 		TargetEntry *ctle = (TargetEntry *) lfirst(lc);
1148 
1149 		if (ptle->resjunk != ctle->resjunk)
1150 			return false;		/* tlist doesn't match junk status */
1151 
1152 		/*
1153 		 * We accept either a Var referencing the corresponding element of the
1154 		 * subplan tlist, or a Const equaling the subplan element. See
1155 		 * generate_setop_tlist() for motivation.
1156 		 */
1157 		if (ptle->expr && IsA(ptle->expr, Var))
1158 		{
1159 			Var		   *var = (Var *) ptle->expr;
1160 
1161 			Assert(var->varno == plan->scan.scanrelid);
1162 			Assert(var->varlevelsup == 0);
1163 			if (var->varattno != attrno)
1164 				return false;	/* out of order */
1165 		}
1166 		else if (ptle->expr && IsA(ptle->expr, Const))
1167 		{
1168 			if (!equal(ptle->expr, ctle->expr))
1169 				return false;
1170 		}
1171 		else
1172 			return false;
1173 
1174 		attrno++;
1175 	}
1176 
1177 	return true;
1178 }
1179 
1180 /*
1181  * set_foreignscan_references
1182  *	   Do set_plan_references processing on a ForeignScan
1183  */
1184 static void
set_foreignscan_references(PlannerInfo * root,ForeignScan * fscan,int rtoffset)1185 set_foreignscan_references(PlannerInfo *root,
1186 						   ForeignScan *fscan,
1187 						   int rtoffset)
1188 {
1189 	/* Adjust scanrelid if it's valid */
1190 	if (fscan->scan.scanrelid > 0)
1191 		fscan->scan.scanrelid += rtoffset;
1192 
1193 	if (fscan->fdw_scan_tlist != NIL || fscan->scan.scanrelid == 0)
1194 	{
1195 		/*
1196 		 * Adjust tlist, qual, fdw_exprs, fdw_recheck_quals to reference
1197 		 * foreign scan tuple
1198 		 */
1199 		indexed_tlist *itlist = build_tlist_index(fscan->fdw_scan_tlist);
1200 
1201 		fscan->scan.plan.targetlist = (List *)
1202 			fix_upper_expr(root,
1203 						   (Node *) fscan->scan.plan.targetlist,
1204 						   itlist,
1205 						   INDEX_VAR,
1206 						   rtoffset);
1207 		fscan->scan.plan.qual = (List *)
1208 			fix_upper_expr(root,
1209 						   (Node *) fscan->scan.plan.qual,
1210 						   itlist,
1211 						   INDEX_VAR,
1212 						   rtoffset);
1213 		fscan->fdw_exprs = (List *)
1214 			fix_upper_expr(root,
1215 						   (Node *) fscan->fdw_exprs,
1216 						   itlist,
1217 						   INDEX_VAR,
1218 						   rtoffset);
1219 		fscan->fdw_recheck_quals = (List *)
1220 			fix_upper_expr(root,
1221 						   (Node *) fscan->fdw_recheck_quals,
1222 						   itlist,
1223 						   INDEX_VAR,
1224 						   rtoffset);
1225 		pfree(itlist);
1226 		/* fdw_scan_tlist itself just needs fix_scan_list() adjustments */
1227 		fscan->fdw_scan_tlist =
1228 			fix_scan_list(root, fscan->fdw_scan_tlist, rtoffset);
1229 	}
1230 	else
1231 	{
1232 		/*
1233 		 * Adjust tlist, qual, fdw_exprs, fdw_recheck_quals in the standard
1234 		 * way
1235 		 */
1236 		fscan->scan.plan.targetlist =
1237 			fix_scan_list(root, fscan->scan.plan.targetlist, rtoffset);
1238 		fscan->scan.plan.qual =
1239 			fix_scan_list(root, fscan->scan.plan.qual, rtoffset);
1240 		fscan->fdw_exprs =
1241 			fix_scan_list(root, fscan->fdw_exprs, rtoffset);
1242 		fscan->fdw_recheck_quals =
1243 			fix_scan_list(root, fscan->fdw_recheck_quals, rtoffset);
1244 	}
1245 
1246 	/* Adjust fs_relids if needed */
1247 	if (rtoffset > 0)
1248 	{
1249 		Bitmapset  *tempset = NULL;
1250 		int			x = -1;
1251 
1252 		while ((x = bms_next_member(fscan->fs_relids, x)) >= 0)
1253 			tempset = bms_add_member(tempset, x + rtoffset);
1254 		fscan->fs_relids = tempset;
1255 	}
1256 }
1257 
1258 /*
1259  * set_customscan_references
1260  *	   Do set_plan_references processing on a CustomScan
1261  */
1262 static void
set_customscan_references(PlannerInfo * root,CustomScan * cscan,int rtoffset)1263 set_customscan_references(PlannerInfo *root,
1264 						  CustomScan *cscan,
1265 						  int rtoffset)
1266 {
1267 	ListCell   *lc;
1268 
1269 	/* Adjust scanrelid if it's valid */
1270 	if (cscan->scan.scanrelid > 0)
1271 		cscan->scan.scanrelid += rtoffset;
1272 
1273 	if (cscan->custom_scan_tlist != NIL || cscan->scan.scanrelid == 0)
1274 	{
1275 		/* Adjust tlist, qual, custom_exprs to reference custom scan tuple */
1276 		indexed_tlist *itlist = build_tlist_index(cscan->custom_scan_tlist);
1277 
1278 		cscan->scan.plan.targetlist = (List *)
1279 			fix_upper_expr(root,
1280 						   (Node *) cscan->scan.plan.targetlist,
1281 						   itlist,
1282 						   INDEX_VAR,
1283 						   rtoffset);
1284 		cscan->scan.plan.qual = (List *)
1285 			fix_upper_expr(root,
1286 						   (Node *) cscan->scan.plan.qual,
1287 						   itlist,
1288 						   INDEX_VAR,
1289 						   rtoffset);
1290 		cscan->custom_exprs = (List *)
1291 			fix_upper_expr(root,
1292 						   (Node *) cscan->custom_exprs,
1293 						   itlist,
1294 						   INDEX_VAR,
1295 						   rtoffset);
1296 		pfree(itlist);
1297 		/* custom_scan_tlist itself just needs fix_scan_list() adjustments */
1298 		cscan->custom_scan_tlist =
1299 			fix_scan_list(root, cscan->custom_scan_tlist, rtoffset);
1300 	}
1301 	else
1302 	{
1303 		/* Adjust tlist, qual, custom_exprs in the standard way */
1304 		cscan->scan.plan.targetlist =
1305 			fix_scan_list(root, cscan->scan.plan.targetlist, rtoffset);
1306 		cscan->scan.plan.qual =
1307 			fix_scan_list(root, cscan->scan.plan.qual, rtoffset);
1308 		cscan->custom_exprs =
1309 			fix_scan_list(root, cscan->custom_exprs, rtoffset);
1310 	}
1311 
1312 	/* Adjust child plan-nodes recursively, if needed */
1313 	foreach(lc, cscan->custom_plans)
1314 	{
1315 		lfirst(lc) = set_plan_refs(root, (Plan *) lfirst(lc), rtoffset);
1316 	}
1317 
1318 	/* Adjust custom_relids if needed */
1319 	if (rtoffset > 0)
1320 	{
1321 		Bitmapset  *tempset = NULL;
1322 		int			x = -1;
1323 
1324 		while ((x = bms_next_member(cscan->custom_relids, x)) >= 0)
1325 			tempset = bms_add_member(tempset, x + rtoffset);
1326 		cscan->custom_relids = tempset;
1327 	}
1328 }
1329 
1330 /*
1331  * copyVar
1332  *		Copy a Var node.
1333  *
1334  * fix_scan_expr and friends do this enough times that it's worth having
1335  * a bespoke routine instead of using the generic copyObject() function.
1336  */
1337 static inline Var *
copyVar(Var * var)1338 copyVar(Var *var)
1339 {
1340 	Var		   *newvar = (Var *) palloc(sizeof(Var));
1341 
1342 	*newvar = *var;
1343 	return newvar;
1344 }
1345 
1346 /*
1347  * fix_expr_common
1348  *		Do generic set_plan_references processing on an expression node
1349  *
1350  * This is code that is common to all variants of expression-fixing.
1351  * We must look up operator opcode info for OpExpr and related nodes,
1352  * add OIDs from regclass Const nodes into root->glob->relationOids, and
1353  * add PlanInvalItems for user-defined functions into root->glob->invalItems.
1354  * We also fill in column index lists for GROUPING() expressions.
1355  *
1356  * We assume it's okay to update opcode info in-place.  So this could possibly
1357  * scribble on the planner's input data structures, but it's OK.
1358  */
1359 static void
fix_expr_common(PlannerInfo * root,Node * node)1360 fix_expr_common(PlannerInfo *root, Node *node)
1361 {
1362 	/* We assume callers won't call us on a NULL pointer */
1363 	if (IsA(node, Aggref))
1364 	{
1365 		record_plan_function_dependency(root,
1366 										((Aggref *) node)->aggfnoid);
1367 	}
1368 	else if (IsA(node, WindowFunc))
1369 	{
1370 		record_plan_function_dependency(root,
1371 										((WindowFunc *) node)->winfnoid);
1372 	}
1373 	else if (IsA(node, FuncExpr))
1374 	{
1375 		record_plan_function_dependency(root,
1376 										((FuncExpr *) node)->funcid);
1377 	}
1378 	else if (IsA(node, OpExpr))
1379 	{
1380 		set_opfuncid((OpExpr *) node);
1381 		record_plan_function_dependency(root,
1382 										((OpExpr *) node)->opfuncid);
1383 	}
1384 	else if (IsA(node, DistinctExpr))
1385 	{
1386 		set_opfuncid((OpExpr *) node);	/* rely on struct equivalence */
1387 		record_plan_function_dependency(root,
1388 										((DistinctExpr *) node)->opfuncid);
1389 	}
1390 	else if (IsA(node, NullIfExpr))
1391 	{
1392 		set_opfuncid((OpExpr *) node);	/* rely on struct equivalence */
1393 		record_plan_function_dependency(root,
1394 										((NullIfExpr *) node)->opfuncid);
1395 	}
1396 	else if (IsA(node, ScalarArrayOpExpr))
1397 	{
1398 		set_sa_opfuncid((ScalarArrayOpExpr *) node);
1399 		record_plan_function_dependency(root,
1400 										((ScalarArrayOpExpr *) node)->opfuncid);
1401 	}
1402 	else if (IsA(node, Const))
1403 	{
1404 		Const	   *con = (Const *) node;
1405 
1406 		/* Check for regclass reference */
1407 		if (ISREGCLASSCONST(con))
1408 			root->glob->relationOids =
1409 				lappend_oid(root->glob->relationOids,
1410 							DatumGetObjectId(con->constvalue));
1411 	}
1412 	else if (IsA(node, GroupingFunc))
1413 	{
1414 		GroupingFunc *g = (GroupingFunc *) node;
1415 		AttrNumber *grouping_map = root->grouping_map;
1416 
1417 		/* If there are no grouping sets, we don't need this. */
1418 
1419 		Assert(grouping_map || g->cols == NIL);
1420 
1421 		if (grouping_map)
1422 		{
1423 			ListCell   *lc;
1424 			List	   *cols = NIL;
1425 
1426 			foreach(lc, g->refs)
1427 			{
1428 				cols = lappend_int(cols, grouping_map[lfirst_int(lc)]);
1429 			}
1430 
1431 			Assert(!g->cols || equal(cols, g->cols));
1432 
1433 			if (!g->cols)
1434 				g->cols = cols;
1435 		}
1436 	}
1437 }
1438 
1439 /*
1440  * fix_param_node
1441  *		Do set_plan_references processing on a Param
1442  *
1443  * If it's a PARAM_MULTIEXPR, replace it with the appropriate Param from
1444  * root->multiexpr_params; otherwise no change is needed.
1445  * Just for paranoia's sake, we make a copy of the node in either case.
1446  */
1447 static Node *
fix_param_node(PlannerInfo * root,Param * p)1448 fix_param_node(PlannerInfo *root, Param *p)
1449 {
1450 	if (p->paramkind == PARAM_MULTIEXPR)
1451 	{
1452 		int			subqueryid = p->paramid >> 16;
1453 		int			colno = p->paramid & 0xFFFF;
1454 		List	   *params;
1455 
1456 		if (subqueryid <= 0 ||
1457 			subqueryid > list_length(root->multiexpr_params))
1458 			elog(ERROR, "unexpected PARAM_MULTIEXPR ID: %d", p->paramid);
1459 		params = (List *) list_nth(root->multiexpr_params, subqueryid - 1);
1460 		if (colno <= 0 || colno > list_length(params))
1461 			elog(ERROR, "unexpected PARAM_MULTIEXPR ID: %d", p->paramid);
1462 		return copyObject(list_nth(params, colno - 1));
1463 	}
1464 	return (Node *) copyObject(p);
1465 }
1466 
1467 /*
1468  * fix_scan_expr
1469  *		Do set_plan_references processing on a scan-level expression
1470  *
1471  * This consists of incrementing all Vars' varnos by rtoffset,
1472  * replacing PARAM_MULTIEXPR Params, expanding PlaceHolderVars,
1473  * replacing Aggref nodes that should be replaced by initplan output Params,
1474  * looking up operator opcode info for OpExpr and related nodes,
1475  * and adding OIDs from regclass Const nodes into root->glob->relationOids.
1476  */
1477 static Node *
fix_scan_expr(PlannerInfo * root,Node * node,int rtoffset)1478 fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset)
1479 {
1480 	fix_scan_expr_context context;
1481 
1482 	context.root = root;
1483 	context.rtoffset = rtoffset;
1484 
1485 	if (rtoffset != 0 ||
1486 		root->multiexpr_params != NIL ||
1487 		root->glob->lastPHId != 0 ||
1488 		root->minmax_aggs != NIL)
1489 	{
1490 		return fix_scan_expr_mutator(node, &context);
1491 	}
1492 	else
1493 	{
1494 		/*
1495 		 * If rtoffset == 0, we don't need to change any Vars, and if there
1496 		 * are no MULTIEXPR subqueries then we don't need to replace
1497 		 * PARAM_MULTIEXPR Params, and if there are no placeholders anywhere
1498 		 * we won't need to remove them, and if there are no minmax Aggrefs we
1499 		 * won't need to replace them.  Then it's OK to just scribble on the
1500 		 * input node tree instead of copying (since the only change, filling
1501 		 * in any unset opfuncid fields, is harmless).  This saves just enough
1502 		 * cycles to be noticeable on trivial queries.
1503 		 */
1504 		(void) fix_scan_expr_walker(node, &context);
1505 		return node;
1506 	}
1507 }
1508 
1509 static Node *
fix_scan_expr_mutator(Node * node,fix_scan_expr_context * context)1510 fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context)
1511 {
1512 	if (node == NULL)
1513 		return NULL;
1514 	if (IsA(node, Var))
1515 	{
1516 		Var		   *var = copyVar((Var *) node);
1517 
1518 		Assert(var->varlevelsup == 0);
1519 
1520 		/*
1521 		 * We should not see any Vars marked INNER_VAR or OUTER_VAR.  But an
1522 		 * indexqual expression could contain INDEX_VAR Vars.
1523 		 */
1524 		Assert(var->varno != INNER_VAR);
1525 		Assert(var->varno != OUTER_VAR);
1526 		if (!IS_SPECIAL_VARNO(var->varno))
1527 			var->varno += context->rtoffset;
1528 		if (var->varnoold > 0)
1529 			var->varnoold += context->rtoffset;
1530 		return (Node *) var;
1531 	}
1532 	if (IsA(node, Param))
1533 		return fix_param_node(context->root, (Param *) node);
1534 	if (IsA(node, Aggref))
1535 	{
1536 		Aggref	   *aggref = (Aggref *) node;
1537 
1538 		/* See if the Aggref should be replaced by a Param */
1539 		if (context->root->minmax_aggs != NIL &&
1540 			list_length(aggref->args) == 1)
1541 		{
1542 			TargetEntry *curTarget = (TargetEntry *) linitial(aggref->args);
1543 			ListCell   *lc;
1544 
1545 			foreach(lc, context->root->minmax_aggs)
1546 			{
1547 				MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
1548 
1549 				if (mminfo->aggfnoid == aggref->aggfnoid &&
1550 					equal(mminfo->target, curTarget->expr))
1551 					return (Node *) copyObject(mminfo->param);
1552 			}
1553 		}
1554 		/* If no match, just fall through to process it normally */
1555 	}
1556 	if (IsA(node, CurrentOfExpr))
1557 	{
1558 		CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node);
1559 
1560 		Assert(cexpr->cvarno != INNER_VAR);
1561 		Assert(cexpr->cvarno != OUTER_VAR);
1562 		if (!IS_SPECIAL_VARNO(cexpr->cvarno))
1563 			cexpr->cvarno += context->rtoffset;
1564 		return (Node *) cexpr;
1565 	}
1566 	if (IsA(node, PlaceHolderVar))
1567 	{
1568 		/* At scan level, we should always just evaluate the contained expr */
1569 		PlaceHolderVar *phv = (PlaceHolderVar *) node;
1570 
1571 		return fix_scan_expr_mutator((Node *) phv->phexpr, context);
1572 	}
1573 	fix_expr_common(context->root, node);
1574 	return expression_tree_mutator(node, fix_scan_expr_mutator,
1575 								   (void *) context);
1576 }
1577 
1578 static bool
fix_scan_expr_walker(Node * node,fix_scan_expr_context * context)1579 fix_scan_expr_walker(Node *node, fix_scan_expr_context *context)
1580 {
1581 	if (node == NULL)
1582 		return false;
1583 	Assert(!IsA(node, PlaceHolderVar));
1584 	fix_expr_common(context->root, node);
1585 	return expression_tree_walker(node, fix_scan_expr_walker,
1586 								  (void *) context);
1587 }
1588 
1589 /*
1590  * set_join_references
1591  *	  Modify the target list and quals of a join node to reference its
1592  *	  subplans, by setting the varnos to OUTER_VAR or INNER_VAR and setting
1593  *	  attno values to the result domain number of either the corresponding
1594  *	  outer or inner join tuple item.  Also perform opcode lookup for these
1595  *	  expressions, and add regclass OIDs to root->glob->relationOids.
1596  */
1597 static void
set_join_references(PlannerInfo * root,Join * join,int rtoffset)1598 set_join_references(PlannerInfo *root, Join *join, int rtoffset)
1599 {
1600 	Plan	   *outer_plan = join->plan.lefttree;
1601 	Plan	   *inner_plan = join->plan.righttree;
1602 	indexed_tlist *outer_itlist;
1603 	indexed_tlist *inner_itlist;
1604 
1605 	outer_itlist = build_tlist_index(outer_plan->targetlist);
1606 	inner_itlist = build_tlist_index(inner_plan->targetlist);
1607 
1608 	/*
1609 	 * First process the joinquals (including merge or hash clauses).  These
1610 	 * are logically below the join so they can always use all values
1611 	 * available from the input tlists.  It's okay to also handle
1612 	 * NestLoopParams now, because those couldn't refer to nullable
1613 	 * subexpressions.
1614 	 */
1615 	join->joinqual = fix_join_expr(root,
1616 								   join->joinqual,
1617 								   outer_itlist,
1618 								   inner_itlist,
1619 								   (Index) 0,
1620 								   rtoffset);
1621 
1622 	/* Now do join-type-specific stuff */
1623 	if (IsA(join, NestLoop))
1624 	{
1625 		NestLoop   *nl = (NestLoop *) join;
1626 		ListCell   *lc;
1627 
1628 		foreach(lc, nl->nestParams)
1629 		{
1630 			NestLoopParam *nlp = (NestLoopParam *) lfirst(lc);
1631 
1632 			nlp->paramval = (Var *) fix_upper_expr(root,
1633 												   (Node *) nlp->paramval,
1634 												   outer_itlist,
1635 												   OUTER_VAR,
1636 												   rtoffset);
1637 			/* Check we replaced any PlaceHolderVar with simple Var */
1638 			if (!(IsA(nlp->paramval, Var) &&
1639 				  nlp->paramval->varno == OUTER_VAR))
1640 				elog(ERROR, "NestLoopParam was not reduced to a simple Var");
1641 		}
1642 	}
1643 	else if (IsA(join, MergeJoin))
1644 	{
1645 		MergeJoin  *mj = (MergeJoin *) join;
1646 
1647 		mj->mergeclauses = fix_join_expr(root,
1648 										 mj->mergeclauses,
1649 										 outer_itlist,
1650 										 inner_itlist,
1651 										 (Index) 0,
1652 										 rtoffset);
1653 	}
1654 	else if (IsA(join, HashJoin))
1655 	{
1656 		HashJoin   *hj = (HashJoin *) join;
1657 
1658 		hj->hashclauses = fix_join_expr(root,
1659 										hj->hashclauses,
1660 										outer_itlist,
1661 										inner_itlist,
1662 										(Index) 0,
1663 										rtoffset);
1664 	}
1665 
1666 	/*
1667 	 * Now we need to fix up the targetlist and qpqual, which are logically
1668 	 * above the join.  This means they should not re-use any input expression
1669 	 * that was computed in the nullable side of an outer join.  Vars and
1670 	 * PlaceHolderVars are fine, so we can implement this restriction just by
1671 	 * clearing has_non_vars in the indexed_tlist structs.
1672 	 *
1673 	 * XXX This is a grotty workaround for the fact that we don't clearly
1674 	 * distinguish between a Var appearing below an outer join and the "same"
1675 	 * Var appearing above it.  If we did, we'd not need to hack the matching
1676 	 * rules this way.
1677 	 */
1678 	switch (join->jointype)
1679 	{
1680 		case JOIN_LEFT:
1681 		case JOIN_SEMI:
1682 		case JOIN_ANTI:
1683 			inner_itlist->has_non_vars = false;
1684 			break;
1685 		case JOIN_RIGHT:
1686 			outer_itlist->has_non_vars = false;
1687 			break;
1688 		case JOIN_FULL:
1689 			outer_itlist->has_non_vars = false;
1690 			inner_itlist->has_non_vars = false;
1691 			break;
1692 		default:
1693 			break;
1694 	}
1695 
1696 	join->plan.targetlist = fix_join_expr(root,
1697 										  join->plan.targetlist,
1698 										  outer_itlist,
1699 										  inner_itlist,
1700 										  (Index) 0,
1701 										  rtoffset);
1702 	join->plan.qual = fix_join_expr(root,
1703 									join->plan.qual,
1704 									outer_itlist,
1705 									inner_itlist,
1706 									(Index) 0,
1707 									rtoffset);
1708 
1709 	pfree(outer_itlist);
1710 	pfree(inner_itlist);
1711 }
1712 
1713 /*
1714  * set_upper_references
1715  *	  Update the targetlist and quals of an upper-level plan node
1716  *	  to refer to the tuples returned by its lefttree subplan.
1717  *	  Also perform opcode lookup for these expressions, and
1718  *	  add regclass OIDs to root->glob->relationOids.
1719  *
1720  * This is used for single-input plan types like Agg, Group, Result.
1721  *
1722  * In most cases, we have to match up individual Vars in the tlist and
1723  * qual expressions with elements of the subplan's tlist (which was
1724  * generated by flattening these selfsame expressions, so it should have all
1725  * the required variables).  There is an important exception, however:
1726  * depending on where we are in the plan tree, sort/group columns may have
1727  * been pushed into the subplan tlist unflattened.  If these values are also
1728  * needed in the output then we want to reference the subplan tlist element
1729  * rather than recomputing the expression.
1730  */
1731 static void
set_upper_references(PlannerInfo * root,Plan * plan,int rtoffset)1732 set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset)
1733 {
1734 	Plan	   *subplan = plan->lefttree;
1735 	indexed_tlist *subplan_itlist;
1736 	List	   *output_targetlist;
1737 	ListCell   *l;
1738 
1739 	subplan_itlist = build_tlist_index(subplan->targetlist);
1740 
1741 	output_targetlist = NIL;
1742 	foreach(l, plan->targetlist)
1743 	{
1744 		TargetEntry *tle = (TargetEntry *) lfirst(l);
1745 		Node	   *newexpr;
1746 
1747 		/* If it's a sort/group item, first try to match by sortref */
1748 		if (tle->ressortgroupref != 0)
1749 		{
1750 			newexpr = (Node *)
1751 				search_indexed_tlist_for_sortgroupref(tle->expr,
1752 													  tle->ressortgroupref,
1753 													  subplan_itlist,
1754 													  OUTER_VAR);
1755 			if (!newexpr)
1756 				newexpr = fix_upper_expr(root,
1757 										 (Node *) tle->expr,
1758 										 subplan_itlist,
1759 										 OUTER_VAR,
1760 										 rtoffset);
1761 		}
1762 		else
1763 			newexpr = fix_upper_expr(root,
1764 									 (Node *) tle->expr,
1765 									 subplan_itlist,
1766 									 OUTER_VAR,
1767 									 rtoffset);
1768 		tle = flatCopyTargetEntry(tle);
1769 		tle->expr = (Expr *) newexpr;
1770 		output_targetlist = lappend(output_targetlist, tle);
1771 	}
1772 	plan->targetlist = output_targetlist;
1773 
1774 	plan->qual = (List *)
1775 		fix_upper_expr(root,
1776 					   (Node *) plan->qual,
1777 					   subplan_itlist,
1778 					   OUTER_VAR,
1779 					   rtoffset);
1780 
1781 	pfree(subplan_itlist);
1782 }
1783 
1784 /*
1785  * set_param_references
1786  *	  Initialize the initParam list in Gather or Gather merge node such that
1787  *	  it contains reference of all the params that needs to be evaluated
1788  *	  before execution of the node.  It contains the initplan params that are
1789  *	  being passed to the plan nodes below it.
1790  */
1791 static void
set_param_references(PlannerInfo * root,Plan * plan)1792 set_param_references(PlannerInfo *root, Plan *plan)
1793 {
1794 	Assert(IsA(plan, Gather) ||IsA(plan, GatherMerge));
1795 
1796 	if (plan->lefttree->extParam)
1797 	{
1798 		PlannerInfo *proot;
1799 		Bitmapset  *initSetParam = NULL;
1800 		ListCell   *l;
1801 
1802 		for (proot = root; proot != NULL; proot = proot->parent_root)
1803 		{
1804 			foreach(l, proot->init_plans)
1805 			{
1806 				SubPlan    *initsubplan = (SubPlan *) lfirst(l);
1807 				ListCell   *l2;
1808 
1809 				foreach(l2, initsubplan->setParam)
1810 				{
1811 					initSetParam = bms_add_member(initSetParam, lfirst_int(l2));
1812 				}
1813 			}
1814 		}
1815 
1816 		/*
1817 		 * Remember the list of all external initplan params that are used by
1818 		 * the children of Gather or Gather merge node.
1819 		 */
1820 		if (IsA(plan, Gather))
1821 			((Gather *) plan)->initParam =
1822 				bms_intersect(plan->lefttree->extParam, initSetParam);
1823 		else
1824 			((GatherMerge *) plan)->initParam =
1825 				bms_intersect(plan->lefttree->extParam, initSetParam);
1826 	}
1827 }
1828 
1829 /*
1830  * Recursively scan an expression tree and convert Aggrefs to the proper
1831  * intermediate form for combining aggregates.  This means (1) replacing each
1832  * one's argument list with a single argument that is the original Aggref
1833  * modified to show partial aggregation and (2) changing the upper Aggref to
1834  * show combining aggregation.
1835  *
1836  * After this step, set_upper_references will replace the partial Aggrefs
1837  * with Vars referencing the lower Agg plan node's outputs, so that the final
1838  * form seen by the executor is a combining Aggref with a Var as input.
1839  *
1840  * It's rather messy to postpone this step until setrefs.c; ideally it'd be
1841  * done in createplan.c.  The difficulty is that once we modify the Aggref
1842  * expressions, they will no longer be equal() to their original form and
1843  * so cross-plan-node-level matches will fail.  So this has to happen after
1844  * the plan node above the Agg has resolved its subplan references.
1845  */
1846 static Node *
convert_combining_aggrefs(Node * node,void * context)1847 convert_combining_aggrefs(Node *node, void *context)
1848 {
1849 	if (node == NULL)
1850 		return NULL;
1851 	if (IsA(node, Aggref))
1852 	{
1853 		Aggref	   *orig_agg = (Aggref *) node;
1854 		Aggref	   *child_agg;
1855 		Aggref	   *parent_agg;
1856 
1857 		/* Assert we've not chosen to partial-ize any unsupported cases */
1858 		Assert(orig_agg->aggorder == NIL);
1859 		Assert(orig_agg->aggdistinct == NIL);
1860 
1861 		/*
1862 		 * Since aggregate calls can't be nested, we needn't recurse into the
1863 		 * arguments.  But for safety, flat-copy the Aggref node itself rather
1864 		 * than modifying it in-place.
1865 		 */
1866 		child_agg = makeNode(Aggref);
1867 		memcpy(child_agg, orig_agg, sizeof(Aggref));
1868 
1869 		/*
1870 		 * For the parent Aggref, we want to copy all the fields of the
1871 		 * original aggregate *except* the args list, which we'll replace
1872 		 * below, and the aggfilter expression, which should be applied only
1873 		 * by the child not the parent.  Rather than explicitly knowing about
1874 		 * all the other fields here, we can momentarily modify child_agg to
1875 		 * provide a suitable source for copyObject.
1876 		 */
1877 		child_agg->args = NIL;
1878 		child_agg->aggfilter = NULL;
1879 		parent_agg = copyObject(child_agg);
1880 		child_agg->args = orig_agg->args;
1881 		child_agg->aggfilter = orig_agg->aggfilter;
1882 
1883 		/*
1884 		 * Now, set up child_agg to represent the first phase of partial
1885 		 * aggregation.  For now, assume serialization is required.
1886 		 */
1887 		mark_partial_aggref(child_agg, AGGSPLIT_INITIAL_SERIAL);
1888 
1889 		/*
1890 		 * And set up parent_agg to represent the second phase.
1891 		 */
1892 		parent_agg->args = list_make1(makeTargetEntry((Expr *) child_agg,
1893 													  1, NULL, false));
1894 		mark_partial_aggref(parent_agg, AGGSPLIT_FINAL_DESERIAL);
1895 
1896 		return (Node *) parent_agg;
1897 	}
1898 	return expression_tree_mutator(node, convert_combining_aggrefs,
1899 								   (void *) context);
1900 }
1901 
1902 /*
1903  * set_dummy_tlist_references
1904  *	  Replace the targetlist of an upper-level plan node with a simple
1905  *	  list of OUTER_VAR references to its child.
1906  *
1907  * This is used for plan types like Sort and Append that don't evaluate
1908  * their targetlists.  Although the executor doesn't care at all what's in
1909  * the tlist, EXPLAIN needs it to be realistic.
1910  *
1911  * Note: we could almost use set_upper_references() here, but it fails for
1912  * Append for lack of a lefttree subplan.  Single-purpose code is faster
1913  * anyway.
1914  */
1915 static void
set_dummy_tlist_references(Plan * plan,int rtoffset)1916 set_dummy_tlist_references(Plan *plan, int rtoffset)
1917 {
1918 	List	   *output_targetlist;
1919 	ListCell   *l;
1920 
1921 	output_targetlist = NIL;
1922 	foreach(l, plan->targetlist)
1923 	{
1924 		TargetEntry *tle = (TargetEntry *) lfirst(l);
1925 		Var		   *oldvar = (Var *) tle->expr;
1926 		Var		   *newvar;
1927 
1928 		/*
1929 		 * As in search_indexed_tlist_for_non_var(), we prefer to keep Consts
1930 		 * as Consts, not Vars referencing Consts.  Here, there's no speed
1931 		 * advantage to be had, but it makes EXPLAIN output look cleaner, and
1932 		 * again it avoids confusing the executor.
1933 		 */
1934 		if (IsA(oldvar, Const))
1935 		{
1936 			/* just reuse the existing TLE node */
1937 			output_targetlist = lappend(output_targetlist, tle);
1938 			continue;
1939 		}
1940 
1941 		newvar = makeVar(OUTER_VAR,
1942 						 tle->resno,
1943 						 exprType((Node *) oldvar),
1944 						 exprTypmod((Node *) oldvar),
1945 						 exprCollation((Node *) oldvar),
1946 						 0);
1947 		if (IsA(oldvar, Var))
1948 		{
1949 			newvar->varnoold = oldvar->varno + rtoffset;
1950 			newvar->varoattno = oldvar->varattno;
1951 		}
1952 		else
1953 		{
1954 			newvar->varnoold = 0;	/* wasn't ever a plain Var */
1955 			newvar->varoattno = 0;
1956 		}
1957 
1958 		tle = flatCopyTargetEntry(tle);
1959 		tle->expr = (Expr *) newvar;
1960 		output_targetlist = lappend(output_targetlist, tle);
1961 	}
1962 	plan->targetlist = output_targetlist;
1963 
1964 	/* We don't touch plan->qual here */
1965 }
1966 
1967 
1968 /*
1969  * build_tlist_index --- build an index data structure for a child tlist
1970  *
1971  * In most cases, subplan tlists will be "flat" tlists with only Vars,
1972  * so we try to optimize that case by extracting information about Vars
1973  * in advance.  Matching a parent tlist to a child is still an O(N^2)
1974  * operation, but at least with a much smaller constant factor than plain
1975  * tlist_member() searches.
1976  *
1977  * The result of this function is an indexed_tlist struct to pass to
1978  * search_indexed_tlist_for_var() or search_indexed_tlist_for_non_var().
1979  * When done, the indexed_tlist may be freed with a single pfree().
1980  */
1981 static indexed_tlist *
build_tlist_index(List * tlist)1982 build_tlist_index(List *tlist)
1983 {
1984 	indexed_tlist *itlist;
1985 	tlist_vinfo *vinfo;
1986 	ListCell   *l;
1987 
1988 	/* Create data structure with enough slots for all tlist entries */
1989 	itlist = (indexed_tlist *)
1990 		palloc(offsetof(indexed_tlist, vars) +
1991 			   list_length(tlist) * sizeof(tlist_vinfo));
1992 
1993 	itlist->tlist = tlist;
1994 	itlist->has_ph_vars = false;
1995 	itlist->has_non_vars = false;
1996 
1997 	/* Find the Vars and fill in the index array */
1998 	vinfo = itlist->vars;
1999 	foreach(l, tlist)
2000 	{
2001 		TargetEntry *tle = (TargetEntry *) lfirst(l);
2002 
2003 		if (tle->expr && IsA(tle->expr, Var))
2004 		{
2005 			Var		   *var = (Var *) tle->expr;
2006 
2007 			vinfo->varno = var->varno;
2008 			vinfo->varattno = var->varattno;
2009 			vinfo->resno = tle->resno;
2010 			vinfo++;
2011 		}
2012 		else if (tle->expr && IsA(tle->expr, PlaceHolderVar))
2013 			itlist->has_ph_vars = true;
2014 		else
2015 			itlist->has_non_vars = true;
2016 	}
2017 
2018 	itlist->num_vars = (vinfo - itlist->vars);
2019 
2020 	return itlist;
2021 }
2022 
2023 /*
2024  * build_tlist_index_other_vars --- build a restricted tlist index
2025  *
2026  * This is like build_tlist_index, but we only index tlist entries that
2027  * are Vars belonging to some rel other than the one specified.  We will set
2028  * has_ph_vars (allowing PlaceHolderVars to be matched), but not has_non_vars
2029  * (so nothing other than Vars and PlaceHolderVars can be matched).
2030  */
2031 static indexed_tlist *
build_tlist_index_other_vars(List * tlist,Index ignore_rel)2032 build_tlist_index_other_vars(List *tlist, Index ignore_rel)
2033 {
2034 	indexed_tlist *itlist;
2035 	tlist_vinfo *vinfo;
2036 	ListCell   *l;
2037 
2038 	/* Create data structure with enough slots for all tlist entries */
2039 	itlist = (indexed_tlist *)
2040 		palloc(offsetof(indexed_tlist, vars) +
2041 			   list_length(tlist) * sizeof(tlist_vinfo));
2042 
2043 	itlist->tlist = tlist;
2044 	itlist->has_ph_vars = false;
2045 	itlist->has_non_vars = false;
2046 
2047 	/* Find the desired Vars and fill in the index array */
2048 	vinfo = itlist->vars;
2049 	foreach(l, tlist)
2050 	{
2051 		TargetEntry *tle = (TargetEntry *) lfirst(l);
2052 
2053 		if (tle->expr && IsA(tle->expr, Var))
2054 		{
2055 			Var		   *var = (Var *) tle->expr;
2056 
2057 			if (var->varno != ignore_rel)
2058 			{
2059 				vinfo->varno = var->varno;
2060 				vinfo->varattno = var->varattno;
2061 				vinfo->resno = tle->resno;
2062 				vinfo++;
2063 			}
2064 		}
2065 		else if (tle->expr && IsA(tle->expr, PlaceHolderVar))
2066 			itlist->has_ph_vars = true;
2067 	}
2068 
2069 	itlist->num_vars = (vinfo - itlist->vars);
2070 
2071 	return itlist;
2072 }
2073 
2074 /*
2075  * search_indexed_tlist_for_var --- find a Var in an indexed tlist
2076  *
2077  * If a match is found, return a copy of the given Var with suitably
2078  * modified varno/varattno (to wit, newvarno and the resno of the TLE entry).
2079  * Also ensure that varnoold is incremented by rtoffset.
2080  * If no match, return NULL.
2081  */
2082 static Var *
search_indexed_tlist_for_var(Var * var,indexed_tlist * itlist,Index newvarno,int rtoffset)2083 search_indexed_tlist_for_var(Var *var, indexed_tlist *itlist,
2084 							 Index newvarno, int rtoffset)
2085 {
2086 	Index		varno = var->varno;
2087 	AttrNumber	varattno = var->varattno;
2088 	tlist_vinfo *vinfo;
2089 	int			i;
2090 
2091 	vinfo = itlist->vars;
2092 	i = itlist->num_vars;
2093 	while (i-- > 0)
2094 	{
2095 		if (vinfo->varno == varno && vinfo->varattno == varattno)
2096 		{
2097 			/* Found a match */
2098 			Var		   *newvar = copyVar(var);
2099 
2100 			newvar->varno = newvarno;
2101 			newvar->varattno = vinfo->resno;
2102 			if (newvar->varnoold > 0)
2103 				newvar->varnoold += rtoffset;
2104 			return newvar;
2105 		}
2106 		vinfo++;
2107 	}
2108 	return NULL;				/* no match */
2109 }
2110 
2111 /*
2112  * search_indexed_tlist_for_non_var --- find a non-Var in an indexed tlist
2113  *
2114  * If a match is found, return a Var constructed to reference the tlist item.
2115  * If no match, return NULL.
2116  *
2117  * NOTE: it is a waste of time to call this unless itlist->has_ph_vars or
2118  * itlist->has_non_vars.  Furthermore, set_join_references() relies on being
2119  * able to prevent matching of non-Vars by clearing itlist->has_non_vars,
2120  * so there's a correctness reason not to call it unless that's set.
2121  */
2122 static Var *
search_indexed_tlist_for_non_var(Expr * node,indexed_tlist * itlist,Index newvarno)2123 search_indexed_tlist_for_non_var(Expr *node,
2124 								 indexed_tlist *itlist, Index newvarno)
2125 {
2126 	TargetEntry *tle;
2127 
2128 	/*
2129 	 * If it's a simple Const, replacing it with a Var is silly, even if there
2130 	 * happens to be an identical Const below; a Var is more expensive to
2131 	 * execute than a Const.  What's more, replacing it could confuse some
2132 	 * places in the executor that expect to see simple Consts for, eg,
2133 	 * dropped columns.
2134 	 */
2135 	if (IsA(node, Const))
2136 		return NULL;
2137 
2138 	tle = tlist_member(node, itlist->tlist);
2139 	if (tle)
2140 	{
2141 		/* Found a matching subplan output expression */
2142 		Var		   *newvar;
2143 
2144 		newvar = makeVarFromTargetEntry(newvarno, tle);
2145 		newvar->varnoold = 0;	/* wasn't ever a plain Var */
2146 		newvar->varoattno = 0;
2147 		return newvar;
2148 	}
2149 	return NULL;				/* no match */
2150 }
2151 
2152 /*
2153  * search_indexed_tlist_for_sortgroupref --- find a sort/group expression
2154  *
2155  * If a match is found, return a Var constructed to reference the tlist item.
2156  * If no match, return NULL.
2157  *
2158  * This is needed to ensure that we select the right subplan TLE in cases
2159  * where there are multiple textually-equal()-but-volatile sort expressions.
2160  * And it's also faster than search_indexed_tlist_for_non_var.
2161  */
2162 static Var *
search_indexed_tlist_for_sortgroupref(Expr * node,Index sortgroupref,indexed_tlist * itlist,Index newvarno)2163 search_indexed_tlist_for_sortgroupref(Expr *node,
2164 									  Index sortgroupref,
2165 									  indexed_tlist *itlist,
2166 									  Index newvarno)
2167 {
2168 	ListCell   *lc;
2169 
2170 	foreach(lc, itlist->tlist)
2171 	{
2172 		TargetEntry *tle = (TargetEntry *) lfirst(lc);
2173 
2174 		/* The equal() check should be redundant, but let's be paranoid */
2175 		if (tle->ressortgroupref == sortgroupref &&
2176 			equal(node, tle->expr))
2177 		{
2178 			/* Found a matching subplan output expression */
2179 			Var		   *newvar;
2180 
2181 			newvar = makeVarFromTargetEntry(newvarno, tle);
2182 			newvar->varnoold = 0;	/* wasn't ever a plain Var */
2183 			newvar->varoattno = 0;
2184 			return newvar;
2185 		}
2186 	}
2187 	return NULL;				/* no match */
2188 }
2189 
2190 /*
2191  * fix_join_expr
2192  *	   Create a new set of targetlist entries or join qual clauses by
2193  *	   changing the varno/varattno values of variables in the clauses
2194  *	   to reference target list values from the outer and inner join
2195  *	   relation target lists.  Also perform opcode lookup and add
2196  *	   regclass OIDs to root->glob->relationOids.
2197  *
2198  * This is used in three different scenarios:
2199  * 1) a normal join clause, where all the Vars in the clause *must* be
2200  *	  replaced by OUTER_VAR or INNER_VAR references.  In this case
2201  *	  acceptable_rel should be zero so that any failure to match a Var will be
2202  *	  reported as an error.
2203  * 2) RETURNING clauses, which may contain both Vars of the target relation
2204  *	  and Vars of other relations. In this case we want to replace the
2205  *	  other-relation Vars by OUTER_VAR references, while leaving target Vars
2206  *	  alone. Thus inner_itlist = NULL and acceptable_rel = the ID of the
2207  *	  target relation should be passed.
2208  * 3) ON CONFLICT UPDATE SET/WHERE clauses.  Here references to EXCLUDED are
2209  *	  to be replaced with INNER_VAR references, while leaving target Vars (the
2210  *	  to-be-updated relation) alone. Correspondingly inner_itlist is to be
2211  *	  EXCLUDED elements, outer_itlist = NULL and acceptable_rel the target
2212  *	  relation.
2213  *
2214  * 'clauses' is the targetlist or list of join clauses
2215  * 'outer_itlist' is the indexed target list of the outer join relation,
2216  *		or NULL
2217  * 'inner_itlist' is the indexed target list of the inner join relation,
2218  *		or NULL
2219  * 'acceptable_rel' is either zero or the rangetable index of a relation
2220  *		whose Vars may appear in the clause without provoking an error
2221  * 'rtoffset': how much to increment varnoold by
2222  *
2223  * Returns the new expression tree.  The original clause structure is
2224  * not modified.
2225  */
2226 static List *
fix_join_expr(PlannerInfo * root,List * clauses,indexed_tlist * outer_itlist,indexed_tlist * inner_itlist,Index acceptable_rel,int rtoffset)2227 fix_join_expr(PlannerInfo *root,
2228 			  List *clauses,
2229 			  indexed_tlist *outer_itlist,
2230 			  indexed_tlist *inner_itlist,
2231 			  Index acceptable_rel,
2232 			  int rtoffset)
2233 {
2234 	fix_join_expr_context context;
2235 
2236 	context.root = root;
2237 	context.outer_itlist = outer_itlist;
2238 	context.inner_itlist = inner_itlist;
2239 	context.acceptable_rel = acceptable_rel;
2240 	context.rtoffset = rtoffset;
2241 	return (List *) fix_join_expr_mutator((Node *) clauses, &context);
2242 }
2243 
2244 static Node *
fix_join_expr_mutator(Node * node,fix_join_expr_context * context)2245 fix_join_expr_mutator(Node *node, fix_join_expr_context *context)
2246 {
2247 	Var		   *newvar;
2248 
2249 	if (node == NULL)
2250 		return NULL;
2251 	if (IsA(node, Var))
2252 	{
2253 		Var		   *var = (Var *) node;
2254 
2255 		/* Look for the var in the input tlists, first in the outer */
2256 		if (context->outer_itlist)
2257 		{
2258 			newvar = search_indexed_tlist_for_var(var,
2259 												  context->outer_itlist,
2260 												  OUTER_VAR,
2261 												  context->rtoffset);
2262 			if (newvar)
2263 				return (Node *) newvar;
2264 		}
2265 
2266 		/* then in the inner. */
2267 		if (context->inner_itlist)
2268 		{
2269 			newvar = search_indexed_tlist_for_var(var,
2270 												  context->inner_itlist,
2271 												  INNER_VAR,
2272 												  context->rtoffset);
2273 			if (newvar)
2274 				return (Node *) newvar;
2275 		}
2276 
2277 		/* If it's for acceptable_rel, adjust and return it */
2278 		if (var->varno == context->acceptable_rel)
2279 		{
2280 			var = copyVar(var);
2281 			var->varno += context->rtoffset;
2282 			if (var->varnoold > 0)
2283 				var->varnoold += context->rtoffset;
2284 			return (Node *) var;
2285 		}
2286 
2287 		/* No referent found for Var */
2288 		elog(ERROR, "variable not found in subplan target lists");
2289 	}
2290 	if (IsA(node, PlaceHolderVar))
2291 	{
2292 		PlaceHolderVar *phv = (PlaceHolderVar *) node;
2293 
2294 		/* See if the PlaceHolderVar has bubbled up from a lower plan node */
2295 		if (context->outer_itlist && context->outer_itlist->has_ph_vars)
2296 		{
2297 			newvar = search_indexed_tlist_for_non_var((Expr *) phv,
2298 													  context->outer_itlist,
2299 													  OUTER_VAR);
2300 			if (newvar)
2301 				return (Node *) newvar;
2302 		}
2303 		if (context->inner_itlist && context->inner_itlist->has_ph_vars)
2304 		{
2305 			newvar = search_indexed_tlist_for_non_var((Expr *) phv,
2306 													  context->inner_itlist,
2307 													  INNER_VAR);
2308 			if (newvar)
2309 				return (Node *) newvar;
2310 		}
2311 
2312 		/* If not supplied by input plans, evaluate the contained expr */
2313 		return fix_join_expr_mutator((Node *) phv->phexpr, context);
2314 	}
2315 	/* Try matching more complex expressions too, if tlists have any */
2316 	if (context->outer_itlist && context->outer_itlist->has_non_vars)
2317 	{
2318 		newvar = search_indexed_tlist_for_non_var((Expr *) node,
2319 												  context->outer_itlist,
2320 												  OUTER_VAR);
2321 		if (newvar)
2322 			return (Node *) newvar;
2323 	}
2324 	if (context->inner_itlist && context->inner_itlist->has_non_vars)
2325 	{
2326 		newvar = search_indexed_tlist_for_non_var((Expr *) node,
2327 												  context->inner_itlist,
2328 												  INNER_VAR);
2329 		if (newvar)
2330 			return (Node *) newvar;
2331 	}
2332 	/* Special cases (apply only AFTER failing to match to lower tlist) */
2333 	if (IsA(node, Param))
2334 		return fix_param_node(context->root, (Param *) node);
2335 	fix_expr_common(context->root, node);
2336 	return expression_tree_mutator(node,
2337 								   fix_join_expr_mutator,
2338 								   (void *) context);
2339 }
2340 
2341 /*
2342  * fix_upper_expr
2343  *		Modifies an expression tree so that all Var nodes reference outputs
2344  *		of a subplan.  Also looks for Aggref nodes that should be replaced
2345  *		by initplan output Params.  Also performs opcode lookup, and adds
2346  *		regclass OIDs to root->glob->relationOids.
2347  *
2348  * This is used to fix up target and qual expressions of non-join upper-level
2349  * plan nodes, as well as index-only scan nodes.
2350  *
2351  * An error is raised if no matching var can be found in the subplan tlist
2352  * --- so this routine should only be applied to nodes whose subplans'
2353  * targetlists were generated by flattening the expressions used in the
2354  * parent node.
2355  *
2356  * If itlist->has_non_vars is true, then we try to match whole subexpressions
2357  * against elements of the subplan tlist, so that we can avoid recomputing
2358  * expressions that were already computed by the subplan.  (This is relatively
2359  * expensive, so we don't want to try it in the common case where the
2360  * subplan tlist is just a flattened list of Vars.)
2361  *
2362  * 'node': the tree to be fixed (a target item or qual)
2363  * 'subplan_itlist': indexed target list for subplan (or index)
2364  * 'newvarno': varno to use for Vars referencing tlist elements
2365  * 'rtoffset': how much to increment varnoold by
2366  *
2367  * The resulting tree is a copy of the original in which all Var nodes have
2368  * varno = newvarno, varattno = resno of corresponding targetlist element.
2369  * The original tree is not modified.
2370  */
2371 static Node *
fix_upper_expr(PlannerInfo * root,Node * node,indexed_tlist * subplan_itlist,Index newvarno,int rtoffset)2372 fix_upper_expr(PlannerInfo *root,
2373 			   Node *node,
2374 			   indexed_tlist *subplan_itlist,
2375 			   Index newvarno,
2376 			   int rtoffset)
2377 {
2378 	fix_upper_expr_context context;
2379 
2380 	context.root = root;
2381 	context.subplan_itlist = subplan_itlist;
2382 	context.newvarno = newvarno;
2383 	context.rtoffset = rtoffset;
2384 	return fix_upper_expr_mutator(node, &context);
2385 }
2386 
2387 static Node *
fix_upper_expr_mutator(Node * node,fix_upper_expr_context * context)2388 fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context)
2389 {
2390 	Var		   *newvar;
2391 
2392 	if (node == NULL)
2393 		return NULL;
2394 	if (IsA(node, Var))
2395 	{
2396 		Var		   *var = (Var *) node;
2397 
2398 		newvar = search_indexed_tlist_for_var(var,
2399 											  context->subplan_itlist,
2400 											  context->newvarno,
2401 											  context->rtoffset);
2402 		if (!newvar)
2403 			elog(ERROR, "variable not found in subplan target list");
2404 		return (Node *) newvar;
2405 	}
2406 	if (IsA(node, PlaceHolderVar))
2407 	{
2408 		PlaceHolderVar *phv = (PlaceHolderVar *) node;
2409 
2410 		/* See if the PlaceHolderVar has bubbled up from a lower plan node */
2411 		if (context->subplan_itlist->has_ph_vars)
2412 		{
2413 			newvar = search_indexed_tlist_for_non_var((Expr *) phv,
2414 													  context->subplan_itlist,
2415 													  context->newvarno);
2416 			if (newvar)
2417 				return (Node *) newvar;
2418 		}
2419 		/* If not supplied by input plan, evaluate the contained expr */
2420 		return fix_upper_expr_mutator((Node *) phv->phexpr, context);
2421 	}
2422 	/* Try matching more complex expressions too, if tlist has any */
2423 	if (context->subplan_itlist->has_non_vars)
2424 	{
2425 		newvar = search_indexed_tlist_for_non_var((Expr *) node,
2426 												  context->subplan_itlist,
2427 												  context->newvarno);
2428 		if (newvar)
2429 			return (Node *) newvar;
2430 	}
2431 	/* Special cases (apply only AFTER failing to match to lower tlist) */
2432 	if (IsA(node, Param))
2433 		return fix_param_node(context->root, (Param *) node);
2434 	if (IsA(node, Aggref))
2435 	{
2436 		Aggref	   *aggref = (Aggref *) node;
2437 
2438 		/* See if the Aggref should be replaced by a Param */
2439 		if (context->root->minmax_aggs != NIL &&
2440 			list_length(aggref->args) == 1)
2441 		{
2442 			TargetEntry *curTarget = (TargetEntry *) linitial(aggref->args);
2443 			ListCell   *lc;
2444 
2445 			foreach(lc, context->root->minmax_aggs)
2446 			{
2447 				MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
2448 
2449 				if (mminfo->aggfnoid == aggref->aggfnoid &&
2450 					equal(mminfo->target, curTarget->expr))
2451 					return (Node *) copyObject(mminfo->param);
2452 			}
2453 		}
2454 		/* If no match, just fall through to process it normally */
2455 	}
2456 	fix_expr_common(context->root, node);
2457 	return expression_tree_mutator(node,
2458 								   fix_upper_expr_mutator,
2459 								   (void *) context);
2460 }
2461 
2462 /*
2463  * set_returning_clause_references
2464  *		Perform setrefs.c's work on a RETURNING targetlist
2465  *
2466  * If the query involves more than just the result table, we have to
2467  * adjust any Vars that refer to other tables to reference junk tlist
2468  * entries in the top subplan's targetlist.  Vars referencing the result
2469  * table should be left alone, however (the executor will evaluate them
2470  * using the actual heap tuple, after firing triggers if any).  In the
2471  * adjusted RETURNING list, result-table Vars will have their original
2472  * varno (plus rtoffset), but Vars for other rels will have varno OUTER_VAR.
2473  *
2474  * We also must perform opcode lookup and add regclass OIDs to
2475  * root->glob->relationOids.
2476  *
2477  * 'rlist': the RETURNING targetlist to be fixed
2478  * 'topplan': the top subplan node that will be just below the ModifyTable
2479  *		node (note it's not yet passed through set_plan_refs)
2480  * 'resultRelation': RT index of the associated result relation
2481  * 'rtoffset': how much to increment varnos by
2482  *
2483  * Note: the given 'root' is for the parent query level, not the 'topplan'.
2484  * This does not matter currently since we only access the dependency-item
2485  * lists in root->glob, but it would need some hacking if we wanted a root
2486  * that actually matches the subplan.
2487  *
2488  * Note: resultRelation is not yet adjusted by rtoffset.
2489  */
2490 static List *
set_returning_clause_references(PlannerInfo * root,List * rlist,Plan * topplan,Index resultRelation,int rtoffset)2491 set_returning_clause_references(PlannerInfo *root,
2492 								List *rlist,
2493 								Plan *topplan,
2494 								Index resultRelation,
2495 								int rtoffset)
2496 {
2497 	indexed_tlist *itlist;
2498 
2499 	/*
2500 	 * We can perform the desired Var fixup by abusing the fix_join_expr
2501 	 * machinery that formerly handled inner indexscan fixup.  We search the
2502 	 * top plan's targetlist for Vars of non-result relations, and use
2503 	 * fix_join_expr to convert RETURNING Vars into references to those tlist
2504 	 * entries, while leaving result-rel Vars as-is.
2505 	 *
2506 	 * PlaceHolderVars will also be sought in the targetlist, but no
2507 	 * more-complex expressions will be.  Note that it is not possible for a
2508 	 * PlaceHolderVar to refer to the result relation, since the result is
2509 	 * never below an outer join.  If that case could happen, we'd have to be
2510 	 * prepared to pick apart the PlaceHolderVar and evaluate its contained
2511 	 * expression instead.
2512 	 */
2513 	itlist = build_tlist_index_other_vars(topplan->targetlist, resultRelation);
2514 
2515 	rlist = fix_join_expr(root,
2516 						  rlist,
2517 						  itlist,
2518 						  NULL,
2519 						  resultRelation,
2520 						  rtoffset);
2521 
2522 	pfree(itlist);
2523 
2524 	return rlist;
2525 }
2526 
2527 
2528 /*****************************************************************************
2529  *					QUERY DEPENDENCY MANAGEMENT
2530  *****************************************************************************/
2531 
2532 /*
2533  * record_plan_function_dependency
2534  *		Mark the current plan as depending on a particular function.
2535  *
2536  * This is exported so that the function-inlining code can record a
2537  * dependency on a function that it's removed from the plan tree.
2538  */
2539 void
record_plan_function_dependency(PlannerInfo * root,Oid funcid)2540 record_plan_function_dependency(PlannerInfo *root, Oid funcid)
2541 {
2542 	/*
2543 	 * For performance reasons, we don't bother to track built-in functions;
2544 	 * we just assume they'll never change (or at least not in ways that'd
2545 	 * invalidate plans using them).  For this purpose we can consider a
2546 	 * built-in function to be one with OID less than FirstBootstrapObjectId.
2547 	 * Note that the OID generator guarantees never to generate such an OID
2548 	 * after startup, even at OID wraparound.
2549 	 */
2550 	if (funcid >= (Oid) FirstBootstrapObjectId)
2551 	{
2552 		PlanInvalItem *inval_item = makeNode(PlanInvalItem);
2553 
2554 		/*
2555 		 * It would work to use any syscache on pg_proc, but the easiest is
2556 		 * PROCOID since we already have the function's OID at hand.  Note
2557 		 * that plancache.c knows we use PROCOID.
2558 		 */
2559 		inval_item->cacheId = PROCOID;
2560 		inval_item->hashValue = GetSysCacheHashValue1(PROCOID,
2561 													  ObjectIdGetDatum(funcid));
2562 
2563 		root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
2564 	}
2565 }
2566 
2567 /*
2568  * extract_query_dependencies
2569  *		Given a rewritten, but not yet planned, query or queries
2570  *		(i.e. a Query node or list of Query nodes), extract dependencies
2571  *		just as set_plan_references would do.  Also detect whether any
2572  *		rewrite steps were affected by RLS.
2573  *
2574  * This is needed by plancache.c to handle invalidation of cached unplanned
2575  * queries.
2576  */
2577 void
extract_query_dependencies(Node * query,List ** relationOids,List ** invalItems,bool * hasRowSecurity)2578 extract_query_dependencies(Node *query,
2579 						   List **relationOids,
2580 						   List **invalItems,
2581 						   bool *hasRowSecurity)
2582 {
2583 	PlannerGlobal glob;
2584 	PlannerInfo root;
2585 
2586 	/* Make up dummy planner state so we can use this module's machinery */
2587 	MemSet(&glob, 0, sizeof(glob));
2588 	glob.type = T_PlannerGlobal;
2589 	glob.relationOids = NIL;
2590 	glob.invalItems = NIL;
2591 	/* Hack: we use glob.dependsOnRole to collect hasRowSecurity flags */
2592 	glob.dependsOnRole = false;
2593 
2594 	MemSet(&root, 0, sizeof(root));
2595 	root.type = T_PlannerInfo;
2596 	root.glob = &glob;
2597 
2598 	(void) extract_query_dependencies_walker(query, &root);
2599 
2600 	*relationOids = glob.relationOids;
2601 	*invalItems = glob.invalItems;
2602 	*hasRowSecurity = glob.dependsOnRole;
2603 }
2604 
2605 static bool
extract_query_dependencies_walker(Node * node,PlannerInfo * context)2606 extract_query_dependencies_walker(Node *node, PlannerInfo *context)
2607 {
2608 	if (node == NULL)
2609 		return false;
2610 	Assert(!IsA(node, PlaceHolderVar));
2611 	/* Extract function dependencies and check for regclass Consts */
2612 	fix_expr_common(context, node);
2613 	if (IsA(node, Query))
2614 	{
2615 		Query	   *query = (Query *) node;
2616 		ListCell   *lc;
2617 
2618 		if (query->commandType == CMD_UTILITY)
2619 		{
2620 			/*
2621 			 * Ignore utility statements, except those (such as EXPLAIN) that
2622 			 * contain a parsed-but-not-planned query.
2623 			 */
2624 			query = UtilityContainsQuery(query->utilityStmt);
2625 			if (query == NULL)
2626 				return false;
2627 		}
2628 
2629 		/* Remember if any Query has RLS quals applied by rewriter */
2630 		if (query->hasRowSecurity)
2631 			context->glob->dependsOnRole = true;
2632 
2633 		/* Collect relation OIDs in this Query's rtable */
2634 		foreach(lc, query->rtable)
2635 		{
2636 			RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
2637 
2638 			if (rte->rtekind == RTE_RELATION)
2639 				context->glob->relationOids =
2640 					lappend_oid(context->glob->relationOids, rte->relid);
2641 			else if (rte->rtekind == RTE_NAMEDTUPLESTORE &&
2642 					 OidIsValid(rte->relid))
2643 				context->glob->relationOids =
2644 					lappend_oid(context->glob->relationOids,
2645 								rte->relid);
2646 		}
2647 
2648 		/* And recurse into the query's subexpressions */
2649 		return query_tree_walker(query, extract_query_dependencies_walker,
2650 								 (void *) context, 0);
2651 	}
2652 	return expression_tree_walker(node, extract_query_dependencies_walker,
2653 								  (void *) context);
2654 }
2655