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