1 /*-------------------------------------------------------------------------
2  *
3  * inherit.c
4  *	  Routines to process child relations in inheritance trees
5  *
6  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *	  src/backend/optimizer/path/inherit.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include "access/sysattr.h"
18 #include "access/table.h"
19 #include "catalog/partition.h"
20 #include "catalog/pg_inherits.h"
21 #include "catalog/pg_type.h"
22 #include "miscadmin.h"
23 #include "nodes/makefuncs.h"
24 #include "optimizer/appendinfo.h"
25 #include "optimizer/inherit.h"
26 #include "optimizer/optimizer.h"
27 #include "optimizer/pathnode.h"
28 #include "optimizer/planmain.h"
29 #include "optimizer/planner.h"
30 #include "optimizer/prep.h"
31 #include "optimizer/restrictinfo.h"
32 #include "parser/parsetree.h"
33 #include "partitioning/partdesc.h"
34 #include "partitioning/partprune.h"
35 #include "utils/rel.h"
36 
37 
38 /* source-code-compatibility hacks for pull_varnos() API change */
39 #define make_restrictinfo(a,b,c,d,e,f,g,h,i) make_restrictinfo_new(a,b,c,d,e,f,g,h,i)
40 
41 static void expand_partitioned_rtentry(PlannerInfo *root, RelOptInfo *relinfo,
42 									   RangeTblEntry *parentrte,
43 									   Index parentRTindex, Relation parentrel,
44 									   PlanRowMark *top_parentrc, LOCKMODE lockmode);
45 static void expand_single_inheritance_child(PlannerInfo *root,
46 											RangeTblEntry *parentrte,
47 											Index parentRTindex, Relation parentrel,
48 											PlanRowMark *top_parentrc, Relation childrel,
49 											RangeTblEntry **childrte_p,
50 											Index *childRTindex_p);
51 static Bitmapset *translate_col_privs(const Bitmapset *parent_privs,
52 									  List *translated_vars);
53 static void expand_appendrel_subquery(PlannerInfo *root, RelOptInfo *rel,
54 									  RangeTblEntry *rte, Index rti);
55 
56 
57 /*
58  * expand_inherited_rtentry
59  *		Expand a rangetable entry that has the "inh" bit set.
60  *
61  * "inh" is only allowed in two cases: RELATION and SUBQUERY RTEs.
62  *
63  * "inh" on a plain RELATION RTE means that it is a partitioned table or the
64  * parent of a traditional-inheritance set.  In this case we must add entries
65  * for all the interesting child tables to the query's rangetable, and build
66  * additional planner data structures for them, including RelOptInfos,
67  * AppendRelInfos, and possibly PlanRowMarks.
68  *
69  * Note that the original RTE is considered to represent the whole inheritance
70  * set.  In the case of traditional inheritance, the first of the generated
71  * RTEs is an RTE for the same table, but with inh = false, to represent the
72  * parent table in its role as a simple member of the inheritance set.  For
73  * partitioning, we don't need a second RTE because the partitioned table
74  * itself has no data and need not be scanned.
75  *
76  * "inh" on a SUBQUERY RTE means that it's the parent of a UNION ALL group,
77  * which is treated as an appendrel similarly to inheritance cases; however,
78  * we already made RTEs and AppendRelInfos for the subqueries.  We only need
79  * to build RelOptInfos for them, which is done by expand_appendrel_subquery.
80  */
81 void
expand_inherited_rtentry(PlannerInfo * root,RelOptInfo * rel,RangeTblEntry * rte,Index rti)82 expand_inherited_rtentry(PlannerInfo *root, RelOptInfo *rel,
83 						 RangeTblEntry *rte, Index rti)
84 {
85 	Oid			parentOID;
86 	Relation	oldrelation;
87 	LOCKMODE	lockmode;
88 	PlanRowMark *oldrc;
89 	bool		old_isParent = false;
90 	int			old_allMarkTypes = 0;
91 
92 	Assert(rte->inh);			/* else caller error */
93 
94 	if (rte->rtekind == RTE_SUBQUERY)
95 	{
96 		expand_appendrel_subquery(root, rel, rte, rti);
97 		return;
98 	}
99 
100 	Assert(rte->rtekind == RTE_RELATION);
101 
102 	parentOID = rte->relid;
103 
104 	/*
105 	 * We used to check has_subclass() here, but there's no longer any need
106 	 * to, because subquery_planner already did.
107 	 */
108 
109 	/*
110 	 * The rewriter should already have obtained an appropriate lock on each
111 	 * relation named in the query, so we can open the parent relation without
112 	 * locking it.  However, for each child relation we add to the query, we
113 	 * must obtain an appropriate lock, because this will be the first use of
114 	 * those relations in the parse/rewrite/plan pipeline.  Child rels should
115 	 * use the same lockmode as their parent.
116 	 */
117 	oldrelation = table_open(parentOID, NoLock);
118 	lockmode = rte->rellockmode;
119 
120 	/*
121 	 * If parent relation is selected FOR UPDATE/SHARE, we need to mark its
122 	 * PlanRowMark as isParent = true, and generate a new PlanRowMark for each
123 	 * child.
124 	 */
125 	oldrc = get_plan_rowmark(root->rowMarks, rti);
126 	if (oldrc)
127 	{
128 		old_isParent = oldrc->isParent;
129 		oldrc->isParent = true;
130 		/* Save initial value of allMarkTypes before children add to it */
131 		old_allMarkTypes = oldrc->allMarkTypes;
132 	}
133 
134 	/* Scan the inheritance set and expand it */
135 	if (oldrelation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
136 	{
137 		/*
138 		 * Partitioned table, so set up for partitioning.
139 		 */
140 		Assert(rte->relkind == RELKIND_PARTITIONED_TABLE);
141 
142 		/*
143 		 * Recursively expand and lock the partitions.  While at it, also
144 		 * extract the partition key columns of all the partitioned tables.
145 		 */
146 		expand_partitioned_rtentry(root, rel, rte, rti,
147 								   oldrelation, oldrc, lockmode);
148 	}
149 	else
150 	{
151 		/*
152 		 * Ordinary table, so process traditional-inheritance children.  (Note
153 		 * that partitioned tables are not allowed to have inheritance
154 		 * children, so it's not possible for both cases to apply.)
155 		 */
156 		List	   *inhOIDs;
157 		ListCell   *l;
158 
159 		/* Scan for all members of inheritance set, acquire needed locks */
160 		inhOIDs = find_all_inheritors(parentOID, lockmode, NULL);
161 
162 		/*
163 		 * We used to special-case the situation where the table no longer has
164 		 * any children, by clearing rte->inh and exiting.  That no longer
165 		 * works, because this function doesn't get run until after decisions
166 		 * have been made that depend on rte->inh.  We have to treat such
167 		 * situations as normal inheritance.  The table itself should always
168 		 * have been found, though.
169 		 */
170 		Assert(inhOIDs != NIL);
171 		Assert(linitial_oid(inhOIDs) == parentOID);
172 
173 		/* Expand simple_rel_array and friends to hold child objects. */
174 		expand_planner_arrays(root, list_length(inhOIDs));
175 
176 		/*
177 		 * Expand inheritance children in the order the OIDs were returned by
178 		 * find_all_inheritors.
179 		 */
180 		foreach(l, inhOIDs)
181 		{
182 			Oid			childOID = lfirst_oid(l);
183 			Relation	newrelation;
184 			RangeTblEntry *childrte;
185 			Index		childRTindex;
186 
187 			/* Open rel if needed; we already have required locks */
188 			if (childOID != parentOID)
189 				newrelation = table_open(childOID, NoLock);
190 			else
191 				newrelation = oldrelation;
192 
193 			/*
194 			 * It is possible that the parent table has children that are temp
195 			 * tables of other backends.  We cannot safely access such tables
196 			 * (because of buffering issues), and the best thing to do seems
197 			 * to be to silently ignore them.
198 			 */
199 			if (childOID != parentOID && RELATION_IS_OTHER_TEMP(newrelation))
200 			{
201 				table_close(newrelation, lockmode);
202 				continue;
203 			}
204 
205 			/* Create RTE and AppendRelInfo, plus PlanRowMark if needed. */
206 			expand_single_inheritance_child(root, rte, rti, oldrelation,
207 											oldrc, newrelation,
208 											&childrte, &childRTindex);
209 
210 			/* Create the otherrel RelOptInfo too. */
211 			(void) build_simple_rel(root, childRTindex, rel);
212 
213 			/* Close child relations, but keep locks */
214 			if (childOID != parentOID)
215 				table_close(newrelation, NoLock);
216 		}
217 	}
218 
219 	/*
220 	 * Some children might require different mark types, which would've been
221 	 * reported into oldrc.  If so, add relevant entries to the top-level
222 	 * targetlist and update parent rel's reltarget.  This should match what
223 	 * preprocess_targetlist() would have added if the mark types had been
224 	 * requested originally.
225 	 */
226 	if (oldrc)
227 	{
228 		int			new_allMarkTypes = oldrc->allMarkTypes;
229 		Var		   *var;
230 		TargetEntry *tle;
231 		char		resname[32];
232 		List	   *newvars = NIL;
233 
234 		/* Add TID junk Var if needed, unless we had it already */
235 		if (new_allMarkTypes & ~(1 << ROW_MARK_COPY) &&
236 			!(old_allMarkTypes & ~(1 << ROW_MARK_COPY)))
237 		{
238 			/* Need to fetch TID */
239 			var = makeVar(oldrc->rti,
240 						  SelfItemPointerAttributeNumber,
241 						  TIDOID,
242 						  -1,
243 						  InvalidOid,
244 						  0);
245 			snprintf(resname, sizeof(resname), "ctid%u", oldrc->rowmarkId);
246 			tle = makeTargetEntry((Expr *) var,
247 								  list_length(root->processed_tlist) + 1,
248 								  pstrdup(resname),
249 								  true);
250 			root->processed_tlist = lappend(root->processed_tlist, tle);
251 			newvars = lappend(newvars, var);
252 		}
253 
254 		/* Add whole-row junk Var if needed, unless we had it already */
255 		if ((new_allMarkTypes & (1 << ROW_MARK_COPY)) &&
256 			!(old_allMarkTypes & (1 << ROW_MARK_COPY)))
257 		{
258 			var = makeWholeRowVar(planner_rt_fetch(oldrc->rti, root),
259 								  oldrc->rti,
260 								  0,
261 								  false);
262 			snprintf(resname, sizeof(resname), "wholerow%u", oldrc->rowmarkId);
263 			tle = makeTargetEntry((Expr *) var,
264 								  list_length(root->processed_tlist) + 1,
265 								  pstrdup(resname),
266 								  true);
267 			root->processed_tlist = lappend(root->processed_tlist, tle);
268 			newvars = lappend(newvars, var);
269 		}
270 
271 		/* Add tableoid junk Var, unless we had it already */
272 		if (!old_isParent)
273 		{
274 			var = makeVar(oldrc->rti,
275 						  TableOidAttributeNumber,
276 						  OIDOID,
277 						  -1,
278 						  InvalidOid,
279 						  0);
280 			snprintf(resname, sizeof(resname), "tableoid%u", oldrc->rowmarkId);
281 			tle = makeTargetEntry((Expr *) var,
282 								  list_length(root->processed_tlist) + 1,
283 								  pstrdup(resname),
284 								  true);
285 			root->processed_tlist = lappend(root->processed_tlist, tle);
286 			newvars = lappend(newvars, var);
287 		}
288 
289 		/*
290 		 * Add the newly added Vars to parent's reltarget.  We needn't worry
291 		 * about the children's reltargets, they'll be made later.
292 		 */
293 		add_vars_to_targetlist(root, newvars, bms_make_singleton(0), false);
294 	}
295 
296 	table_close(oldrelation, NoLock);
297 }
298 
299 /*
300  * expand_partitioned_rtentry
301  *		Recursively expand an RTE for a partitioned table.
302  */
303 static void
expand_partitioned_rtentry(PlannerInfo * root,RelOptInfo * relinfo,RangeTblEntry * parentrte,Index parentRTindex,Relation parentrel,PlanRowMark * top_parentrc,LOCKMODE lockmode)304 expand_partitioned_rtentry(PlannerInfo *root, RelOptInfo *relinfo,
305 						   RangeTblEntry *parentrte,
306 						   Index parentRTindex, Relation parentrel,
307 						   PlanRowMark *top_parentrc, LOCKMODE lockmode)
308 {
309 	PartitionDesc partdesc;
310 	Bitmapset  *live_parts;
311 	int			num_live_parts;
312 	int			i;
313 
314 	check_stack_depth();
315 
316 	Assert(parentrte->inh);
317 
318 	partdesc = PartitionDirectoryLookup(root->glob->partition_directory,
319 										parentrel);
320 
321 	/* A partitioned table should always have a partition descriptor. */
322 	Assert(partdesc);
323 
324 	/*
325 	 * Note down whether any partition key cols are being updated. Though it's
326 	 * the root partitioned table's updatedCols we are interested in, we
327 	 * instead use parentrte to get the updatedCols. This is convenient
328 	 * because parentrte already has the root partrel's updatedCols translated
329 	 * to match the attribute ordering of parentrel.
330 	 */
331 	if (!root->partColsUpdated)
332 		root->partColsUpdated =
333 			has_partition_attrs(parentrel, parentrte->updatedCols, NULL);
334 
335 	/*
336 	 * There shouldn't be any generated columns in the partition key.
337 	 */
338 	Assert(!has_partition_attrs(parentrel, parentrte->extraUpdatedCols, NULL));
339 
340 	/* Nothing further to do here if there are no partitions. */
341 	if (partdesc->nparts == 0)
342 		return;
343 
344 	/*
345 	 * Perform partition pruning using restriction clauses assigned to parent
346 	 * relation.  live_parts will contain PartitionDesc indexes of partitions
347 	 * that survive pruning.  Below, we will initialize child objects for the
348 	 * surviving partitions.
349 	 */
350 	live_parts = prune_append_rel_partitions(relinfo);
351 
352 	/* Expand simple_rel_array and friends to hold child objects. */
353 	num_live_parts = bms_num_members(live_parts);
354 	if (num_live_parts > 0)
355 		expand_planner_arrays(root, num_live_parts);
356 
357 	/*
358 	 * We also store partition RelOptInfo pointers in the parent relation.
359 	 * Since we're palloc0'ing, slots corresponding to pruned partitions will
360 	 * contain NULL.
361 	 */
362 	Assert(relinfo->part_rels == NULL);
363 	relinfo->part_rels = (RelOptInfo **)
364 		palloc0(relinfo->nparts * sizeof(RelOptInfo *));
365 
366 	/*
367 	 * Create a child RTE for each live partition.  Note that unlike
368 	 * traditional inheritance, we don't need a child RTE for the partitioned
369 	 * table itself, because it's not going to be scanned.
370 	 */
371 	i = -1;
372 	while ((i = bms_next_member(live_parts, i)) >= 0)
373 	{
374 		Oid			childOID = partdesc->oids[i];
375 		Relation	childrel;
376 		RangeTblEntry *childrte;
377 		Index		childRTindex;
378 		RelOptInfo *childrelinfo;
379 
380 		/* Open rel, acquiring required locks */
381 		childrel = table_open(childOID, lockmode);
382 
383 		/*
384 		 * Temporary partitions belonging to other sessions should have been
385 		 * disallowed at definition, but for paranoia's sake, let's double
386 		 * check.
387 		 */
388 		if (RELATION_IS_OTHER_TEMP(childrel))
389 			elog(ERROR, "temporary relation from another session found as partition");
390 
391 		/* Create RTE and AppendRelInfo, plus PlanRowMark if needed. */
392 		expand_single_inheritance_child(root, parentrte, parentRTindex,
393 										parentrel, top_parentrc, childrel,
394 										&childrte, &childRTindex);
395 
396 		/* Create the otherrel RelOptInfo too. */
397 		childrelinfo = build_simple_rel(root, childRTindex, relinfo);
398 		relinfo->part_rels[i] = childrelinfo;
399 
400 		/* If this child is itself partitioned, recurse */
401 		if (childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
402 			expand_partitioned_rtentry(root, childrelinfo,
403 									   childrte, childRTindex,
404 									   childrel, top_parentrc, lockmode);
405 
406 		/* Close child relation, but keep locks */
407 		table_close(childrel, NoLock);
408 	}
409 }
410 
411 /*
412  * expand_single_inheritance_child
413  *		Build a RangeTblEntry and an AppendRelInfo, plus maybe a PlanRowMark.
414  *
415  * We now expand the partition hierarchy level by level, creating a
416  * corresponding hierarchy of AppendRelInfos and RelOptInfos, where each
417  * partitioned descendant acts as a parent of its immediate partitions.
418  * (This is a difference from what older versions of PostgreSQL did and what
419  * is still done in the case of table inheritance for unpartitioned tables,
420  * where the hierarchy is flattened during RTE expansion.)
421  *
422  * PlanRowMarks still carry the top-parent's RTI, and the top-parent's
423  * allMarkTypes field still accumulates values from all descendents.
424  *
425  * "parentrte" and "parentRTindex" are immediate parent's RTE and
426  * RTI. "top_parentrc" is top parent's PlanRowMark.
427  *
428  * The child RangeTblEntry and its RTI are returned in "childrte_p" and
429  * "childRTindex_p" resp.
430  */
431 static void
expand_single_inheritance_child(PlannerInfo * root,RangeTblEntry * parentrte,Index parentRTindex,Relation parentrel,PlanRowMark * top_parentrc,Relation childrel,RangeTblEntry ** childrte_p,Index * childRTindex_p)432 expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
433 								Index parentRTindex, Relation parentrel,
434 								PlanRowMark *top_parentrc, Relation childrel,
435 								RangeTblEntry **childrte_p,
436 								Index *childRTindex_p)
437 {
438 	Query	   *parse = root->parse;
439 	Oid			parentOID = RelationGetRelid(parentrel);
440 	Oid			childOID = RelationGetRelid(childrel);
441 	RangeTblEntry *childrte;
442 	Index		childRTindex;
443 	AppendRelInfo *appinfo;
444 
445 	/*
446 	 * Build an RTE for the child, and attach to query's rangetable list. We
447 	 * copy most fields of the parent's RTE, but replace relation OID,
448 	 * relkind, and inh for the child.  Also, set requiredPerms to zero since
449 	 * all required permissions checks are done on the original RTE. Likewise,
450 	 * set the child's securityQuals to empty, because we only want to apply
451 	 * the parent's RLS conditions regardless of what RLS properties
452 	 * individual children may have.  (This is an intentional choice to make
453 	 * inherited RLS work like regular permissions checks.) The parent
454 	 * securityQuals will be propagated to children along with other base
455 	 * restriction clauses, so we don't need to do it here.
456 	 */
457 	childrte = copyObject(parentrte);
458 	*childrte_p = childrte;
459 	childrte->relid = childOID;
460 	childrte->relkind = childrel->rd_rel->relkind;
461 	/* A partitioned child will need to be expanded further. */
462 	if (childrte->relkind == RELKIND_PARTITIONED_TABLE)
463 	{
464 		Assert(childOID != parentOID);
465 		childrte->inh = true;
466 	}
467 	else
468 		childrte->inh = false;
469 	childrte->requiredPerms = 0;
470 	childrte->securityQuals = NIL;
471 	parse->rtable = lappend(parse->rtable, childrte);
472 	childRTindex = list_length(parse->rtable);
473 	*childRTindex_p = childRTindex;
474 
475 	/*
476 	 * Build an AppendRelInfo struct for each parent/child pair.
477 	 */
478 	appinfo = make_append_rel_info(parentrel, childrel,
479 								   parentRTindex, childRTindex);
480 	root->append_rel_list = lappend(root->append_rel_list, appinfo);
481 
482 	/*
483 	 * Translate the column permissions bitmaps to the child's attnums (we
484 	 * have to build the translated_vars list before we can do this).  But if
485 	 * this is the parent table, we can leave copyObject's result alone.
486 	 *
487 	 * Note: we need to do this even though the executor won't run any
488 	 * permissions checks on the child RTE.  The insertedCols/updatedCols
489 	 * bitmaps may be examined for trigger-firing purposes.
490 	 */
491 	if (childOID != parentOID)
492 	{
493 		childrte->selectedCols = translate_col_privs(parentrte->selectedCols,
494 													 appinfo->translated_vars);
495 		childrte->insertedCols = translate_col_privs(parentrte->insertedCols,
496 													 appinfo->translated_vars);
497 		childrte->updatedCols = translate_col_privs(parentrte->updatedCols,
498 													appinfo->translated_vars);
499 		childrte->extraUpdatedCols = translate_col_privs(parentrte->extraUpdatedCols,
500 														 appinfo->translated_vars);
501 	}
502 
503 	/*
504 	 * Store the RTE and appinfo in the respective PlannerInfo arrays, which
505 	 * the caller must already have allocated space for.
506 	 */
507 	Assert(childRTindex < root->simple_rel_array_size);
508 	Assert(root->simple_rte_array[childRTindex] == NULL);
509 	root->simple_rte_array[childRTindex] = childrte;
510 	Assert(root->append_rel_array[childRTindex] == NULL);
511 	root->append_rel_array[childRTindex] = appinfo;
512 
513 	/*
514 	 * Build a PlanRowMark if parent is marked FOR UPDATE/SHARE.
515 	 */
516 	if (top_parentrc)
517 	{
518 		PlanRowMark *childrc = makeNode(PlanRowMark);
519 
520 		childrc->rti = childRTindex;
521 		childrc->prti = top_parentrc->rti;
522 		childrc->rowmarkId = top_parentrc->rowmarkId;
523 		/* Reselect rowmark type, because relkind might not match parent */
524 		childrc->markType = select_rowmark_type(childrte,
525 												top_parentrc->strength);
526 		childrc->allMarkTypes = (1 << childrc->markType);
527 		childrc->strength = top_parentrc->strength;
528 		childrc->waitPolicy = top_parentrc->waitPolicy;
529 
530 		/*
531 		 * We mark RowMarks for partitioned child tables as parent RowMarks so
532 		 * that the executor ignores them (except their existence means that
533 		 * the child tables will be locked using the appropriate mode).
534 		 */
535 		childrc->isParent = (childrte->relkind == RELKIND_PARTITIONED_TABLE);
536 
537 		/* Include child's rowmark type in top parent's allMarkTypes */
538 		top_parentrc->allMarkTypes |= childrc->allMarkTypes;
539 
540 		root->rowMarks = lappend(root->rowMarks, childrc);
541 	}
542 }
543 
544 /*
545  * translate_col_privs
546  *	  Translate a bitmapset representing per-column privileges from the
547  *	  parent rel's attribute numbering to the child's.
548  *
549  * The only surprise here is that we don't translate a parent whole-row
550  * reference into a child whole-row reference.  That would mean requiring
551  * permissions on all child columns, which is overly strict, since the
552  * query is really only going to reference the inherited columns.  Instead
553  * we set the per-column bits for all inherited columns.
554  */
555 static Bitmapset *
translate_col_privs(const Bitmapset * parent_privs,List * translated_vars)556 translate_col_privs(const Bitmapset *parent_privs,
557 					List *translated_vars)
558 {
559 	Bitmapset  *child_privs = NULL;
560 	bool		whole_row;
561 	int			attno;
562 	ListCell   *lc;
563 
564 	/* System attributes have the same numbers in all tables */
565 	for (attno = FirstLowInvalidHeapAttributeNumber + 1; attno < 0; attno++)
566 	{
567 		if (bms_is_member(attno - FirstLowInvalidHeapAttributeNumber,
568 						  parent_privs))
569 			child_privs = bms_add_member(child_privs,
570 										 attno - FirstLowInvalidHeapAttributeNumber);
571 	}
572 
573 	/* Check if parent has whole-row reference */
574 	whole_row = bms_is_member(InvalidAttrNumber - FirstLowInvalidHeapAttributeNumber,
575 							  parent_privs);
576 
577 	/* And now translate the regular user attributes, using the vars list */
578 	attno = InvalidAttrNumber;
579 	foreach(lc, translated_vars)
580 	{
581 		Var		   *var = lfirst_node(Var, lc);
582 
583 		attno++;
584 		if (var == NULL)		/* ignore dropped columns */
585 			continue;
586 		if (whole_row ||
587 			bms_is_member(attno - FirstLowInvalidHeapAttributeNumber,
588 						  parent_privs))
589 			child_privs = bms_add_member(child_privs,
590 										 var->varattno - FirstLowInvalidHeapAttributeNumber);
591 	}
592 
593 	return child_privs;
594 }
595 
596 /*
597  * expand_appendrel_subquery
598  *		Add "other rel" RelOptInfos for the children of an appendrel baserel
599  *
600  * "rel" is a subquery relation that has the rte->inh flag set, meaning it
601  * is a UNION ALL subquery that's been flattened into an appendrel, with
602  * child subqueries listed in root->append_rel_list.  We need to build
603  * a RelOptInfo for each child relation so that we can plan scans on them.
604  */
605 static void
expand_appendrel_subquery(PlannerInfo * root,RelOptInfo * rel,RangeTblEntry * rte,Index rti)606 expand_appendrel_subquery(PlannerInfo *root, RelOptInfo *rel,
607 						  RangeTblEntry *rte, Index rti)
608 {
609 	ListCell   *l;
610 
611 	foreach(l, root->append_rel_list)
612 	{
613 		AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
614 		Index		childRTindex = appinfo->child_relid;
615 		RangeTblEntry *childrte;
616 		RelOptInfo *childrel;
617 
618 		/* append_rel_list contains all append rels; ignore others */
619 		if (appinfo->parent_relid != rti)
620 			continue;
621 
622 		/* find the child RTE, which should already exist */
623 		Assert(childRTindex < root->simple_rel_array_size);
624 		childrte = root->simple_rte_array[childRTindex];
625 		Assert(childrte != NULL);
626 
627 		/* Build the child RelOptInfo. */
628 		childrel = build_simple_rel(root, childRTindex, rel);
629 
630 		/* Child may itself be an inherited rel, either table or subquery. */
631 		if (childrte->inh)
632 			expand_inherited_rtentry(root, childrel, childrte, childRTindex);
633 	}
634 }
635 
636 
637 /*
638  * apply_child_basequals
639  *		Populate childrel's base restriction quals from parent rel's quals,
640  *		translating them using appinfo.
641  *
642  * If any of the resulting clauses evaluate to constant false or NULL, we
643  * return false and don't apply any quals.  Caller should mark the relation as
644  * a dummy rel in this case, since it doesn't need to be scanned.
645  */
646 bool
apply_child_basequals(PlannerInfo * root,RelOptInfo * parentrel,RelOptInfo * childrel,RangeTblEntry * childRTE,AppendRelInfo * appinfo)647 apply_child_basequals(PlannerInfo *root, RelOptInfo *parentrel,
648 					  RelOptInfo *childrel, RangeTblEntry *childRTE,
649 					  AppendRelInfo *appinfo)
650 {
651 	List	   *childquals;
652 	Index		cq_min_security;
653 	ListCell   *lc;
654 
655 	/*
656 	 * The child rel's targetlist might contain non-Var expressions, which
657 	 * means that substitution into the quals could produce opportunities for
658 	 * const-simplification, and perhaps even pseudoconstant quals. Therefore,
659 	 * transform each RestrictInfo separately to see if it reduces to a
660 	 * constant or pseudoconstant.  (We must process them separately to keep
661 	 * track of the security level of each qual.)
662 	 */
663 	childquals = NIL;
664 	cq_min_security = UINT_MAX;
665 	foreach(lc, parentrel->baserestrictinfo)
666 	{
667 		RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
668 		Node	   *childqual;
669 		ListCell   *lc2;
670 
671 		Assert(IsA(rinfo, RestrictInfo));
672 		childqual = adjust_appendrel_attrs(root,
673 										   (Node *) rinfo->clause,
674 										   1, &appinfo);
675 		childqual = eval_const_expressions(root, childqual);
676 		/* check for flat-out constant */
677 		if (childqual && IsA(childqual, Const))
678 		{
679 			if (((Const *) childqual)->constisnull ||
680 				!DatumGetBool(((Const *) childqual)->constvalue))
681 			{
682 				/* Restriction reduces to constant FALSE or NULL */
683 				return false;
684 			}
685 			/* Restriction reduces to constant TRUE, so drop it */
686 			continue;
687 		}
688 		/* might have gotten an AND clause, if so flatten it */
689 		foreach(lc2, make_ands_implicit((Expr *) childqual))
690 		{
691 			Node	   *onecq = (Node *) lfirst(lc2);
692 			bool		pseudoconstant;
693 
694 			/* check for pseudoconstant (no Vars or volatile functions) */
695 			pseudoconstant =
696 				!contain_vars_of_level(onecq, 0) &&
697 				!contain_volatile_functions(onecq);
698 			if (pseudoconstant)
699 			{
700 				/* tell createplan.c to check for gating quals */
701 				root->hasPseudoConstantQuals = true;
702 			}
703 			/* reconstitute RestrictInfo with appropriate properties */
704 			childquals = lappend(childquals,
705 								 make_restrictinfo(root,
706 												   (Expr *) onecq,
707 												   rinfo->is_pushed_down,
708 												   rinfo->outerjoin_delayed,
709 												   pseudoconstant,
710 												   rinfo->security_level,
711 												   NULL, NULL, NULL));
712 			/* track minimum security level among child quals */
713 			cq_min_security = Min(cq_min_security, rinfo->security_level);
714 		}
715 	}
716 
717 	/*
718 	 * In addition to the quals inherited from the parent, we might have
719 	 * securityQuals associated with this particular child node.  (Currently
720 	 * this can only happen in appendrels originating from UNION ALL;
721 	 * inheritance child tables don't have their own securityQuals, see
722 	 * expand_single_inheritance_child().)  Pull any such securityQuals up
723 	 * into the baserestrictinfo for the child.  This is similar to
724 	 * process_security_barrier_quals() for the parent rel, except that we
725 	 * can't make any general deductions from such quals, since they don't
726 	 * hold for the whole appendrel.
727 	 */
728 	if (childRTE->securityQuals)
729 	{
730 		Index		security_level = 0;
731 
732 		foreach(lc, childRTE->securityQuals)
733 		{
734 			List	   *qualset = (List *) lfirst(lc);
735 			ListCell   *lc2;
736 
737 			foreach(lc2, qualset)
738 			{
739 				Expr	   *qual = (Expr *) lfirst(lc2);
740 
741 				/* not likely that we'd see constants here, so no check */
742 				childquals = lappend(childquals,
743 									 make_restrictinfo(root, qual,
744 													   true, false, false,
745 													   security_level,
746 													   NULL, NULL, NULL));
747 				cq_min_security = Min(cq_min_security, security_level);
748 			}
749 			security_level++;
750 		}
751 		Assert(security_level <= root->qual_security_level);
752 	}
753 
754 	/*
755 	 * OK, we've got all the baserestrictinfo quals for this child.
756 	 */
757 	childrel->baserestrictinfo = childquals;
758 	childrel->baserestrict_min_security = cq_min_security;
759 
760 	return true;
761 }
762