diff options
Diffstat (limited to 'src/backend/optimizer/plan/setrefs.c')
-rw-r--r-- | src/backend/optimizer/plan/setrefs.c | 73 |
1 files changed, 58 insertions, 15 deletions
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index 399c1812d40..596f1fbc8e5 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)); + } } /* |