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-2023, 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"
24 #include "optimizer/appendinfo.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"
32 #include "optimizer/restrictinfo.h"
33 #include "parser/parsetree.h"
34 #include "parser/parse_relation.h"
35 #include "partitioning/partdesc.h"
36 #include "partitioning/partprune.h"
37 #include "utils/rel.h"
38 
39 
40 static void expand_partitioned_rtentry(PlannerInfo *root, RelOptInfo *relinfo,
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);
51 static Bitmapset *translate_col_privs(const Bitmapset *parent_privs,
52  List *translated_vars);
54  RelOptInfo *rel,
55  RelOptInfo *parent_rel,
56  Bitmapset *parent_cols);
57 static void expand_appendrel_subquery(PlannerInfo *root, RelOptInfo *rel,
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  */
85 void
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. */
184  expand_planner_arrays(root, list_length(inhOIDs));
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,
257  InvalidOid,
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  {
272  var = makeWholeRowVar(planner_rt_fetch(oldrc->rti, root),
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,
292  InvalidOid,
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  */
307  add_vars_to_targetlist(root, newvars, bms_make_singleton(0));
308  }
309 
310  table_close(oldrelation, NoLock);
311 }
312 
313 /*
314  * expand_partitioned_rtentry
315  * Recursively expand an RTE for a partitioned table.
316  */
317 static 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  /* Open rel, acquiring required locks */
390  childrel = table_open(childOID, lockmode);
391 
392  /*
393  * Temporary partitions belonging to other sessions should have been
394  * disallowed at definition, but for paranoia's sake, let's double
395  * check.
396  */
397  if (RELATION_IS_OTHER_TEMP(childrel))
398  elog(ERROR, "temporary relation from another session found as partition");
399 
400  /* Create RTE and AppendRelInfo, plus PlanRowMark if needed. */
401  expand_single_inheritance_child(root, parentrte, parentRTindex,
402  parentrel, top_parentrc, childrel,
403  &childrte, &childRTindex);
404 
405  /* Create the otherrel RelOptInfo too. */
406  childrelinfo = build_simple_rel(root, childRTindex, relinfo);
407  relinfo->part_rels[i] = childrelinfo;
408  relinfo->all_partrels = bms_add_members(relinfo->all_partrels,
409  childrelinfo->relids);
410 
411  /* If this child is itself partitioned, recurse */
412  if (childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
413  {
414  AppendRelInfo *appinfo = root->append_rel_array[childRTindex];
415  Bitmapset *child_updatedCols;
416 
417  child_updatedCols = translate_col_privs(parent_updatedCols,
418  appinfo->translated_vars);
419 
420  expand_partitioned_rtentry(root, childrelinfo,
421  childrte, childRTindex,
422  childrel,
423  child_updatedCols,
424  top_parentrc, lockmode);
425  }
426 
427  /* Close child relation, but keep locks */
428  table_close(childrel, NoLock);
429  }
430 }
431 
432 /*
433  * expand_single_inheritance_child
434  * Build a RangeTblEntry and an AppendRelInfo, plus maybe a PlanRowMark.
435  *
436  * We now expand the partition hierarchy level by level, creating a
437  * corresponding hierarchy of AppendRelInfos and RelOptInfos, where each
438  * partitioned descendant acts as a parent of its immediate partitions.
439  * (This is a difference from what older versions of PostgreSQL did and what
440  * is still done in the case of table inheritance for unpartitioned tables,
441  * where the hierarchy is flattened during RTE expansion.)
442  *
443  * PlanRowMarks still carry the top-parent's RTI, and the top-parent's
444  * allMarkTypes field still accumulates values from all descendents.
445  *
446  * "parentrte" and "parentRTindex" are immediate parent's RTE and
447  * RTI. "top_parentrc" is top parent's PlanRowMark.
448  *
449  * The child RangeTblEntry and its RTI are returned in "childrte_p" and
450  * "childRTindex_p" resp.
451  */
452 static void
454  Index parentRTindex, Relation parentrel,
455  PlanRowMark *top_parentrc, Relation childrel,
456  RangeTblEntry **childrte_p,
457  Index *childRTindex_p)
458 {
459  Query *parse = root->parse;
460  Oid parentOID = RelationGetRelid(parentrel);
461  Oid childOID = RelationGetRelid(childrel);
462  RangeTblEntry *childrte;
463  Index childRTindex;
464  AppendRelInfo *appinfo;
465  TupleDesc child_tupdesc;
466  List *parent_colnames;
467  List *child_colnames;
468 
469  /*
470  * Build an RTE for the child, and attach to query's rangetable list. We
471  * copy most scalar fields of the parent's RTE, but replace relation OID,
472  * relkind, and inh for the child. Set the child's securityQuals to
473  * empty, because we only want to apply the parent's RLS conditions
474  * regardless of what RLS properties individual children may have. (This
475  * is an intentional choice to make inherited RLS work like regular
476  * permissions checks.) The parent securityQuals will be propagated to
477  * children along with other base restriction clauses, so we don't need to
478  * do it here. Other infrastructure of the parent RTE has to be
479  * translated to match the child table's column ordering, which we do
480  * below, so a "flat" copy is sufficient to start with.
481  */
482  childrte = makeNode(RangeTblEntry);
483  memcpy(childrte, parentrte, sizeof(RangeTblEntry));
484  Assert(parentrte->rtekind == RTE_RELATION); /* else this is dubious */
485  childrte->relid = childOID;
486  childrte->relkind = childrel->rd_rel->relkind;
487  /* A partitioned child will need to be expanded further. */
488  if (childrte->relkind == RELKIND_PARTITIONED_TABLE)
489  {
490  Assert(childOID != parentOID);
491  childrte->inh = true;
492  }
493  else
494  childrte->inh = false;
495  childrte->securityQuals = NIL;
496 
497  /*
498  * No permission checking for the child RTE unless it's the parent
499  * relation in its child role, which only applies to traditional
500  * inheritance.
501  */
502  if (childOID != parentOID)
503  childrte->perminfoindex = 0;
504 
505  /* Link not-yet-fully-filled child RTE into data structures */
506  parse->rtable = lappend(parse->rtable, childrte);
507  childRTindex = list_length(parse->rtable);
508  *childrte_p = childrte;
509  *childRTindex_p = childRTindex;
510 
511  /*
512  * Build an AppendRelInfo struct for each parent/child pair.
513  */
514  appinfo = make_append_rel_info(parentrel, childrel,
515  parentRTindex, childRTindex);
516  root->append_rel_list = lappend(root->append_rel_list, appinfo);
517 
518  /* tablesample is probably null, but copy it */
519  childrte->tablesample = copyObject(parentrte->tablesample);
520 
521  /*
522  * Construct an alias clause for the child, which we can also use as eref.
523  * This is important so that EXPLAIN will print the right column aliases
524  * for child-table columns. (Since ruleutils.c doesn't have any easy way
525  * to reassociate parent and child columns, we must get the child column
526  * aliases right to start with. Note that setting childrte->alias forces
527  * ruleutils.c to use these column names, which it otherwise would not.)
528  */
529  child_tupdesc = RelationGetDescr(childrel);
530  parent_colnames = parentrte->eref->colnames;
531  child_colnames = NIL;
532  for (int cattno = 0; cattno < child_tupdesc->natts; cattno++)
533  {
534  Form_pg_attribute att = TupleDescAttr(child_tupdesc, cattno);
535  const char *attname;
536 
537  if (att->attisdropped)
538  {
539  /* Always insert an empty string for a dropped column */
540  attname = "";
541  }
542  else if (appinfo->parent_colnos[cattno] > 0 &&
543  appinfo->parent_colnos[cattno] <= list_length(parent_colnames))
544  {
545  /* Duplicate the query-assigned name for the parent column */
546  attname = strVal(list_nth(parent_colnames,
547  appinfo->parent_colnos[cattno] - 1));
548  }
549  else
550  {
551  /* New column, just use its real name */
552  attname = NameStr(att->attname);
553  }
554  child_colnames = lappend(child_colnames, makeString(pstrdup(attname)));
555  }
556 
557  /*
558  * We just duplicate the parent's table alias name for each child. If the
559  * plan gets printed, ruleutils.c has to sort out unique table aliases to
560  * use, which it can handle.
561  */
562  childrte->alias = childrte->eref = makeAlias(parentrte->eref->aliasname,
563  child_colnames);
564 
565  /*
566  * Store the RTE and appinfo in the respective PlannerInfo arrays, which
567  * the caller must already have allocated space for.
568  */
569  Assert(childRTindex < root->simple_rel_array_size);
570  Assert(root->simple_rte_array[childRTindex] == NULL);
571  root->simple_rte_array[childRTindex] = childrte;
572  Assert(root->append_rel_array[childRTindex] == NULL);
573  root->append_rel_array[childRTindex] = appinfo;
574 
575  /*
576  * Build a PlanRowMark if parent is marked FOR UPDATE/SHARE.
577  */
578  if (top_parentrc)
579  {
580  PlanRowMark *childrc = makeNode(PlanRowMark);
581 
582  childrc->rti = childRTindex;
583  childrc->prti = top_parentrc->rti;
584  childrc->rowmarkId = top_parentrc->rowmarkId;
585  /* Reselect rowmark type, because relkind might not match parent */
586  childrc->markType = select_rowmark_type(childrte,
587  top_parentrc->strength);
588  childrc->allMarkTypes = (1 << childrc->markType);
589  childrc->strength = top_parentrc->strength;
590  childrc->waitPolicy = top_parentrc->waitPolicy;
591 
592  /*
593  * We mark RowMarks for partitioned child tables as parent RowMarks so
594  * that the executor ignores them (except their existence means that
595  * the child tables will be locked using the appropriate mode).
596  */
597  childrc->isParent = (childrte->relkind == RELKIND_PARTITIONED_TABLE);
598 
599  /* Include child's rowmark type in top parent's allMarkTypes */
600  top_parentrc->allMarkTypes |= childrc->allMarkTypes;
601 
602  root->rowMarks = lappend(root->rowMarks, childrc);
603  }
604 
605  /*
606  * If we are creating a child of the query target relation (only possible
607  * in UPDATE/DELETE/MERGE), add it to all_result_relids, as well as
608  * leaf_result_relids if appropriate, and make sure that we generate
609  * required row-identity data.
610  */
611  if (bms_is_member(parentRTindex, root->all_result_relids))
612  {
613  /* OK, record the child as a result rel too. */
615  childRTindex);
616 
617  /* Non-leaf partitions don't need any row identity info. */
618  if (childrte->relkind != RELKIND_PARTITIONED_TABLE)
619  {
620  Var *rrvar;
621 
623  childRTindex);
624 
625  /*
626  * If we have any child target relations, assume they all need to
627  * generate a junk "tableoid" column. (If only one child survives
628  * pruning, we wouldn't really need this, but it's not worth
629  * thrashing about to avoid it.)
630  */
631  rrvar = makeVar(childRTindex,
633  OIDOID,
634  -1,
635  InvalidOid,
636  0);
637  add_row_identity_var(root, rrvar, childRTindex, "tableoid");
638 
639  /* Register any row-identity columns needed by this child. */
640  add_row_identity_columns(root, childRTindex,
641  childrte, childrel);
642  }
643  }
644 }
645 
646 /*
647  * get_rel_all_updated_cols
648  * Returns the set of columns of a given "simple" relation that are
649  * updated by this query.
650  */
651 Bitmapset *
653 {
654  Index relid;
655  RangeTblEntry *rte;
656  RTEPermissionInfo *perminfo;
657  Bitmapset *updatedCols,
658  *extraUpdatedCols;
659 
660  Assert(root->parse->commandType == CMD_UPDATE);
661  Assert(IS_SIMPLE_REL(rel));
662 
663  /*
664  * We obtain updatedCols for the query's result relation. Then, if
665  * necessary, we map it to the column numbers of the relation for which
666  * they were requested.
667  */
668  relid = root->parse->resultRelation;
669  rte = planner_rt_fetch(relid, root);
670  perminfo = getRTEPermissionInfo(root->parse->rteperminfos, rte);
671 
672  updatedCols = perminfo->updatedCols;
673 
674  if (rel->relid != relid)
675  {
676  RelOptInfo *top_parent_rel = find_base_rel(root, relid);
677 
678  Assert(IS_OTHER_REL(rel));
679 
680  updatedCols = translate_col_privs_multilevel(root, rel, top_parent_rel,
681  updatedCols);
682  }
683 
684  /*
685  * Now we must check to see if there are any generated columns that depend
686  * on the updatedCols, and add them to the result.
687  */
688  extraUpdatedCols = get_dependent_generated_columns(root, rel->relid,
689  updatedCols);
690 
691  return bms_union(updatedCols, extraUpdatedCols);
692 }
693 
694 /*
695  * translate_col_privs
696  * Translate a bitmapset representing per-column privileges from the
697  * parent rel's attribute numbering to the child's.
698  *
699  * The only surprise here is that we don't translate a parent whole-row
700  * reference into a child whole-row reference. That would mean requiring
701  * permissions on all child columns, which is overly strict, since the
702  * query is really only going to reference the inherited columns. Instead
703  * we set the per-column bits for all inherited columns.
704  */
705 static Bitmapset *
706 translate_col_privs(const Bitmapset *parent_privs,
707  List *translated_vars)
708 {
709  Bitmapset *child_privs = NULL;
710  bool whole_row;
711  int attno;
712  ListCell *lc;
713 
714  /* System attributes have the same numbers in all tables */
715  for (attno = FirstLowInvalidHeapAttributeNumber + 1; attno < 0; attno++)
716  {
718  parent_privs))
719  child_privs = bms_add_member(child_privs,
721  }
722 
723  /* Check if parent has whole-row reference */
725  parent_privs);
726 
727  /* And now translate the regular user attributes, using the vars list */
728  attno = InvalidAttrNumber;
729  foreach(lc, translated_vars)
730  {
731  Var *var = lfirst_node(Var, lc);
732 
733  attno++;
734  if (var == NULL) /* ignore dropped columns */
735  continue;
736  if (whole_row ||
738  parent_privs))
739  child_privs = bms_add_member(child_privs,
741  }
742 
743  return child_privs;
744 }
745 
746 /*
747  * translate_col_privs_multilevel
748  * Recursively translates the column numbers contained in 'parent_cols'
749  * to the column numbers of a descendant relation given by 'rel'
750  *
751  * Note that because this is based on translate_col_privs, it will expand
752  * a whole-row reference into all inherited columns. This is not an issue
753  * for current usages, but beware.
754  */
755 static Bitmapset *
757  RelOptInfo *parent_rel,
758  Bitmapset *parent_cols)
759 {
760  AppendRelInfo *appinfo;
761 
762  /* Fast path for easy case. */
763  if (parent_cols == NULL)
764  return NULL;
765 
766  /* Recurse if immediate parent is not the top parent. */
767  if (rel->parent != parent_rel)
768  {
769  if (rel->parent)
770  parent_cols = translate_col_privs_multilevel(root, rel->parent,
771  parent_rel,
772  parent_cols);
773  else
774  elog(ERROR, "rel with relid %u is not a child rel", rel->relid);
775  }
776 
777  /* Now translate for this child. */
778  Assert(root->append_rel_array != NULL);
779  appinfo = root->append_rel_array[rel->relid];
780  Assert(appinfo != NULL);
781 
782  return translate_col_privs(parent_cols, appinfo->translated_vars);
783 }
784 
785 /*
786  * expand_appendrel_subquery
787  * Add "other rel" RelOptInfos for the children of an appendrel baserel
788  *
789  * "rel" is a subquery relation that has the rte->inh flag set, meaning it
790  * is a UNION ALL subquery that's been flattened into an appendrel, with
791  * child subqueries listed in root->append_rel_list. We need to build
792  * a RelOptInfo for each child relation so that we can plan scans on them.
793  */
794 static void
796  RangeTblEntry *rte, Index rti)
797 {
798  ListCell *l;
799 
800  foreach(l, root->append_rel_list)
801  {
802  AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
803  Index childRTindex = appinfo->child_relid;
804  RangeTblEntry *childrte;
805  RelOptInfo *childrel;
806 
807  /* append_rel_list contains all append rels; ignore others */
808  if (appinfo->parent_relid != rti)
809  continue;
810 
811  /* find the child RTE, which should already exist */
812  Assert(childRTindex < root->simple_rel_array_size);
813  childrte = root->simple_rte_array[childRTindex];
814  Assert(childrte != NULL);
815 
816  /* Build the child RelOptInfo. */
817  childrel = build_simple_rel(root, childRTindex, rel);
818 
819  /* Child may itself be an inherited rel, either table or subquery. */
820  if (childrte->inh)
821  expand_inherited_rtentry(root, childrel, childrte, childRTindex);
822  }
823 }
824 
825 
826 /*
827  * apply_child_basequals
828  * Populate childrel's base restriction quals from parent rel's quals,
829  * translating them using appinfo.
830  *
831  * If any of the resulting clauses evaluate to constant false or NULL, we
832  * return false and don't apply any quals. Caller should mark the relation as
833  * a dummy rel in this case, since it doesn't need to be scanned.
834  */
835 bool
837  RelOptInfo *childrel, RangeTblEntry *childRTE,
838  AppendRelInfo *appinfo)
839 {
840  List *childquals;
841  Index cq_min_security;
842  ListCell *lc;
843 
844  /*
845  * The child rel's targetlist might contain non-Var expressions, which
846  * means that substitution into the quals could produce opportunities for
847  * const-simplification, and perhaps even pseudoconstant quals. Therefore,
848  * transform each RestrictInfo separately to see if it reduces to a
849  * constant or pseudoconstant. (We must process them separately to keep
850  * track of the security level of each qual.)
851  */
852  childquals = NIL;
853  cq_min_security = UINT_MAX;
854  foreach(lc, parentrel->baserestrictinfo)
855  {
856  RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
857  Node *childqual;
858  ListCell *lc2;
859 
860  Assert(IsA(rinfo, RestrictInfo));
861  childqual = adjust_appendrel_attrs(root,
862  (Node *) rinfo->clause,
863  1, &appinfo);
864  childqual = eval_const_expressions(root, childqual);
865  /* check for flat-out constant */
866  if (childqual && IsA(childqual, Const))
867  {
868  if (((Const *) childqual)->constisnull ||
869  !DatumGetBool(((Const *) childqual)->constvalue))
870  {
871  /* Restriction reduces to constant FALSE or NULL */
872  return false;
873  }
874  /* Restriction reduces to constant TRUE, so drop it */
875  continue;
876  }
877  /* might have gotten an AND clause, if so flatten it */
878  foreach(lc2, make_ands_implicit((Expr *) childqual))
879  {
880  Node *onecq = (Node *) lfirst(lc2);
881  bool pseudoconstant;
882 
883  /* check for pseudoconstant (no Vars or volatile functions) */
884  pseudoconstant =
885  !contain_vars_of_level(onecq, 0) &&
887  if (pseudoconstant)
888  {
889  /* tell createplan.c to check for gating quals */
890  root->hasPseudoConstantQuals = true;
891  }
892  /* reconstitute RestrictInfo with appropriate properties */
893  childquals = lappend(childquals,
894  make_restrictinfo(root,
895  (Expr *) onecq,
896  rinfo->is_pushed_down,
897  pseudoconstant,
898  rinfo->security_level,
899  NULL, NULL));
900  /* track minimum security level among child quals */
901  cq_min_security = Min(cq_min_security, rinfo->security_level);
902  }
903  }
904 
905  /*
906  * In addition to the quals inherited from the parent, we might have
907  * securityQuals associated with this particular child node. (Currently
908  * this can only happen in appendrels originating from UNION ALL;
909  * inheritance child tables don't have their own securityQuals, see
910  * expand_single_inheritance_child().) Pull any such securityQuals up
911  * into the baserestrictinfo for the child. This is similar to
912  * process_security_barrier_quals() for the parent rel, except that we
913  * can't make any general deductions from such quals, since they don't
914  * hold for the whole appendrel.
915  */
916  if (childRTE->securityQuals)
917  {
918  Index security_level = 0;
919 
920  foreach(lc, childRTE->securityQuals)
921  {
922  List *qualset = (List *) lfirst(lc);
923  ListCell *lc2;
924 
925  foreach(lc2, qualset)
926  {
927  Expr *qual = (Expr *) lfirst(lc2);
928 
929  /* not likely that we'd see constants here, so no check */
930  childquals = lappend(childquals,
931  make_restrictinfo(root, qual,
932  true, false,
933  security_level,
934  NULL, NULL));
935  cq_min_security = Min(cq_min_security, security_level);
936  }
937  security_level++;
938  }
939  Assert(security_level <= root->qual_security_level);
940  }
941 
942  /*
943  * OK, we've got all the baserestrictinfo quals for this child.
944  */
945  childrel->baserestrictinfo = childquals;
946  childrel->baserestrict_min_security = cq_min_security;
947 
948  return true;
949 }
Node * adjust_appendrel_attrs(PlannerInfo *root, Node *node, int nappinfos, AppendRelInfo **appinfos)
Definition: appendinfo.c:195
void add_row_identity_columns(PlannerInfo *root, Index rtindex, RangeTblEntry *target_rte, Relation target_relation)
Definition: appendinfo.c:883
AppendRelInfo * make_append_rel_info(Relation parentrel, Relation childrel, Index parentRTindex, Index childRTindex)
Definition: appendinfo.c:50
void add_row_identity_var(PlannerInfo *root, Var *orig_var, Index rtindex, const char *rowid_name)
Definition: appendinfo.c:788
#define InvalidAttrNumber
Definition: attnum.h:23
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1039
int bms_num_members(const Bitmapset *a)
Definition: bitmapset.c:665
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:444
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:186
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:755
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:226
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:818
#define NameStr(name)
Definition: c.h:730
#define Min(x, y)
Definition: c.h:988
unsigned int Index
Definition: c.h:598
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2134
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:448
#define ERROR
Definition: elog.h:39
static Bitmapset * translate_col_privs(const Bitmapset *parent_privs, List *translated_vars)
Definition: inherit.c:706
Bitmapset * get_rel_all_updated_cols(PlannerInfo *root, RelOptInfo *rel)
Definition: inherit.c:652
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:836
static void expand_appendrel_subquery(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte, Index rti)
Definition: inherit.c:795
static Bitmapset * translate_col_privs_multilevel(PlannerInfo *root, RelOptInfo *rel, RelOptInfo *parent_rel, Bitmapset *parent_cols)
Definition: inherit.c:756
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:453
void expand_inherited_rtentry(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte, Index rti)
Definition: inherit.c:86
void add_vars_to_targetlist(PlannerInfo *root, List *vars, Relids where_needed)
Definition: initsplan.c:278
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
List * lappend(List *list, void *datum)
Definition: list.c:338
int LOCKMODE
Definition: lockdefs.h:26
#define NoLock
Definition: lockdefs.h:34
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:389
Var * makeWholeRowVar(RangeTblEntry *rte, int varno, Index varlevelsup, bool allowScalar)
Definition: makefuncs.c:135
List * make_ands_implicit(Expr *clause)
Definition: makefuncs.c:721
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:240
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
char * pstrdup(const char *in)
Definition: mcxt.c:1624
void * palloc0(Size size)
Definition: mcxt.c:1241
#define IsA(nodeptr, _type_)
Definition: nodes.h:179
#define copyObject(obj)
Definition: nodes.h:244
@ CMD_UPDATE
Definition: nodes.h:277
#define makeNode(_type_)
Definition: nodes.h:176
RTEPermissionInfo * getRTEPermissionInfo(List *rteperminfos, RangeTblEntry *rte)
@ RTE_SUBQUERY
Definition: parsenodes.h:1015
@ RTE_RELATION
Definition: parsenodes.h:1014
PartitionDesc PartitionDirectoryLookup(PartitionDirectory pdir, Relation rel)
Definition: partdesc.c:416
bool has_partition_attrs(Relation rel, Bitmapset *attnums, bool *used_in_expr)
Definition: partition.c:254
Bitmapset * prune_append_rel_partitions(RelOptInfo *rel)
Definition: partprune.c:759
#define IS_SIMPLE_REL(rel)
Definition: pathnodes.h:830
#define planner_rt_fetch(rti, root)
Definition: pathnodes.h:561
#define IS_OTHER_REL(rel)
Definition: pathnodes.h:845
NameData attname
Definition: pg_attribute.h:41
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:256
#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:2269
RowMarkType select_rowmark_type(RangeTblEntry *rte, LockClauseStrength strength)
Definition: planner.c:2335
@ ROW_MARK_COPY
Definition: plannodes.h:1335
#define snprintf
Definition: port.h:238
void check_stack_depth(void)
Definition: postgres.c:3461
static bool DatumGetBool(Datum X)
Definition: postgres.h:90
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
PlanRowMark * get_plan_rowmark(List *rowmarks, Index rtindex)
Definition: preptlist.c:485
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:503
#define RelationGetDescr(relation)
Definition: rel.h:529
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:658
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition: relnode.c:404
RelOptInfo * build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
Definition: relnode.c:190
void expand_planner_arrays(PlannerInfo *root, int add_size)
Definition: relnode.c:161
RestrictInfo * make_restrictinfo(PlannerInfo *root, Expr *clause, bool is_pushed_down, bool pseudoconstant, Index security_level, Relids required_relids, Relids outer_relids)
Definition: restrictinfo.c:61
char * aliasname
Definition: primnodes.h:42
List * colnames
Definition: primnodes.h:43
Index child_relid
Definition: pathnodes.h:2904
List * translated_vars
Definition: pathnodes.h:2931
Index parent_relid
Definition: pathnodes.h:2903
Definition: pg_list.h:54
Definition: nodes.h:129
LockClauseStrength strength
Definition: plannodes.h:1388
Index prti
Definition: plannodes.h:1384
RowMarkType markType
Definition: plannodes.h:1386
LockWaitPolicy waitPolicy
Definition: plannodes.h:1389
bool isParent
Definition: plannodes.h:1390
Index rowmarkId
Definition: plannodes.h:1385
int allMarkTypes
Definition: plannodes.h:1387
bool partColsUpdated
Definition: pathnodes.h:549
List * processed_tlist
Definition: pathnodes.h:456
List * append_rel_list
Definition: pathnodes.h:365
PlannerGlobal * glob
Definition: pathnodes.h:205
Query * parse
Definition: pathnodes.h:202
List * rowMarks
Definition: pathnodes.h:371
bool hasPseudoConstantQuals
Definition: pathnodes.h:498
Relids all_result_relids
Definition: pathnodes.h:354
Relids leaf_result_relids
Definition: pathnodes.h:356
CmdType commandType
Definition: parsenodes.h:128
Bitmapset * updatedCols
Definition: parsenodes.h:1250
struct TableSampleClause * tablesample
Definition: parsenodes.h:1075
List * securityQuals
Definition: parsenodes.h:1204
Alias * eref
Definition: parsenodes.h:1200
Alias * alias
Definition: parsenodes.h:1199
Index perminfoindex
Definition: parsenodes.h:1076
RTEKind rtekind
Definition: parsenodes.h:1033
List * baserestrictinfo
Definition: pathnodes.h:970
Relids relids
Definition: pathnodes.h:862
Index relid
Definition: pathnodes.h:909
Relids all_partrels
Definition: pathnodes.h:1026
Bitmapset * live_parts
Definition: pathnodes.h:1024
Index baserestrict_min_security
Definition: pathnodes.h:974
Form_pg_class rd_rel
Definition: rel.h:110
bool is_pushed_down
Definition: pathnodes.h:2516
Index security_level
Definition: pathnodes.h:2535
Expr * clause
Definition: pathnodes.h:2513
Definition: primnodes.h:226
AttrNumber varattno
Definition: primnodes.h:238
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
#define TableOidAttributeNumber
Definition: sysattr.h:26
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
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:441