aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util/inherit.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/util/inherit.c')
-rw-r--r--src/backend/optimizer/util/inherit.c173
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;
+}