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.c74
1 files changed, 69 insertions, 5 deletions
diff --git a/src/backend/optimizer/util/inherit.c b/src/backend/optimizer/util/inherit.c
index 38bc61e6878..a38df47e47e 100644
--- a/src/backend/optimizer/util/inherit.c
+++ b/src/backend/optimizer/util/inherit.c
@@ -421,10 +421,13 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
RangeTblEntry *childrte;
Index childRTindex;
AppendRelInfo *appinfo;
+ TupleDesc child_tupdesc;
+ List *parent_colnames;
+ List *child_colnames;
/*
* Build an RTE for the child, and attach to query's rangetable list. We
- * copy most fields of the parent's RTE, but replace relation OID,
+ * 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
@@ -432,10 +435,14 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
* 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.
+ * 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 = copyObject(parentrte);
- *childrte_p = childrte;
+ childrte = makeNode(RangeTblEntry);
+ memcpy(childrte, parentrte, sizeof(RangeTblEntry));
+ Assert(parentrte->rtekind == RTE_RELATION); /* else this is dubious */
childrte->relid = childOID;
childrte->relkind = childrel->rd_rel->relkind;
/* A partitioned child will need to be expanded further. */
@@ -448,8 +455,11 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
childrte->inh = false;
childrte->requiredPerms = 0;
childrte->securityQuals = NIL;
+
+ /* Link not-yet-fully-filled child RTE into data structures */
parse->rtable = lappend(parse->rtable, childrte);
childRTindex = list_length(parse->rtable);
+ *childrte_p = childrte;
*childRTindex_p = childRTindex;
/*
@@ -459,10 +469,57 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
parentRTindex, childRTindex);
root->append_rel_list = lappend(root->append_rel_list, appinfo);
+ /* tablesample is probably null, but copy it */
+ childrte->tablesample = copyObject(parentrte->tablesample);
+
+ /*
+ * Construct an alias clause for the child, which we can also use as eref.
+ * This is important so that EXPLAIN will print the right column aliases
+ * for child-table columns. (Since ruleutils.c doesn't have any easy way
+ * to reassociate parent and child columns, we must get the child column
+ * aliases right to start with. Note that setting childrte->alias forces
+ * ruleutils.c to use these column names, which it otherwise would not.)
+ */
+ child_tupdesc = RelationGetDescr(childrel);
+ parent_colnames = parentrte->eref->colnames;
+ child_colnames = NIL;
+ for (int cattno = 0; cattno < child_tupdesc->natts; cattno++)
+ {
+ Form_pg_attribute att = TupleDescAttr(child_tupdesc, cattno);
+ const char *attname;
+
+ if (att->attisdropped)
+ {
+ /* Always insert an empty string for a dropped column */
+ attname = "";
+ }
+ else if (appinfo->parent_colnos[cattno] > 0 &&
+ appinfo->parent_colnos[cattno] <= list_length(parent_colnames))
+ {
+ /* Duplicate the query-assigned name for the parent column */
+ attname = strVal(list_nth(parent_colnames,
+ appinfo->parent_colnos[cattno] - 1));
+ }
+ else
+ {
+ /* New column, just use its real name */
+ attname = NameStr(att->attname);
+ }
+ child_colnames = lappend(child_colnames, makeString(pstrdup(attname)));
+ }
+
+ /*
+ * We just duplicate the parent's table alias name for each child. If the
+ * plan gets printed, ruleutils.c has to sort out unique table aliases to
+ * use, which it can handle.
+ */
+ 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 leave copyObject's result alone.
+ * 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
@@ -479,6 +536,13 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
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