>From 5d8145dd0c47fb891139568f82ac87bc2403cfec Mon Sep 17 00:00:00 2001 From: Craig Ringer Date: Mon, 20 Jan 2014 13:44:45 +0800 Subject: [PATCH 01/10] RLS: Make plan caching dependent on user ID. --- src/backend/optimizer/plan/planner.c | 2 ++ src/backend/utils/cache/plancache.c | 32 ++++++++++++++++++++++++++++++++ src/include/nodes/plannodes.h | 2 ++ src/include/nodes/relation.h | 2 ++ src/include/utils/plancache.h | 2 ++ 5 files changed, 40 insertions(+) diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 35bda67..8c12eb9 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -177,6 +177,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) glob->lastPHId = 0; glob->lastRowMarkId = 0; glob->transientPlan = false; + glob->planUserId = InvalidOid; /* Determine what fraction of the plan is likely to be scanned */ if (cursorOptions & CURSOR_OPT_FAST_PLAN) @@ -254,6 +255,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) result->relationOids = glob->relationOids; result->invalItems = glob->invalItems; result->nParamExec = glob->nParamExec; + result->planUserId = glob->planUserId; return result; } diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c index d492cbb..77de2df 100644 --- a/src/backend/utils/cache/plancache.c +++ b/src/backend/utils/cache/plancache.c @@ -53,6 +53,7 @@ #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" @@ -795,6 +796,16 @@ CheckCachedPlan(CachedPlanSource *plansource) AcquireExecutorLocks(plan->stmt_list, true); /* + * If plan was constructed with assumption of a particular user-id, + * and it is different from the current one, the cached-plan shall + * be invalidated to construct suitable query plan. + */ + if (plan->is_valid && + OidIsValid(plan->planUserId) && + plan->planUserId == GetUserId()) + plan->is_valid = false; + + /* * If plan was transient, check to see if TransactionXmin has * advanced, and if so invalidate it. */ @@ -847,6 +858,8 @@ BuildCachedPlan(CachedPlanSource *plansource, List *qlist, { CachedPlan *plan; List *plist; + ListCell *cell; + Oid planUserId = InvalidOid; bool snapshot_set; bool spi_pushed; MemoryContext plan_context; @@ -914,6 +927,24 @@ BuildCachedPlan(CachedPlanSource *plansource, List *qlist, PopActiveSnapshot(); /* + * Check whether the generated plan assumes a particular user-id, or not. + * In case when a valid user-id is recorded on PlannedStmt->planUserId, + * it should be kept and used to validation check of the cached plan + * under the "current" user-id. + */ + foreach (cell, plist) + { + PlannedStmt *pstmt = lfirst(cell); + + if (IsA(pstmt, PlannedStmt) && OidIsValid(pstmt->planUserId)) + { + Assert(!OidIsValid(planUserId) || planUserId == pstmt->planUserId); + + planUserId = pstmt->planUserId; + } + } + + /* * Normally we make a dedicated memory context for the CachedPlan and its * subsidiary data. (It's probably not going to be large, but just in * case, use the default maxsize parameter. It's transient for the @@ -956,6 +987,7 @@ BuildCachedPlan(CachedPlanSource *plansource, List *qlist, plan->is_oneshot = plansource->is_oneshot; plan->is_saved = false; plan->is_valid = true; + plan->planUserId = planUserId; /* assign generation number to new plan */ plan->generation = ++(plansource->generation); diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index 38c039c..35c88cc 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -67,6 +67,8 @@ typedef struct PlannedStmt List *invalItems; /* other dependencies, as PlanInvalItems */ int nParamExec; /* number of PARAM_EXEC Params used */ + + Oid planUserId; /* user-id this plan assumed, or InvalidOid */ } PlannedStmt; /* macro for fetching the Plan associated with a SubPlan node */ diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index 8aa40d0..74d0e12 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -99,6 +99,8 @@ typedef struct PlannerGlobal Index lastRowMarkId; /* highest PlanRowMark ID assigned */ bool transientPlan; /* redo plan when TransactionXmin changes? */ + + Oid planUserId; /* User-Id to be assumed on this plan */ } PlannerGlobal; /* macro for fetching the Plan associated with a SubPlan node */ diff --git a/src/include/utils/plancache.h b/src/include/utils/plancache.h index b8ca643..ff89700 100644 --- a/src/include/utils/plancache.h +++ b/src/include/utils/plancache.h @@ -128,6 +128,8 @@ typedef struct CachedPlan bool is_oneshot; /* is it a "oneshot" plan? */ bool is_saved; /* is CachedPlan in a long-lived context? */ bool is_valid; /* is the stmt_list currently valid? */ + Oid planUserId; /* is user-id that is assumed on this cached + plan, or InvalidOid if portable for anybody */ TransactionId saved_xmin; /* if valid, replan when TransactionXmin * changes from this value */ int generation; /* parent's generation number for this plan */ -- 1.8.3.1