diff options
Diffstat (limited to 'src/backend/utils/cache')
-rw-r--r-- | src/backend/utils/cache/plancache.c | 45 | ||||
-rw-r--r-- | src/backend/utils/cache/relcache.c | 28 |
2 files changed, 69 insertions, 4 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 diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index b6f03df6a43..e7f7129bd9d 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -55,6 +55,7 @@ #include "catalog/pg_type.h" #include "catalog/schemapg.h" #include "catalog/storage.h" +#include "commands/policy.h" #include "commands/trigger.h" #include "miscadmin.h" #include "optimizer/clauses.h" @@ -966,6 +967,11 @@ RelationBuildDesc(Oid targetRelId, bool insertIt) else relation->trigdesc = NULL; + if (relation->rd_rel->relhasrowsecurity) + RelationBuildRowSecurity(relation); + else + relation->rsdesc = NULL; + /* * if it's an index, initialize index-related information */ @@ -1936,6 +1942,8 @@ RelationDestroyRelation(Relation relation, bool remember_tupdesc) MemoryContextDelete(relation->rd_indexcxt); if (relation->rd_rulescxt) MemoryContextDelete(relation->rd_rulescxt); + if (relation->rsdesc) + MemoryContextDelete(relation->rsdesc->rscxt); if (relation->rd_fdwroutine) pfree(relation->rd_fdwroutine); pfree(relation); @@ -3242,8 +3250,8 @@ RelationCacheInitializePhase3(void) * wrong in the results from formrdesc or the relcache cache file. If we * faked up relcache entries using formrdesc, then read the real pg_class * rows and replace the fake entries with them. Also, if any of the - * relcache entries have rules or triggers, load that info the hard way - * since it isn't recorded in the cache file. + * relcache entries have rules, triggers, or security policies, load that + * info the hard way since it isn't recorded in the cache file. * * Whenever we access the catalogs to read data, there is a possibility of * a shared-inval cache flush causing relcache entries to be removed. @@ -3334,6 +3342,21 @@ RelationCacheInitializePhase3(void) restart = true; } + /* + * Re-load the row security policies if the relation has them, since + * they are not preserved in the cache. Note that we can never NOT + * have a policy while relhasrowsecurity is true- + * RelationBuildRowSecurity will create a single default-deny policy + * if there is no policy defined in pg_rowsecurity. + */ + if (relation->rd_rel->relhasrowsecurity && relation->rsdesc == NULL) + { + RelationBuildRowSecurity(relation); + + Assert (relation->rsdesc != NULL); + restart = true; + } + /* Release hold on the relation */ RelationDecrementReferenceCount(relation); @@ -4706,6 +4729,7 @@ load_relcache_init_file(bool shared) rel->rd_rules = NULL; rel->rd_rulescxt = NULL; rel->trigdesc = NULL; + rel->rsdesc = NULL; rel->rd_indexprs = NIL; rel->rd_indpred = NIL; rel->rd_exclops = NULL; |