diff options
Diffstat (limited to 'src/backend/utils/cache/plancache.c')
-rw-r--r-- | src/backend/utils/cache/plancache.c | 45 |
1 files changed, 43 insertions, 2 deletions
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c index d03d3b3cdff..26ef2fa6ff1 100644 --- a/src/backend/utils/cache/plancache.c +++ b/src/backend/utils/cache/plancache.c @@ -53,12 +53,14 @@ #include "catalog/namespace.h" #include "executor/executor.h" #include "executor/spi.h" +#include "miscadmin.h" #include "nodes/nodeFuncs.h" #include "optimizer/cost.h" #include "optimizer/planmain.h" #include "optimizer/prep.h" #include "parser/analyze.h" #include "parser/parsetree.h" +#include "rewrite/rowsecurity.h" #include "storage/lmgr.h" #include "tcop/pquery.h" #include "tcop/utility.h" @@ -151,6 +153,8 @@ CreateCachedPlan(Node *raw_parse_tree, CachedPlanSource *plansource; MemoryContext source_context; MemoryContext oldcxt; + Oid user_id; + int security_context; Assert(query_string != NULL); /* required as of 8.4 */ @@ -173,6 +177,8 @@ CreateCachedPlan(Node *raw_parse_tree, */ oldcxt = MemoryContextSwitchTo(source_context); + GetUserIdAndSecContext(&user_id, &security_context); + plansource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource)); plansource->magic = CACHEDPLANSOURCE_MAGIC; plansource->raw_parse_tree = copyObject(raw_parse_tree); @@ -201,6 +207,11 @@ CreateCachedPlan(Node *raw_parse_tree, plansource->generic_cost = -1; plansource->total_custom_cost = 0; plansource->num_custom_plans = 0; + plansource->has_rls = false; + plansource->rowSecurityDisabled + = (security_context & SECURITY_ROW_LEVEL_DISABLED) != 0; + plansource->row_security_env = row_security; + plansource->planUserId = InvalidOid; MemoryContextSwitchTo(oldcxt); @@ -371,7 +382,8 @@ CompleteCachedPlan(CachedPlanSource *plansource, */ extract_query_dependencies((Node *) querytree_list, &plansource->relationOids, - &plansource->invalItems); + &plansource->invalItems, + &plansource->has_rls); /* * Also save the current search_path in the query_context. (This @@ -566,6 +578,17 @@ RevalidateCachedQuery(CachedPlanSource *plansource) } /* + * If this is a new cached plan, then set the user id it was planned by + * and under what row security settings; these are needed to determine + * plan invalidation when RLS is involved. + */ + if (!OidIsValid(plansource->planUserId)) + { + plansource->planUserId = GetUserId(); + plansource->row_security_env = row_security; + } + + /* * If the query is currently valid, we should have a saved search_path --- * check to see if that matches the current environment. If not, we want * to force replan. @@ -583,6 +606,23 @@ RevalidateCachedQuery(CachedPlanSource *plansource) } /* + * Check if row security is enabled for this query and things have changed + * such that we need to invalidate this plan and rebuild it. Note that if + * row security was explicitly disabled (eg: this is a FK check plan) then + * we don't invalidate due to RLS. + * + * Otherwise, if the plan has a possible RLS dependency, force a replan if + * either the role under which the plan was planned or the row_security + * setting has been changed. + */ + if (plansource->is_valid + && !plansource->rowSecurityDisabled + && plansource->has_rls + && (plansource->planUserId != GetUserId() + || plansource->row_security_env != row_security)) + plansource->is_valid = false; + + /* * If the query is currently valid, acquire locks on the referenced * objects; then check again. We need to do it this way to cover the race * condition that an invalidation message arrives before we get the locks. @@ -723,7 +763,8 @@ RevalidateCachedQuery(CachedPlanSource *plansource) */ extract_query_dependencies((Node *) qlist, &plansource->relationOids, - &plansource->invalItems); + &plansource->invalItems, + &plansource->has_rls); /* * Also save the current search_path in the query_context. (This should |