aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/commands/prepare.c7
-rw-r--r--src/backend/executor/spi.c106
-rw-r--r--src/backend/tcop/postgres.c2
-rw-r--r--src/backend/utils/cache/plancache.c32
-rw-r--r--src/backend/utils/mmgr/portalmem.c2
-rw-r--r--src/backend/utils/resowner/resowner.c8
6 files changed, 91 insertions, 66 deletions
diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c
index 653ef8e41a6..f767751c71a 100644
--- a/src/backend/commands/prepare.c
+++ b/src/backend/commands/prepare.c
@@ -230,7 +230,7 @@ ExecuteQuery(ParseState *pstate,
entry->plansource->query_string);
/* Replan if needed, and increment plan refcount for portal */
- cplan = GetCachedPlan(entry->plansource, paramLI, false, NULL);
+ cplan = GetCachedPlan(entry->plansource, paramLI, NULL, NULL);
plan_list = cplan->stmt_list;
/*
@@ -651,7 +651,8 @@ ExplainExecuteQuery(ExecuteStmt *execstmt, IntoClause *into, ExplainState *es,
}
/* Replan if needed, and acquire a transient refcount */
- cplan = GetCachedPlan(entry->plansource, paramLI, true, queryEnv);
+ cplan = GetCachedPlan(entry->plansource, paramLI,
+ CurrentResourceOwner, queryEnv);
INSTR_TIME_SET_CURRENT(planduration);
INSTR_TIME_SUBTRACT(planduration, planstart);
@@ -687,7 +688,7 @@ ExplainExecuteQuery(ExecuteStmt *execstmt, IntoClause *into, ExplainState *es,
if (estate)
FreeExecutorState(estate);
- ReleaseCachedPlan(cplan, true);
+ ReleaseCachedPlan(cplan, CurrentResourceOwner);
}
/*
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index e28d2429222..68a6bcea02d 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -66,8 +66,10 @@ static void _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan);
static int _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
Snapshot snapshot, Snapshot crosscheck_snapshot,
- bool read_only, bool fire_triggers, uint64 tcount,
- DestReceiver *caller_dest);
+ bool read_only, bool no_snapshots,
+ bool fire_triggers, uint64 tcount,
+ DestReceiver *caller_dest,
+ ResourceOwner plan_owner);
static ParamListInfo _SPI_convert_params(int nargs, Oid *argtypes,
Datum *Values, const char *Nulls);
@@ -521,7 +523,9 @@ SPI_execute(const char *src, bool read_only, long tcount)
res = _SPI_execute_plan(&plan, NULL,
InvalidSnapshot, InvalidSnapshot,
- read_only, true, tcount, NULL);
+ read_only, false,
+ true, tcount,
+ NULL, NULL);
_SPI_end_call(true);
return res;
@@ -555,7 +559,9 @@ SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls,
_SPI_convert_params(plan->nargs, plan->argtypes,
Values, Nulls),
InvalidSnapshot, InvalidSnapshot,
- read_only, true, tcount, NULL);
+ read_only, false,
+ true, tcount,
+ NULL, NULL);
_SPI_end_call(true);
return res;
@@ -570,37 +576,32 @@ SPI_execp(SPIPlanPtr plan, Datum *Values, const char *Nulls, long tcount)
/* Execute a previously prepared plan */
int
-SPI_execute_plan_with_paramlist(SPIPlanPtr plan, ParamListInfo params,
- bool read_only, long tcount)
+SPI_execute_plan_extended(SPIPlanPtr plan,
+ const SPIExecuteOptions *options)
{
int res;
- if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || tcount < 0)
+ if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || options == NULL)
return SPI_ERROR_ARGUMENT;
res = _SPI_begin_call(true);
if (res < 0)
return res;
- res = _SPI_execute_plan(plan, params,
+ res = _SPI_execute_plan(plan, options->params,
InvalidSnapshot, InvalidSnapshot,
- read_only, true, tcount, NULL);
+ options->read_only, options->no_snapshots,
+ true, options->tcount,
+ options->dest, options->owner);
_SPI_end_call(true);
return res;
}
-/*
- * Execute a previously prepared plan. If dest isn't NULL, we send result
- * tuples to the caller-supplied DestReceiver rather than through the usual
- * SPI output arrangements. If dest is NULL this is equivalent to
- * SPI_execute_plan_with_paramlist.
- */
+/* Execute a previously prepared plan */
int
-SPI_execute_plan_with_receiver(SPIPlanPtr plan,
- ParamListInfo params,
- bool read_only, long tcount,
- DestReceiver *dest)
+SPI_execute_plan_with_paramlist(SPIPlanPtr plan, ParamListInfo params,
+ bool read_only, long tcount)
{
int res;
@@ -613,7 +614,9 @@ SPI_execute_plan_with_receiver(SPIPlanPtr plan,
res = _SPI_execute_plan(plan, params,
InvalidSnapshot, InvalidSnapshot,
- read_only, true, tcount, dest);
+ read_only, false,
+ true, tcount,
+ NULL, NULL);
_SPI_end_call(true);
return res;
@@ -654,7 +657,9 @@ SPI_execute_snapshot(SPIPlanPtr plan,
_SPI_convert_params(plan->nargs, plan->argtypes,
Values, Nulls),
snapshot, crosscheck_snapshot,
- read_only, fire_triggers, tcount, NULL);
+ read_only, false,
+ fire_triggers, tcount,
+ NULL, NULL);
_SPI_end_call(true);
return res;
@@ -702,7 +707,9 @@ SPI_execute_with_args(const char *src,
res = _SPI_execute_plan(&plan, paramLI,
InvalidSnapshot, InvalidSnapshot,
- read_only, true, tcount, NULL);
+ read_only, false,
+ true, tcount,
+ NULL, NULL);
_SPI_end_call(true);
return res;
@@ -746,7 +753,9 @@ SPI_execute_with_receiver(const char *src,
res = _SPI_execute_plan(&plan, params,
InvalidSnapshot, InvalidSnapshot,
- read_only, true, tcount, dest);
+ read_only, false,
+ true, tcount,
+ dest, NULL);
_SPI_end_call(true);
return res;
@@ -1554,7 +1563,7 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
*/
/* Replan if needed, and increment plan refcount for portal */
- cplan = GetCachedPlan(plansource, paramLI, false, _SPI_current->queryEnv);
+ cplan = GetCachedPlan(plansource, paramLI, NULL, _SPI_current->queryEnv);
stmt_list = cplan->stmt_list;
if (!plan->saved)
@@ -1568,7 +1577,7 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
oldcontext = MemoryContextSwitchTo(portal->portalContext);
stmt_list = copyObject(stmt_list);
MemoryContextSwitchTo(oldcontext);
- ReleaseCachedPlan(cplan, false);
+ ReleaseCachedPlan(cplan, NULL);
cplan = NULL; /* portal shouldn't depend on cplan */
}
@@ -1950,7 +1959,10 @@ SPI_plan_get_plan_sources(SPIPlanPtr plan)
/*
* SPI_plan_get_cached_plan --- get a SPI plan's generic CachedPlan,
* if the SPI plan contains exactly one CachedPlanSource. If not,
- * return NULL. Caller is responsible for doing ReleaseCachedPlan().
+ * return NULL.
+ *
+ * The plan's refcount is incremented (and logged in CurrentResourceOwner,
+ * if it's a saved plan). Caller is responsible for doing ReleaseCachedPlan.
*
* This is exported so that PL/pgSQL can use it (this beats letting PL/pgSQL
* look directly into the SPIPlan for itself). It's not documented in
@@ -1984,7 +1996,8 @@ SPI_plan_get_cached_plan(SPIPlanPtr plan)
error_context_stack = &spierrcontext;
/* Get the generic plan for the query */
- cplan = GetCachedPlan(plansource, NULL, plan->saved,
+ cplan = GetCachedPlan(plansource, NULL,
+ plan->saved ? CurrentResourceOwner : NULL,
_SPI_current->queryEnv);
Assert(cplan == plansource->gplan);
@@ -2265,16 +2278,20 @@ _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan)
* behavior of taking a new snapshot for each query.
* crosscheck_snapshot: for RI use, all others pass InvalidSnapshot
* read_only: true for read-only execution (no CommandCounterIncrement)
+ * no_snapshots: true to skip snapshot management
* fire_triggers: true to fire AFTER triggers at end of query (normal case);
* false means any AFTER triggers are postponed to end of outer query
* tcount: execution tuple-count limit, or 0 for none
* caller_dest: DestReceiver to receive output, or NULL for normal SPI output
+ * plan_owner: ResourceOwner that will be used to hold refcount on plan;
+ * if NULL, CurrentResourceOwner is used (ignored for non-saved plan)
*/
static int
_SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
Snapshot snapshot, Snapshot crosscheck_snapshot,
- bool read_only, bool fire_triggers, uint64 tcount,
- DestReceiver *caller_dest)
+ bool read_only, bool no_snapshots,
+ bool fire_triggers, uint64 tcount,
+ DestReceiver *caller_dest, ResourceOwner plan_owner)
{
int my_res = 0;
uint64 my_processed = 0;
@@ -2315,10 +2332,10 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
* In the first two cases, we can just push the snap onto the stack once
* for the whole plan list.
*
- * But if the plan has no_snapshots set to true, then don't manage
- * snapshots at all. The caller should then take care of that.
+ * But if no_snapshots is true, then don't manage snapshots at all here.
+ * The caller must then take care of that.
*/
- if (snapshot != InvalidSnapshot && !plan->no_snapshots)
+ if (snapshot != InvalidSnapshot && !no_snapshots)
{
if (read_only)
{
@@ -2333,6 +2350,15 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
}
}
+ /*
+ * Ensure that we have a resource owner if plan is saved, and not if it
+ * isn't.
+ */
+ if (!plan->saved)
+ plan_owner = NULL;
+ else if (plan_owner == NULL)
+ plan_owner = CurrentResourceOwner;
+
foreach(lc1, plan->plancache_list)
{
CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc1);
@@ -2388,16 +2414,18 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
/*
* Replan if needed, and increment plan refcount. If it's a saved
- * plan, the refcount must be backed by the CurrentResourceOwner.
+ * plan, the refcount must be backed by the plan_owner.
*/
- cplan = GetCachedPlan(plansource, paramLI, plan->saved, _SPI_current->queryEnv);
+ cplan = GetCachedPlan(plansource, paramLI,
+ plan_owner, _SPI_current->queryEnv);
+
stmt_list = cplan->stmt_list;
/*
* In the default non-read-only case, get a new snapshot, replacing
* any that we pushed in a previous cycle.
*/
- if (snapshot == InvalidSnapshot && !read_only && !plan->no_snapshots)
+ if (snapshot == InvalidSnapshot && !read_only && !no_snapshots)
{
if (pushed_active_snap)
PopActiveSnapshot();
@@ -2450,7 +2478,7 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
* If not read-only mode, advance the command counter before each
* command and update the snapshot.
*/
- if (!read_only && !plan->no_snapshots)
+ if (!read_only && !no_snapshots)
{
CommandCounterIncrement();
UpdateActiveSnapshotCommandId();
@@ -2499,7 +2527,7 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
* caller must be in a nonatomic SPI context and manage
* snapshots itself.
*/
- if (_SPI_current->atomic || !plan->no_snapshots)
+ if (_SPI_current->atomic || !no_snapshots)
context = PROCESS_UTILITY_QUERY;
else
context = PROCESS_UTILITY_QUERY_NONATOMIC;
@@ -2586,7 +2614,7 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
}
/* Done with this plan, so release refcount */
- ReleaseCachedPlan(cplan, plan->saved);
+ ReleaseCachedPlan(cplan, plan_owner);
cplan = NULL;
/*
@@ -2606,7 +2634,7 @@ fail:
/* We no longer need the cached plan refcount, if any */
if (cplan)
- ReleaseCachedPlan(cplan, plan->saved);
+ ReleaseCachedPlan(cplan, plan_owner);
/*
* Pop the error context stack
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 8dab9fd5780..cb5a96117f6 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -1963,7 +1963,7 @@ exec_bind_message(StringInfo input_message)
* will be generated in MessageContext. The plan refcount will be
* assigned to the Portal, so it will be released at portal destruction.
*/
- cplan = GetCachedPlan(psrc, params, false, NULL);
+ cplan = GetCachedPlan(psrc, params, NULL, NULL);
/*
* Now we can define the portal.
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index cc04b5b4bef..1a0950489d7 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -533,7 +533,7 @@ ReleaseGenericPlan(CachedPlanSource *plansource)
Assert(plan->magic == CACHEDPLAN_MAGIC);
plansource->gplan = NULL;
- ReleaseCachedPlan(plan, false);
+ ReleaseCachedPlan(plan, NULL);
}
}
@@ -1130,16 +1130,16 @@ cached_plan_cost(CachedPlan *plan, bool include_planner)
* execution.
*
* On return, the refcount of the plan has been incremented; a later
- * ReleaseCachedPlan() call is expected. The refcount has been reported
- * to the CurrentResourceOwner if useResOwner is true (note that that must
- * only be true if it's a "saved" CachedPlanSource).
+ * ReleaseCachedPlan() call is expected. If "owner" is not NULL then
+ * the refcount has been reported to that ResourceOwner (note that this
+ * is only supported for "saved" CachedPlanSources).
*
* Note: if any replanning activity is required, the caller's memory context
* is used for that work.
*/
CachedPlan *
GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams,
- bool useResOwner, QueryEnvironment *queryEnv)
+ ResourceOwner owner, QueryEnvironment *queryEnv)
{
CachedPlan *plan = NULL;
List *qlist;
@@ -1149,7 +1149,7 @@ GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams,
Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
Assert(plansource->is_complete);
/* This seems worth a real test, though */
- if (useResOwner && !plansource->is_saved)
+ if (owner && !plansource->is_saved)
elog(ERROR, "cannot apply ResourceOwner to non-saved cached plan");
/* Make sure the querytree list is valid and we have parse-time locks */
@@ -1228,11 +1228,11 @@ GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams,
Assert(plan != NULL);
/* Flag the plan as in use by caller */
- if (useResOwner)
- ResourceOwnerEnlargePlanCacheRefs(CurrentResourceOwner);
+ if (owner)
+ ResourceOwnerEnlargePlanCacheRefs(owner);
plan->refcount++;
- if (useResOwner)
- ResourceOwnerRememberPlanCacheRef(CurrentResourceOwner, plan);
+ if (owner)
+ ResourceOwnerRememberPlanCacheRef(owner, plan);
/*
* Saved plans should be under CacheMemoryContext so they will not go away
@@ -1253,21 +1253,21 @@ GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams,
* ReleaseCachedPlan: release active use of a cached plan.
*
* This decrements the reference count, and frees the plan if the count
- * has thereby gone to zero. If useResOwner is true, it is assumed that
- * the reference count is managed by the CurrentResourceOwner.
+ * has thereby gone to zero. If "owner" is not NULL, it is assumed that
+ * the reference count is managed by that ResourceOwner.
*
- * Note: useResOwner = false is used for releasing references that are in
+ * Note: owner == NULL is used for releasing references that are in
* persistent data structures, such as the parent CachedPlanSource or a
* Portal. Transient references should be protected by a resource owner.
*/
void
-ReleaseCachedPlan(CachedPlan *plan, bool useResOwner)
+ReleaseCachedPlan(CachedPlan *plan, ResourceOwner owner)
{
Assert(plan->magic == CACHEDPLAN_MAGIC);
- if (useResOwner)
+ if (owner)
{
Assert(plan->is_saved);
- ResourceOwnerForgetPlanCacheRef(CurrentResourceOwner, plan);
+ ResourceOwnerForgetPlanCacheRef(owner, plan);
}
Assert(plan->refcount > 0);
plan->refcount--;
diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c
index 22c6d2ba5b2..66e31818156 100644
--- a/src/backend/utils/mmgr/portalmem.c
+++ b/src/backend/utils/mmgr/portalmem.c
@@ -310,7 +310,7 @@ PortalReleaseCachedPlan(Portal portal)
{
if (portal->cplan)
{
- ReleaseCachedPlan(portal->cplan, false);
+ ReleaseCachedPlan(portal->cplan, NULL);
portal->cplan = NULL;
/*
diff --git a/src/backend/utils/resowner/resowner.c b/src/backend/utils/resowner/resowner.c
index 10f15f6a357..a171df573ce 100644
--- a/src/backend/utils/resowner/resowner.c
+++ b/src/backend/utils/resowner/resowner.c
@@ -652,7 +652,7 @@ ResourceOwnerReleaseInternal(ResourceOwner owner,
if (isCommit)
PrintPlanCacheLeakWarning(res);
- ReleaseCachedPlan(res, true);
+ ReleaseCachedPlan(res, owner);
}
/* Ditto for tupdesc references */
@@ -703,18 +703,14 @@ ResourceOwnerReleaseInternal(ResourceOwner owner,
void
ResourceOwnerReleaseAllPlanCacheRefs(ResourceOwner owner)
{
- ResourceOwner save;
Datum foundres;
- save = CurrentResourceOwner;
- CurrentResourceOwner = owner;
while (ResourceArrayGetAny(&(owner->planrefarr), &foundres))
{
CachedPlan *res = (CachedPlan *) DatumGetPointer(foundres);
- ReleaseCachedPlan(res, true);
+ ReleaseCachedPlan(res, owner);
}
- CurrentResourceOwner = save;
}
/*