diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index 39f5729..d3bfe80 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -204,6 +204,29 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent) rel->partitioned_child_rels = NIL; /* + * Pass top parent's relid down the inheritance hierarchy. If the parent + * has inh_root_parent set then pass it down. + */ + if (parent) + { + if (parent->inh_root_parent) + rel->inh_root_parent = parent->inh_root_parent; + else + { + RangeTblEntry *parent_rte; + + parent_rte = root->simple_rte_array[parent->relid]; + + if (parent_rte->rtekind == RTE_RELATION) + rel->inh_root_parent = parent->relid; + else + rel->inh_root_parent = 0; + } + } + else + rel->inh_root_parent = 0; + + /* * Pass top parent's relids down the inheritance hierarchy. If the parent * has top_parent_relids set, it's a direct or an indirect child of the * top parent indicated by top_parent_relids. By extension this child is diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index e0ece74..56451f1 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -4924,8 +4924,18 @@ examine_variable(PlannerInfo *root, Node *node, int varRelid, { /* Get index's table for permission check */ RangeTblEntry *rte; + RelOptInfo *rel = index->rel; + + /* + * For the child partition fetch the index of + * the root parent. + */ + if (rel->inh_root_parent) + rte = planner_rt_fetch(rel->inh_root_parent, + root); + else + rte = planner_rt_fetch(rel->relid, root); - rte = planner_rt_fetch(index->rel->relid, root); Assert(rte->rtekind == RTE_RELATION); /* @@ -4957,6 +4967,39 @@ examine_variable(PlannerInfo *root, Node *node, int varRelid, } /* + * transalate_varattno + * + * translate child attno to parent attno. + */ +static int +transalate_varattno(Oid oldrelid, Oid newrelid, int old_attno) +{ + Relation oldrelation = heap_open(oldrelid, NoLock); + TupleDesc old_tupdesc = RelationGetDescr(oldrelation); + HeapTuple newtup; + Form_pg_attribute att; + int new_attno = old_attno; + char *attname; + + att = TupleDescAttr(old_tupdesc, old_attno - 1); + attname = NameStr(att->attname); + + newtup = SearchSysCacheAttName(newrelid, attname); + if (!newtup) + { + heap_close(oldrelation, NoLock); + return InvalidAttrNumber; + } + + new_attno = ((Form_pg_attribute) GETSTRUCT(newtup))->attnum; + ReleaseSysCache(newtup); + + heap_close(oldrelation, NoLock); + + return new_attno; +} + +/* * examine_simple_variable * Handle a simple Var for examine_variable * @@ -4998,11 +5041,28 @@ examine_simple_variable(PlannerInfo *root, Var *var, if (HeapTupleIsValid(vardata->statsTuple)) { + RelOptInfo *rel; + Oid relid = rte->relid; + int varattno = var->varattno; + + rel = root->simple_rel_array[var->varno]; + + /* For the child partition fetch the index of the root parent. */ + if (rel->inh_root_parent) + { + rte = planner_rt_fetch(rel->inh_root_parent, root); + + varattno = transalate_varattno(relid, rte->relid, var->varattno); + if (AttributeNumberIsValid(varattno)) + relid = rte->relid; + else + varattno = var->varattno; + } /* check if user has permission to read this column */ vardata->acl_ok = - (pg_class_aclcheck(rte->relid, GetUserId(), + (pg_class_aclcheck(relid, GetUserId(), ACL_SELECT) == ACLCHECK_OK) || - (pg_attribute_aclcheck(rte->relid, var->varattno, GetUserId(), + (pg_attribute_aclcheck(relid, varattno, GetUserId(), ACL_SELECT) == ACLCHECK_OK); } else diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index 88d3723..9688fec 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -694,6 +694,7 @@ typedef struct RelOptInfo * rel) */ /* used for partitioned relations */ + Index inh_root_parent; /* RTI index of the inheritance root. */ PartitionScheme part_scheme; /* Partitioning scheme. */ int nparts; /* number of partitions */ struct PartitionBoundInfoData *boundinfo; /* Partition bounds */