diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/commands/prepare.c | 7 | ||||
-rw-r--r-- | src/backend/executor/spi.c | 106 | ||||
-rw-r--r-- | src/backend/tcop/postgres.c | 2 | ||||
-rw-r--r-- | src/backend/utils/cache/plancache.c | 32 | ||||
-rw-r--r-- | src/backend/utils/mmgr/portalmem.c | 2 | ||||
-rw-r--r-- | src/backend/utils/resowner/resowner.c | 8 |
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; } /* |