#include "access/tupdesc.h"
#include "nodes/params.h"
Go to the source code of this file.
Data Structures | |
struct | CachedPlanSource |
struct | CachedPlan |
Defines | |
#define | CACHEDPLANSOURCE_MAGIC 195726186 |
#define | CACHEDPLAN_MAGIC 953717834 |
Typedefs | |
typedef struct CachedPlanSource | CachedPlanSource |
typedef struct CachedPlan | CachedPlan |
Functions | |
void | InitPlanCache (void) |
void | ResetPlanCache (void) |
CachedPlanSource * | CreateCachedPlan (Node *raw_parse_tree, const char *query_string, const char *commandTag) |
CachedPlanSource * | CreateOneShotCachedPlan (Node *raw_parse_tree, const char *query_string, const char *commandTag) |
void | CompleteCachedPlan (CachedPlanSource *plansource, List *querytree_list, MemoryContext querytree_context, Oid *param_types, int num_params, ParserSetupHook parserSetup, void *parserSetupArg, int cursor_options, bool fixed_result) |
void | SaveCachedPlan (CachedPlanSource *plansource) |
void | DropCachedPlan (CachedPlanSource *plansource) |
void | CachedPlanSetParentContext (CachedPlanSource *plansource, MemoryContext newcontext) |
CachedPlanSource * | CopyCachedPlan (CachedPlanSource *plansource) |
bool | CachedPlanIsValid (CachedPlanSource *plansource) |
List * | CachedPlanGetTargetList (CachedPlanSource *plansource) |
CachedPlan * | GetCachedPlan (CachedPlanSource *plansource, ParamListInfo boundParams, bool useResOwner) |
void | ReleaseCachedPlan (CachedPlan *plan, bool useResOwner) |
#define CACHEDPLAN_MAGIC 953717834 |
Definition at line 22 of file plancache.h.
Referenced by CachedPlanSetParentContext(), CheckCachedPlan(), GetCachedPlan(), ReleaseCachedPlan(), and ReleaseGenericPlan().
#define CACHEDPLANSOURCE_MAGIC 195726186 |
Definition at line 21 of file plancache.h.
Referenced by CachedPlanGetTargetList(), CachedPlanIsValid(), CachedPlanSetParentContext(), CompleteCachedPlan(), CopyCachedPlan(), DropCachedPlan(), GetCachedPlan(), PlanCacheFuncCallback(), PlanCacheRelCallback(), ResetPlanCache(), and SaveCachedPlan().
typedef struct CachedPlan CachedPlan |
typedef struct CachedPlanSource CachedPlanSource |
List* CachedPlanGetTargetList | ( | CachedPlanSource * | plansource | ) |
Definition at line 1345 of file plancache.c.
References Assert, CACHEDPLANSOURCE_MAGIC, FetchStatementTargetList(), CachedPlanSource::is_complete, CachedPlanSource::magic, NULL, PortalListGetPrimaryStmt(), CachedPlanSource::query_list, CachedPlanSource::resultDesc, and RevalidateCachedQuery().
Referenced by exec_describe_statement_message(), and FetchPreparedStatementTargetList().
{ Node *pstmt; /* Assert caller is doing things in a sane order */ Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC); Assert(plansource->is_complete); /* * No work needed if statement doesn't return tuples (we assume this * feature cannot be changed by an invalidation) */ if (plansource->resultDesc == NULL) return NIL; /* Make sure the querytree list is valid and we have parse-time locks */ RevalidateCachedQuery(plansource); /* Get the primary statement and find out what it returns */ pstmt = PortalListGetPrimaryStmt(plansource->query_list); return FetchStatementTargetList(pstmt); }
bool CachedPlanIsValid | ( | CachedPlanSource * | plansource | ) |
Definition at line 1332 of file plancache.c.
References Assert, CACHEDPLANSOURCE_MAGIC, CachedPlanSource::is_valid, and CachedPlanSource::magic.
Referenced by SPI_plan_is_valid().
{ Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC); return plansource->is_valid; }
void CachedPlanSetParentContext | ( | CachedPlanSource * | plansource, | |
MemoryContext | newcontext | |||
) |
Definition at line 1203 of file plancache.c.
References Assert, CACHEDPLAN_MAGIC, CACHEDPLANSOURCE_MAGIC, CachedPlan::context, CachedPlanSource::context, elog, ERROR, CachedPlanSource::gplan, CachedPlanSource::is_complete, CachedPlanSource::is_oneshot, CachedPlanSource::is_saved, CachedPlan::magic, CachedPlanSource::magic, and MemoryContextSetParent().
Referenced by _SPI_make_plan_non_temp().
{ /* Assert caller is doing things in a sane order */ Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC); Assert(plansource->is_complete); /* These seem worth real tests, though */ if (plansource->is_saved) elog(ERROR, "cannot move a saved cached plan to another context"); if (plansource->is_oneshot) elog(ERROR, "cannot move a one-shot cached plan to another context"); /* OK, let the caller keep the plan where he wishes */ MemoryContextSetParent(plansource->context, newcontext); /* * The query_context needs no special handling, since it's a child of * plansource->context. But if there's a generic plan, it should be * maintained as a sibling of plansource->context. */ if (plansource->gplan) { Assert(plansource->gplan->magic == CACHEDPLAN_MAGIC); MemoryContextSetParent(plansource->gplan->context, newcontext); } }
void CompleteCachedPlan | ( | CachedPlanSource * | plansource, | |
List * | querytree_list, | |||
MemoryContext | querytree_context, | |||
Oid * | param_types, | |||
int | num_params, | |||
ParserSetupHook | parserSetup, | |||
void * | parserSetupArg, | |||
int | cursor_options, | |||
bool | fixed_result | |||
) |
Definition at line 315 of file plancache.c.
References ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MINSIZE, AllocSetContextCreate(), Assert, CACHEDPLANSOURCE_MAGIC, CachedPlanSource::context, copyObject(), CurrentMemoryContext, CachedPlanSource::cursor_options, extract_query_dependencies(), CachedPlanSource::fixed_result, GetOverrideSearchPath(), CachedPlanSource::invalItems, CachedPlanSource::is_complete, CachedPlanSource::is_oneshot, CachedPlanSource::is_valid, IsTransactionStmtPlan, CachedPlanSource::magic, MemoryContextSetParent(), MemoryContextSwitchTo(), NULL, CachedPlanSource::num_params, palloc(), CachedPlanSource::param_types, CachedPlanSource::parserSetup, CachedPlanSource::parserSetupArg, PlanCacheComputeResultDesc(), CachedPlanSource::query_context, CachedPlanSource::query_list, CachedPlanSource::relationOids, CachedPlanSource::resultDesc, and CachedPlanSource::search_path.
Referenced by _SPI_execute_plan(), _SPI_prepare_plan(), exec_parse_message(), and PrepareQuery().
{ MemoryContext source_context = plansource->context; MemoryContext oldcxt = CurrentMemoryContext; /* Assert caller is doing things in a sane order */ Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC); Assert(!plansource->is_complete); /* * If caller supplied a querytree_context, reparent it underneath the * CachedPlanSource's context; otherwise, create a suitable context and * copy the querytree_list into it. But no data copying should be done * for one-shot plans; for those, assume the passed querytree_list is * sufficiently long-lived. */ if (plansource->is_oneshot) { querytree_context = CurrentMemoryContext; } else if (querytree_context != NULL) { MemoryContextSetParent(querytree_context, source_context); MemoryContextSwitchTo(querytree_context); } else { /* Again, it's a good bet the querytree_context can be small */ querytree_context = AllocSetContextCreate(source_context, "CachedPlanQuery", ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); MemoryContextSwitchTo(querytree_context); querytree_list = (List *) copyObject(querytree_list); } plansource->query_context = querytree_context; plansource->query_list = querytree_list; if (!plansource->is_oneshot && !IsTransactionStmtPlan(plansource)) { /* * Use the planner machinery to extract dependencies. Data is saved * in query_context. (We assume that not a lot of extra cruft is * created by this call.) We can skip this for one-shot plans, and * transaction control commands have no such dependencies anyway. */ extract_query_dependencies((Node *) querytree_list, &plansource->relationOids, &plansource->invalItems); /* * Also save the current search_path in the query_context. (This * should not generate much extra cruft either, since almost certainly * the path is already valid.) Again, we don't really need this for * one-shot plans; and we *must* skip this for transaction control * commands, because this could result in catalog accesses. */ plansource->search_path = GetOverrideSearchPath(querytree_context); } /* * Save the final parameter types (or other parameter specification data) * into the source_context, as well as our other parameters. Also save * the result tuple descriptor. */ MemoryContextSwitchTo(source_context); if (num_params > 0) { plansource->param_types = (Oid *) palloc(num_params * sizeof(Oid)); memcpy(plansource->param_types, param_types, num_params * sizeof(Oid)); } else plansource->param_types = NULL; plansource->num_params = num_params; plansource->parserSetup = parserSetup; plansource->parserSetupArg = parserSetupArg; plansource->cursor_options = cursor_options; plansource->fixed_result = fixed_result; plansource->resultDesc = PlanCacheComputeResultDesc(querytree_list); MemoryContextSwitchTo(oldcxt); plansource->is_complete = true; plansource->is_valid = true; }
CachedPlanSource* CopyCachedPlan | ( | CachedPlanSource * | plansource | ) |
Definition at line 1241 of file plancache.c.
References ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MINSIZE, AllocSetContextCreate(), Assert, CACHEDPLANSOURCE_MAGIC, CachedPlanSource::commandTag, CachedPlanSource::context, copyObject(), CopyOverrideSearchPath(), CreateTupleDescCopy(), CurrentMemoryContext, CachedPlanSource::cursor_options, elog, ERROR, CachedPlanSource::fixed_result, CachedPlanSource::generation, CachedPlanSource::generic_cost, CachedPlanSource::gplan, CachedPlanSource::invalItems, CachedPlanSource::is_complete, CachedPlanSource::is_oneshot, CachedPlanSource::is_saved, CachedPlanSource::is_valid, CachedPlanSource::magic, MemoryContextSwitchTo(), CachedPlanSource::next_saved, CachedPlanSource::num_custom_plans, CachedPlanSource::num_params, palloc(), palloc0(), CachedPlanSource::param_types, CachedPlanSource::parserSetup, CachedPlanSource::parserSetupArg, pstrdup(), CachedPlanSource::query_context, CachedPlanSource::query_list, CachedPlanSource::query_string, CachedPlanSource::raw_parse_tree, CachedPlanSource::relationOids, CachedPlanSource::resultDesc, CachedPlanSource::search_path, and CachedPlanSource::total_custom_cost.
Referenced by _SPI_save_plan().
{ CachedPlanSource *newsource; MemoryContext source_context; MemoryContext querytree_context; MemoryContext oldcxt; Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC); Assert(plansource->is_complete); /* * One-shot plans can't be copied, because we haven't taken care that * parsing/planning didn't scribble on the raw parse tree or querytrees. */ if (plansource->is_oneshot) elog(ERROR, "cannot copy a one-shot cached plan"); source_context = AllocSetContextCreate(CurrentMemoryContext, "CachedPlanSource", ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); oldcxt = MemoryContextSwitchTo(source_context); newsource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource)); newsource->magic = CACHEDPLANSOURCE_MAGIC; newsource->raw_parse_tree = copyObject(plansource->raw_parse_tree); newsource->query_string = pstrdup(plansource->query_string); newsource->commandTag = plansource->commandTag; if (plansource->num_params > 0) { newsource->param_types = (Oid *) palloc(plansource->num_params * sizeof(Oid)); memcpy(newsource->param_types, plansource->param_types, plansource->num_params * sizeof(Oid)); } else newsource->param_types = NULL; newsource->num_params = plansource->num_params; newsource->parserSetup = plansource->parserSetup; newsource->parserSetupArg = plansource->parserSetupArg; newsource->cursor_options = plansource->cursor_options; newsource->fixed_result = plansource->fixed_result; if (plansource->resultDesc) newsource->resultDesc = CreateTupleDescCopy(plansource->resultDesc); else newsource->resultDesc = NULL; newsource->context = source_context; querytree_context = AllocSetContextCreate(source_context, "CachedPlanQuery", ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); MemoryContextSwitchTo(querytree_context); newsource->query_list = (List *) copyObject(plansource->query_list); newsource->relationOids = (List *) copyObject(plansource->relationOids); newsource->invalItems = (List *) copyObject(plansource->invalItems); if (plansource->search_path) newsource->search_path = CopyOverrideSearchPath(plansource->search_path); newsource->query_context = querytree_context; newsource->gplan = NULL; newsource->is_oneshot = false; newsource->is_complete = true; newsource->is_saved = false; newsource->is_valid = plansource->is_valid; newsource->generation = plansource->generation; newsource->next_saved = NULL; /* We may as well copy any acquired cost knowledge */ newsource->generic_cost = plansource->generic_cost; newsource->total_custom_cost = plansource->total_custom_cost; newsource->num_custom_plans = plansource->num_custom_plans; MemoryContextSwitchTo(oldcxt); return newsource; }
CachedPlanSource* CreateCachedPlan | ( | Node * | raw_parse_tree, | |
const char * | query_string, | |||
const char * | commandTag | |||
) |
Definition at line 146 of file plancache.c.
References ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MINSIZE, AllocSetContextCreate(), Assert, CachedPlanSource::commandTag, CachedPlanSource::context, copyObject(), CurrentMemoryContext, CachedPlanSource::cursor_options, CachedPlanSource::fixed_result, CachedPlanSource::generation, CachedPlanSource::generic_cost, CachedPlanSource::gplan, CachedPlanSource::invalItems, CachedPlanSource::is_complete, CachedPlanSource::is_oneshot, CachedPlanSource::is_saved, CachedPlanSource::is_valid, CachedPlanSource::magic, MemoryContextSwitchTo(), CachedPlanSource::next_saved, NULL, CachedPlanSource::num_custom_plans, CachedPlanSource::num_params, palloc0(), CachedPlanSource::param_types, CachedPlanSource::parserSetup, CachedPlanSource::parserSetupArg, pstrdup(), CachedPlanSource::query_context, CachedPlanSource::query_list, CachedPlanSource::query_string, CachedPlanSource::raw_parse_tree, CachedPlanSource::relationOids, CachedPlanSource::resultDesc, CachedPlanSource::search_path, and CachedPlanSource::total_custom_cost.
Referenced by _SPI_prepare_plan(), exec_parse_message(), and PrepareQuery().
{ CachedPlanSource *plansource; MemoryContext source_context; MemoryContext oldcxt; Assert(query_string != NULL); /* required as of 8.4 */ /* * Make a dedicated memory context for the CachedPlanSource and its * permanent subsidiary data. It's probably not going to be large, but * just in case, use the default maxsize parameter. Initially it's a * child of the caller's context (which we assume to be transient), so * that it will be cleaned up on error. */ source_context = AllocSetContextCreate(CurrentMemoryContext, "CachedPlanSource", ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); /* * Create and fill the CachedPlanSource struct within the new context. * Most fields are just left empty for the moment. */ oldcxt = MemoryContextSwitchTo(source_context); plansource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource)); plansource->magic = CACHEDPLANSOURCE_MAGIC; plansource->raw_parse_tree = copyObject(raw_parse_tree); plansource->query_string = pstrdup(query_string); plansource->commandTag = commandTag; plansource->param_types = NULL; plansource->num_params = 0; plansource->parserSetup = NULL; plansource->parserSetupArg = NULL; plansource->cursor_options = 0; plansource->fixed_result = false; plansource->resultDesc = NULL; plansource->context = source_context; plansource->query_list = NIL; plansource->relationOids = NIL; plansource->invalItems = NIL; plansource->search_path = NULL; plansource->query_context = NULL; plansource->gplan = NULL; plansource->is_oneshot = false; plansource->is_complete = false; plansource->is_saved = false; plansource->is_valid = false; plansource->generation = 0; plansource->next_saved = NULL; plansource->generic_cost = -1; plansource->total_custom_cost = 0; plansource->num_custom_plans = 0; MemoryContextSwitchTo(oldcxt); return plansource; }
CachedPlanSource* CreateOneShotCachedPlan | ( | Node * | raw_parse_tree, | |
const char * | query_string, | |||
const char * | commandTag | |||
) |
Definition at line 228 of file plancache.c.
References Assert, CachedPlanSource::commandTag, CachedPlanSource::context, CurrentMemoryContext, CachedPlanSource::cursor_options, CachedPlanSource::fixed_result, CachedPlanSource::generation, CachedPlanSource::generic_cost, CachedPlanSource::gplan, CachedPlanSource::invalItems, CachedPlanSource::is_complete, CachedPlanSource::is_oneshot, CachedPlanSource::is_saved, CachedPlanSource::is_valid, CachedPlanSource::magic, CachedPlanSource::next_saved, NULL, CachedPlanSource::num_custom_plans, CachedPlanSource::num_params, palloc0(), CachedPlanSource::param_types, CachedPlanSource::parserSetup, CachedPlanSource::parserSetupArg, CachedPlanSource::query_context, CachedPlanSource::query_list, CachedPlanSource::query_string, CachedPlanSource::raw_parse_tree, CachedPlanSource::relationOids, CachedPlanSource::resultDesc, CachedPlanSource::search_path, and CachedPlanSource::total_custom_cost.
Referenced by _SPI_prepare_oneshot_plan().
{ CachedPlanSource *plansource; Assert(query_string != NULL); /* required as of 8.4 */ /* * Create and fill the CachedPlanSource struct within the caller's memory * context. Most fields are just left empty for the moment. */ plansource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource)); plansource->magic = CACHEDPLANSOURCE_MAGIC; plansource->raw_parse_tree = raw_parse_tree; plansource->query_string = query_string; plansource->commandTag = commandTag; plansource->param_types = NULL; plansource->num_params = 0; plansource->parserSetup = NULL; plansource->parserSetupArg = NULL; plansource->cursor_options = 0; plansource->fixed_result = false; plansource->resultDesc = NULL; plansource->context = CurrentMemoryContext; plansource->query_list = NIL; plansource->relationOids = NIL; plansource->invalItems = NIL; plansource->search_path = NULL; plansource->query_context = NULL; plansource->gplan = NULL; plansource->is_oneshot = true; plansource->is_complete = false; plansource->is_saved = false; plansource->is_valid = false; plansource->generation = 0; plansource->next_saved = NULL; plansource->generic_cost = -1; plansource->total_custom_cost = 0; plansource->num_custom_plans = 0; return plansource; }
void DropCachedPlan | ( | CachedPlanSource * | plansource | ) |
Definition at line 473 of file plancache.c.
References Assert, CACHEDPLANSOURCE_MAGIC, CachedPlanSource::context, CachedPlanSource::is_oneshot, CachedPlanSource::is_saved, CachedPlanSource::magic, MemoryContextDelete(), CachedPlanSource::next_saved, and ReleaseGenericPlan().
Referenced by drop_unnamed_stmt(), DropAllPreparedStatements(), DropPreparedStatement(), and SPI_freeplan().
{ Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC); /* If it's been saved, remove it from the list */ if (plansource->is_saved) { if (first_saved_plan == plansource) first_saved_plan = plansource->next_saved; else { CachedPlanSource *psrc; for (psrc = first_saved_plan; psrc; psrc = psrc->next_saved) { if (psrc->next_saved == plansource) { psrc->next_saved = plansource->next_saved; break; } } } plansource->is_saved = false; } /* Decrement generic CachePlan's refcount and drop if no longer needed */ ReleaseGenericPlan(plansource); /* Mark it no longer valid */ plansource->magic = 0; /* * Remove the CachedPlanSource and all subsidiary data (including the * query_context if any). But if it's a one-shot we can't free anything. */ if (!plansource->is_oneshot) MemoryContextDelete(plansource->context); }
CachedPlan* GetCachedPlan | ( | CachedPlanSource * | plansource, | |
ParamListInfo | boundParams, | |||
bool | useResOwner | |||
) |
Definition at line 1056 of file plancache.c.
References Assert, BuildCachedPlan(), cached_plan_cost(), CACHEDPLAN_MAGIC, CACHEDPLANSOURCE_MAGIC, CacheMemoryContext, CheckCachedPlan(), choose_custom_plan(), CachedPlanSource::context, CachedPlan::context, CurrentResourceOwner, elog, ERROR, CachedPlanSource::generic_cost, CachedPlanSource::gplan, CachedPlanSource::is_complete, CachedPlan::is_saved, CachedPlanSource::is_saved, CachedPlan::magic, CachedPlanSource::magic, MemoryContextGetParent(), MemoryContextSetParent(), NULL, CachedPlanSource::num_custom_plans, CachedPlan::refcount, ReleaseGenericPlan(), ResourceOwnerEnlargePlanCacheRefs(), ResourceOwnerRememberPlanCacheRef(), RevalidateCachedQuery(), and CachedPlanSource::total_custom_cost.
Referenced by _SPI_execute_plan(), exec_bind_message(), ExecuteQuery(), ExplainExecuteQuery(), SPI_cursor_open_internal(), and SPI_plan_get_cached_plan().
{ CachedPlan *plan; List *qlist; bool customplan; /* Assert caller is doing things in a sane order */ Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC); Assert(plansource->is_complete); /* This seems worth a real test, though */ if (useResOwner && !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 */ qlist = RevalidateCachedQuery(plansource); /* Decide whether to use a custom plan */ customplan = choose_custom_plan(plansource, boundParams); if (!customplan) { if (CheckCachedPlan(plansource)) { /* We want a generic plan, and we already have a valid one */ plan = plansource->gplan; Assert(plan->magic == CACHEDPLAN_MAGIC); } else { /* Build a new generic plan */ plan = BuildCachedPlan(plansource, qlist, NULL); /* Just make real sure plansource->gplan is clear */ ReleaseGenericPlan(plansource); /* Link the new generic plan into the plansource */ plansource->gplan = plan; plan->refcount++; /* Immediately reparent into appropriate context */ if (plansource->is_saved) { /* saved plans all live under CacheMemoryContext */ MemoryContextSetParent(plan->context, CacheMemoryContext); plan->is_saved = true; } else { /* otherwise, it should be a sibling of the plansource */ MemoryContextSetParent(plan->context, MemoryContextGetParent(plansource->context)); } /* Update generic_cost whenever we make a new generic plan */ plansource->generic_cost = cached_plan_cost(plan); /* * If, based on the now-known value of generic_cost, we'd not have * chosen to use a generic plan, then forget it and make a custom * plan. This is a bit of a wart but is necessary to avoid a * glitch in behavior when the custom plans are consistently big * winners; at some point we'll experiment with a generic plan and * find it's a loser, but we don't want to actually execute that * plan. */ customplan = choose_custom_plan(plansource, boundParams); /* * If we choose to plan again, we need to re-copy the query_list, * since the planner probably scribbled on it. We can force * BuildCachedPlan to do that by passing NIL. */ qlist = NIL; } } if (customplan) { /* Build a custom plan */ plan = BuildCachedPlan(plansource, qlist, boundParams); /* Accumulate total costs of custom plans, but 'ware overflow */ if (plansource->num_custom_plans < INT_MAX) { plansource->total_custom_cost += cached_plan_cost(plan); plansource->num_custom_plans++; } } /* Flag the plan as in use by caller */ if (useResOwner) ResourceOwnerEnlargePlanCacheRefs(CurrentResourceOwner); plan->refcount++; if (useResOwner) ResourceOwnerRememberPlanCacheRef(CurrentResourceOwner, plan); /* * Saved plans should be under CacheMemoryContext so they will not go away * until their reference count goes to zero. In the generic-plan cases we * already took care of that, but for a custom plan, do it as soon as we * have created a reference-counted link. */ if (customplan && plansource->is_saved) { MemoryContextSetParent(plan->context, CacheMemoryContext); plan->is_saved = true; } return plan; }
void InitPlanCache | ( | void | ) |
Definition at line 112 of file plancache.c.
References AMOPOPID, CacheRegisterRelcacheCallback(), CacheRegisterSyscacheCallback(), NAMESPACEOID, OPEROID, PlanCacheFuncCallback(), PlanCacheRelCallback(), PlanCacheSysCallback(), and PROCOID.
Referenced by InitPostgres().
{ CacheRegisterRelcacheCallback(PlanCacheRelCallback, (Datum) 0); CacheRegisterSyscacheCallback(PROCOID, PlanCacheFuncCallback, (Datum) 0); CacheRegisterSyscacheCallback(NAMESPACEOID, PlanCacheSysCallback, (Datum) 0); CacheRegisterSyscacheCallback(OPEROID, PlanCacheSysCallback, (Datum) 0); CacheRegisterSyscacheCallback(AMOPOPID, PlanCacheSysCallback, (Datum) 0); }
void ReleaseCachedPlan | ( | CachedPlan * | plan, | |
bool | useResOwner | |||
) |
Definition at line 1175 of file plancache.c.
References Assert, CACHEDPLAN_MAGIC, CachedPlan::context, CurrentResourceOwner, CachedPlan::is_oneshot, CachedPlan::is_saved, CachedPlan::magic, MemoryContextDelete(), CachedPlan::refcount, and ResourceOwnerForgetPlanCacheRef().
Referenced by _SPI_execute_plan(), exec_eval_simple_expr(), exec_simple_check_plan(), ExplainExecuteQuery(), PortalReleaseCachedPlan(), ReleaseGenericPlan(), ResourceOwnerReleaseInternal(), and SPI_cursor_open_internal().
{ Assert(plan->magic == CACHEDPLAN_MAGIC); if (useResOwner) { Assert(plan->is_saved); ResourceOwnerForgetPlanCacheRef(CurrentResourceOwner, plan); } Assert(plan->refcount > 0); plan->refcount--; if (plan->refcount == 0) { /* Mark it no longer valid */ plan->magic = 0; /* One-shot plans do not own their context, so we can't free them */ if (!plan->is_oneshot) MemoryContextDelete(plan->context); } }
void ResetPlanCache | ( | void | ) |
Definition at line 1785 of file plancache.c.
References Assert, CACHEDPLANSOURCE_MAGIC, CMD_UTILITY, Query::commandType, CachedPlanSource::gplan, CachedPlan::is_valid, CachedPlanSource::is_valid, IsA, IsTransactionStmtPlan, lfirst, CachedPlanSource::magic, CachedPlanSource::next_saved, CachedPlanSource::query_list, UtilityContainsQuery(), and Query::utilityStmt.
Referenced by assign_session_replication_role(), DiscardAll(), DiscardCommand(), and PlanCacheSysCallback().
{ CachedPlanSource *plansource; for (plansource = first_saved_plan; plansource; plansource = plansource->next_saved) { ListCell *lc; Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC); /* No work if it's already invalidated */ if (!plansource->is_valid) continue; /* * We *must not* mark transaction control statements as invalid, * particularly not ROLLBACK, because they may need to be executed in * aborted transactions when we can't revalidate them (cf bug #5269). */ if (IsTransactionStmtPlan(plansource)) continue; /* * In general there is no point in invalidating utility statements * since they have no plans anyway. So invalidate it only if it * contains at least one non-utility statement, or contains a utility * statement that contains a pre-analyzed query (which could have * dependencies.) */ foreach(lc, plansource->query_list) { Query *query = (Query *) lfirst(lc); Assert(IsA(query, Query)); if (query->commandType != CMD_UTILITY || UtilityContainsQuery(query->utilityStmt)) { /* non-utility statement, so invalidate */ plansource->is_valid = false; if (plansource->gplan) plansource->gplan->is_valid = false; /* no need to look further */ break; } } } }
void SaveCachedPlan | ( | CachedPlanSource * | plansource | ) |
Definition at line 428 of file plancache.c.
References Assert, CACHEDPLANSOURCE_MAGIC, CacheMemoryContext, CachedPlanSource::context, elog, ERROR, CachedPlanSource::is_complete, CachedPlanSource::is_oneshot, CachedPlanSource::is_saved, CachedPlanSource::magic, MemoryContextSetParent(), CachedPlanSource::next_saved, and ReleaseGenericPlan().
Referenced by _SPI_save_plan(), exec_parse_message(), SPI_keepplan(), and StorePreparedStatement().
{ /* Assert caller is doing things in a sane order */ Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC); Assert(plansource->is_complete); Assert(!plansource->is_saved); /* This seems worth a real test, though */ if (plansource->is_oneshot) elog(ERROR, "cannot save one-shot cached plan"); /* * In typical use, this function would be called before generating any * plans from the CachedPlanSource. If there is a generic plan, moving it * into CacheMemoryContext would be pretty risky since it's unclear * whether the caller has taken suitable care with making references * long-lived. Best thing to do seems to be to discard the plan. */ ReleaseGenericPlan(plansource); /* * Reparent the source memory context under CacheMemoryContext so that it * will live indefinitely. The query_context follows along since it's * already a child of the other one. */ MemoryContextSetParent(plansource->context, CacheMemoryContext); /* * Add the entry to the global list of cached plans. */ plansource->next_saved = first_saved_plan; first_saved_plan = plansource; plansource->is_saved = true; }