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