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