Age Owner TLA Line data Source code
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);
45 : static void expand_single_inheritance_child(PlannerInfo *root,
46 : RangeTblEntry *parentrte,
47 : Index parentRTindex, Relation parentrel,
48 : PlanRowMark *top_parentrc, Relation childrel,
49 : RangeTblEntry **childrte_p,
50 : Index *childRTindex_p);
51 : static Bitmapset *translate_col_privs(const Bitmapset *parent_privs,
52 : List *translated_vars);
53 : static Bitmapset *translate_col_privs_multilevel(PlannerInfo *root,
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
1471 tgl 86 GIC 7850 : expand_inherited_rtentry(PlannerInfo *root, RelOptInfo *rel,
87 : RangeTblEntry *rte, Index rti)
1550 alvherre 88 ECB : {
89 : Oid parentOID;
90 : Relation oldrelation;
91 : LOCKMODE lockmode;
92 : PlanRowMark *oldrc;
1471 tgl 93 GIC 7850 : bool old_isParent = false;
94 7850 : int old_allMarkTypes = 0;
1550 alvherre 95 ECB :
1471 tgl 96 CBC 7850 : Assert(rte->inh); /* else caller error */
97 :
98 7850 : if (rte->rtekind == RTE_SUBQUERY)
99 : {
100 761 : expand_appendrel_subquery(root, rel, rte, rti);
1550 alvherre 101 GIC 761 : return;
1550 alvherre 102 ECB : }
1471 tgl 103 :
1471 tgl 104 GIC 7089 : Assert(rte->rtekind == RTE_RELATION);
105 :
1550 alvherre 106 CBC 7089 : parentOID = rte->relid;
107 :
1471 tgl 108 ECB : /*
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 : */
1503 rhaas 121 GIC 7089 : oldrelation = table_open(parentOID, NoLock);
1550 alvherre 122 7089 : lockmode = rte->rellockmode;
1550 alvherre 123 ECB :
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 : */
1550 alvherre 129 GIC 7089 : oldrc = get_plan_rowmark(root->rowMarks, rti);
130 7089 : if (oldrc)
1471 tgl 131 ECB : {
1471 tgl 132 CBC 656 : old_isParent = oldrc->isParent;
1550 alvherre 133 GIC 656 : oldrc->isParent = true;
1471 tgl 134 ECB : /* Save initial value of allMarkTypes before children add to it */
1471 tgl 135 CBC 656 : old_allMarkTypes = oldrc->allMarkTypes;
136 : }
1550 alvherre 137 ECB :
138 : /* Scan the inheritance set and expand it */
1503 rhaas 139 GIC 7089 : if (oldrelation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
140 : {
141 : RTEPermissionInfo *perminfo;
142 :
124 alvherre 143 GNC 5901 : perminfo = getRTEPermissionInfo(root->parse->rteperminfos, rte);
144 :
1475 tgl 145 ECB : /*
146 : * Partitioned table, so set up for partitioning.
147 : */
1550 alvherre 148 GIC 5901 : Assert(rte->relkind == RELKIND_PARTITIONED_TABLE);
1550 alvherre 149 ECB :
150 : /*
151 : * Recursively expand and lock the partitions. While at it, also
152 : * extract the partition key columns of all the partitioned tables.
153 : */
1471 tgl 154 CBC 5901 : expand_partitioned_rtentry(root, rel, rte, rti,
155 : oldrelation,
156 : perminfo->updatedCols,
157 : oldrc, lockmode);
158 : }
159 : else
160 : {
161 : /*
1475 tgl 162 ECB : * 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 */
1503 rhaas 170 GIC 1188 : 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
1471 tgl 178 ECB : * have been found, though.
179 : */
1471 tgl 180 GIC 1188 : Assert(inhOIDs != NIL);
181 1188 : Assert(linitial_oid(inhOIDs) == parentOID);
182 :
183 : /* Expand simple_rel_array and friends to hold child objects. */
184 1188 : expand_planner_arrays(root, list_length(inhOIDs));
185 :
186 : /*
187 : * Expand inheritance children in the order the OIDs were returned by
1550 alvherre 188 ECB : * find_all_inheritors.
189 : */
1550 alvherre 190 GIC 4449 : foreach(l, inhOIDs)
191 : {
1550 alvherre 192 CBC 3262 : 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 3262 : if (childOID != parentOID)
1539 andres 199 GIC 2074 : newrelation = table_open(childOID, NoLock);
1550 alvherre 200 ECB : else
1550 alvherre 201 GIC 1188 : 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
1550 alvherre 206 ECB : * (because of buffering issues), and the best thing to do seems
207 : * to be to silently ignore them.
208 : */
1550 alvherre 209 CBC 3262 : if (childOID != parentOID && RELATION_IS_OTHER_TEMP(newrelation))
210 : {
1539 andres 211 GIC 21 : table_close(newrelation, lockmode);
1550 alvherre 212 21 : continue;
213 : }
214 :
215 : /* Create RTE and AppendRelInfo, plus PlanRowMark if needed. */
1471 tgl 216 3241 : expand_single_inheritance_child(root, rte, rti, oldrelation,
1471 tgl 217 ECB : oldrc, newrelation,
218 : &childrte, &childRTindex);
219 :
220 : /* Create the otherrel RelOptInfo too. */
1471 tgl 221 GIC 3240 : (void) build_simple_rel(root, childRTindex, rel);
222 :
223 : /* Close child relations, but keep locks */
1550 alvherre 224 CBC 3240 : if (childOID != parentOID)
1539 andres 225 GIC 2052 : table_close(newrelation, NoLock);
226 : }
227 : }
228 :
1471 tgl 229 ECB : /*
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 : */
1471 tgl 240 GIC 7088 : if (oldrc)
241 : {
242 656 : int new_allMarkTypes = oldrc->allMarkTypes;
243 : Var *var;
244 : TargetEntry *tle;
245 : char resname[32];
246 656 : List *newvars = NIL;
247 :
676 tgl 248 ECB : /* Add TID junk Var if needed, unless we had it already */
676 tgl 249 GIC 656 : if (new_allMarkTypes & ~(1 << ROW_MARK_COPY) &&
676 tgl 250 CBC 654 : !(old_allMarkTypes & ~(1 << ROW_MARK_COPY)))
251 : {
252 : /* Need to fetch TID */
676 tgl 253 GIC 2 : var = makeVar(oldrc->rti,
676 tgl 254 ECB : SelfItemPointerAttributeNumber,
255 : TIDOID,
256 : -1,
257 : InvalidOid,
258 : 0);
676 tgl 259 GIC 2 : snprintf(resname, sizeof(resname), "ctid%u", oldrc->rowmarkId);
260 2 : tle = makeTargetEntry((Expr *) var,
676 tgl 261 CBC 2 : list_length(root->processed_tlist) + 1,
262 : pstrdup(resname),
263 : true);
676 tgl 264 GIC 2 : root->processed_tlist = lappend(root->processed_tlist, tle);
265 2 : newvars = lappend(newvars, var);
266 : }
1471 tgl 267 ECB :
268 : /* Add whole-row junk Var if needed, unless we had it already */
1471 tgl 269 CBC 656 : if ((new_allMarkTypes & (1 << ROW_MARK_COPY)) &&
1471 tgl 270 GIC 23 : !(old_allMarkTypes & (1 << ROW_MARK_COPY)))
271 : {
1471 tgl 272 CBC 19 : var = makeWholeRowVar(planner_rt_fetch(oldrc->rti, root),
273 19 : oldrc->rti,
274 : 0,
275 : false);
1471 tgl 276 GIC 19 : snprintf(resname, sizeof(resname), "wholerow%u", oldrc->rowmarkId);
1471 tgl 277 CBC 19 : tle = makeTargetEntry((Expr *) var,
278 19 : list_length(root->processed_tlist) + 1,
279 : pstrdup(resname),
1471 tgl 280 ECB : true);
1471 tgl 281 CBC 19 : root->processed_tlist = lappend(root->processed_tlist, tle);
1471 tgl 282 GIC 19 : newvars = lappend(newvars, var);
283 : }
1471 tgl 284 ECB :
285 : /* Add tableoid junk Var, unless we had it already */
1471 tgl 286 CBC 656 : if (!old_isParent)
287 : {
1471 tgl 288 GIC 656 : var = makeVar(oldrc->rti,
1471 tgl 289 ECB : TableOidAttributeNumber,
290 : OIDOID,
291 : -1,
292 : InvalidOid,
293 : 0);
1471 tgl 294 CBC 656 : snprintf(resname, sizeof(resname), "tableoid%u", oldrc->rowmarkId);
1471 tgl 295 GIC 656 : tle = makeTargetEntry((Expr *) var,
1471 tgl 296 CBC 656 : list_length(root->processed_tlist) + 1,
297 : pstrdup(resname),
298 : true);
1471 tgl 299 GIC 656 : root->processed_tlist = lappend(root->processed_tlist, tle);
300 656 : newvars = lappend(newvars, var);
301 : }
1550 alvherre 302 ECB :
303 : /*
1471 tgl 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 : */
235 tgl 307 GNC 656 : add_vars_to_targetlist(root, newvars, bms_make_singleton(0));
1550 alvherre 308 ECB : }
309 :
1539 andres 310 GIC 7088 : table_close(oldrelation, NoLock);
311 : }
312 :
313 : /*
314 : * expand_partitioned_rtentry
1550 alvherre 315 ECB : * Recursively expand an RTE for a partitioned table.
316 : */
317 : static void
1471 tgl 318 CBC 7401 : expand_partitioned_rtentry(PlannerInfo *root, RelOptInfo *relinfo,
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;
1471 tgl 327 ECB : int i;
328 :
1471 tgl 329 GIC 7401 : check_stack_depth();
330 :
331 7401 : Assert(parentrte->inh);
332 :
1494 rhaas 333 7401 : partdesc = PartitionDirectoryLookup(root->glob->partition_directory,
334 : parentrel);
335 :
336 : /* A partitioned table should always have a partition descriptor. */
1550 alvherre 337 7401 : Assert(partdesc);
1550 alvherre 338 ECB :
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 : */
1550 alvherre 345 CBC 7401 : if (!root->partColsUpdated)
1550 alvherre 346 GIC 7257 : root->partColsUpdated =
124 alvherre 347 GNC 7257 : has_partition_attrs(parentrel, parent_updatedCols, NULL);
348 :
349 : /* Nothing further to do here if there are no partitions. */
1550 alvherre 350 GIC 7401 : if (partdesc->nparts == 0)
351 18 : return;
352 :
1475 tgl 353 ECB : /*
1471 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.
1475 358 : */
614 drowley 359 CBC 7383 : relinfo->live_parts = live_parts = prune_append_rel_partitions(relinfo);
360 :
361 : /* Expand simple_rel_array and friends to hold child objects. */
1471 tgl 362 GIC 7383 : num_live_parts = bms_num_members(live_parts);
363 7383 : if (num_live_parts > 0)
364 7245 : expand_planner_arrays(root, num_live_parts);
365 :
366 : /*
1471 tgl 367 ECB : * 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 : */
1471 tgl 371 CBC 7383 : Assert(relinfo->part_rels == NULL);
372 7383 : relinfo->part_rels = (RelOptInfo **)
1471 tgl 373 GIC 7383 : 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.
1471 tgl 379 ECB : */
1471 tgl 380 CBC 7383 : i = -1;
381 21965 : while ((i = bms_next_member(live_parts, i)) >= 0)
382 : {
1550 alvherre 383 GIC 14582 : Oid childOID = partdesc->oids[i];
384 : Relation childrel;
385 : RangeTblEntry *childrte;
386 : Index childRTindex;
387 : RelOptInfo *childrelinfo;
1550 alvherre 388 ECB :
1503 rhaas 389 : /* Open rel, acquiring required locks */
1503 rhaas 390 GIC 14582 : childrel = table_open(childOID, lockmode);
1550 alvherre 391 ECB :
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 : */
1550 alvherre 397 GIC 14582 : if (RELATION_IS_OTHER_TEMP(childrel))
1550 alvherre 398 LBC 0 : elog(ERROR, "temporary relation from another session found as partition");
399 :
400 : /* Create RTE and AppendRelInfo, plus PlanRowMark if needed. */
1550 alvherre 401 GIC 14582 : expand_single_inheritance_child(root, parentrte, parentRTindex,
402 : parentrel, top_parentrc, childrel,
403 : &childrte, &childRTindex);
404 :
1471 tgl 405 ECB : /* Create the otherrel RelOptInfo too. */
1471 tgl 406 GBC 14582 : childrelinfo = build_simple_rel(root, childRTindex, relinfo);
1471 tgl 407 GIC 14582 : relinfo->part_rels[i] = childrelinfo;
1096 efujita 408 29164 : relinfo->all_partrels = bms_add_members(relinfo->all_partrels,
1096 efujita 409 CBC 14582 : childrelinfo->relids);
410 :
411 : /* If this child is itself partitioned, recurse */
1550 alvherre 412 GIC 14582 : if (childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
413 : {
124 alvherre 414 GNC 1500 : AppendRelInfo *appinfo = root->append_rel_array[childRTindex];
415 : Bitmapset *child_updatedCols;
416 :
417 1500 : child_updatedCols = translate_col_privs(parent_updatedCols,
418 : appinfo->translated_vars);
419 :
1471 tgl 420 GIC 1500 : expand_partitioned_rtentry(root, childrelinfo,
1471 tgl 421 ECB : childrte, childRTindex,
422 : childrel,
423 : child_updatedCols,
424 : top_parentrc, lockmode);
425 : }
1550 alvherre 426 :
427 : /* Close child relation, but keep locks */
1539 andres 428 GIC 14582 : table_close(childrel, NoLock);
429 : }
1550 alvherre 430 ECB : }
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
1550 alvherre 453 GIC 17823 : expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
454 : Index parentRTindex, Relation parentrel,
455 : PlanRowMark *top_parentrc, Relation childrel,
456 : RangeTblEntry **childrte_p,
457 : Index *childRTindex_p)
458 : {
459 17823 : Query *parse = root->parse;
460 17823 : Oid parentOID = RelationGetRelid(parentrel);
461 17823 : 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
1224 tgl 471 ECB : * 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 : */
1224 tgl 482 GIC 17823 : childrte = makeNode(RangeTblEntry);
483 17823 : memcpy(childrte, parentrte, sizeof(RangeTblEntry));
484 17823 : Assert(parentrte->rtekind == RTE_RELATION); /* else this is dubious */
1550 alvherre 485 17823 : childrte->relid = childOID;
486 17823 : childrte->relkind = childrel->rd_rel->relkind;
487 : /* A partitioned child will need to be expanded further. */
1475 tgl 488 17823 : if (childrte->relkind == RELKIND_PARTITIONED_TABLE)
489 : {
490 1500 : Assert(childOID != parentOID);
1550 alvherre 491 1500 : childrte->inh = true;
492 : }
493 : else
494 16323 : childrte->inh = false;
495 17823 : 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 : */
124 alvherre 502 GNC 17823 : if (childOID != parentOID)
503 16635 : childrte->perminfoindex = 0;
504 :
1224 tgl 505 ECB : /* Link not-yet-fully-filled child RTE into data structures */
1550 alvherre 506 CBC 17823 : parse->rtable = lappend(parse->rtable, childrte);
507 17823 : childRTindex = list_length(parse->rtable);
1224 tgl 508 17823 : *childrte_p = childrte;
1550 alvherre 509 17823 : *childRTindex_p = childRTindex;
510 :
1550 alvherre 511 ECB : /*
512 : * Build an AppendRelInfo struct for each parent/child pair.
513 : */
1475 tgl 514 CBC 17823 : appinfo = make_append_rel_info(parentrel, childrel,
515 : parentRTindex, childRTindex);
1471 tgl 516 GIC 17822 : root->append_rel_list = lappend(root->append_rel_list, appinfo);
1550 alvherre 517 ECB :
1224 tgl 518 : /* tablesample is probably null, but copy it */
1224 tgl 519 GIC 17822 : 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
1224 tgl 525 ECB : * 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 : */
1224 tgl 529 CBC 17822 : child_tupdesc = RelationGetDescr(childrel);
530 17822 : parent_colnames = parentrte->eref->colnames;
531 17822 : child_colnames = NIL;
532 68243 : for (int cattno = 0; cattno < child_tupdesc->natts; cattno++)
533 : {
1224 tgl 534 GIC 50421 : Form_pg_attribute att = TupleDescAttr(child_tupdesc, cattno);
535 : const char *attname;
536 :
1224 tgl 537 CBC 50421 : if (att->attisdropped)
538 : {
1224 tgl 539 ECB : /* Always insert an empty string for a dropped column */
1224 tgl 540 GIC 1078 : attname = "";
541 : }
1224 tgl 542 CBC 96751 : else if (appinfo->parent_colnos[cattno] > 0 &&
1224 tgl 543 GIC 47408 : appinfo->parent_colnos[cattno] <= list_length(parent_colnames))
544 : {
545 : /* Duplicate the query-assigned name for the parent column */
546 47408 : attname = strVal(list_nth(parent_colnames,
547 : appinfo->parent_colnos[cattno] - 1));
548 : }
549 : else
550 : {
551 : /* New column, just use its real name */
1224 tgl 552 CBC 1935 : attname = NameStr(att->attname);
1224 tgl 553 ECB : }
1224 tgl 554 CBC 50421 : child_colnames = lappend(child_colnames, makeString(pstrdup(attname)));
1224 tgl 555 ECB : }
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 : */
1224 tgl 562 GIC 17822 : childrte->alias = childrte->eref = makeAlias(parentrte->eref->aliasname,
1224 tgl 563 ECB : child_colnames);
564 :
565 : /*
566 : * Store the RTE and appinfo in the respective PlannerInfo arrays, which
1471 567 : * the caller must already have allocated space for.
568 : */
1471 tgl 569 CBC 17822 : Assert(childRTindex < root->simple_rel_array_size);
570 17822 : Assert(root->simple_rte_array[childRTindex] == NULL);
571 17822 : root->simple_rte_array[childRTindex] = childrte;
1471 tgl 572 GIC 17822 : Assert(root->append_rel_array[childRTindex] == NULL);
573 17822 : root->append_rel_array[childRTindex] = appinfo;
574 :
575 : /*
1550 alvherre 576 ECB : * Build a PlanRowMark if parent is marked FOR UPDATE/SHARE.
577 : */
1550 alvherre 578 CBC 17822 : if (top_parentrc)
579 : {
580 918 : PlanRowMark *childrc = makeNode(PlanRowMark);
1550 alvherre 581 ECB :
1550 alvherre 582 CBC 918 : childrc->rti = childRTindex;
1550 alvherre 583 GIC 918 : childrc->prti = top_parentrc->rti;
1550 alvherre 584 CBC 918 : childrc->rowmarkId = top_parentrc->rowmarkId;
585 : /* Reselect rowmark type, because relkind might not match parent */
586 918 : childrc->markType = select_rowmark_type(childrte,
1550 alvherre 587 ECB : top_parentrc->strength);
1550 alvherre 588 CBC 918 : childrc->allMarkTypes = (1 << childrc->markType);
1550 alvherre 589 GIC 918 : childrc->strength = top_parentrc->strength;
590 918 : 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
1471 tgl 595 ECB : * the child tables will be locked using the appropriate mode).
596 : */
1550 alvherre 597 GIC 918 : childrc->isParent = (childrte->relkind == RELKIND_PARTITIONED_TABLE);
1550 alvherre 598 ECB :
599 : /* Include child's rowmark type in top parent's allMarkTypes */
1550 alvherre 600 CBC 918 : top_parentrc->allMarkTypes |= childrc->allMarkTypes;
601 :
1550 alvherre 602 GIC 918 : 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
739 tgl 609 ECB : * required row-identity data.
610 : */
739 tgl 611 GIC 17822 : if (bms_is_member(parentRTindex, root->all_result_relids))
739 tgl 612 ECB : {
613 : /* OK, record the child as a result rel too. */
739 tgl 614 GIC 2519 : root->all_result_relids = bms_add_member(root->all_result_relids,
615 : childRTindex);
739 tgl 616 ECB :
617 : /* Non-leaf partitions don't need any row identity info. */
739 tgl 618 GIC 2519 : if (childrte->relkind != RELKIND_PARTITIONED_TABLE)
619 : {
739 tgl 620 ECB : Var *rrvar;
621 :
739 tgl 622 GIC 2255 : root->leaf_result_relids = bms_add_member(root->leaf_result_relids,
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
739 tgl 629 ECB : * thrashing about to avoid it.)
630 : */
739 tgl 631 GIC 2255 : rrvar = makeVar(childRTindex,
632 : TableOidAttributeNumber,
633 : OIDOID,
634 : -1,
739 tgl 635 ECB : InvalidOid,
636 : 0);
739 tgl 637 GIC 2255 : add_row_identity_var(root, rrvar, childRTindex, "tableoid");
739 tgl 638 ECB :
639 : /* Register any row-identity columns needed by this child. */
739 tgl 640 GIC 2255 : add_row_identity_columns(root, childRTindex,
641 : childrte, childrel);
739 tgl 642 ECB : }
643 : }
1550 alvherre 644 GIC 17822 : }
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.
124 alvherre 650 ECB : */
651 : Bitmapset *
124 alvherre 652 GIC 35 : get_rel_all_updated_cols(PlannerInfo *root, RelOptInfo *rel)
653 : {
654 : Index relid;
655 : RangeTblEntry *rte;
656 : RTEPermissionInfo *perminfo;
657 : Bitmapset *updatedCols,
658 : *extraUpdatedCols;
124 alvherre 659 ECB :
124 alvherre 660 CBC 35 : Assert(root->parse->commandType == CMD_UPDATE);
124 alvherre 661 GIC 35 : 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.
124 alvherre 667 ECB : */
124 alvherre 668 CBC 35 : relid = root->parse->resultRelation;
669 35 : rte = planner_rt_fetch(relid, root);
124 alvherre 670 GNC 35 : perminfo = getRTEPermissionInfo(root->parse->rteperminfos, rte);
671 :
672 35 : updatedCols = perminfo->updatedCols;
673 :
124 alvherre 674 CBC 35 : if (rel->relid != relid)
675 : {
676 17 : RelOptInfo *top_parent_rel = find_base_rel(root, relid);
677 :
678 17 : Assert(IS_OTHER_REL(rel));
679 :
680 17 : 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 : */
94 tgl 688 35 : extraUpdatedCols = get_dependent_generated_columns(root, rel->relid,
689 : updatedCols);
690 :
124 alvherre 691 35 : 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 *
1544 706 1519 : translate_col_privs(const Bitmapset *parent_privs,
707 : List *translated_vars)
708 : {
709 1519 : 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 10633 : for (attno = FirstLowInvalidHeapAttributeNumber + 1; attno < 0; attno++)
716 : {
717 9114 : if (bms_is_member(attno - FirstLowInvalidHeapAttributeNumber,
718 : parent_privs))
1544 alvherre 719 UBC 0 : child_privs = bms_add_member(child_privs,
720 : attno - FirstLowInvalidHeapAttributeNumber);
721 : }
722 :
723 : /* Check if parent has whole-row reference */
1544 alvherre 724 CBC 1519 : whole_row = bms_is_member(InvalidAttrNumber - FirstLowInvalidHeapAttributeNumber,
725 : parent_privs);
726 :
727 : /* And now translate the regular user attributes, using the vars list */
728 1519 : attno = InvalidAttrNumber;
729 5481 : foreach(lc, translated_vars)
730 : {
731 3962 : Var *var = lfirst_node(Var, lc);
732 :
733 3962 : attno++;
734 3962 : if (var == NULL) /* ignore dropped columns */
735 63 : continue;
736 7798 : if (whole_row ||
737 3899 : bms_is_member(attno - FirstLowInvalidHeapAttributeNumber,
738 : parent_privs))
739 261 : child_privs = bms_add_member(child_privs,
740 261 : var->varattno - FirstLowInvalidHeapAttributeNumber);
741 : }
742 :
743 1519 : 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 *
94 tgl 756 19 : translate_col_privs_multilevel(PlannerInfo *root, RelOptInfo *rel,
757 : RelOptInfo *parent_rel,
758 : Bitmapset *parent_cols)
759 : {
760 : AppendRelInfo *appinfo;
761 :
762 : /* Fast path for easy case. */
763 19 : if (parent_cols == NULL)
94 tgl 764 UBC 0 : return NULL;
765 :
766 : /* Recurse if immediate parent is not the top parent. */
94 tgl 767 GNC 19 : if (rel->parent != parent_rel)
768 : {
769 2 : if (rel->parent)
770 2 : parent_cols = translate_col_privs_multilevel(root, rel->parent,
771 : parent_rel,
772 : parent_cols);
773 : else
94 tgl 774 UNC 0 : elog(ERROR, "rel with relid %u is not a child rel", rel->relid);
775 : }
776 :
777 : /* Now translate for this child. */
94 tgl 778 GIC 19 : Assert(root->append_rel_array != NULL);
94 tgl 779 CBC 19 : appinfo = root->append_rel_array[rel->relid];
94 tgl 780 GIC 19 : Assert(appinfo != NULL);
94 tgl 781 ECB :
94 tgl 782 GIC 19 : return translate_col_privs(parent_cols, appinfo->translated_vars);
94 tgl 783 ECB : }
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
1471 tgl 795 GIC 761 : expand_appendrel_subquery(PlannerInfo *root, RelOptInfo *rel,
1471 tgl 796 ECB : RangeTblEntry *rte, Index rti)
797 : {
798 : ListCell *l;
799 :
1471 tgl 800 GIC 3102 : foreach(l, root->append_rel_list)
1471 tgl 801 ECB : {
1471 tgl 802 GIC 2341 : AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
1471 tgl 803 CBC 2341 : Index childRTindex = appinfo->child_relid;
1471 tgl 804 ECB : RangeTblEntry *childrte;
805 : RelOptInfo *childrel;
806 :
807 : /* append_rel_list contains all append rels; ignore others */
1471 tgl 808 GIC 2341 : if (appinfo->parent_relid != rti)
1471 tgl 809 CBC 573 : continue;
1471 tgl 810 ECB :
811 : /* find the child RTE, which should already exist */
1471 tgl 812 GIC 1768 : Assert(childRTindex < root->simple_rel_array_size);
1471 tgl 813 CBC 1768 : childrte = root->simple_rte_array[childRTindex];
814 1768 : Assert(childrte != NULL);
1471 tgl 815 ECB :
816 : /* Build the child RelOptInfo. */
1471 tgl 817 GIC 1768 : childrel = build_simple_rel(root, childRTindex, rel);
1471 tgl 818 ECB :
819 : /* Child may itself be an inherited rel, either table or subquery. */
1471 tgl 820 GIC 1768 : if (childrte->inh)
1471 tgl 821 CBC 106 : expand_inherited_rtentry(root, childrel, childrte, childRTindex);
1471 tgl 822 ECB : }
1471 tgl 823 GIC 761 : }
1471 tgl 824 ECB :
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
1471 tgl 836 GIC 19590 : apply_child_basequals(PlannerInfo *root, RelOptInfo *parentrel,
1471 tgl 837 ECB : 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 : */
1471 tgl 852 GIC 19590 : childquals = NIL;
1471 tgl 853 CBC 19590 : cq_min_security = UINT_MAX;
854 31982 : foreach(lc, parentrel->baserestrictinfo)
1471 tgl 855 ECB : {
1471 tgl 856 GIC 12431 : RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1471 tgl 857 ECB : Node *childqual;
858 : ListCell *lc2;
859 :
1471 tgl 860 GIC 12431 : Assert(IsA(rinfo, RestrictInfo));
1471 tgl 861 CBC 12431 : childqual = adjust_appendrel_attrs(root,
862 12431 : (Node *) rinfo->clause,
1471 tgl 863 ECB : 1, &appinfo);
1471 tgl 864 GIC 12431 : childqual = eval_const_expressions(root, childqual);
1471 tgl 865 ECB : /* check for flat-out constant */
1471 tgl 866 GIC 12431 : if (childqual && IsA(childqual, Const))
1471 tgl 867 ECB : {
1471 tgl 868 GIC 78 : if (((Const *) childqual)->constisnull ||
1471 tgl 869 CBC 78 : !DatumGetBool(((Const *) childqual)->constvalue))
1471 tgl 870 ECB : {
871 : /* Restriction reduces to constant FALSE or NULL */
1471 tgl 872 GIC 39 : return false;
1471 tgl 873 ECB : }
874 : /* Restriction reduces to constant TRUE, so drop it */
1471 tgl 875 GIC 39 : continue;
1471 tgl 876 ECB : }
877 : /* might have gotten an AND clause, if so flatten it */
1471 tgl 878 GIC 24712 : foreach(lc2, make_ands_implicit((Expr *) childqual))
1471 tgl 879 ECB : {
1471 tgl 880 GIC 12359 : Node *onecq = (Node *) lfirst(lc2);
1471 tgl 881 ECB : bool pseudoconstant;
882 :
883 : /* check for pseudoconstant (no Vars or volatile functions) */
1471 tgl 884 GIC 12359 : pseudoconstant =
1471 tgl 885 CBC 12382 : !contain_vars_of_level(onecq, 0) &&
886 23 : !contain_volatile_functions(onecq);
887 12359 : if (pseudoconstant)
1471 tgl 888 ECB : {
889 : /* tell createplan.c to check for gating quals */
1471 tgl 890 GIC 23 : root->hasPseudoConstantQuals = true;
1471 tgl 891 ECB : }
892 : /* reconstitute RestrictInfo with appropriate properties */
1471 tgl 893 GIC 12359 : childquals = lappend(childquals,
808 tgl 894 CBC 12359 : make_restrictinfo(root,
808 tgl 895 ECB : (Expr *) onecq,
1471 tgl 896 GIC 12359 : rinfo->is_pushed_down,
897 : pseudoconstant,
898 : rinfo->security_level,
899 : NULL, NULL));
900 : /* track minimum security level among child quals */
1471 tgl 901 CBC 12359 : 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 19551 : if (childRTE->securityQuals)
917 : {
918 6 : Index security_level = 0;
919 :
920 12 : foreach(lc, childRTE->securityQuals)
921 : {
922 6 : List *qualset = (List *) lfirst(lc);
923 : ListCell *lc2;
924 :
925 12 : foreach(lc2, qualset)
926 : {
927 6 : Expr *qual = (Expr *) lfirst(lc2);
928 :
929 : /* not likely that we'd see constants here, so no check */
930 6 : childquals = lappend(childquals,
808 931 6 : make_restrictinfo(root, qual,
932 : true, false,
933 : security_level,
934 : NULL, NULL));
1471 935 6 : cq_min_security = Min(cq_min_security, security_level);
936 : }
937 6 : security_level++;
938 : }
939 6 : Assert(security_level <= root->qual_security_level);
940 : }
941 :
942 : /*
943 : * OK, we've got all the baserestrictinfo quals for this child.
944 : */
945 19551 : childrel->baserestrictinfo = childquals;
946 19551 : childrel->baserestrict_min_security = cq_min_security;
947 :
948 19551 : return true;
949 : }
|