aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/cache/plancache.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/cache/plancache.c')
-rw-r--r--src/backend/utils/cache/plancache.c45
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