From 293913568e6a7a86fd1479e1cff8e2ecb58d6568 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 13 Apr 2024 15:44:03 +0200 Subject: Adding upstream version 16.2. Signed-off-by: Daniel Baumann --- src/include/utils/plancache.h | 236 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 src/include/utils/plancache.h (limited to 'src/include/utils/plancache.h') diff --git a/src/include/utils/plancache.h b/src/include/utils/plancache.h new file mode 100644 index 0000000..a443181 --- /dev/null +++ b/src/include/utils/plancache.h @@ -0,0 +1,236 @@ +/*------------------------------------------------------------------------- + * + * plancache.h + * Plan cache definitions. + * + * See plancache.c for comments. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/plancache.h + * + *------------------------------------------------------------------------- + */ +#ifndef PLANCACHE_H +#define PLANCACHE_H + +#include "access/tupdesc.h" +#include "lib/ilist.h" +#include "nodes/params.h" +#include "tcop/cmdtag.h" +#include "utils/queryenvironment.h" +#include "utils/resowner.h" + + +/* Forward declaration, to avoid including parsenodes.h here */ +struct RawStmt; + +/* possible values for plan_cache_mode */ +typedef enum +{ + PLAN_CACHE_MODE_AUTO, + PLAN_CACHE_MODE_FORCE_GENERIC_PLAN, + PLAN_CACHE_MODE_FORCE_CUSTOM_PLAN +} PlanCacheMode; + +/* GUC parameter */ +extern PGDLLIMPORT int plan_cache_mode; + +#define CACHEDPLANSOURCE_MAGIC 195726186 +#define CACHEDPLAN_MAGIC 953717834 +#define CACHEDEXPR_MAGIC 838275847 + +/* + * CachedPlanSource (which might better have been called CachedQuery) + * represents a SQL query that we expect to use multiple times. It stores + * the query source text, the raw parse tree, and the analyzed-and-rewritten + * query tree, as well as adjunct data. Cache invalidation can happen as a + * result of DDL affecting objects used by the query. In that case we discard + * the analyzed-and-rewritten query tree, and rebuild it when next needed. + * + * An actual execution plan, represented by CachedPlan, is derived from the + * CachedPlanSource when we need to execute the query. The plan could be + * either generic (usable with any set of plan parameters) or custom (for a + * specific set of parameters). plancache.c contains the logic that decides + * which way to do it for any particular execution. If we are using a generic + * cached plan then it is meant to be re-used across multiple executions, so + * callers must always treat CachedPlans as read-only. + * + * Once successfully built and "saved", CachedPlanSources typically live + * for the life of the backend, although they can be dropped explicitly. + * CachedPlans are reference-counted and go away automatically when the last + * reference is dropped. A CachedPlan can outlive the CachedPlanSource it + * was created from. + * + * An "unsaved" CachedPlanSource can be used for generating plans, but it + * lives in transient storage and will not be updated in response to sinval + * events. + * + * CachedPlans made from saved CachedPlanSources are likewise in permanent + * storage, so to avoid memory leaks, the reference-counted references to them + * must be held in permanent data structures or ResourceOwners. CachedPlans + * made from unsaved CachedPlanSources are in children of the caller's + * memory context, so references to them should not be longer-lived than + * that context. (Reference counting is somewhat pro forma in that case, + * though it may be useful if the CachedPlan can be discarded early.) + * + * A CachedPlanSource has two associated memory contexts: one that holds the + * struct itself, the query source text and the raw parse tree, and another + * context that holds the rewritten query tree and associated data. This + * allows the query tree to be discarded easily when it is invalidated. + * + * Some callers wish to use the CachedPlan API even with one-shot queries + * that have no reason to be saved at all. We therefore support a "oneshot" + * variant that does no data copying or invalidation checking. In this case + * there are no separate memory contexts: the CachedPlanSource struct and + * all subsidiary data live in the caller's CurrentMemoryContext, and there + * is no way to free memory short of clearing that entire context. A oneshot + * plan is always treated as unsaved. + * + * Note: the string referenced by commandTag is not subsidiary storage; + * it is assumed to be a compile-time-constant string. As with portals, + * commandTag shall be NULL if and only if the original query string (before + * rewriting) was an empty string. + */ +typedef struct CachedPlanSource +{ + int magic; /* should equal CACHEDPLANSOURCE_MAGIC */ + struct RawStmt *raw_parse_tree; /* output of raw_parser(), or NULL */ + const char *query_string; /* source text of query */ + CommandTag commandTag; /* 'nuff said */ + Oid *param_types; /* array of parameter type OIDs, or NULL */ + int num_params; /* length of param_types array */ + ParserSetupHook parserSetup; /* alternative parameter spec method */ + void *parserSetupArg; + int cursor_options; /* cursor options used for planning */ + bool fixed_result; /* disallow change in result tupdesc? */ + TupleDesc resultDesc; /* result type; NULL = doesn't return tuples */ + MemoryContext context; /* memory context holding all above */ + /* These fields describe the current analyzed-and-rewritten query tree: */ + List *query_list; /* list of Query nodes, or NIL if not valid */ + List *relationOids; /* OIDs of relations the queries depend on */ + List *invalItems; /* other dependencies, as PlanInvalItems */ + struct OverrideSearchPath *search_path; /* search_path used for parsing + * and planning */ + MemoryContext query_context; /* context holding the above, or NULL */ + Oid rewriteRoleId; /* Role ID we did rewriting for */ + bool rewriteRowSecurity; /* row_security used during rewrite */ + bool dependsOnRLS; /* is rewritten query specific to the above? */ + /* If we have a generic plan, this is a reference-counted link to it: */ + struct CachedPlan *gplan; /* generic plan, or NULL if not valid */ + /* Some state flags: */ + bool is_oneshot; /* is it a "oneshot" plan? */ + bool is_complete; /* has CompleteCachedPlan been done? */ + bool is_saved; /* has CachedPlanSource been "saved"? */ + bool is_valid; /* is the query_list currently valid? */ + int generation; /* increments each time we create a plan */ + /* If CachedPlanSource has been saved, it is a member of a global list */ + dlist_node node; /* list link, if is_saved */ + /* State kept to help decide whether to use custom or generic plans: */ + double generic_cost; /* cost of generic plan, or -1 if not known */ + double total_custom_cost; /* total cost of custom plans so far */ + int64 num_custom_plans; /* # of custom plans included in total */ + int64 num_generic_plans; /* # of generic plans */ +} CachedPlanSource; + +/* + * CachedPlan represents an execution plan derived from a CachedPlanSource. + * The reference count includes both the link from the parent CachedPlanSource + * (if any), and any active plan executions, so the plan can be discarded + * exactly when refcount goes to zero. Both the struct itself and the + * subsidiary data live in the context denoted by the context field. + * This makes it easy to free a no-longer-needed cached plan. (However, + * if is_oneshot is true, the context does not belong solely to the CachedPlan + * so no freeing is possible.) + */ +typedef struct CachedPlan +{ + int magic; /* should equal CACHEDPLAN_MAGIC */ + List *stmt_list; /* list of PlannedStmts */ + bool is_oneshot; /* is it a "oneshot" plan? */ + bool is_saved; /* is CachedPlan in a long-lived context? */ + bool is_valid; /* is the stmt_list currently valid? */ + Oid planRoleId; /* Role ID the plan was created for */ + bool dependsOnRole; /* is plan specific to that role? */ + TransactionId saved_xmin; /* if valid, replan when TransactionXmin + * changes from this value */ + int generation; /* parent's generation number for this plan */ + int refcount; /* count of live references to this struct */ + MemoryContext context; /* context containing this CachedPlan */ +} CachedPlan; + +/* + * CachedExpression is a low-overhead mechanism for caching the planned form + * of standalone scalar expressions. While such expressions are not usually + * subject to cache invalidation events, that can happen, for example because + * of replacement of a SQL function that was inlined into the expression. + * The plancache takes care of storing the expression tree and marking it + * invalid if a cache invalidation occurs, but the caller must notice the + * !is_valid status and discard the obsolete expression without reusing it. + * We do not store the original parse tree, only the planned expression; + * this is an optimization based on the assumption that we usually will not + * need to replan for the life of the session. + */ +typedef struct CachedExpression +{ + int magic; /* should equal CACHEDEXPR_MAGIC */ + Node *expr; /* planned form of expression */ + bool is_valid; /* is the expression still valid? */ + /* remaining fields should be treated as private to plancache.c: */ + List *relationOids; /* OIDs of relations the expr depends on */ + List *invalItems; /* other dependencies, as PlanInvalItems */ + MemoryContext context; /* context containing this CachedExpression */ + dlist_node node; /* link in global list of CachedExpressions */ +} CachedExpression; + + +extern void InitPlanCache(void); +extern void ResetPlanCache(void); + +extern CachedPlanSource *CreateCachedPlan(struct RawStmt *raw_parse_tree, + const char *query_string, + CommandTag commandTag); +extern CachedPlanSource *CreateOneShotCachedPlan(struct RawStmt *raw_parse_tree, + const char *query_string, + CommandTag commandTag); +extern 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); + +extern void SaveCachedPlan(CachedPlanSource *plansource); +extern void DropCachedPlan(CachedPlanSource *plansource); + +extern void CachedPlanSetParentContext(CachedPlanSource *plansource, + MemoryContext newcontext); + +extern CachedPlanSource *CopyCachedPlan(CachedPlanSource *plansource); + +extern bool CachedPlanIsValid(CachedPlanSource *plansource); + +extern List *CachedPlanGetTargetList(CachedPlanSource *plansource, + QueryEnvironment *queryEnv); + +extern CachedPlan *GetCachedPlan(CachedPlanSource *plansource, + ParamListInfo boundParams, + ResourceOwner owner, + QueryEnvironment *queryEnv); +extern void ReleaseCachedPlan(CachedPlan *plan, ResourceOwner owner); + +extern bool CachedPlanAllowsSimpleValidityCheck(CachedPlanSource *plansource, + CachedPlan *plan, + ResourceOwner owner); +extern bool CachedPlanIsSimplyValid(CachedPlanSource *plansource, + CachedPlan *plan, + ResourceOwner owner); + +extern CachedExpression *GetCachedExpression(Node *expr); +extern void FreeCachedExpression(CachedExpression *cexpr); + +#endif /* PLANCACHE_H */ -- cgit v1.2.3