Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * plancache.h
4 : * Plan cache definitions.
5 : *
6 : * See plancache.c for comments.
7 : *
8 : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
9 : * Portions Copyright (c) 1994, Regents of the University of California
10 : *
11 : * src/include/utils/plancache.h
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 : #ifndef PLANCACHE_H
16 : #define PLANCACHE_H
17 :
18 : #include "access/tupdesc.h"
19 : #include "lib/ilist.h"
20 : #include "nodes/params.h"
21 : #include "nodes/parsenodes.h"
22 : #include "nodes/plannodes.h"
23 : #include "tcop/cmdtag.h"
24 : #include "utils/queryenvironment.h"
25 : #include "utils/resowner.h"
26 :
27 :
28 : /* Forward declarations, to avoid including parsenodes.h here */
29 : struct Query;
30 : struct RawStmt;
31 :
32 : /* possible values for plan_cache_mode */
33 : typedef enum
34 : {
35 : PLAN_CACHE_MODE_AUTO,
36 : PLAN_CACHE_MODE_FORCE_GENERIC_PLAN,
37 : PLAN_CACHE_MODE_FORCE_CUSTOM_PLAN,
38 : } PlanCacheMode;
39 :
40 : /* GUC parameter */
41 : extern PGDLLIMPORT int plan_cache_mode;
42 :
43 : /* Optional callback to editorialize on rewritten parse trees */
44 : typedef void (*PostRewriteHook) (List *querytree_list, void *arg);
45 :
46 : #define CACHEDPLANSOURCE_MAGIC 195726186
47 : #define CACHEDPLAN_MAGIC 953717834
48 : #define CACHEDEXPR_MAGIC 838275847
49 :
50 : /*
51 : * CachedPlanSource (which might better have been called CachedQuery)
52 : * represents a SQL query that we expect to use multiple times. It stores the
53 : * query source text, the source parse tree, and the analyzed-and-rewritten
54 : * query tree, as well as adjunct data. Cache invalidation can happen as a
55 : * result of DDL affecting objects used by the query. In that case we discard
56 : * the analyzed-and-rewritten query tree, and rebuild it when next needed.
57 : *
58 : * There are two ways in which the source query can be represented: either
59 : * as a raw parse tree, or as an analyzed-but-not-rewritten parse tree.
60 : * In the latter case we expect that cache invalidation need not affect
61 : * the parse-analysis results, only the rewriting and planning steps.
62 : * Only one of raw_parse_tree and analyzed_parse_tree can be non-NULL.
63 : * (If both are NULL, the CachedPlanSource represents an empty query.)
64 : * Note that query_string is typically just an empty string when the
65 : * source query is an analyzed parse tree; also, param_types, num_params,
66 : * parserSetup, and parserSetupArg will not be used.
67 : *
68 : * An actual execution plan, represented by CachedPlan, is derived from the
69 : * CachedPlanSource when we need to execute the query. The plan could be
70 : * either generic (usable with any set of plan parameters) or custom (for a
71 : * specific set of parameters). plancache.c contains the logic that decides
72 : * which way to do it for any particular execution. If we are using a generic
73 : * cached plan then it is meant to be re-used across multiple executions, so
74 : * callers must always treat CachedPlans as read-only.
75 : *
76 : * Once successfully built and "saved", CachedPlanSources typically live
77 : * for the life of the backend, although they can be dropped explicitly.
78 : * CachedPlans are reference-counted and go away automatically when the last
79 : * reference is dropped. A CachedPlan can outlive the CachedPlanSource it
80 : * was created from.
81 : *
82 : * An "unsaved" CachedPlanSource can be used for generating plans, but it
83 : * lives in transient storage and will not be updated in response to sinval
84 : * events.
85 : *
86 : * CachedPlans made from saved CachedPlanSources are likewise in permanent
87 : * storage, so to avoid memory leaks, the reference-counted references to them
88 : * must be held in permanent data structures or ResourceOwners. CachedPlans
89 : * made from unsaved CachedPlanSources are in children of the caller's
90 : * memory context, so references to them should not be longer-lived than
91 : * that context. (Reference counting is somewhat pro forma in that case,
92 : * though it may be useful if the CachedPlan can be discarded early.)
93 : *
94 : * A CachedPlanSource has two associated memory contexts: one that holds the
95 : * struct itself, the query source text and the source parse tree, and another
96 : * context that holds the rewritten query tree and associated data. This
97 : * allows the query tree to be discarded easily when it is invalidated.
98 : *
99 : * Some callers wish to use the CachedPlan API even with one-shot queries
100 : * that have no reason to be saved at all. We therefore support a "oneshot"
101 : * variant that does no data copying or invalidation checking. In this case
102 : * there are no separate memory contexts: the CachedPlanSource struct and
103 : * all subsidiary data live in the caller's CurrentMemoryContext, and there
104 : * is no way to free memory short of clearing that entire context. A oneshot
105 : * plan is always treated as unsaved.
106 : */
107 : typedef struct CachedPlanSource
108 : {
109 : int magic; /* should equal CACHEDPLANSOURCE_MAGIC */
110 : struct RawStmt *raw_parse_tree; /* output of raw_parser(), or NULL */
111 : struct Query *analyzed_parse_tree; /* analyzed parse tree, or NULL */
112 : const char *query_string; /* source text of query */
113 : CommandTag commandTag; /* command tag for query */
114 : Oid *param_types; /* array of parameter type OIDs, or NULL */
115 : int num_params; /* length of param_types array */
116 : ParserSetupHook parserSetup; /* alternative parameter spec method */
117 : void *parserSetupArg;
118 : PostRewriteHook postRewrite; /* see SetPostRewriteHook */
119 : void *postRewriteArg;
120 : int cursor_options; /* cursor options used for planning */
121 : bool fixed_result; /* disallow change in result tupdesc? */
122 : TupleDesc resultDesc; /* result type; NULL = doesn't return tuples */
123 : MemoryContext context; /* memory context holding all above */
124 : /* These fields describe the current analyzed-and-rewritten query tree: */
125 : List *query_list; /* list of Query nodes, or NIL if not valid */
126 : List *relationOids; /* OIDs of relations the queries depend on */
127 : List *invalItems; /* other dependencies, as PlanInvalItems */
128 : struct SearchPathMatcher *search_path; /* search_path used for parsing
129 : * and planning */
130 : MemoryContext query_context; /* context holding the above, or NULL */
131 : Oid rewriteRoleId; /* Role ID we did rewriting for */
132 : bool rewriteRowSecurity; /* row_security used during rewrite */
133 : bool dependsOnRLS; /* is rewritten query specific to the above? */
134 : /* If we have a generic plan, this is a reference-counted link to it: */
135 : struct CachedPlan *gplan; /* generic plan, or NULL if not valid */
136 : /* Some state flags: */
137 : bool is_oneshot; /* is it a "oneshot" plan? */
138 : bool is_complete; /* has CompleteCachedPlan been done? */
139 : bool is_saved; /* has CachedPlanSource been "saved"? */
140 : bool is_valid; /* is the query_list currently valid? */
141 : int generation; /* increments each time we create a plan */
142 : /* If CachedPlanSource has been saved, it is a member of a global list */
143 : dlist_node node; /* list link, if is_saved */
144 : /* State kept to help decide whether to use custom or generic plans: */
145 : double generic_cost; /* cost of generic plan, or -1 if not known */
146 : double total_custom_cost; /* total cost of custom plans so far */
147 : int64 num_custom_plans; /* # of custom plans included in total */
148 : int64 num_generic_plans; /* # of generic plans */
149 : } CachedPlanSource;
150 :
151 : /*
152 : * CachedPlan represents an execution plan derived from a CachedPlanSource.
153 : * The reference count includes both the link from the parent CachedPlanSource
154 : * (if any), and any active plan executions, so the plan can be discarded
155 : * exactly when refcount goes to zero. Both the struct itself and the
156 : * subsidiary data, except the PlannedStmts in stmt_list live in the context
157 : * denoted by the context field; the PlannedStmts live in the context denoted
158 : * by stmt_context. Separate contexts makes it easy to free a no-longer-needed
159 : * cached plan. (However, if is_oneshot is true, the context does not belong
160 : * solely to the CachedPlan so no freeing is possible.)
161 : */
162 : typedef struct CachedPlan
163 : {
164 : int magic; /* should equal CACHEDPLAN_MAGIC */
165 : List *stmt_list; /* list of PlannedStmts */
166 : bool is_oneshot; /* is it a "oneshot" plan? */
167 : bool is_saved; /* is CachedPlan in a long-lived context? */
168 : bool is_reused; /* is it a reused generic plan? */
169 : bool is_valid; /* is the stmt_list currently valid? */
170 : Oid planRoleId; /* Role ID the plan was created for */
171 : bool dependsOnRole; /* is plan specific to that role? */
172 : TransactionId saved_xmin; /* if valid, replan when TransactionXmin
173 : * changes from this value */
174 : int generation; /* parent's generation number for this plan */
175 : int refcount; /* count of live references to this struct */
176 : MemoryContext context; /* context containing this CachedPlan */
177 : MemoryContext stmt_context; /* context containing the PlannedStmts in
178 : * stmt_list, but not the List itself which is
179 : * in the above context; NULL if is_oneshot is
180 : * true. */
181 : } CachedPlan;
182 :
183 : /*
184 : * CachedExpression is a low-overhead mechanism for caching the planned form
185 : * of standalone scalar expressions. While such expressions are not usually
186 : * subject to cache invalidation events, that can happen, for example because
187 : * of replacement of a SQL function that was inlined into the expression.
188 : * The plancache takes care of storing the expression tree and marking it
189 : * invalid if a cache invalidation occurs, but the caller must notice the
190 : * !is_valid status and discard the obsolete expression without reusing it.
191 : * We do not store the original parse tree, only the planned expression;
192 : * this is an optimization based on the assumption that we usually will not
193 : * need to replan for the life of the session.
194 : */
195 : typedef struct CachedExpression
196 : {
197 : int magic; /* should equal CACHEDEXPR_MAGIC */
198 : Node *expr; /* planned form of expression */
199 : bool is_valid; /* is the expression still valid? */
200 : /* remaining fields should be treated as private to plancache.c: */
201 : List *relationOids; /* OIDs of relations the expr depends on */
202 : List *invalItems; /* other dependencies, as PlanInvalItems */
203 : MemoryContext context; /* context containing this CachedExpression */
204 : dlist_node node; /* link in global list of CachedExpressions */
205 : } CachedExpression;
206 :
207 :
208 : extern void InitPlanCache(void);
209 : extern void ResetPlanCache(void);
210 :
211 : extern void ReleaseAllPlanCacheRefsInOwner(ResourceOwner owner);
212 :
213 : extern CachedPlanSource *CreateCachedPlan(struct RawStmt *raw_parse_tree,
214 : const char *query_string,
215 : CommandTag commandTag);
216 : extern CachedPlanSource *CreateCachedPlanForQuery(struct Query *analyzed_parse_tree,
217 : const char *query_string,
218 : CommandTag commandTag);
219 : extern CachedPlanSource *CreateOneShotCachedPlan(struct RawStmt *raw_parse_tree,
220 : const char *query_string,
221 : CommandTag commandTag);
222 : extern void CompleteCachedPlan(CachedPlanSource *plansource,
223 : List *querytree_list,
224 : MemoryContext querytree_context,
225 : Oid *param_types,
226 : int num_params,
227 : ParserSetupHook parserSetup,
228 : void *parserSetupArg,
229 : int cursor_options,
230 : bool fixed_result);
231 : extern void SetPostRewriteHook(CachedPlanSource *plansource,
232 : PostRewriteHook postRewrite,
233 : void *postRewriteArg);
234 :
235 : extern void SaveCachedPlan(CachedPlanSource *plansource);
236 : extern void DropCachedPlan(CachedPlanSource *plansource);
237 :
238 : extern void CachedPlanSetParentContext(CachedPlanSource *plansource,
239 : MemoryContext newcontext);
240 :
241 : extern CachedPlanSource *CopyCachedPlan(CachedPlanSource *plansource);
242 :
243 : extern bool CachedPlanIsValid(CachedPlanSource *plansource);
244 :
245 : extern List *CachedPlanGetTargetList(CachedPlanSource *plansource,
246 : QueryEnvironment *queryEnv);
247 :
248 : extern CachedPlan *GetCachedPlan(CachedPlanSource *plansource,
249 : ParamListInfo boundParams,
250 : ResourceOwner owner,
251 : QueryEnvironment *queryEnv);
252 : extern PlannedStmt *UpdateCachedPlan(CachedPlanSource *plansource,
253 : int query_index,
254 : QueryEnvironment *queryEnv);
255 :
256 : extern void ReleaseCachedPlan(CachedPlan *plan, ResourceOwner owner);
257 :
258 : extern bool CachedPlanAllowsSimpleValidityCheck(CachedPlanSource *plansource,
259 : CachedPlan *plan,
260 : ResourceOwner owner);
261 : extern bool CachedPlanIsSimplyValid(CachedPlanSource *plansource,
262 : CachedPlan *plan,
263 : ResourceOwner owner);
264 :
265 : extern CachedExpression *GetCachedExpression(Node *expr);
266 : extern void FreeCachedExpression(CachedExpression *cexpr);
267 :
268 : /*
269 : * CachedPlanRequiresLocking: should the executor acquire additional locks?
270 : *
271 : * If the plan is a saved generic plan, the executor must acquire locks for
272 : * relations that are not covered by AcquireExecutorLocks(), such as partitions
273 : * that are subject to initial runtime pruning.
274 : */
275 : static inline bool
276 39972 : CachedPlanRequiresLocking(CachedPlan *cplan)
277 : {
278 39972 : return !cplan->is_oneshot && cplan->is_reused;
279 : }
280 :
281 : /*
282 : * CachedPlanValid
283 : * Returns whether a cached generic plan is still valid.
284 : *
285 : * Invoked by the executor to check if the plan has not been invalidated after
286 : * taking locks during the initialization of the plan.
287 : */
288 : static inline bool
289 382308 : CachedPlanValid(CachedPlan *cplan)
290 : {
291 382308 : return cplan->is_valid;
292 : }
293 :
294 : #endif /* PLANCACHE_H */
|