PostgreSQL Source Code  git master
inherit.c File Reference
Include dependency graph for inherit.c:

Go to the source code of this file.

Functions

static void expand_partitioned_rtentry (PlannerInfo *root, RelOptInfo *relinfo, RangeTblEntry *parentrte, Index parentRTindex, Relation parentrel, PlanRowMark *top_parentrc, LOCKMODE lockmode)
 
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)
 
static Bitmapsettranslate_col_privs (const Bitmapset *parent_privs, List *translated_vars)
 
static void expand_appendrel_subquery (PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte, Index rti)
 
void expand_inherited_rtentry (PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte, Index rti)
 
bool apply_child_basequals (PlannerInfo *root, RelOptInfo *parentrel, RelOptInfo *childrel, RangeTblEntry *childRTE, AppendRelInfo *appinfo)
 

Function Documentation

◆ apply_child_basequals()

bool apply_child_basequals ( PlannerInfo root,
RelOptInfo parentrel,
RelOptInfo childrel,
RangeTblEntry childRTE,
AppendRelInfo appinfo 
)

Definition at line 754 of file inherit.c.

References adjust_appendrel_attrs(), Assert, RelOptInfo::baserestrict_min_security, RelOptInfo::baserestrictinfo, RestrictInfo::clause, contain_vars_of_level(), contain_volatile_functions(), DatumGetBool, eval_const_expressions(), PlannerInfo::hasPseudoConstantQuals, RestrictInfo::is_pushed_down, IsA, lappend(), lfirst, make_ands_implicit(), make_restrictinfo(), Min, NIL, RestrictInfo::outerjoin_delayed, RestrictInfo::security_level, and RangeTblEntry::securityQuals.

Referenced by build_simple_rel().

757 {
758  List *childquals;
759  Index cq_min_security;
760  ListCell *lc;
761 
762  /*
763  * The child rel's targetlist might contain non-Var expressions, which
764  * means that substitution into the quals could produce opportunities for
765  * const-simplification, and perhaps even pseudoconstant quals. Therefore,
766  * transform each RestrictInfo separately to see if it reduces to a
767  * constant or pseudoconstant. (We must process them separately to keep
768  * track of the security level of each qual.)
769  */
770  childquals = NIL;
771  cq_min_security = UINT_MAX;
772  foreach(lc, parentrel->baserestrictinfo)
773  {
774  RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
775  Node *childqual;
776  ListCell *lc2;
777 
778  Assert(IsA(rinfo, RestrictInfo));
779  childqual = adjust_appendrel_attrs(root,
780  (Node *) rinfo->clause,
781  1, &appinfo);
782  childqual = eval_const_expressions(root, childqual);
783  /* check for flat-out constant */
784  if (childqual && IsA(childqual, Const))
785  {
786  if (((Const *) childqual)->constisnull ||
787  !DatumGetBool(((Const *) childqual)->constvalue))
788  {
789  /* Restriction reduces to constant FALSE or NULL */
790  return false;
791  }
792  /* Restriction reduces to constant TRUE, so drop it */
793  continue;
794  }
795  /* might have gotten an AND clause, if so flatten it */
796  foreach(lc2, make_ands_implicit((Expr *) childqual))
797  {
798  Node *onecq = (Node *) lfirst(lc2);
799  bool pseudoconstant;
800 
801  /* check for pseudoconstant (no Vars or volatile functions) */
802  pseudoconstant =
803  !contain_vars_of_level(onecq, 0) &&
805  if (pseudoconstant)
806  {
807  /* tell createplan.c to check for gating quals */
808  root->hasPseudoConstantQuals = true;
809  }
810  /* reconstitute RestrictInfo with appropriate properties */
811  childquals = lappend(childquals,
812  make_restrictinfo(root,
813  (Expr *) onecq,
814  rinfo->is_pushed_down,
815  rinfo->outerjoin_delayed,
816  pseudoconstant,
817  rinfo->security_level,
818  NULL, NULL, NULL));
819  /* track minimum security level among child quals */
820  cq_min_security = Min(cq_min_security, rinfo->security_level);
821  }
822  }
823 
824  /*
825  * In addition to the quals inherited from the parent, we might have
826  * securityQuals associated with this particular child node. (Currently
827  * this can only happen in appendrels originating from UNION ALL;
828  * inheritance child tables don't have their own securityQuals, see
829  * expand_single_inheritance_child().) Pull any such securityQuals up
830  * into the baserestrictinfo for the child. This is similar to
831  * process_security_barrier_quals() for the parent rel, except that we
832  * can't make any general deductions from such quals, since they don't
833  * hold for the whole appendrel.
834  */
835  if (childRTE->securityQuals)
836  {
837  Index security_level = 0;
838 
839  foreach(lc, childRTE->securityQuals)
840  {
841  List *qualset = (List *) lfirst(lc);
842  ListCell *lc2;
843 
844  foreach(lc2, qualset)
845  {
846  Expr *qual = (Expr *) lfirst(lc2);
847 
848  /* not likely that we'd see constants here, so no check */
849  childquals = lappend(childquals,
850  make_restrictinfo(root, qual,
851  true, false, false,
852  security_level,
853  NULL, NULL, NULL));
854  cq_min_security = Min(cq_min_security, security_level);
855  }
856  security_level++;
857  }
858  Assert(security_level <= root->qual_security_level);
859  }
860 
861  /*
862  * OK, we've got all the baserestrictinfo quals for this child.
863  */
864  childrel->baserestrictinfo = childquals;
865  childrel->baserestrict_min_security = cq_min_security;
866 
867  return true;
868 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:587
Index security_level
Definition: pathnodes.h:2071
List * securityQuals
Definition: parsenodes.h:1163
List * baserestrictinfo
Definition: pathnodes.h:745
#define Min(x, y)
Definition: c.h:986
Definition: nodes.h:536
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2094
Index baserestrict_min_security
Definition: pathnodes.h:747
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:452
bool outerjoin_delayed
Definition: pathnodes.h:2060
#define DatumGetBool(X)
Definition: postgres.h:437
RestrictInfo * make_restrictinfo(PlannerInfo *root, Expr *clause, bool is_pushed_down, bool outerjoin_delayed, bool pseudoconstant, Index security_level, Relids required_relids, Relids outer_relids, Relids nullable_relids)
Definition: restrictinfo.c:61
List * lappend(List *list, void *datum)
Definition: list.c:336
Expr * clause
Definition: pathnodes.h:2056
List * make_ands_implicit(Expr *clause)
Definition: makefuncs.c:719
unsigned int Index
Definition: c.h:549
bool hasPseudoConstantQuals
Definition: pathnodes.h:349
bool is_pushed_down
Definition: pathnodes.h:2058
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
bool contain_vars_of_level(Node *node, int levelsup)
Definition: var.c:431
Definition: pg_list.h:50
Node * adjust_appendrel_attrs(PlannerInfo *root, Node *node, int nappinfos, AppendRelInfo **appinfos)
Definition: appendinfo.c:195

◆ expand_appendrel_subquery()

static void expand_appendrel_subquery ( PlannerInfo root,
RelOptInfo rel,
RangeTblEntry rte,
Index  rti 
)
static

Definition at line 713 of file inherit.c.

References PlannerInfo::append_rel_list, Assert, build_simple_rel(), AppendRelInfo::child_relid, expand_inherited_rtentry(), RangeTblEntry::inh, lfirst, AppendRelInfo::parent_relid, and PlannerInfo::simple_rte_array.

Referenced by expand_inherited_rtentry().

715 {
716  ListCell *l;
717 
718  foreach(l, root->append_rel_list)
719  {
720  AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
721  Index childRTindex = appinfo->child_relid;
722  RangeTblEntry *childrte;
723  RelOptInfo *childrel;
724 
725  /* append_rel_list contains all append rels; ignore others */
726  if (appinfo->parent_relid != rti)
727  continue;
728 
729  /* find the child RTE, which should already exist */
730  Assert(childRTindex < root->simple_rel_array_size);
731  childrte = root->simple_rte_array[childRTindex];
732  Assert(childrte != NULL);
733 
734  /* Build the child RelOptInfo. */
735  childrel = build_simple_rel(root, childRTindex, rel);
736 
737  /* Child may itself be an inherited rel, either table or subquery. */
738  if (childrte->inh)
739  expand_inherited_rtentry(root, childrel, childrte, childRTindex);
740  }
741 }
RelOptInfo * build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
Definition: relnode.c:194
RangeTblEntry ** simple_rte_array
Definition: pathnodes.h:194
List * append_rel_list
Definition: pathnodes.h:284
unsigned int Index
Definition: c.h:549
void expand_inherited_rtentry(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte, Index rti)
Definition: inherit.c:79
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
Index child_relid
Definition: pathnodes.h:2307
Index parent_relid
Definition: pathnodes.h:2306

◆ expand_inherited_rtentry()

void expand_inherited_rtentry ( PlannerInfo root,
RelOptInfo rel,
RangeTblEntry rte,
Index  rti 
)

Definition at line 79 of file inherit.c.

References add_vars_to_targetlist(), PlanRowMark::allMarkTypes, Assert, bms_make_singleton(), build_simple_rel(), expand_appendrel_subquery(), expand_partitioned_rtentry(), expand_planner_arrays(), expand_single_inheritance_child(), find_all_inheritors(), get_plan_rowmark(), RangeTblEntry::inh, InvalidOid, PlanRowMark::isParent, lappend(), lfirst_oid, linitial_oid, list_length(), makeTargetEntry(), makeVar(), makeWholeRowVar(), NIL, NoLock, planner_rt_fetch, PlannerInfo::processed_tlist, pstrdup(), RelationData::rd_rel, RELATION_IS_OTHER_TEMP, RangeTblEntry::relid, RangeTblEntry::relkind, RangeTblEntry::rellockmode, ROW_MARK_COPY, PlanRowMark::rowmarkId, PlannerInfo::rowMarks, RTE_RELATION, RTE_SUBQUERY, RangeTblEntry::rtekind, PlanRowMark::rti, SelfItemPointerAttributeNumber, snprintf, table_close(), table_open(), and TableOidAttributeNumber.

Referenced by add_other_rels_to_query(), and expand_appendrel_subquery().

81 {
82  Oid parentOID;
83  Relation oldrelation;
84  LOCKMODE lockmode;
85  PlanRowMark *oldrc;
86  bool old_isParent = false;
87  int old_allMarkTypes = 0;
88 
89  Assert(rte->inh); /* else caller error */
90 
91  if (rte->rtekind == RTE_SUBQUERY)
92  {
93  expand_appendrel_subquery(root, rel, rte, rti);
94  return;
95  }
96 
97  Assert(rte->rtekind == RTE_RELATION);
98 
99  parentOID = rte->relid;
100 
101  /*
102  * We used to check has_subclass() here, but there's no longer any need
103  * to, because subquery_planner already did.
104  */
105 
106  /*
107  * The rewriter should already have obtained an appropriate lock on each
108  * relation named in the query, so we can open the parent relation without
109  * locking it. However, for each child relation we add to the query, we
110  * must obtain an appropriate lock, because this will be the first use of
111  * those relations in the parse/rewrite/plan pipeline. Child rels should
112  * use the same lockmode as their parent.
113  */
114  oldrelation = table_open(parentOID, NoLock);
115  lockmode = rte->rellockmode;
116 
117  /*
118  * If parent relation is selected FOR UPDATE/SHARE, we need to mark its
119  * PlanRowMark as isParent = true, and generate a new PlanRowMark for each
120  * child.
121  */
122  oldrc = get_plan_rowmark(root->rowMarks, rti);
123  if (oldrc)
124  {
125  old_isParent = oldrc->isParent;
126  oldrc->isParent = true;
127  /* Save initial value of allMarkTypes before children add to it */
128  old_allMarkTypes = oldrc->allMarkTypes;
129  }
130 
131  /* Scan the inheritance set and expand it */
132  if (oldrelation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
133  {
134  /*
135  * Partitioned table, so set up for partitioning.
136  */
137  Assert(rte->relkind == RELKIND_PARTITIONED_TABLE);
138 
139  /*
140  * Recursively expand and lock the partitions. While at it, also
141  * extract the partition key columns of all the partitioned tables.
142  */
143  expand_partitioned_rtentry(root, rel, rte, rti,
144  oldrelation, oldrc, lockmode);
145  }
146  else
147  {
148  /*
149  * Ordinary table, so process traditional-inheritance children. (Note
150  * that partitioned tables are not allowed to have inheritance
151  * children, so it's not possible for both cases to apply.)
152  */
153  List *inhOIDs;
154  ListCell *l;
155 
156  /* Scan for all members of inheritance set, acquire needed locks */
157  inhOIDs = find_all_inheritors(parentOID, lockmode, NULL);
158 
159  /*
160  * We used to special-case the situation where the table no longer has
161  * any children, by clearing rte->inh and exiting. That no longer
162  * works, because this function doesn't get run until after decisions
163  * have been made that depend on rte->inh. We have to treat such
164  * situations as normal inheritance. The table itself should always
165  * have been found, though.
166  */
167  Assert(inhOIDs != NIL);
168  Assert(linitial_oid(inhOIDs) == parentOID);
169 
170  /* Expand simple_rel_array and friends to hold child objects. */
171  expand_planner_arrays(root, list_length(inhOIDs));
172 
173  /*
174  * Expand inheritance children in the order the OIDs were returned by
175  * find_all_inheritors.
176  */
177  foreach(l, inhOIDs)
178  {
179  Oid childOID = lfirst_oid(l);
180  Relation newrelation;
181  RangeTblEntry *childrte;
182  Index childRTindex;
183 
184  /* Open rel if needed; we already have required locks */
185  if (childOID != parentOID)
186  newrelation = table_open(childOID, NoLock);
187  else
188  newrelation = oldrelation;
189 
190  /*
191  * It is possible that the parent table has children that are temp
192  * tables of other backends. We cannot safely access such tables
193  * (because of buffering issues), and the best thing to do seems
194  * to be to silently ignore them.
195  */
196  if (childOID != parentOID && RELATION_IS_OTHER_TEMP(newrelation))
197  {
198  table_close(newrelation, lockmode);
199  continue;
200  }
201 
202  /* Create RTE and AppendRelInfo, plus PlanRowMark if needed. */
203  expand_single_inheritance_child(root, rte, rti, oldrelation,
204  oldrc, newrelation,
205  &childrte, &childRTindex);
206 
207  /* Create the otherrel RelOptInfo too. */
208  (void) build_simple_rel(root, childRTindex, rel);
209 
210  /* Close child relations, but keep locks */
211  if (childOID != parentOID)
212  table_close(newrelation, NoLock);
213  }
214  }
215 
216  /*
217  * Some children might require different mark types, which would've been
218  * reported into oldrc. If so, add relevant entries to the top-level
219  * targetlist and update parent rel's reltarget. This should match what
220  * preprocess_targetlist() would have added if the mark types had been
221  * requested originally.
222  *
223  * (Someday it might be useful to fold these resjunk columns into the
224  * row-identity-column management used for UPDATE/DELETE. Today is not
225  * that day, however.)
226  */
227  if (oldrc)
228  {
229  int new_allMarkTypes = oldrc->allMarkTypes;
230  Var *var;
231  TargetEntry *tle;
232  char resname[32];
233  List *newvars = NIL;
234 
235  /* Add TID junk Var if needed, unless we had it already */
236  if (new_allMarkTypes & ~(1 << ROW_MARK_COPY) &&
237  !(old_allMarkTypes & ~(1 << ROW_MARK_COPY)))
238  {
239  /* Need to fetch TID */
240  var = makeVar(oldrc->rti,
242  TIDOID,
243  -1,
244  InvalidOid,
245  0);
246  snprintf(resname, sizeof(resname), "ctid%u", oldrc->rowmarkId);
247  tle = makeTargetEntry((Expr *) var,
248  list_length(root->processed_tlist) + 1,
249  pstrdup(resname),
250  true);
251  root->processed_tlist = lappend(root->processed_tlist, tle);
252  newvars = lappend(newvars, var);
253  }
254 
255  /* Add whole-row junk Var if needed, unless we had it already */
256  if ((new_allMarkTypes & (1 << ROW_MARK_COPY)) &&
257  !(old_allMarkTypes & (1 << ROW_MARK_COPY)))
258  {
259  var = makeWholeRowVar(planner_rt_fetch(oldrc->rti, root),
260  oldrc->rti,
261  0,
262  false);
263  snprintf(resname, sizeof(resname), "wholerow%u", oldrc->rowmarkId);
264  tle = makeTargetEntry((Expr *) var,
265  list_length(root->processed_tlist) + 1,
266  pstrdup(resname),
267  true);
268  root->processed_tlist = lappend(root->processed_tlist, tle);
269  newvars = lappend(newvars, var);
270  }
271 
272  /* Add tableoid junk Var, unless we had it already */
273  if (!old_isParent)
274  {
275  var = makeVar(oldrc->rti,
277  OIDOID,
278  -1,
279  InvalidOid,
280  0);
281  snprintf(resname, sizeof(resname), "tableoid%u", oldrc->rowmarkId);
282  tle = makeTargetEntry((Expr *) var,
283  list_length(root->processed_tlist) + 1,
284  pstrdup(resname),
285  true);
286  root->processed_tlist = lappend(root->processed_tlist, tle);
287  newvars = lappend(newvars, var);
288  }
289 
290  /*
291  * Add the newly added Vars to parent's reltarget. We needn't worry
292  * about the children's reltargets, they'll be made later.
293  */
294  add_vars_to_targetlist(root, newvars, bms_make_singleton(0), false);
295  }
296 
297  table_close(oldrelation, NoLock);
298 }
#define NIL
Definition: pg_list.h:65
List * rowMarks
Definition: pathnodes.h:288
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
int LOCKMODE
Definition: lockdefs.h:26
char * pstrdup(const char *in)
Definition: mcxt.c:1299
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
static void expand_appendrel_subquery(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte, Index rti)
Definition: inherit.c:713
Form_pg_class rd_rel
Definition: rel.h:109
unsigned int Oid
Definition: postgres_ext.h:31
Definition: primnodes.h:186
Index rowmarkId
Definition: plannodes.h:1122
void add_vars_to_targetlist(PlannerInfo *root, List *vars, Relids where_needed, bool create_new_ph)
Definition: initsplan.c:230
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:435
#define planner_rt_fetch(rti, root)
Definition: pathnodes.h:388
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:186
#define NoLock
Definition: lockdefs.h:34
Var * makeWholeRowVar(RangeTblEntry *rte, int varno, Index varlevelsup, bool allowScalar)
Definition: makefuncs.c:133
#define TableOidAttributeNumber
Definition: sysattr.h:26
int allMarkTypes
Definition: plannodes.h:1124
RelOptInfo * build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
Definition: relnode.c:194
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:238
List * lappend(List *list, void *datum)
Definition: list.c:336
unsigned int Index
Definition: c.h:549
#define InvalidOid
Definition: postgres_ext.h:36
#define Assert(condition)
Definition: c.h:804
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:631
#define linitial_oid(l)
Definition: pg_list.h:176
static int list_length(const List *l)
Definition: pg_list.h:149
static void expand_partitioned_rtentry(PlannerInfo *root, RelOptInfo *relinfo, RangeTblEntry *parentrte, Index parentRTindex, Relation parentrel, PlanRowMark *top_parentrc, LOCKMODE lockmode)
Definition: inherit.c:305
RTEKind rtekind
Definition: parsenodes.h:1007
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:256
void expand_planner_arrays(PlannerInfo *root, int add_size)
Definition: relnode.c:152
PlanRowMark * get_plan_rowmark(List *rowmarks, Index rtindex)
Definition: preptlist.c:425
bool isParent
Definition: plannodes.h:1127
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21
List * processed_tlist
Definition: pathnodes.h:321
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define snprintf
Definition: port.h:217
#define lfirst_oid(lc)
Definition: pg_list.h:171

◆ expand_partitioned_rtentry()

static void expand_partitioned_rtentry ( PlannerInfo root,
RelOptInfo relinfo,
RangeTblEntry parentrte,
Index  parentRTindex,
Relation  parentrel,
PlanRowMark top_parentrc,
LOCKMODE  lockmode 
)
static

Definition at line 305 of file inherit.c.

References RelOptInfo::all_partrels, Assert, bms_add_members(), bms_next_member(), bms_num_members(), build_simple_rel(), check_stack_depth(), elog, ERROR, expand_planner_arrays(), expand_single_inheritance_child(), RangeTblEntry::extraUpdatedCols, PlannerInfo::glob, has_partition_attrs(), i, RangeTblEntry::inh, RelOptInfo::live_parts, NoLock, PartitionDescData::nparts, RelOptInfo::nparts, PartitionDescData::oids, palloc0(), RelOptInfo::part_rels, PlannerInfo::partColsUpdated, PlannerGlobal::partition_directory, PartitionDirectoryLookup(), prune_append_rel_partitions(), RelationData::rd_rel, RELATION_IS_OTHER_TEMP, RelOptInfo::relids, table_close(), table_open(), and RangeTblEntry::updatedCols.

Referenced by expand_inherited_rtentry().

309 {
310  PartitionDesc partdesc;
311  Bitmapset *live_parts;
312  int num_live_parts;
313  int i;
314 
316 
317  Assert(parentrte->inh);
318 
320  parentrel);
321 
322  /* A partitioned table should always have a partition descriptor. */
323  Assert(partdesc);
324 
325  /*
326  * Note down whether any partition key cols are being updated. Though it's
327  * the root partitioned table's updatedCols we are interested in, we
328  * instead use parentrte to get the updatedCols. This is convenient
329  * because parentrte already has the root partrel's updatedCols translated
330  * to match the attribute ordering of parentrel.
331  */
332  if (!root->partColsUpdated)
333  root->partColsUpdated =
334  has_partition_attrs(parentrel, parentrte->updatedCols, NULL);
335 
336  /*
337  * There shouldn't be any generated columns in the partition key.
338  */
339  Assert(!has_partition_attrs(parentrel, parentrte->extraUpdatedCols, NULL));
340 
341  /* Nothing further to do here if there are no partitions. */
342  if (partdesc->nparts == 0)
343  return;
344 
345  /*
346  * Perform partition pruning using restriction clauses assigned to parent
347  * relation. live_parts will contain PartitionDesc indexes of partitions
348  * that survive pruning. Below, we will initialize child objects for the
349  * surviving partitions.
350  */
351  relinfo->live_parts = live_parts = prune_append_rel_partitions(relinfo);
352 
353  /* Expand simple_rel_array and friends to hold child objects. */
354  num_live_parts = bms_num_members(live_parts);
355  if (num_live_parts > 0)
356  expand_planner_arrays(root, num_live_parts);
357 
358  /*
359  * We also store partition RelOptInfo pointers in the parent relation.
360  * Since we're palloc0'ing, slots corresponding to pruned partitions will
361  * contain NULL.
362  */
363  Assert(relinfo->part_rels == NULL);
364  relinfo->part_rels = (RelOptInfo **)
365  palloc0(relinfo->nparts * sizeof(RelOptInfo *));
366 
367  /*
368  * Create a child RTE for each live partition. Note that unlike
369  * traditional inheritance, we don't need a child RTE for the partitioned
370  * table itself, because it's not going to be scanned.
371  */
372  i = -1;
373  while ((i = bms_next_member(live_parts, i)) >= 0)
374  {
375  Oid childOID = partdesc->oids[i];
376  Relation childrel;
377  RangeTblEntry *childrte;
378  Index childRTindex;
379  RelOptInfo *childrelinfo;
380 
381  /* Open rel, acquiring required locks */
382  childrel = table_open(childOID, lockmode);
383 
384  /*
385  * Temporary partitions belonging to other sessions should have been
386  * disallowed at definition, but for paranoia's sake, let's double
387  * check.
388  */
389  if (RELATION_IS_OTHER_TEMP(childrel))
390  elog(ERROR, "temporary relation from another session found as partition");
391 
392  /* Create RTE and AppendRelInfo, plus PlanRowMark if needed. */
393  expand_single_inheritance_child(root, parentrte, parentRTindex,
394  parentrel, top_parentrc, childrel,
395  &childrte, &childRTindex);
396 
397  /* Create the otherrel RelOptInfo too. */
398  childrelinfo = build_simple_rel(root, childRTindex, relinfo);
399  relinfo->part_rels[i] = childrelinfo;
400  relinfo->all_partrels = bms_add_members(relinfo->all_partrels,
401  childrelinfo->relids);
402 
403  /* If this child is itself partitioned, recurse */
404  if (childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
405  expand_partitioned_rtentry(root, childrelinfo,
406  childrte, childRTindex,
407  childrel, top_parentrc, lockmode);
408 
409  /* Close child relation, but keep locks */
410  table_close(childrel, NoLock);
411  }
412 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1043
Relids all_partrels
Definition: pathnodes.h:773
Form_pg_class rd_rel
Definition: rel.h:109
unsigned int Oid
Definition: postgres_ext.h:31
Bitmapset * live_parts
Definition: pathnodes.h:770
Bitmapset * extraUpdatedCols
Definition: parsenodes.h:1162
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:435
#define ERROR
Definition: elog.h:46
int bms_num_members(const Bitmapset *a)
Definition: bitmapset.c:646
bool has_partition_attrs(Relation rel, Bitmapset *attnums, bool *used_in_expr)
Definition: partition.c:253
#define NoLock
Definition: lockdefs.h:34
void check_stack_depth(void)
Definition: postgres.c:3469
PlannerGlobal * glob
Definition: pathnodes.h:164
bool partColsUpdated
Definition: pathnodes.h:379
int nparts
Definition: pathnodes.h:761
Relids relids
Definition: pathnodes.h:681
RelOptInfo * build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
Definition: relnode.c:194
void * palloc0(Size size)
Definition: mcxt.c:1093
unsigned int Index
Definition: c.h:549
Bitmapset * updatedCols
Definition: parsenodes.h:1161
#define Assert(condition)
Definition: c.h:804
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:631
struct RelOptInfo ** part_rels
Definition: pathnodes.h:768
static void expand_partitioned_rtentry(PlannerInfo *root, RelOptInfo *relinfo, RangeTblEntry *parentrte, Index parentRTindex, Relation parentrel, PlanRowMark *top_parentrc, LOCKMODE lockmode)
Definition: inherit.c:305
Bitmapset * prune_append_rel_partitions(RelOptInfo *rel)
Definition: partprune.c:752
void expand_planner_arrays(PlannerInfo *root, int add_size)
Definition: relnode.c:152
#define elog(elevel,...)
Definition: elog.h:232
int i
PartitionDesc PartitionDirectoryLookup(PartitionDirectory pdir, Relation rel)
Definition: partdesc.c:410
PartitionDirectory partition_directory
Definition: pathnodes.h:132
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:793

◆ expand_single_inheritance_child()

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 
)
static

Definition at line 435 of file inherit.c.

References add_row_identity_columns(), add_row_identity_var(), RangeTblEntry::alias, Alias::aliasname, PlannerInfo::all_result_relids, PlanRowMark::allMarkTypes, PlannerInfo::append_rel_array, PlannerInfo::append_rel_list, Assert, attname, bms_add_member(), bms_copy(), bms_is_member(), Alias::colnames, copyObject, RangeTblEntry::eref, RangeTblEntry::extraUpdatedCols, RangeTblEntry::inh, RangeTblEntry::insertedCols, InvalidOid, PlanRowMark::isParent, lappend(), PlannerInfo::leaf_result_relids, list_length(), list_nth(), make_append_rel_info(), makeAlias(), makeNode, makeString(), makeVar(), PlanRowMark::markType, NameStr, TupleDescData::natts, NIL, AppendRelInfo::parent_colnos, parse(), PlannerInfo::parse, PlanRowMark::prti, pstrdup(), RelationData::rd_rel, RelationGetDescr, RelationGetRelid, RangeTblEntry::relid, RangeTblEntry::relkind, RangeTblEntry::requiredPerms, PlanRowMark::rowmarkId, PlannerInfo::rowMarks, Query::rtable, RTE_RELATION, RangeTblEntry::rtekind, PlanRowMark::rti, RangeTblEntry::securityQuals, select_rowmark_type(), RangeTblEntry::selectedCols, PlannerInfo::simple_rte_array, PlanRowMark::strength, strVal, TableOidAttributeNumber, RangeTblEntry::tablesample, translate_col_privs(), AppendRelInfo::translated_vars, TupleDescAttr, RangeTblEntry::updatedCols, and PlanRowMark::waitPolicy.

Referenced by expand_inherited_rtentry(), and expand_partitioned_rtentry().

440 {
441  Query *parse = root->parse;
442  Oid parentOID = RelationGetRelid(parentrel);
443  Oid childOID = RelationGetRelid(childrel);
444  RangeTblEntry *childrte;
445  Index childRTindex;
446  AppendRelInfo *appinfo;
447  TupleDesc child_tupdesc;
448  List *parent_colnames;
449  List *child_colnames;
450 
451  /*
452  * Build an RTE for the child, and attach to query's rangetable list. We
453  * copy most scalar fields of the parent's RTE, but replace relation OID,
454  * relkind, and inh for the child. Also, set requiredPerms to zero since
455  * all required permissions checks are done on the original RTE. Likewise,
456  * set the child's securityQuals to empty, because we only want to apply
457  * the parent's RLS conditions regardless of what RLS properties
458  * individual children may have. (This is an intentional choice to make
459  * inherited RLS work like regular permissions checks.) The parent
460  * securityQuals will be propagated to children along with other base
461  * restriction clauses, so we don't need to do it here. Other
462  * infrastructure of the parent RTE has to be translated to match the
463  * child table's column ordering, which we do below, so a "flat" copy is
464  * sufficient to start with.
465  */
466  childrte = makeNode(RangeTblEntry);
467  memcpy(childrte, parentrte, sizeof(RangeTblEntry));
468  Assert(parentrte->rtekind == RTE_RELATION); /* else this is dubious */
469  childrte->relid = childOID;
470  childrte->relkind = childrel->rd_rel->relkind;
471  /* A partitioned child will need to be expanded further. */
472  if (childrte->relkind == RELKIND_PARTITIONED_TABLE)
473  {
474  Assert(childOID != parentOID);
475  childrte->inh = true;
476  }
477  else
478  childrte->inh = false;
479  childrte->requiredPerms = 0;
480  childrte->securityQuals = NIL;
481 
482  /* Link not-yet-fully-filled child RTE into data structures */
483  parse->rtable = lappend(parse->rtable, childrte);
484  childRTindex = list_length(parse->rtable);
485  *childrte_p = childrte;
486  *childRTindex_p = childRTindex;
487 
488  /*
489  * Build an AppendRelInfo struct for each parent/child pair.
490  */
491  appinfo = make_append_rel_info(parentrel, childrel,
492  parentRTindex, childRTindex);
493  root->append_rel_list = lappend(root->append_rel_list, appinfo);
494 
495  /* tablesample is probably null, but copy it */
496  childrte->tablesample = copyObject(parentrte->tablesample);
497 
498  /*
499  * Construct an alias clause for the child, which we can also use as eref.
500  * This is important so that EXPLAIN will print the right column aliases
501  * for child-table columns. (Since ruleutils.c doesn't have any easy way
502  * to reassociate parent and child columns, we must get the child column
503  * aliases right to start with. Note that setting childrte->alias forces
504  * ruleutils.c to use these column names, which it otherwise would not.)
505  */
506  child_tupdesc = RelationGetDescr(childrel);
507  parent_colnames = parentrte->eref->colnames;
508  child_colnames = NIL;
509  for (int cattno = 0; cattno < child_tupdesc->natts; cattno++)
510  {
511  Form_pg_attribute att = TupleDescAttr(child_tupdesc, cattno);
512  const char *attname;
513 
514  if (att->attisdropped)
515  {
516  /* Always insert an empty string for a dropped column */
517  attname = "";
518  }
519  else if (appinfo->parent_colnos[cattno] > 0 &&
520  appinfo->parent_colnos[cattno] <= list_length(parent_colnames))
521  {
522  /* Duplicate the query-assigned name for the parent column */
523  attname = strVal(list_nth(parent_colnames,
524  appinfo->parent_colnos[cattno] - 1));
525  }
526  else
527  {
528  /* New column, just use its real name */
529  attname = NameStr(att->attname);
530  }
531  child_colnames = lappend(child_colnames, makeString(pstrdup(attname)));
532  }
533 
534  /*
535  * We just duplicate the parent's table alias name for each child. If the
536  * plan gets printed, ruleutils.c has to sort out unique table aliases to
537  * use, which it can handle.
538  */
539  childrte->alias = childrte->eref = makeAlias(parentrte->eref->aliasname,
540  child_colnames);
541 
542  /*
543  * Translate the column permissions bitmaps to the child's attnums (we
544  * have to build the translated_vars list before we can do this). But if
545  * this is the parent table, we can just duplicate the parent's bitmaps.
546  *
547  * Note: we need to do this even though the executor won't run any
548  * permissions checks on the child RTE. The insertedCols/updatedCols
549  * bitmaps may be examined for trigger-firing purposes.
550  */
551  if (childOID != parentOID)
552  {
553  childrte->selectedCols = translate_col_privs(parentrte->selectedCols,
554  appinfo->translated_vars);
555  childrte->insertedCols = translate_col_privs(parentrte->insertedCols,
556  appinfo->translated_vars);
557  childrte->updatedCols = translate_col_privs(parentrte->updatedCols,
558  appinfo->translated_vars);
560  appinfo->translated_vars);
561  }
562  else
563  {
564  childrte->selectedCols = bms_copy(parentrte->selectedCols);
565  childrte->insertedCols = bms_copy(parentrte->insertedCols);
566  childrte->updatedCols = bms_copy(parentrte->updatedCols);
567  childrte->extraUpdatedCols = bms_copy(parentrte->extraUpdatedCols);
568  }
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), 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. */
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 
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,
640  InvalidOid,
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 }
static Bitmapset * translate_col_privs(const Bitmapset *parent_privs, List *translated_vars)
Definition: inherit.c:663
#define NIL
Definition: pg_list.h:65
List * rowMarks
Definition: pathnodes.h:288
Relids all_result_relids
Definition: pathnodes.h:276
Query * parse
Definition: pathnodes.h:162
RowMarkType markType
Definition: plannodes.h:1123
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
Alias * alias
Definition: parsenodes.h:1152
List * colnames
Definition: primnodes.h:43
#define RelationGetDescr(relation)
Definition: rel.h:503
AttrNumber * parent_colnos
Definition: pathnodes.h:2343
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
RowMarkType select_rowmark_type(RangeTblEntry *rte, LockClauseStrength strength)
Definition: planner.c:2238
List * securityQuals
Definition: parsenodes.h:1163
char * pstrdup(const char *in)
Definition: mcxt.c:1299
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
#define strVal(v)
Definition: value.h:65
Index prti
Definition: plannodes.h:1121
String * makeString(char *str)
Definition: value.c:51
AclMode requiredPerms
Definition: parsenodes.h:1157
Form_pg_class rd_rel
Definition: rel.h:109
unsigned int Oid
Definition: postgres_ext.h:31
Definition: primnodes.h:186
Index rowmarkId
Definition: plannodes.h:1122
LockWaitPolicy waitPolicy
Definition: plannodes.h:1126
List * translated_vars
Definition: pathnodes.h:2334
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:387
Bitmapset * extraUpdatedCols
Definition: parsenodes.h:1162
Bitmapset * selectedCols
Definition: parsenodes.h:1159
List * rtable
Definition: parsenodes.h:147
NameData attname
Definition: pg_attribute.h:41
static void * list_nth(const List *list, int n)
Definition: pg_list.h:278
#define TableOidAttributeNumber
Definition: sysattr.h:26
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
int allMarkTypes
Definition: plannodes.h:1124
List * lappend(List *list, void *datum)
Definition: list.c:336
RangeTblEntry ** simple_rte_array
Definition: pathnodes.h:194
List * append_rel_list
Definition: pathnodes.h:284
struct AppendRelInfo ** append_rel_array
Definition: pathnodes.h:202
unsigned int Index
Definition: c.h:549
#define InvalidOid
Definition: postgres_ext.h:36
Bitmapset * updatedCols
Definition: parsenodes.h:1161
#define makeNode(_type_)
Definition: nodes.h:584
#define Assert(condition)
Definition: c.h:804
char * aliasname
Definition: primnodes.h:42
LockClauseStrength strength
Definition: plannodes.h:1125
static int list_length(const List *l)
Definition: pg_list.h:149
void add_row_identity_var(PlannerInfo *root, Var *orig_var, Index rtindex, const char *rowid_name)
Definition: appendinfo.c:763
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
RTEKind rtekind
Definition: parsenodes.h:1007
Bitmapset * insertedCols
Definition: parsenodes.h:1160
Relids leaf_result_relids
Definition: pathnodes.h:277
#define NameStr(name)
Definition: c.h:681
bool isParent
Definition: plannodes.h:1127
Alias * eref
Definition: parsenodes.h:1153
#define copyObject(obj)
Definition: nodes.h:652
Definition: pg_list.h:50
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427
struct TableSampleClause * tablesample
Definition: parsenodes.h:1037
#define RelationGetRelid(relation)
Definition: rel.h:477
AppendRelInfo * make_append_rel_info(Relation parentrel, Relation childrel, Index parentRTindex, Index childRTindex)
Definition: appendinfo.c:50
void add_row_identity_columns(PlannerInfo *root, Index rtindex, RangeTblEntry *target_rte, Relation target_relation)
Definition: appendinfo.c:857
static struct subre * parse(struct vars *, int, int, struct state *, struct state *)
Definition: regcomp.c:673

◆ translate_col_privs()

static Bitmapset * translate_col_privs ( const Bitmapset parent_privs,
List translated_vars 
)
static

Definition at line 663 of file inherit.c.

References bms_add_member(), bms_is_member(), FirstLowInvalidHeapAttributeNumber, InvalidAttrNumber, lfirst_node, and Var::varattno.

Referenced by expand_single_inheritance_child().

665 {
666  Bitmapset *child_privs = NULL;
667  bool whole_row;
668  int attno;
669  ListCell *lc;
670 
671  /* System attributes have the same numbers in all tables */
672  for (attno = FirstLowInvalidHeapAttributeNumber + 1; attno < 0; attno++)
673  {
675  parent_privs))
676  child_privs = bms_add_member(child_privs,
678  }
679 
680  /* Check if parent has whole-row reference */
682  parent_privs);
683 
684  /* And now translate the regular user attributes, using the vars list */
685  attno = InvalidAttrNumber;
686  foreach(lc, translated_vars)
687  {
688  Var *var = lfirst_node(Var, lc);
689 
690  attno++;
691  if (var == NULL) /* ignore dropped columns */
692  continue;
693  if (whole_row ||
695  parent_privs))
696  child_privs = bms_add_member(child_privs,
698  }
699 
700  return child_privs;
701 }
AttrNumber varattno
Definition: primnodes.h:191
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
Definition: primnodes.h:186
#define lfirst_node(type, lc)
Definition: pg_list.h:172
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
#define InvalidAttrNumber
Definition: attnum.h:23
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427