summaryrefslogtreecommitdiff
path: root/src/backend/optimizer
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer')
-rw-r--r--src/backend/optimizer/plan/planner.c6
-rw-r--r--src/backend/optimizer/plan/setrefs.c73
-rw-r--r--src/backend/optimizer/plan/subselect.c8
-rw-r--r--src/backend/optimizer/prep/prepjointree.c21
-rw-r--r--src/backend/optimizer/util/inherit.c173
-rw-r--r--src/backend/optimizer/util/relnode.c21
6 files changed, 230 insertions, 72 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 799602f5ea..15aa9c5087 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -57,6 +57,7 @@
#include "optimizer/tlist.h"
#include "parser/analyze.h"
#include "parser/parse_agg.h"
+#include "parser/parse_relation.h"
#include "parser/parsetree.h"
#include "partitioning/partdesc.h"
#include "rewrite/rewriteManip.h"
@@ -306,6 +307,7 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
glob->subroots = NIL;
glob->rewindPlanIDs = NULL;
glob->finalrtable = NIL;
+ glob->finalrteperminfos = NIL;
glob->finalrowmarks = NIL;
glob->resultRelations = NIL;
glob->appendRelations = NIL;
@@ -493,6 +495,7 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
/* final cleanup of the plan */
Assert(glob->finalrtable == NIL);
+ Assert(glob->finalrteperminfos == NIL);
Assert(glob->finalrowmarks == NIL);
Assert(glob->resultRelations == NIL);
Assert(glob->appendRelations == NIL);
@@ -521,6 +524,7 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
result->planTree = top_plan;
result->partPruneInfos = glob->partPruneInfos;
result->rtable = glob->finalrtable;
+ result->permInfos = glob->finalrteperminfos;
result->resultRelations = glob->resultRelations;
result->appendRelations = glob->appendRelations;
result->subplans = glob->subplans;
@@ -6266,6 +6270,7 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid)
rte->inh = false;
rte->inFromCl = true;
query->rtable = list_make1(rte);
+ addRTEPermissionInfo(&query->rteperminfos, rte);
/* Set up RTE/RelOptInfo arrays */
setup_simple_rel_arrays(root);
@@ -6393,6 +6398,7 @@ plan_create_index_workers(Oid tableOid, Oid indexOid)
rte->inh = true;
rte->inFromCl = true;
query->rtable = list_make1(rte);
+ addRTEPermissionInfo(&query->rteperminfos, rte);
/* Set up RTE/RelOptInfo arrays */
setup_simple_rel_arrays(root);
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 399c1812d4..596f1fbc8e 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -24,6 +24,7 @@
#include "optimizer/planmain.h"
#include "optimizer/planner.h"
#include "optimizer/tlist.h"
+#include "parser/parse_relation.h"
#include "tcop/utility.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
@@ -78,6 +79,13 @@ typedef struct
int newvarno;
} fix_windowagg_cond_context;
+/* Context info for flatten_rtes_walker() */
+typedef struct
+{
+ PlannerGlobal *glob;
+ Query *query;
+} flatten_rtes_walker_context;
+
/*
* Selecting the best alternative in an AlternativeSubPlan expression requires
* estimating how many times that expression will be evaluated. For an
@@ -113,8 +121,9 @@ typedef struct
static void add_rtes_to_flat_rtable(PlannerInfo *root, bool recursing);
static void flatten_unplanned_rtes(PlannerGlobal *glob, RangeTblEntry *rte);
-static bool flatten_rtes_walker(Node *node, PlannerGlobal *glob);
-static void add_rte_to_flat_rtable(PlannerGlobal *glob, RangeTblEntry *rte);
+static bool flatten_rtes_walker(Node *node, flatten_rtes_walker_context *cxt);
+static void add_rte_to_flat_rtable(PlannerGlobal *glob, List *rteperminfos,
+ RangeTblEntry *rte);
static Plan *set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset);
static Plan *set_indexonlyscan_references(PlannerInfo *root,
IndexOnlyScan *plan,
@@ -380,6 +389,9 @@ set_plan_references(PlannerInfo *root, Plan *plan)
* Extract RangeTblEntries from the plan's rangetable, and add to flat rtable
*
* This can recurse into subquery plans; "recursing" is true if so.
+ *
+ * This also seems like a good place to add the query's RTEPermissionInfos to
+ * the flat rteperminfos.
*/
static void
add_rtes_to_flat_rtable(PlannerInfo *root, bool recursing)
@@ -400,7 +412,7 @@ add_rtes_to_flat_rtable(PlannerInfo *root, bool recursing)
RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
if (!recursing || rte->rtekind == RTE_RELATION)
- add_rte_to_flat_rtable(glob, rte);
+ add_rte_to_flat_rtable(glob, root->parse->rteperminfos, rte);
}
/*
@@ -467,18 +479,21 @@ add_rtes_to_flat_rtable(PlannerInfo *root, bool recursing)
/*
* Extract RangeTblEntries from a subquery that was never planned at all
*/
+
static void
flatten_unplanned_rtes(PlannerGlobal *glob, RangeTblEntry *rte)
{
+ flatten_rtes_walker_context cxt = {glob, rte->subquery};
+
/* Use query_tree_walker to find all RTEs in the parse tree */
(void) query_tree_walker(rte->subquery,
flatten_rtes_walker,
- (void *) glob,
+ (void *) &cxt,
QTW_EXAMINE_RTES_BEFORE);
}
static bool
-flatten_rtes_walker(Node *node, PlannerGlobal *glob)
+flatten_rtes_walker(Node *node, flatten_rtes_walker_context *cxt)
{
if (node == NULL)
return false;
@@ -488,33 +503,38 @@ flatten_rtes_walker(Node *node, PlannerGlobal *glob)
/* As above, we need only save relation RTEs */
if (rte->rtekind == RTE_RELATION)
- add_rte_to_flat_rtable(glob, rte);
+ add_rte_to_flat_rtable(cxt->glob, cxt->query->rteperminfos, rte);
return false;
}
if (IsA(node, Query))
{
- /* Recurse into subselects */
+ /*
+ * Recurse into subselects. Must update cxt->query to this query so
+ * that the rtable and rteperminfos correspond with each other.
+ */
+ cxt->query = (Query *) node;
return query_tree_walker((Query *) node,
flatten_rtes_walker,
- (void *) glob,
+ (void *) cxt,
QTW_EXAMINE_RTES_BEFORE);
}
return expression_tree_walker(node, flatten_rtes_walker,
- (void *) glob);
+ (void *) cxt);
}
/*
- * Add (a copy of) the given RTE to the final rangetable
+ * Add (a copy of) the given RTE to the final rangetable and also the
+ * corresponding RTEPermissionInfo, if any, to final rteperminfos.
*
* In the flat rangetable, we zero out substructure pointers that are not
* needed by the executor; this reduces the storage space and copying cost
- * for cached plans. We keep only the ctename, alias and eref Alias fields,
- * which are needed by EXPLAIN, and the selectedCols, insertedCols,
- * updatedCols, and extraUpdatedCols bitmaps, which are needed for
- * executor-startup permissions checking and for trigger event checking.
+ * for cached plans. We keep only the ctename, alias, eref Alias fields,
+ * which are needed by EXPLAIN, and perminfoindex which is needed by the
+ * executor to fetch the RTE's RTEPermissionInfo.
*/
static void
-add_rte_to_flat_rtable(PlannerGlobal *glob, RangeTblEntry *rte)
+add_rte_to_flat_rtable(PlannerGlobal *glob, List *rteperminfos,
+ RangeTblEntry *rte)
{
RangeTblEntry *newrte;
@@ -552,6 +572,29 @@ add_rte_to_flat_rtable(PlannerGlobal *glob, RangeTblEntry *rte)
*/
if (newrte->rtekind == RTE_RELATION)
glob->relationOids = lappend_oid(glob->relationOids, newrte->relid);
+
+ /*
+ * Add a copy of the RTEPermissionInfo, if any, corresponding to this RTE
+ * to the flattened global list.
+ */
+ if (rte->perminfoindex > 0)
+ {
+ RTEPermissionInfo *perminfo;
+ RTEPermissionInfo *newperminfo;
+
+ /* Get the existing one from this query's rteperminfos. */
+ perminfo = getRTEPermissionInfo(rteperminfos, newrte);
+
+ /*
+ * Add a new one to finalrteperminfos and copy the contents of the
+ * existing one into it. Note that addRTEPermissionInfo() also
+ * updates newrte->perminfoindex to point to newperminfo in
+ * finalrteperminfos.
+ */
+ newrte->perminfoindex = 0; /* expected by addRTEPermissionInfo() */
+ newperminfo = addRTEPermissionInfo(&glob->finalrteperminfos, newrte);
+ memcpy(newperminfo, perminfo, sizeof(RTEPermissionInfo));
+ }
}
/*
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index 92e3338584..abd407825b 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -1496,8 +1496,12 @@ convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink,
if (!bms_is_subset(upper_varnos, available_rels))
return NULL;
- /* Now we can attach the modified subquery rtable to the parent */
- parse->rtable = list_concat(parse->rtable, subselect->rtable);
+ /*
+ * Now we can attach the modified subquery rtable to the parent. This also
+ * adds subquery's RTEPermissionInfos into the upper query.
+ */
+ CombineRangeTables(&parse->rtable, &parse->rteperminfos,
+ subselect->rtable, subselect->rteperminfos);
/*
* And finally, build the JoinExpr node.
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c
index 2ea3ca734e..57fea35e44 100644
--- a/src/backend/optimizer/prep/prepjointree.c
+++ b/src/backend/optimizer/prep/prepjointree.c
@@ -176,13 +176,6 @@ transform_MERGE_to_join(Query *parse)
joinrte->lateral = false;
joinrte->inh = false;
joinrte->inFromCl = true;
- joinrte->requiredPerms = 0;
- joinrte->checkAsUser = InvalidOid;
- joinrte->selectedCols = NULL;
- joinrte->insertedCols = NULL;
- joinrte->updatedCols = NULL;
- joinrte->extraUpdatedCols = NULL;
- joinrte->securityQuals = NIL;
/*
* Add completed RTE to pstate's range table list, so that we know its
@@ -1206,11 +1199,12 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
}
/*
- * Now append the adjusted rtable entries to upper query. (We hold off
- * until after fixing the upper rtable entries; no point in running that
- * code on the subquery ones too.)
+ * Now append the adjusted rtable entries and their perminfos to upper
+ * query. (We hold off until after fixing the upper rtable entries; no
+ * point in running that code on the subquery ones too.)
*/
- parse->rtable = list_concat(parse->rtable, subquery->rtable);
+ CombineRangeTables(&parse->rtable, &parse->rteperminfos,
+ subquery->rtable, subquery->rteperminfos);
/*
* Pull up any FOR UPDATE/SHARE markers, too. (OffsetVarNodes already
@@ -1346,9 +1340,10 @@ pull_up_simple_union_all(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte)
}
/*
- * Append child RTEs to parent rtable.
+ * Append child RTEs (and their perminfos) to parent rtable.
*/
- root->parse->rtable = list_concat(root->parse->rtable, rtable);
+ CombineRangeTables(&root->parse->rtable, &root->parse->rteperminfos,
+ rtable, subquery->rteperminfos);
/*
* Recursively scan the subquery's setOperations tree and add
diff --git a/src/backend/optimizer/util/inherit.c b/src/backend/optimizer/util/inherit.c
index 3d270e91d6..f51ce45cd3 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;
+}
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index d7b4434e7f..7085cf3c41 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -28,6 +28,7 @@
#include "optimizer/plancat.h"
#include "optimizer/restrictinfo.h"
#include "optimizer/tlist.h"
+#include "parser/parse_relation.h"
#include "utils/hsearch.h"
#include "utils/lsyscache.h"
@@ -223,7 +224,25 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
rel->rel_parallel_workers = -1; /* set up in get_relation_info */
rel->amflags = 0;
rel->serverid = InvalidOid;
- rel->userid = rte->checkAsUser;
+ if (rte->rtekind == RTE_RELATION)
+ {
+ /*
+ * Get the userid from the relation's RTEPermissionInfo, though only
+ * the tables mentioned in query are assigned RTEPermissionInfos.
+ * Child relations (otherrels) simply use the parent's value.
+ */
+ if (parent == NULL)
+ {
+ RTEPermissionInfo *perminfo;
+
+ perminfo = getRTEPermissionInfo(root->parse->rteperminfos, rte);
+ rel->userid = perminfo->checkAsUser;
+ }
+ else
+ rel->userid = parent->userid;
+ }
+ else
+ rel->userid = InvalidOid;
rel->useridiscurrent = false;
rel->fdwroutine = NULL;
rel->fdw_private = NULL;