PostgreSQL Source Code git master
inherit.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * inherit.c
4 * Routines to process child relations in inheritance trees
5 *
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/backend/optimizer/util/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"
25#include "optimizer/inherit.h"
26#include "optimizer/optimizer.h"
27#include "optimizer/pathnode.h"
28#include "optimizer/plancat.h"
29#include "optimizer/planmain.h"
30#include "optimizer/planner.h"
31#include "optimizer/prep.h"
33#include "parser/parsetree.h"
37#include "utils/rel.h"
38
39
41 RangeTblEntry *parentrte,
42 Index parentRTindex, Relation parentrel,
43 Bitmapset *parent_updatedCols,
44 PlanRowMark *top_parentrc, LOCKMODE lockmode);
46 RangeTblEntry *parentrte,
47 Index parentRTindex, Relation parentrel,
48 PlanRowMark *top_parentrc, Relation childrel,
49 RangeTblEntry **childrte_p,
50 Index *childRTindex_p);
51static Bitmapset *translate_col_privs(const Bitmapset *parent_privs,
52 List *translated_vars);
54 RelOptInfo *rel,
55 RelOptInfo *parent_rel,
56 Bitmapset *parent_cols);
58 RangeTblEntry *rte, Index rti);
59
60
61/*
62 * expand_inherited_rtentry
63 * Expand a rangetable entry that has the "inh" bit set.
64 *
65 * "inh" is only allowed in two cases: RELATION and SUBQUERY RTEs.
66 *
67 * "inh" on a plain RELATION RTE means that it is a partitioned table or the
68 * parent of a traditional-inheritance set. In this case we must add entries
69 * for all the interesting child tables to the query's rangetable, and build
70 * additional planner data structures for them, including RelOptInfos,
71 * AppendRelInfos, and possibly PlanRowMarks.
72 *
73 * Note that the original RTE is considered to represent the whole inheritance
74 * set. In the case of traditional inheritance, the first of the generated
75 * RTEs is an RTE for the same table, but with inh = false, to represent the
76 * parent table in its role as a simple member of the inheritance set. For
77 * partitioning, we don't need a second RTE because the partitioned table
78 * itself has no data and need not be scanned.
79 *
80 * "inh" on a SUBQUERY RTE means that it's the parent of a UNION ALL group,
81 * which is treated as an appendrel similarly to inheritance cases; however,
82 * we already made RTEs and AppendRelInfos for the subqueries. We only need
83 * to build RelOptInfos for them, which is done by expand_appendrel_subquery.
84 */
85void
87 RangeTblEntry *rte, Index rti)
88{
89 Oid parentOID;
90 Relation oldrelation;
91 LOCKMODE lockmode;
92 PlanRowMark *oldrc;
93 bool old_isParent = false;
94 int old_allMarkTypes = 0;
95
96 Assert(rte->inh); /* else caller error */
97
98 if (rte->rtekind == RTE_SUBQUERY)
99 {
100 expand_appendrel_subquery(root, rel, rte, rti);
101 return;
102 }
103
104 Assert(rte->rtekind == RTE_RELATION);
105
106 parentOID = rte->relid;
107
108 /*
109 * We used to check has_subclass() here, but there's no longer any need
110 * to, because subquery_planner already did.
111 */
112
113 /*
114 * The rewriter should already have obtained an appropriate lock on each
115 * relation named in the query, so we can open the parent relation without
116 * locking it. However, for each child relation we add to the query, we
117 * must obtain an appropriate lock, because this will be the first use of
118 * those relations in the parse/rewrite/plan pipeline. Child rels should
119 * use the same lockmode as their parent.
120 */
121 oldrelation = table_open(parentOID, NoLock);
122 lockmode = rte->rellockmode;
123
124 /*
125 * If parent relation is selected FOR UPDATE/SHARE, we need to mark its
126 * PlanRowMark as isParent = true, and generate a new PlanRowMark for each
127 * child.
128 */
129 oldrc = get_plan_rowmark(root->rowMarks, rti);
130 if (oldrc)
131 {
132 old_isParent = oldrc->isParent;
133 oldrc->isParent = true;
134 /* Save initial value of allMarkTypes before children add to it */
135 old_allMarkTypes = oldrc->allMarkTypes;
136 }
137
138 /* Scan the inheritance set and expand it */
139 if (oldrelation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
140 {
141 RTEPermissionInfo *perminfo;
142
143 perminfo = getRTEPermissionInfo(root->parse->rteperminfos, rte);
144
145 /*
146 * Partitioned table, so set up for partitioning.
147 */
148 Assert(rte->relkind == RELKIND_PARTITIONED_TABLE);
149
150 /*
151 * Recursively expand and lock the partitions. While at it, also
152 * extract the partition key columns of all the partitioned tables.
153 */
154 expand_partitioned_rtentry(root, rel, rte, rti,
155 oldrelation,
156 perminfo->updatedCols,
157 oldrc, lockmode);
158 }
159 else
160 {
161 /*
162 * Ordinary table, so process traditional-inheritance children. (Note
163 * that partitioned tables are not allowed to have inheritance
164 * children, so it's not possible for both cases to apply.)
165 */
166 List *inhOIDs;
167 ListCell *l;
168
169 /* Scan for all members of inheritance set, acquire needed locks */
170 inhOIDs = find_all_inheritors(parentOID, lockmode, NULL);
171
172 /*
173 * We used to special-case the situation where the table no longer has
174 * any children, by clearing rte->inh and exiting. That no longer
175 * works, because this function doesn't get run until after decisions
176 * have been made that depend on rte->inh. We have to treat such
177 * situations as normal inheritance. The table itself should always
178 * have been found, though.
179 */
180 Assert(inhOIDs != NIL);
181 Assert(linitial_oid(inhOIDs) == parentOID);
182
183 /* Expand simple_rel_array and friends to hold child objects. */
185
186 /*
187 * Expand inheritance children in the order the OIDs were returned by
188 * find_all_inheritors.
189 */
190 foreach(l, inhOIDs)
191 {
192 Oid childOID = lfirst_oid(l);
193 Relation newrelation;
194 RangeTblEntry *childrte;
195 Index childRTindex;
196
197 /* Open rel if needed; we already have required locks */
198 if (childOID != parentOID)
199 newrelation = table_open(childOID, NoLock);
200 else
201 newrelation = oldrelation;
202
203 /*
204 * It is possible that the parent table has children that are temp
205 * tables of other backends. We cannot safely access such tables
206 * (because of buffering issues), and the best thing to do seems
207 * to be to silently ignore them.
208 */
209 if (childOID != parentOID && RELATION_IS_OTHER_TEMP(newrelation))
210 {
211 table_close(newrelation, lockmode);
212 continue;
213 }
214
215 /* Create RTE and AppendRelInfo, plus PlanRowMark if needed. */
216 expand_single_inheritance_child(root, rte, rti, oldrelation,
217 oldrc, newrelation,
218 &childrte, &childRTindex);
219
220 /* Create the otherrel RelOptInfo too. */
221 (void) build_simple_rel(root, childRTindex, rel);
222
223 /* Close child relations, but keep locks */
224 if (childOID != parentOID)
225 table_close(newrelation, NoLock);
226 }
227 }
228
229 /*
230 * Some children might require different mark types, which would've been
231 * reported into oldrc. If so, add relevant entries to the top-level
232 * targetlist and update parent rel's reltarget. This should match what
233 * preprocess_targetlist() would have added if the mark types had been
234 * requested originally.
235 *
236 * (Someday it might be useful to fold these resjunk columns into the
237 * row-identity-column management used for UPDATE/DELETE. Today is not
238 * that day, however.)
239 */
240 if (oldrc)
241 {
242 int new_allMarkTypes = oldrc->allMarkTypes;
243 Var *var;
244 TargetEntry *tle;
245 char resname[32];
246 List *newvars = NIL;
247
248 /* Add TID junk Var if needed, unless we had it already */
249 if (new_allMarkTypes & ~(1 << ROW_MARK_COPY) &&
250 !(old_allMarkTypes & ~(1 << ROW_MARK_COPY)))
251 {
252 /* Need to fetch TID */
253 var = makeVar(oldrc->rti,
255 TIDOID,
256 -1,
258 0);
259 snprintf(resname, sizeof(resname), "ctid%u", oldrc->rowmarkId);
260 tle = makeTargetEntry((Expr *) var,
261 list_length(root->processed_tlist) + 1,
262 pstrdup(resname),
263 true);
264 root->processed_tlist = lappend(root->processed_tlist, tle);
265 newvars = lappend(newvars, var);
266 }
267
268 /* Add whole-row junk Var if needed, unless we had it already */
269 if ((new_allMarkTypes & (1 << ROW_MARK_COPY)) &&
270 !(old_allMarkTypes & (1 << ROW_MARK_COPY)))
271 {
273 oldrc->rti,
274 0,
275 false);
276 snprintf(resname, sizeof(resname), "wholerow%u", oldrc->rowmarkId);
277 tle = makeTargetEntry((Expr *) var,
278 list_length(root->processed_tlist) + 1,
279 pstrdup(resname),
280 true);
281 root->processed_tlist = lappend(root->processed_tlist, tle);
282 newvars = lappend(newvars, var);
283 }
284
285 /* Add tableoid junk Var, unless we had it already */
286 if (!old_isParent)
287 {
288 var = makeVar(oldrc->rti,
290 OIDOID,
291 -1,
293 0);
294 snprintf(resname, sizeof(resname), "tableoid%u", oldrc->rowmarkId);
295 tle = makeTargetEntry((Expr *) var,
296 list_length(root->processed_tlist) + 1,
297 pstrdup(resname),
298 true);
299 root->processed_tlist = lappend(root->processed_tlist, tle);
300 newvars = lappend(newvars, var);
301 }
302
303 /*
304 * Add the newly added Vars to parent's reltarget. We needn't worry
305 * about the children's reltargets, they'll be made later.
306 */
308 }
309
310 table_close(oldrelation, NoLock);
311}
312
313/*
314 * expand_partitioned_rtentry
315 * Recursively expand an RTE for a partitioned table.
316 */
317static void
319 RangeTblEntry *parentrte,
320 Index parentRTindex, Relation parentrel,
321 Bitmapset *parent_updatedCols,
322 PlanRowMark *top_parentrc, LOCKMODE lockmode)
323{
324 PartitionDesc partdesc;
325 Bitmapset *live_parts;
326 int num_live_parts;
327 int i;
328
330
331 Assert(parentrte->inh);
332
333 partdesc = PartitionDirectoryLookup(root->glob->partition_directory,
334 parentrel);
335
336 /* A partitioned table should always have a partition descriptor. */
337 Assert(partdesc);
338
339 /*
340 * Note down whether any partition key cols are being updated. Though it's
341 * the root partitioned table's updatedCols we are interested in,
342 * parent_updatedCols provided by the caller contains the root partrel's
343 * updatedCols translated to match the attribute ordering of parentrel.
344 */
345 if (!root->partColsUpdated)
346 root->partColsUpdated =
347 has_partition_attrs(parentrel, parent_updatedCols, NULL);
348
349 /* Nothing further to do here if there are no partitions. */
350 if (partdesc->nparts == 0)
351 return;
352
353 /*
354 * Perform partition pruning using restriction clauses assigned to parent
355 * relation. live_parts will contain PartitionDesc indexes of partitions
356 * that survive pruning. Below, we will initialize child objects for the
357 * surviving partitions.
358 */
359 relinfo->live_parts = live_parts = prune_append_rel_partitions(relinfo);
360
361 /* Expand simple_rel_array and friends to hold child objects. */
362 num_live_parts = bms_num_members(live_parts);
363 if (num_live_parts > 0)
364 expand_planner_arrays(root, num_live_parts);
365
366 /*
367 * We also store partition RelOptInfo pointers in the parent relation.
368 * Since we're palloc0'ing, slots corresponding to pruned partitions will
369 * contain NULL.
370 */
371 Assert(relinfo->part_rels == NULL);
372 relinfo->part_rels = (RelOptInfo **)
373 palloc0(relinfo->nparts * sizeof(RelOptInfo *));
374
375 /*
376 * Create a child RTE for each live partition. Note that unlike
377 * traditional inheritance, we don't need a child RTE for the partitioned
378 * table itself, because it's not going to be scanned.
379 */
380 i = -1;
381 while ((i = bms_next_member(live_parts, i)) >= 0)
382 {
383 Oid childOID = partdesc->oids[i];
384 Relation childrel;
385 RangeTblEntry *childrte;
386 Index childRTindex;
387 RelOptInfo *childrelinfo;
388
389 /*
390 * Open rel, acquiring required locks. If a partition was recently
391 * detached and subsequently dropped, then opening it will fail. In
392 * this case, behave as though the partition had been pruned.
393 */
394 childrel = try_table_open(childOID, lockmode);
395 if (childrel == NULL)
396 {
397 relinfo->live_parts = bms_del_member(relinfo->live_parts, i);
398 continue;
399 }
400
401 /*
402 * Temporary partitions belonging to other sessions should have been
403 * disallowed at definition, but for paranoia's sake, let's double
404 * check.
405 */
406 if (RELATION_IS_OTHER_TEMP(childrel))
407 elog(ERROR, "temporary relation from another session found as partition");
408
409 /* Create RTE and AppendRelInfo, plus PlanRowMark if needed. */
410 expand_single_inheritance_child(root, parentrte, parentRTindex,
411 parentrel, top_parentrc, childrel,
412 &childrte, &childRTindex);
413
414 /* Create the otherrel RelOptInfo too. */
415 childrelinfo = build_simple_rel(root, childRTindex, relinfo);
416 relinfo->part_rels[i] = childrelinfo;
417 relinfo->all_partrels = bms_add_members(relinfo->all_partrels,
418 childrelinfo->relids);
419
420 /* If this child is itself partitioned, recurse */
421 if (childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
422 {
423 AppendRelInfo *appinfo = root->append_rel_array[childRTindex];
424 Bitmapset *child_updatedCols;
425
426 child_updatedCols = translate_col_privs(parent_updatedCols,
427 appinfo->translated_vars);
428
429 expand_partitioned_rtentry(root, childrelinfo,
430 childrte, childRTindex,
431 childrel,
432 child_updatedCols,
433 top_parentrc, lockmode);
434 }
435
436 /* Close child relation, but keep locks */
437 table_close(childrel, NoLock);
438 }
439}
440
441/*
442 * expand_single_inheritance_child
443 * Build a RangeTblEntry and an AppendRelInfo, plus maybe a PlanRowMark.
444 *
445 * We now expand the partition hierarchy level by level, creating a
446 * corresponding hierarchy of AppendRelInfos and RelOptInfos, where each
447 * partitioned descendant acts as a parent of its immediate partitions.
448 * (This is a difference from what older versions of PostgreSQL did and what
449 * is still done in the case of table inheritance for unpartitioned tables,
450 * where the hierarchy is flattened during RTE expansion.)
451 *
452 * PlanRowMarks still carry the top-parent's RTI, and the top-parent's
453 * allMarkTypes field still accumulates values from all descendents.
454 *
455 * "parentrte" and "parentRTindex" are immediate parent's RTE and
456 * RTI. "top_parentrc" is top parent's PlanRowMark.
457 *
458 * The child RangeTblEntry and its RTI are returned in "childrte_p" and
459 * "childRTindex_p" resp.
460 */
461static void
463 Index parentRTindex, Relation parentrel,
464 PlanRowMark *top_parentrc, Relation childrel,
465 RangeTblEntry **childrte_p,
466 Index *childRTindex_p)
467{
468 Query *parse = root->parse;
469 Oid parentOID PG_USED_FOR_ASSERTS_ONLY =
470 RelationGetRelid(parentrel);
471 Oid childOID = RelationGetRelid(childrel);
472 RangeTblEntry *childrte;
473 Index childRTindex;
474 AppendRelInfo *appinfo;
475 TupleDesc child_tupdesc;
476 List *parent_colnames;
477 List *child_colnames;
478
479 /*
480 * Build an RTE for the child, and attach to query's rangetable list. We
481 * copy most scalar fields of the parent's RTE, but replace relation OID,
482 * relkind, and inh for the child. Set the child's securityQuals to
483 * empty, because we only want to apply the parent's RLS conditions
484 * regardless of what RLS properties individual children may have. (This
485 * is an intentional choice to make inherited RLS work like regular
486 * permissions checks.) The parent securityQuals will be propagated to
487 * children along with other base restriction clauses, so we don't need to
488 * do it here. Other infrastructure of the parent RTE has to be
489 * translated to match the child table's column ordering, which we do
490 * below, so a "flat" copy is sufficient to start with.
491 */
492 childrte = makeNode(RangeTblEntry);
493 memcpy(childrte, parentrte, sizeof(RangeTblEntry));
494 Assert(parentrte->rtekind == RTE_RELATION); /* else this is dubious */
495 childrte->relid = childOID;
496 childrte->relkind = childrel->rd_rel->relkind;
497 /* A partitioned child will need to be expanded further. */
498 if (childrte->relkind == RELKIND_PARTITIONED_TABLE)
499 {
500 Assert(childOID != parentOID);
501 childrte->inh = true;
502 }
503 else
504 childrte->inh = false;
505 childrte->securityQuals = NIL;
506
507 /* No permission checking for child RTEs. */
508 childrte->perminfoindex = 0;
509
510 /* Link not-yet-fully-filled child RTE into data structures */
511 parse->rtable = lappend(parse->rtable, childrte);
512 childRTindex = list_length(parse->rtable);
513 *childrte_p = childrte;
514 *childRTindex_p = childRTindex;
515
516 /*
517 * Build an AppendRelInfo struct for each parent/child pair.
518 */
519 appinfo = make_append_rel_info(parentrel, childrel,
520 parentRTindex, childRTindex);
521 root->append_rel_list = lappend(root->append_rel_list, appinfo);
522
523 /* tablesample is probably null, but copy it */
524 childrte->tablesample = copyObject(parentrte->tablesample);
525
526 /*
527 * Construct an alias clause for the child, which we can also use as eref.
528 * This is important so that EXPLAIN will print the right column aliases
529 * for child-table columns. (Since ruleutils.c doesn't have any easy way
530 * to reassociate parent and child columns, we must get the child column
531 * aliases right to start with. Note that setting childrte->alias forces
532 * ruleutils.c to use these column names, which it otherwise would not.)
533 */
534 child_tupdesc = RelationGetDescr(childrel);
535 parent_colnames = parentrte->eref->colnames;
536 child_colnames = NIL;
537 for (int cattno = 0; cattno < child_tupdesc->natts; cattno++)
538 {
539 Form_pg_attribute att = TupleDescAttr(child_tupdesc, cattno);
540 const char *attname;
541
542 if (att->attisdropped)
543 {
544 /* Always insert an empty string for a dropped column */
545 attname = "";
546 }
547 else if (appinfo->parent_colnos[cattno] > 0 &&
548 appinfo->parent_colnos[cattno] <= list_length(parent_colnames))
549 {
550 /* Duplicate the query-assigned name for the parent column */
551 attname = strVal(list_nth(parent_colnames,
552 appinfo->parent_colnos[cattno] - 1));
553 }
554 else
555 {
556 /* New column, just use its real name */
557 attname = NameStr(att->attname);
558 }
559 child_colnames = lappend(child_colnames, makeString(pstrdup(attname)));
560 }
561
562 /*
563 * We just duplicate the parent's table alias name for each child. If the
564 * plan gets printed, ruleutils.c has to sort out unique table aliases to
565 * use, which it can handle.
566 */
567 childrte->alias = childrte->eref = makeAlias(parentrte->eref->aliasname,
568 child_colnames);
569
570 /*
571 * Store the RTE and appinfo in the respective PlannerInfo arrays, which
572 * the caller must already have allocated space for.
573 */
574 Assert(childRTindex < root->simple_rel_array_size);
575 Assert(root->simple_rte_array[childRTindex] == NULL);
576 root->simple_rte_array[childRTindex] = childrte;
577 Assert(root->append_rel_array[childRTindex] == NULL);
578 root->append_rel_array[childRTindex] = appinfo;
579
580 /*
581 * Build a PlanRowMark if parent is marked FOR UPDATE/SHARE.
582 */
583 if (top_parentrc)
584 {
585 PlanRowMark *childrc = makeNode(PlanRowMark);
586
587 childrc->rti = childRTindex;
588 childrc->prti = top_parentrc->rti;
589 childrc->rowmarkId = top_parentrc->rowmarkId;
590 /* Reselect rowmark type, because relkind might not match parent */
591 childrc->markType = select_rowmark_type(childrte,
592 top_parentrc->strength);
593 childrc->allMarkTypes = (1 << childrc->markType);
594 childrc->strength = top_parentrc->strength;
595 childrc->waitPolicy = top_parentrc->waitPolicy;
596
597 /*
598 * We mark RowMarks for partitioned child tables as parent RowMarks so
599 * that the executor ignores them (except their existence means that
600 * the child tables will be locked using the appropriate mode).
601 */
602 childrc->isParent = (childrte->relkind == RELKIND_PARTITIONED_TABLE);
603
604 /* Include child's rowmark type in top parent's allMarkTypes */
605 top_parentrc->allMarkTypes |= childrc->allMarkTypes;
606
607 root->rowMarks = lappend(root->rowMarks, childrc);
608 }
609
610 /*
611 * If we are creating a child of the query target relation (only possible
612 * in UPDATE/DELETE/MERGE), add it to all_result_relids, as well as
613 * leaf_result_relids if appropriate, and make sure that we generate
614 * required row-identity data.
615 */
616 if (bms_is_member(parentRTindex, root->all_result_relids))
617 {
618 /* OK, record the child as a result rel too. */
619 root->all_result_relids = bms_add_member(root->all_result_relids,
620 childRTindex);
621
622 /* Non-leaf partitions don't need any row identity info. */
623 if (childrte->relkind != RELKIND_PARTITIONED_TABLE)
624 {
625 Var *rrvar;
626
627 root->leaf_result_relids = bms_add_member(root->leaf_result_relids,
628 childRTindex);
629
630 /*
631 * If we have any child target relations, assume they all need to
632 * generate a junk "tableoid" column. (If only one child survives
633 * pruning, we wouldn't really need this, but it's not worth
634 * thrashing about to avoid it.)
635 */
636 rrvar = makeVar(childRTindex,
638 OIDOID,
639 -1,
641 0);
642 add_row_identity_var(root, rrvar, childRTindex, "tableoid");
643
644 /* Register any row-identity columns needed by this child. */
645 add_row_identity_columns(root, childRTindex,
646 childrte, childrel);
647 }
648 }
649}
650
651/*
652 * get_rel_all_updated_cols
653 * Returns the set of columns of a given "simple" relation that are
654 * updated by this query.
655 */
656Bitmapset *
658{
659 Index relid;
660 RangeTblEntry *rte;
661 RTEPermissionInfo *perminfo;
662 Bitmapset *updatedCols,
663 *extraUpdatedCols;
664
665 Assert(root->parse->commandType == CMD_UPDATE);
666 Assert(IS_SIMPLE_REL(rel));
667
668 /*
669 * We obtain updatedCols for the query's result relation. Then, if
670 * necessary, we map it to the column numbers of the relation for which
671 * they were requested.
672 */
673 relid = root->parse->resultRelation;
674 rte = planner_rt_fetch(relid, root);
675 perminfo = getRTEPermissionInfo(root->parse->rteperminfos, rte);
676
677 updatedCols = perminfo->updatedCols;
678
679 if (rel->relid != relid)
680 {
681 RelOptInfo *top_parent_rel = find_base_rel(root, relid);
682
683 Assert(IS_OTHER_REL(rel));
684
685 updatedCols = translate_col_privs_multilevel(root, rel, top_parent_rel,
686 updatedCols);
687 }
688
689 /*
690 * Now we must check to see if there are any generated columns that depend
691 * on the updatedCols, and add them to the result.
692 */
693 extraUpdatedCols = get_dependent_generated_columns(root, rel->relid,
694 updatedCols);
695
696 return bms_union(updatedCols, extraUpdatedCols);
697}
698
699/*
700 * translate_col_privs
701 * Translate a bitmapset representing per-column privileges from the
702 * parent rel's attribute numbering to the child's.
703 *
704 * The only surprise here is that we don't translate a parent whole-row
705 * reference into a child whole-row reference. That would mean requiring
706 * permissions on all child columns, which is overly strict, since the
707 * query is really only going to reference the inherited columns. Instead
708 * we set the per-column bits for all inherited columns.
709 */
710static Bitmapset *
711translate_col_privs(const Bitmapset *parent_privs,
712 List *translated_vars)
713{
714 Bitmapset *child_privs = NULL;
715 bool whole_row;
716 int attno;
717 ListCell *lc;
718
719 /* System attributes have the same numbers in all tables */
720 for (attno = FirstLowInvalidHeapAttributeNumber + 1; attno < 0; attno++)
721 {
723 parent_privs))
724 child_privs = bms_add_member(child_privs,
726 }
727
728 /* Check if parent has whole-row reference */
730 parent_privs);
731
732 /* And now translate the regular user attributes, using the vars list */
733 attno = InvalidAttrNumber;
734 foreach(lc, translated_vars)
735 {
736 Var *var = lfirst_node(Var, lc);
737
738 attno++;
739 if (var == NULL) /* ignore dropped columns */
740 continue;
741 if (whole_row ||
743 parent_privs))
744 child_privs = bms_add_member(child_privs,
746 }
747
748 return child_privs;
749}
750
751/*
752 * translate_col_privs_multilevel
753 * Recursively translates the column numbers contained in 'parent_cols'
754 * to the column numbers of a descendant relation given by 'rel'
755 *
756 * Note that because this is based on translate_col_privs, it will expand
757 * a whole-row reference into all inherited columns. This is not an issue
758 * for current usages, but beware.
759 */
760static Bitmapset *
762 RelOptInfo *parent_rel,
763 Bitmapset *parent_cols)
764{
765 AppendRelInfo *appinfo;
766
767 /* Fast path for easy case. */
768 if (parent_cols == NULL)
769 return NULL;
770
771 /* Recurse if immediate parent is not the top parent. */
772 if (rel->parent != parent_rel)
773 {
774 if (rel->parent)
775 parent_cols = translate_col_privs_multilevel(root, rel->parent,
776 parent_rel,
777 parent_cols);
778 else
779 elog(ERROR, "rel with relid %u is not a child rel", rel->relid);
780 }
781
782 /* Now translate for this child. */
783 Assert(root->append_rel_array != NULL);
784 appinfo = root->append_rel_array[rel->relid];
785 Assert(appinfo != NULL);
786
787 return translate_col_privs(parent_cols, appinfo->translated_vars);
788}
789
790/*
791 * expand_appendrel_subquery
792 * Add "other rel" RelOptInfos for the children of an appendrel baserel
793 *
794 * "rel" is a subquery relation that has the rte->inh flag set, meaning it
795 * is a UNION ALL subquery that's been flattened into an appendrel, with
796 * child subqueries listed in root->append_rel_list. We need to build
797 * a RelOptInfo for each child relation so that we can plan scans on them.
798 */
799static void
801 RangeTblEntry *rte, Index rti)
802{
803 ListCell *l;
804
805 foreach(l, root->append_rel_list)
806 {
807 AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
808 Index childRTindex = appinfo->child_relid;
809 RangeTblEntry *childrte;
810 RelOptInfo *childrel;
811
812 /* append_rel_list contains all append rels; ignore others */
813 if (appinfo->parent_relid != rti)
814 continue;
815
816 /* find the child RTE, which should already exist */
817 Assert(childRTindex < root->simple_rel_array_size);
818 childrte = root->simple_rte_array[childRTindex];
819 Assert(childrte != NULL);
820
821 /* Build the child RelOptInfo. */
822 childrel = build_simple_rel(root, childRTindex, rel);
823
824 /* Child may itself be an inherited rel, either table or subquery. */
825 if (childrte->inh)
826 expand_inherited_rtentry(root, childrel, childrte, childRTindex);
827 }
828}
829
830
831/*
832 * apply_child_basequals
833 * Populate childrel's base restriction quals from parent rel's quals,
834 * translating Vars using appinfo and re-checking for quals which are
835 * constant-TRUE or constant-FALSE when applied to this child relation.
836 *
837 * If any of the resulting clauses evaluate to constant false or NULL, we
838 * return false and don't apply any quals. Caller should mark the relation as
839 * a dummy rel in this case, since it doesn't need to be scanned. Constant
840 * true quals are ignored.
841 */
842bool
844 RelOptInfo *childrel, RangeTblEntry *childRTE,
845 AppendRelInfo *appinfo)
846{
847 List *childquals;
848 Index cq_min_security;
849 ListCell *lc;
850
851 /*
852 * The child rel's targetlist might contain non-Var expressions, which
853 * means that substitution into the quals could produce opportunities for
854 * const-simplification, and perhaps even pseudoconstant quals. Therefore,
855 * transform each RestrictInfo separately to see if it reduces to a
856 * constant or pseudoconstant. (We must process them separately to keep
857 * track of the security level of each qual.)
858 */
859 childquals = NIL;
860 cq_min_security = UINT_MAX;
861 foreach(lc, parentrel->baserestrictinfo)
862 {
863 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
864 Node *childqual;
865 ListCell *lc2;
866
867 Assert(IsA(rinfo, RestrictInfo));
868 childqual = adjust_appendrel_attrs(root,
869 (Node *) rinfo->clause,
870 1, &appinfo);
871 childqual = eval_const_expressions(root, childqual);
872 /* check for flat-out constant */
873 if (childqual && IsA(childqual, Const))
874 {
875 if (((Const *) childqual)->constisnull ||
876 !DatumGetBool(((Const *) childqual)->constvalue))
877 {
878 /* Restriction reduces to constant FALSE or NULL */
879 return false;
880 }
881 /* Restriction reduces to constant TRUE, so drop it */
882 continue;
883 }
884 /* might have gotten an AND clause, if so flatten it */
885 foreach(lc2, make_ands_implicit((Expr *) childqual))
886 {
887 Node *onecq = (Node *) lfirst(lc2);
888 bool pseudoconstant;
889 RestrictInfo *childrinfo;
890
891 /* check for pseudoconstant (no Vars or volatile functions) */
892 pseudoconstant =
893 !contain_vars_of_level(onecq, 0) &&
895 if (pseudoconstant)
896 {
897 /* tell createplan.c to check for gating quals */
898 root->hasPseudoConstantQuals = true;
899 }
900 /* reconstitute RestrictInfo with appropriate properties */
901 childrinfo = make_restrictinfo(root,
902 (Expr *) onecq,
903 rinfo->is_pushed_down,
904 rinfo->has_clone,
905 rinfo->is_clone,
906 pseudoconstant,
907 rinfo->security_level,
908 NULL, NULL, NULL);
909
910 /* Restriction is proven always false */
911 if (restriction_is_always_false(root, childrinfo))
912 return false;
913 /* Restriction is proven always true, so drop it */
914 if (restriction_is_always_true(root, childrinfo))
915 continue;
916
917 childquals = lappend(childquals, childrinfo);
918 /* track minimum security level among child quals */
919 cq_min_security = Min(cq_min_security, rinfo->security_level);
920 }
921 }
922
923 /*
924 * In addition to the quals inherited from the parent, we might have
925 * securityQuals associated with this particular child node. (Currently
926 * this can only happen in appendrels originating from UNION ALL;
927 * inheritance child tables don't have their own securityQuals, see
928 * expand_single_inheritance_child().) Pull any such securityQuals up
929 * into the baserestrictinfo for the child. This is similar to
930 * process_security_barrier_quals() for the parent rel, except that we
931 * can't make any general deductions from such quals, since they don't
932 * hold for the whole appendrel.
933 */
934 if (childRTE->securityQuals)
935 {
936 Index security_level = 0;
937
938 foreach(lc, childRTE->securityQuals)
939 {
940 List *qualset = (List *) lfirst(lc);
941 ListCell *lc2;
942
943 foreach(lc2, qualset)
944 {
945 Expr *qual = (Expr *) lfirst(lc2);
946
947 /* not likely that we'd see constants here, so no check */
948 childquals = lappend(childquals,
950 true,
951 false, false,
952 false,
953 security_level,
954 NULL, NULL, NULL));
955 cq_min_security = Min(cq_min_security, security_level);
956 }
957 security_level++;
958 }
959 Assert(security_level <= root->qual_security_level);
960 }
961
962 /*
963 * OK, we've got all the baserestrictinfo quals for this child.
964 */
965 childrel->baserestrictinfo = childquals;
966 childrel->baserestrict_min_security = cq_min_security;
967
968 return true;
969}
Node * adjust_appendrel_attrs(PlannerInfo *root, Node *node, int nappinfos, AppendRelInfo **appinfos)
Definition: appendinfo.c:200
void add_row_identity_columns(PlannerInfo *root, Index rtindex, RangeTblEntry *target_rte, Relation target_relation)
Definition: appendinfo.c:904
AppendRelInfo * make_append_rel_info(Relation parentrel, Relation childrel, Index parentRTindex, Index childRTindex)
Definition: appendinfo.c:51
void add_row_identity_var(PlannerInfo *root, Var *orig_var, Index rtindex, const char *rowid_name)
Definition: appendinfo.c:809
#define InvalidAttrNumber
Definition: attnum.h:23
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:216
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1306
Bitmapset * bms_del_member(Bitmapset *a, int x)
Definition: bitmapset.c:868
int bms_num_members(const Bitmapset *a)
Definition: bitmapset.c:751
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:917
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:251
#define NameStr(name)
Definition: c.h:703
#define Min(x, y)
Definition: c.h:961
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:204
#define Assert(condition)
Definition: c.h:815
unsigned int Index
Definition: c.h:571
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2254
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:537
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
static Bitmapset * translate_col_privs(const Bitmapset *parent_privs, List *translated_vars)
Definition: inherit.c:711
static void expand_partitioned_rtentry(PlannerInfo *root, RelOptInfo *relinfo, RangeTblEntry *parentrte, Index parentRTindex, Relation parentrel, Bitmapset *parent_updatedCols, PlanRowMark *top_parentrc, LOCKMODE lockmode)
Definition: inherit.c:318
bool apply_child_basequals(PlannerInfo *root, RelOptInfo *parentrel, RelOptInfo *childrel, RangeTblEntry *childRTE, AppendRelInfo *appinfo)
Definition: inherit.c:843
static void expand_appendrel_subquery(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte, Index rti)
Definition: inherit.c:800
static Bitmapset * translate_col_privs_multilevel(PlannerInfo *root, RelOptInfo *rel, RelOptInfo *parent_rel, Bitmapset *parent_cols)
Definition: inherit.c:761
Bitmapset * get_rel_all_updated_cols(PlannerInfo *root, RelOptInfo *rel)
Definition: inherit.c:657
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)
Definition: inherit.c:462
void expand_inherited_rtentry(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte, Index rti)
Definition: inherit.c:86
bool restriction_is_always_true(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:3091
void add_vars_to_targetlist(PlannerInfo *root, List *vars, Relids where_needed)
Definition: initsplan.c:282
bool restriction_is_always_false(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: initsplan.c:3140
int i
Definition: isn.c:72
List * lappend(List *list, void *datum)
Definition: list.c:339
int LOCKMODE
Definition: lockdefs.h:26
#define NoLock
Definition: lockdefs.h:34
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:391
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
Var * makeWholeRowVar(RangeTblEntry *rte, int varno, Index varlevelsup, bool allowScalar)
Definition: makefuncs.c:137
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:242
List * make_ands_implicit(Expr *clause)
Definition: makefuncs.c:763
char * pstrdup(const char *in)
Definition: mcxt.c:1696
void * palloc0(Size size)
Definition: mcxt.c:1347
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
#define copyObject(obj)
Definition: nodes.h:224
@ CMD_UPDATE
Definition: nodes.h:266
#define makeNode(_type_)
Definition: nodes.h:155
RTEPermissionInfo * getRTEPermissionInfo(List *rteperminfos, RangeTblEntry *rte)
@ RTE_SUBQUERY
Definition: parsenodes.h:1027
@ RTE_RELATION
Definition: parsenodes.h:1026
PartitionDesc PartitionDirectoryLookup(PartitionDirectory pdir, Relation rel)
Definition: partdesc.c:456
bool has_partition_attrs(Relation rel, Bitmapset *attnums, bool *used_in_expr)
Definition: partition.c:255
Bitmapset * prune_append_rel_partitions(RelOptInfo *rel)
Definition: partprune.c:772
#define IS_SIMPLE_REL(rel)
Definition: pathnodes.h:858
#define planner_rt_fetch(rti, root)
Definition: pathnodes.h:589
#define IS_OTHER_REL(rel)
Definition: pathnodes.h:873
NameData attname
Definition: pg_attribute.h:41
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:255
#define lfirst(lc)
Definition: pg_list.h:172
#define lfirst_node(type, lc)
Definition: pg_list.h:176
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
#define linitial_oid(l)
Definition: pg_list.h:180
#define lfirst_oid(lc)
Definition: pg_list.h:174
Bitmapset * get_dependent_generated_columns(PlannerInfo *root, Index rti, Bitmapset *target_cols)
Definition: plancat.c:2337
RowMarkType select_rowmark_type(RangeTblEntry *rte, LockClauseStrength strength)
Definition: planner.c:2437
@ ROW_MARK_COPY
Definition: plannodes.h:1478
#define snprintf
Definition: port.h:239
static bool DatumGetBool(Datum X)
Definition: postgres.h:95
#define InvalidOid
Definition: postgres_ext.h:37
unsigned int Oid
Definition: postgres_ext.h:32
PlanRowMark * get_plan_rowmark(List *rowmarks, Index rtindex)
Definition: preptlist.c:503
tree ctl root
Definition: radixtree.h:1857
static struct subre * parse(struct vars *v, int stopper, int type, struct state *init, struct state *final)
Definition: regcomp.c:717
#define RelationGetRelid(relation)
Definition: rel.h:512
#define RelationGetDescr(relation)
Definition: rel.h:538
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:665
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition: relnode.c:414
void expand_planner_arrays(PlannerInfo *root, int add_size)
Definition: relnode.c:163
RelOptInfo * build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
Definition: relnode.c:192
RestrictInfo * make_restrictinfo(PlannerInfo *root, Expr *clause, bool is_pushed_down, bool has_clone, bool is_clone, bool pseudoconstant, Index security_level, Relids required_relids, Relids incompatible_relids, Relids outer_relids)
Definition: restrictinfo.c:52
void check_stack_depth(void)
Definition: stack_depth.c:95
Index child_relid
Definition: pathnodes.h:3000
List * translated_vars
Definition: pathnodes.h:3027
Index parent_relid
Definition: pathnodes.h:2999
Definition: pg_list.h:54
Definition: nodes.h:129
LockClauseStrength strength
Definition: plannodes.h:1537
Index prti
Definition: plannodes.h:1529
RowMarkType markType
Definition: plannodes.h:1533
LockWaitPolicy waitPolicy
Definition: plannodes.h:1539
bool isParent
Definition: plannodes.h:1541
Index rowmarkId
Definition: plannodes.h:1531
int allMarkTypes
Definition: plannodes.h:1535
Bitmapset * updatedCols
Definition: parsenodes.h:1304
struct TableSampleClause * tablesample
Definition: parsenodes.h:1107
RTEKind rtekind
Definition: parsenodes.h:1056
List * baserestrictinfo
Definition: pathnodes.h:1004
Relids relids
Definition: pathnodes.h:890
Index relid
Definition: pathnodes.h:937
Relids all_partrels
Definition: pathnodes.h:1060
Bitmapset * live_parts
Definition: pathnodes.h:1058
Index baserestrict_min_security
Definition: pathnodes.h:1008
Form_pg_class rd_rel
Definition: rel.h:111
bool is_pushed_down
Definition: pathnodes.h:2597
Index security_level
Definition: pathnodes.h:2616
Expr * clause
Definition: pathnodes.h:2594
bool has_clone
Definition: pathnodes.h:2606
Definition: primnodes.h:262
AttrNumber varattno
Definition: primnodes.h:274
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
#define TableOidAttributeNumber
Definition: sysattr.h:26
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21
Relation try_table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:60
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:154
String * makeString(char *str)
Definition: value.c:63
#define strVal(v)
Definition: value.h:82
bool contain_vars_of_level(Node *node, int levelsup)
Definition: var.c:444