diff options
Diffstat (limited to 'src/backend/optimizer/util/inherit.c')
-rw-r--r-- | src/backend/optimizer/util/inherit.c | 173 |
1 files changed, 132 insertions, 41 deletions
diff --git a/src/backend/optimizer/util/inherit.c b/src/backend/optimizer/util/inherit.c index 3d270e91d66..f51ce45cd3b 100644 --- a/src/backend/optimizer/util/inherit.c +++ b/src/backend/optimizer/util/inherit.c @@ -30,6 +30,7 @@ #include "optimizer/prep.h" #include "optimizer/restrictinfo.h" #include "parser/parsetree.h" +#include "parser/parse_relation.h" #include "partitioning/partdesc.h" #include "partitioning/partprune.h" #include "utils/rel.h" @@ -38,6 +39,7 @@ static void expand_partitioned_rtentry(PlannerInfo *root, RelOptInfo *relinfo, RangeTblEntry *parentrte, Index parentRTindex, Relation parentrel, + Bitmapset *parent_updatedCols, PlanRowMark *top_parentrc, LOCKMODE lockmode); static void expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte, @@ -47,6 +49,10 @@ static void expand_single_inheritance_child(PlannerInfo *root, Index *childRTindex_p); static Bitmapset *translate_col_privs(const Bitmapset *parent_privs, List *translated_vars); +static Bitmapset *translate_col_privs_multilevel(PlannerInfo *root, + RelOptInfo *rel, + RelOptInfo *top_parent_rel, + Bitmapset *top_parent_cols); static void expand_appendrel_subquery(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte, Index rti); @@ -131,6 +137,10 @@ expand_inherited_rtentry(PlannerInfo *root, RelOptInfo *rel, /* Scan the inheritance set and expand it */ if (oldrelation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) { + RTEPermissionInfo *perminfo; + + perminfo = getRTEPermissionInfo(root->parse->rteperminfos, rte); + /* * Partitioned table, so set up for partitioning. */ @@ -141,7 +151,9 @@ expand_inherited_rtentry(PlannerInfo *root, RelOptInfo *rel, * extract the partition key columns of all the partitioned tables. */ expand_partitioned_rtentry(root, rel, rte, rti, - oldrelation, oldrc, lockmode); + oldrelation, + perminfo->updatedCols, + oldrc, lockmode); } else { @@ -305,6 +317,7 @@ static void expand_partitioned_rtentry(PlannerInfo *root, RelOptInfo *relinfo, RangeTblEntry *parentrte, Index parentRTindex, Relation parentrel, + Bitmapset *parent_updatedCols, PlanRowMark *top_parentrc, LOCKMODE lockmode) { PartitionDesc partdesc; @@ -324,14 +337,13 @@ expand_partitioned_rtentry(PlannerInfo *root, RelOptInfo *relinfo, /* * Note down whether any partition key cols are being updated. Though it's - * the root partitioned table's updatedCols we are interested in, we - * instead use parentrte to get the updatedCols. This is convenient - * because parentrte already has the root partrel's updatedCols translated - * to match the attribute ordering of parentrel. + * the root partitioned table's updatedCols we are interested in, + * parent_updatedCols provided by the caller contains the root partrel's + * updatedCols translated to match the attribute ordering of parentrel. */ if (!root->partColsUpdated) root->partColsUpdated = - has_partition_attrs(parentrel, parentrte->updatedCols, NULL); + has_partition_attrs(parentrel, parent_updatedCols, NULL); /* * There shouldn't be any generated columns in the partition key. @@ -402,9 +414,19 @@ expand_partitioned_rtentry(PlannerInfo *root, RelOptInfo *relinfo, /* If this child is itself partitioned, recurse */ if (childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + { + AppendRelInfo *appinfo = root->append_rel_array[childRTindex]; + Bitmapset *child_updatedCols; + + child_updatedCols = translate_col_privs(parent_updatedCols, + appinfo->translated_vars); + expand_partitioned_rtentry(root, childrelinfo, childrte, childRTindex, - childrel, top_parentrc, lockmode); + childrel, + child_updatedCols, + top_parentrc, lockmode); + } /* Close child relation, but keep locks */ table_close(childrel, NoLock); @@ -451,17 +473,15 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte, /* * Build an RTE for the child, and attach to query's rangetable list. We * copy most scalar fields of the parent's RTE, but replace relation OID, - * relkind, and inh for the child. Also, set requiredPerms to zero since - * all required permissions checks are done on the original RTE. Likewise, - * set the child's securityQuals to empty, because we only want to apply - * the parent's RLS conditions regardless of what RLS properties - * individual children may have. (This is an intentional choice to make - * inherited RLS work like regular permissions checks.) The parent - * securityQuals will be propagated to children along with other base - * restriction clauses, so we don't need to do it here. Other - * infrastructure of the parent RTE has to be translated to match the - * child table's column ordering, which we do below, so a "flat" copy is - * sufficient to start with. + * relkind, and inh for the child. Set the child's securityQuals to + * empty, because we only want to apply the parent's RLS conditions + * regardless of what RLS properties individual children may have. (This + * is an intentional choice to make inherited RLS work like regular + * permissions checks.) The parent securityQuals will be propagated to + * children along with other base restriction clauses, so we don't need to + * do it here. Other infrastructure of the parent RTE has to be + * translated to match the child table's column ordering, which we do + * below, so a "flat" copy is sufficient to start with. */ childrte = makeNode(RangeTblEntry); memcpy(childrte, parentrte, sizeof(RangeTblEntry)); @@ -476,9 +496,16 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte, } else childrte->inh = false; - childrte->requiredPerms = 0; childrte->securityQuals = NIL; + /* + * No permission checking for the child RTE unless it's the parent + * relation in its child role, which only applies to traditional + * inheritance. + */ + if (childOID != parentOID) + childrte->perminfoindex = 0; + /* Link not-yet-fully-filled child RTE into data structures */ parse->rtable = lappend(parse->rtable, childrte); childRTindex = list_length(parse->rtable); @@ -539,33 +566,12 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte, childrte->alias = childrte->eref = makeAlias(parentrte->eref->aliasname, child_colnames); - /* - * Translate the column permissions bitmaps to the child's attnums (we - * have to build the translated_vars list before we can do this). But if - * this is the parent table, we can just duplicate the parent's bitmaps. - * - * Note: we need to do this even though the executor won't run any - * permissions checks on the child RTE. The insertedCols/updatedCols - * bitmaps may be examined for trigger-firing purposes. - */ + /* Translate the bitmapset of generated columns being updated. */ if (childOID != parentOID) - { - childrte->selectedCols = translate_col_privs(parentrte->selectedCols, - appinfo->translated_vars); - childrte->insertedCols = translate_col_privs(parentrte->insertedCols, - appinfo->translated_vars); - childrte->updatedCols = translate_col_privs(parentrte->updatedCols, - appinfo->translated_vars); childrte->extraUpdatedCols = translate_col_privs(parentrte->extraUpdatedCols, appinfo->translated_vars); - } else - { - childrte->selectedCols = bms_copy(parentrte->selectedCols); - childrte->insertedCols = bms_copy(parentrte->insertedCols); - childrte->updatedCols = bms_copy(parentrte->updatedCols); childrte->extraUpdatedCols = bms_copy(parentrte->extraUpdatedCols); - } /* * Store the RTE and appinfo in the respective PlannerInfo arrays, which @@ -649,6 +655,54 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte, } /* + * get_rel_all_updated_cols + * Returns the set of columns of a given "simple" relation that are + * updated by this query. + */ +Bitmapset * +get_rel_all_updated_cols(PlannerInfo *root, RelOptInfo *rel) +{ + Index relid; + RangeTblEntry *rte; + RTEPermissionInfo *perminfo; + Bitmapset *updatedCols, + *extraUpdatedCols; + + Assert(root->parse->commandType == CMD_UPDATE); + Assert(IS_SIMPLE_REL(rel)); + + /* + * We obtain updatedCols and extraUpdatedCols for the query's result + * relation. Then, if necessary, we map it to the column numbers of the + * relation for which they were requested. + */ + relid = root->parse->resultRelation; + rte = planner_rt_fetch(relid, root); + perminfo = getRTEPermissionInfo(root->parse->rteperminfos, rte); + + updatedCols = perminfo->updatedCols; + extraUpdatedCols = rte->extraUpdatedCols; + + /* + * For "other" rels, we must look up the root parent relation mentioned in + * the query, and translate the column numbers. + */ + if (rel->relid != relid) + { + RelOptInfo *top_parent_rel = find_base_rel(root, relid); + + Assert(IS_OTHER_REL(rel)); + + updatedCols = translate_col_privs_multilevel(root, rel, top_parent_rel, + updatedCols); + extraUpdatedCols = translate_col_privs_multilevel(root, rel, top_parent_rel, + extraUpdatedCols); + } + + return bms_union(updatedCols, extraUpdatedCols); +} + +/* * translate_col_privs * Translate a bitmapset representing per-column privileges from the * parent rel's attribute numbering to the child's. @@ -866,3 +920,40 @@ apply_child_basequals(PlannerInfo *root, RelOptInfo *parentrel, return true; } + +/* + * translate_col_privs_multilevel + * Recursively translates the column numbers contained in + * 'top_parent_cols' to the columns numbers of a descendent relation + * given by 'relid' + */ +static Bitmapset * +translate_col_privs_multilevel(PlannerInfo *root, RelOptInfo *rel, + RelOptInfo *top_parent_rel, + Bitmapset *top_parent_cols) +{ + Bitmapset *result; + AppendRelInfo *appinfo; + + if (top_parent_cols == NULL) + return NULL; + + /* Recurse if immediate parent is not the top parent. */ + if (rel->parent != top_parent_rel) + { + if (rel->parent) + result = translate_col_privs_multilevel(root, rel->parent, + top_parent_rel, + top_parent_cols); + else + elog(ERROR, "rel with relid %u is not a child rel", rel->relid); + } + + Assert(root->append_rel_array != NULL); + appinfo = root->append_rel_array[rel->relid]; + Assert(appinfo != NULL); + + result = translate_col_privs(top_parent_cols, appinfo->translated_vars); + + return result; +} |