aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/utils/cache/plancache.c31
-rw-r--r--src/include/utils/plancache.h3
-rw-r--r--src/pl/plpgsql/src/pl_exec.c34
3 files changed, 42 insertions, 26 deletions
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index 8e27b03cbb6..5011d3eb861 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -1290,6 +1290,10 @@ ReleaseCachedPlan(CachedPlan *plan, bool useResOwner)
* to be invalidated, for example due to a change in a function that was
* inlined into the plan.)
*
+ * If the plan is simply valid, and "owner" is not NULL, record a refcount on
+ * the plan in that resowner before returning. It is caller's responsibility
+ * to be sure that a refcount is held on any plan that's being actively used.
+ *
* This must only be called on known-valid generic plans (eg, ones just
* returned by GetCachedPlan). If it returns true, the caller may re-use
* the cached plan as long as CachedPlanIsSimplyValid returns true; that
@@ -1298,16 +1302,24 @@ ReleaseCachedPlan(CachedPlan *plan, bool useResOwner)
*/
bool
CachedPlanAllowsSimpleValidityCheck(CachedPlanSource *plansource,
- CachedPlan *plan)
+ CachedPlan *plan, ResourceOwner owner)
{
ListCell *lc;
- /* Sanity-check that the caller gave us a validated generic plan. */
+ /*
+ * Sanity-check that the caller gave us a validated generic plan. Notice
+ * that we *don't* assert plansource->is_valid as you might expect; that's
+ * because it's possible that that's already false when GetCachedPlan
+ * returns, e.g. because ResetPlanCache happened partway through. We
+ * should accept the plan as long as plan->is_valid is true, and expect to
+ * replan after the next CachedPlanIsSimplyValid call.
+ */
Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
Assert(plan->magic == CACHEDPLAN_MAGIC);
- Assert(plansource->is_valid);
Assert(plan->is_valid);
Assert(plan == plansource->gplan);
+ Assert(plansource->search_path != NULL);
+ Assert(OverrideSearchPathMatchesCurrent(plansource->search_path));
/* We don't support oneshot plans here. */
if (plansource->is_oneshot)
@@ -1371,6 +1383,15 @@ CachedPlanAllowsSimpleValidityCheck(CachedPlanSource *plansource,
* Okay, it's simple. Note that what we've primarily established here is
* that no locks need be taken before checking the plan's is_valid flag.
*/
+
+ /* Bump refcount if requested. */
+ if (owner)
+ {
+ ResourceOwnerEnlargePlanCacheRefs(owner);
+ plan->refcount++;
+ ResourceOwnerRememberPlanCacheRef(owner, plan);
+ }
+
return true;
}
@@ -1408,7 +1429,9 @@ CachedPlanIsSimplyValid(CachedPlanSource *plansource, CachedPlan *plan,
/*
* Has cache invalidation fired on this plan? We can check this right
- * away since there are no locks that we'd need to acquire first.
+ * away since there are no locks that we'd need to acquire first. Note
+ * that here we *do* check plansource->is_valid, so as to force plan
+ * rebuild if that's become false.
*/
if (!plansource->is_valid || plan != plansource->gplan || !plan->is_valid)
return false;
diff --git a/src/include/utils/plancache.h b/src/include/utils/plancache.h
index 037edd057b8..522020d7635 100644
--- a/src/include/utils/plancache.h
+++ b/src/include/utils/plancache.h
@@ -223,7 +223,8 @@ extern CachedPlan *GetCachedPlan(CachedPlanSource *plansource,
extern void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner);
extern bool CachedPlanAllowsSimpleValidityCheck(CachedPlanSource *plansource,
- CachedPlan *plan);
+ CachedPlan *plan,
+ ResourceOwner owner);
extern bool CachedPlanIsSimplyValid(CachedPlanSource *plansource,
CachedPlan *plan,
ResourceOwner owner);
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 0663ccbd114..1c40709b3c9 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -6181,14 +6181,13 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate,
Assert(cplan != NULL);
/*
- * These tests probably can't fail either, but if they do, cope by
+ * This test probably can't fail either, but if it does, cope by
* declaring the plan to be non-simple. On success, we'll acquire a
* refcount on the new plan, stored in simple_eval_resowner.
*/
if (CachedPlanAllowsSimpleValidityCheck(expr->expr_simple_plansource,
- cplan) &&
- CachedPlanIsSimplyValid(expr->expr_simple_plansource, cplan,
- estate->simple_eval_resowner))
+ cplan,
+ estate->simple_eval_resowner))
{
/* Remember that we have the refcount */
expr->expr_simple_plan = cplan;
@@ -8089,26 +8088,19 @@ exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
/*
* Verify that plancache.c thinks the plan is simple enough to use
* CachedPlanIsSimplyValid. Given the restrictions above, it's unlikely
- * that this could fail, but if it does, just treat plan as not simple.
+ * that this could fail, but if it does, just treat plan as not simple. On
+ * success, save a refcount on the plan in the simple-expression resowner.
*/
- if (CachedPlanAllowsSimpleValidityCheck(plansource, cplan))
+ if (CachedPlanAllowsSimpleValidityCheck(plansource, cplan,
+ estate->simple_eval_resowner))
{
- /*
- * OK, use CachedPlanIsSimplyValid to save a refcount on the plan in
- * the simple-expression resowner. This shouldn't fail either, but if
- * somehow it does, again we can cope by treating plan as not simple.
- */
- if (CachedPlanIsSimplyValid(plansource, cplan,
- estate->simple_eval_resowner))
- {
- /* Remember that we have the refcount */
- expr->expr_simple_plansource = plansource;
- expr->expr_simple_plan = cplan;
- expr->expr_simple_plan_lxid = MyProc->lxid;
+ /* Remember that we have the refcount */
+ expr->expr_simple_plansource = plansource;
+ expr->expr_simple_plan = cplan;
+ expr->expr_simple_plan_lxid = MyProc->lxid;
- /* Share the remaining work with the replan code path */
- exec_save_simple_expr(expr, cplan);
- }
+ /* Share the remaining work with the replan code path */
+ exec_save_simple_expr(expr, cplan);
}
/*