Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * plancache.c
4 : * Plan cache management.
5 : *
6 : * The plan cache manager has two principal responsibilities: deciding when
7 : * to use a generic plan versus a custom (parameter-value-specific) plan,
8 : * and tracking whether cached plans need to be invalidated because of schema
9 : * changes in the objects they depend on.
10 : *
11 : * The logic for choosing generic or custom plans is in choose_custom_plan,
12 : * which see for comments.
13 : *
14 : * Cache invalidation is driven off sinval events. Any CachedPlanSource
15 : * that matches the event is marked invalid, as is its generic CachedPlan
16 : * if it has one. When (and if) the next demand for a cached plan occurs,
17 : * parse analysis and/or rewrite is repeated to build a new valid query tree,
18 : * and then planning is performed as normal. We also force re-analysis and
19 : * re-planning if the active search_path is different from the previous time
20 : * or, if RLS is involved, if the user changes or the RLS environment changes.
21 : *
22 : * Note that if the sinval was a result of user DDL actions, parse analysis
23 : * could throw an error, for example if a column referenced by the query is
24 : * no longer present. Another possibility is for the query's output tupdesc
25 : * to change (for instance "SELECT *" might expand differently than before).
26 : * The creator of a cached plan can specify whether it is allowable for the
27 : * query to change output tupdesc on replan --- if so, it's up to the
28 : * caller to notice changes and cope with them.
29 : *
30 : * Currently, we track exactly the dependencies of plans on relations,
31 : * user-defined functions, and domains. On relcache invalidation events or
32 : * pg_proc or pg_type syscache invalidation events, we invalidate just those
33 : * plans that depend on the particular object being modified. (Note: this
34 : * scheme assumes that any table modification that requires replanning will
35 : * generate a relcache inval event.) We also watch for inval events on
36 : * certain other system catalogs, such as pg_namespace; but for them, our
37 : * response is just to invalidate all plans. We expect updates on those
38 : * catalogs to be infrequent enough that more-detailed tracking is not worth
39 : * the effort.
40 : *
41 : * In addition to full-fledged query plans, we provide a facility for
42 : * detecting invalidations of simple scalar expressions. This is fairly
43 : * bare-bones; it's the caller's responsibility to build a new expression
44 : * if the old one gets invalidated.
45 : *
46 : *
47 : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
48 : * Portions Copyright (c) 1994, Regents of the University of California
49 : *
50 : * IDENTIFICATION
51 : * src/backend/utils/cache/plancache.c
52 : *
53 : *-------------------------------------------------------------------------
54 : */
55 : #include "postgres.h"
56 :
57 : #include <limits.h>
58 :
59 : #include "access/transam.h"
60 : #include "catalog/namespace.h"
61 : #include "executor/executor.h"
62 : #include "miscadmin.h"
63 : #include "nodes/nodeFuncs.h"
64 : #include "optimizer/optimizer.h"
65 : #include "parser/analyze.h"
66 : #include "rewrite/rewriteHandler.h"
67 : #include "storage/lmgr.h"
68 : #include "tcop/pquery.h"
69 : #include "tcop/utility.h"
70 : #include "utils/inval.h"
71 : #include "utils/memutils.h"
72 : #include "utils/resowner.h"
73 : #include "utils/rls.h"
74 : #include "utils/snapmgr.h"
75 : #include "utils/syscache.h"
76 :
77 :
78 : /*
79 : * This is the head of the backend's list of "saved" CachedPlanSources (i.e.,
80 : * those that are in long-lived storage and are examined for sinval events).
81 : * We use a dlist instead of separate List cells so that we can guarantee
82 : * to save a CachedPlanSource without error.
83 : */
84 : static dlist_head saved_plan_list = DLIST_STATIC_INIT(saved_plan_list);
85 :
86 : /*
87 : * This is the head of the backend's list of CachedExpressions.
88 : */
89 : static dlist_head cached_expression_list = DLIST_STATIC_INIT(cached_expression_list);
90 :
91 : static void ReleaseGenericPlan(CachedPlanSource *plansource);
92 : static bool StmtPlanRequiresRevalidation(CachedPlanSource *plansource);
93 : static bool BuildingPlanRequiresSnapshot(CachedPlanSource *plansource);
94 : static List *RevalidateCachedQuery(CachedPlanSource *plansource,
95 : QueryEnvironment *queryEnv,
96 : bool release_generic);
97 : static bool CheckCachedPlan(CachedPlanSource *plansource);
98 : static CachedPlan *BuildCachedPlan(CachedPlanSource *plansource, List *qlist,
99 : ParamListInfo boundParams, QueryEnvironment *queryEnv);
100 : static bool choose_custom_plan(CachedPlanSource *plansource,
101 : ParamListInfo boundParams);
102 : static double cached_plan_cost(CachedPlan *plan, bool include_planner);
103 : static Query *QueryListGetPrimaryStmt(List *stmts);
104 : static void AcquireExecutorLocks(List *stmt_list, bool acquire);
105 : static void AcquirePlannerLocks(List *stmt_list, bool acquire);
106 : static void ScanQueryForLocks(Query *parsetree, bool acquire);
107 : static bool ScanQueryWalker(Node *node, bool *acquire);
108 : static TupleDesc PlanCacheComputeResultDesc(List *stmt_list);
109 : static void PlanCacheRelCallback(Datum arg, Oid relid);
110 : static void PlanCacheObjectCallback(Datum arg, int cacheid, uint32 hashvalue);
111 : static void PlanCacheSysCallback(Datum arg, int cacheid, uint32 hashvalue);
112 :
113 : /* ResourceOwner callbacks to track plancache references */
114 : static void ResOwnerReleaseCachedPlan(Datum res);
115 :
116 : static const ResourceOwnerDesc planref_resowner_desc =
117 : {
118 : .name = "plancache reference",
119 : .release_phase = RESOURCE_RELEASE_AFTER_LOCKS,
120 : .release_priority = RELEASE_PRIO_PLANCACHE_REFS,
121 : .ReleaseResource = ResOwnerReleaseCachedPlan,
122 : .DebugPrint = NULL /* the default message is fine */
123 : };
124 :
125 : /* Convenience wrappers over ResourceOwnerRemember/Forget */
126 : static inline void
127 298830 : ResourceOwnerRememberPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
128 : {
129 298830 : ResourceOwnerRemember(owner, PointerGetDatum(plan), &planref_resowner_desc);
130 298830 : }
131 : static inline void
132 208474 : ResourceOwnerForgetPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
133 : {
134 208474 : ResourceOwnerForget(owner, PointerGetDatum(plan), &planref_resowner_desc);
135 208474 : }
136 :
137 :
138 : /* GUC parameter */
139 : int plan_cache_mode = PLAN_CACHE_MODE_AUTO;
140 :
141 : /*
142 : * InitPlanCache: initialize module during InitPostgres.
143 : *
144 : * All we need to do is hook into inval.c's callback lists.
145 : */
146 : void
147 35218 : InitPlanCache(void)
148 : {
149 35218 : CacheRegisterRelcacheCallback(PlanCacheRelCallback, (Datum) 0);
150 35218 : CacheRegisterSyscacheCallback(PROCOID, PlanCacheObjectCallback, (Datum) 0);
151 35218 : CacheRegisterSyscacheCallback(TYPEOID, PlanCacheObjectCallback, (Datum) 0);
152 35218 : CacheRegisterSyscacheCallback(NAMESPACEOID, PlanCacheSysCallback, (Datum) 0);
153 35218 : CacheRegisterSyscacheCallback(OPEROID, PlanCacheSysCallback, (Datum) 0);
154 35218 : CacheRegisterSyscacheCallback(AMOPOPID, PlanCacheSysCallback, (Datum) 0);
155 35218 : CacheRegisterSyscacheCallback(FOREIGNSERVEROID, PlanCacheSysCallback, (Datum) 0);
156 35218 : CacheRegisterSyscacheCallback(FOREIGNDATAWRAPPEROID, PlanCacheSysCallback, (Datum) 0);
157 35218 : }
158 :
159 : /*
160 : * CreateCachedPlan: initially create a plan cache entry for a raw parse tree.
161 : *
162 : * Creation of a cached plan is divided into two steps, CreateCachedPlan and
163 : * CompleteCachedPlan. CreateCachedPlan should be called after running the
164 : * query through raw_parser, but before doing parse analysis and rewrite;
165 : * CompleteCachedPlan is called after that. The reason for this arrangement
166 : * is that it can save one round of copying of the raw parse tree, since
167 : * the parser will normally scribble on the raw parse tree. Callers would
168 : * otherwise need to make an extra copy of the parse tree to ensure they
169 : * still had a clean copy to present at plan cache creation time.
170 : *
171 : * All arguments presented to CreateCachedPlan are copied into a memory
172 : * context created as a child of the call-time CurrentMemoryContext, which
173 : * should be a reasonably short-lived working context that will go away in
174 : * event of an error. This ensures that the cached plan data structure will
175 : * likewise disappear if an error occurs before we have fully constructed it.
176 : * Once constructed, the cached plan can be made longer-lived, if needed,
177 : * by calling SaveCachedPlan.
178 : *
179 : * raw_parse_tree: output of raw_parser(), or NULL if empty query
180 : * query_string: original query text
181 : * commandTag: command tag for query, or UNKNOWN if empty query
182 : */
183 : CachedPlanSource *
184 58376 : CreateCachedPlan(RawStmt *raw_parse_tree,
185 : const char *query_string,
186 : CommandTag commandTag)
187 : {
188 : CachedPlanSource *plansource;
189 : MemoryContext source_context;
190 : MemoryContext oldcxt;
191 :
192 : Assert(query_string != NULL); /* required as of 8.4 */
193 :
194 : /*
195 : * Make a dedicated memory context for the CachedPlanSource and its
196 : * permanent subsidiary data. It's probably not going to be large, but
197 : * just in case, allow it to grow large. Initially it's a child of the
198 : * caller's context (which we assume to be transient), so that it will be
199 : * cleaned up on error.
200 : */
201 58376 : source_context = AllocSetContextCreate(CurrentMemoryContext,
202 : "CachedPlanSource",
203 : ALLOCSET_START_SMALL_SIZES);
204 :
205 : /*
206 : * Create and fill the CachedPlanSource struct within the new context.
207 : * Most fields are just left empty for the moment.
208 : */
209 58376 : oldcxt = MemoryContextSwitchTo(source_context);
210 :
211 58376 : plansource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
212 58376 : plansource->magic = CACHEDPLANSOURCE_MAGIC;
213 58376 : plansource->raw_parse_tree = copyObject(raw_parse_tree);
214 58376 : plansource->analyzed_parse_tree = NULL;
215 58376 : plansource->query_string = pstrdup(query_string);
216 58376 : MemoryContextSetIdentifier(source_context, plansource->query_string);
217 58376 : plansource->commandTag = commandTag;
218 58376 : plansource->param_types = NULL;
219 58376 : plansource->num_params = 0;
220 58376 : plansource->parserSetup = NULL;
221 58376 : plansource->parserSetupArg = NULL;
222 58376 : plansource->postRewrite = NULL;
223 58376 : plansource->postRewriteArg = NULL;
224 58376 : plansource->cursor_options = 0;
225 58376 : plansource->fixed_result = false;
226 58376 : plansource->resultDesc = NULL;
227 58376 : plansource->context = source_context;
228 58376 : plansource->query_list = NIL;
229 58376 : plansource->relationOids = NIL;
230 58376 : plansource->invalItems = NIL;
231 58376 : plansource->search_path = NULL;
232 58376 : plansource->query_context = NULL;
233 58376 : plansource->rewriteRoleId = InvalidOid;
234 58376 : plansource->rewriteRowSecurity = false;
235 58376 : plansource->dependsOnRLS = false;
236 58376 : plansource->gplan = NULL;
237 58376 : plansource->is_oneshot = false;
238 58376 : plansource->is_complete = false;
239 58376 : plansource->is_saved = false;
240 58376 : plansource->is_valid = false;
241 58376 : plansource->generation = 0;
242 58376 : plansource->generic_cost = -1;
243 58376 : plansource->total_custom_cost = 0;
244 58376 : plansource->num_generic_plans = 0;
245 58376 : plansource->num_custom_plans = 0;
246 :
247 58376 : MemoryContextSwitchTo(oldcxt);
248 :
249 58376 : return plansource;
250 : }
251 :
252 : /*
253 : * CreateCachedPlanForQuery: initially create a plan cache entry for a Query.
254 : *
255 : * This is used in the same way as CreateCachedPlan, except that the source
256 : * query has already been through parse analysis, and the plancache will never
257 : * try to re-do that step.
258 : *
259 : * Currently this is used only for new-style SQL functions, where we have a
260 : * Query from the function's prosqlbody, but no source text. The query_string
261 : * is typically empty, but is required anyway.
262 : */
263 : CachedPlanSource *
264 886 : CreateCachedPlanForQuery(Query *analyzed_parse_tree,
265 : const char *query_string,
266 : CommandTag commandTag)
267 : {
268 : CachedPlanSource *plansource;
269 : MemoryContext oldcxt;
270 :
271 : /* Rather than duplicating CreateCachedPlan, just do this: */
272 886 : plansource = CreateCachedPlan(NULL, query_string, commandTag);
273 886 : oldcxt = MemoryContextSwitchTo(plansource->context);
274 886 : plansource->analyzed_parse_tree = copyObject(analyzed_parse_tree);
275 886 : MemoryContextSwitchTo(oldcxt);
276 :
277 886 : return plansource;
278 : }
279 :
280 : /*
281 : * CreateOneShotCachedPlan: initially create a one-shot plan cache entry.
282 : *
283 : * This variant of CreateCachedPlan creates a plan cache entry that is meant
284 : * to be used only once. No data copying occurs: all data structures remain
285 : * in the caller's memory context (which typically should get cleared after
286 : * completing execution). The CachedPlanSource struct itself is also created
287 : * in that context.
288 : *
289 : * A one-shot plan cannot be saved or copied, since we make no effort to
290 : * preserve the raw parse tree unmodified. There is also no support for
291 : * invalidation, so plan use must be completed in the current transaction,
292 : * and DDL that might invalidate the querytree_list must be avoided as well.
293 : *
294 : * raw_parse_tree: output of raw_parser(), or NULL if empty query
295 : * query_string: original query text
296 : * commandTag: command tag for query, or NULL if empty query
297 : */
298 : CachedPlanSource *
299 19776 : CreateOneShotCachedPlan(RawStmt *raw_parse_tree,
300 : const char *query_string,
301 : CommandTag commandTag)
302 : {
303 : CachedPlanSource *plansource;
304 :
305 : Assert(query_string != NULL); /* required as of 8.4 */
306 :
307 : /*
308 : * Create and fill the CachedPlanSource struct within the caller's memory
309 : * context. Most fields are just left empty for the moment.
310 : */
311 19776 : plansource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
312 19776 : plansource->magic = CACHEDPLANSOURCE_MAGIC;
313 19776 : plansource->raw_parse_tree = raw_parse_tree;
314 19776 : plansource->analyzed_parse_tree = NULL;
315 19776 : plansource->query_string = query_string;
316 19776 : plansource->commandTag = commandTag;
317 19776 : plansource->param_types = NULL;
318 19776 : plansource->num_params = 0;
319 19776 : plansource->parserSetup = NULL;
320 19776 : plansource->parserSetupArg = NULL;
321 19776 : plansource->postRewrite = NULL;
322 19776 : plansource->postRewriteArg = NULL;
323 19776 : plansource->cursor_options = 0;
324 19776 : plansource->fixed_result = false;
325 19776 : plansource->resultDesc = NULL;
326 19776 : plansource->context = CurrentMemoryContext;
327 19776 : plansource->query_list = NIL;
328 19776 : plansource->relationOids = NIL;
329 19776 : plansource->invalItems = NIL;
330 19776 : plansource->search_path = NULL;
331 19776 : plansource->query_context = NULL;
332 19776 : plansource->rewriteRoleId = InvalidOid;
333 19776 : plansource->rewriteRowSecurity = false;
334 19776 : plansource->dependsOnRLS = false;
335 19776 : plansource->gplan = NULL;
336 19776 : plansource->is_oneshot = true;
337 19776 : plansource->is_complete = false;
338 19776 : plansource->is_saved = false;
339 19776 : plansource->is_valid = false;
340 19776 : plansource->generation = 0;
341 19776 : plansource->generic_cost = -1;
342 19776 : plansource->total_custom_cost = 0;
343 19776 : plansource->num_generic_plans = 0;
344 19776 : plansource->num_custom_plans = 0;
345 :
346 19776 : return plansource;
347 : }
348 :
349 : /*
350 : * CompleteCachedPlan: second step of creating a plan cache entry.
351 : *
352 : * Pass in the analyzed-and-rewritten form of the query, as well as the
353 : * required subsidiary data about parameters and such. All passed values will
354 : * be copied into the CachedPlanSource's memory, except as specified below.
355 : * After this is called, GetCachedPlan can be called to obtain a plan, and
356 : * optionally the CachedPlanSource can be saved using SaveCachedPlan.
357 : *
358 : * If querytree_context is not NULL, the querytree_list must be stored in that
359 : * context (but the other parameters need not be). The querytree_list is not
360 : * copied, rather the given context is kept as the initial query_context of
361 : * the CachedPlanSource. (It should have been created as a child of the
362 : * caller's working memory context, but it will now be reparented to belong
363 : * to the CachedPlanSource.) The querytree_context is normally the context in
364 : * which the caller did raw parsing and parse analysis. This approach saves
365 : * one tree copying step compared to passing NULL, but leaves lots of extra
366 : * cruft in the query_context, namely whatever extraneous stuff parse analysis
367 : * created, as well as whatever went unused from the raw parse tree. Using
368 : * this option is a space-for-time tradeoff that is appropriate if the
369 : * CachedPlanSource is not expected to survive long.
370 : *
371 : * plancache.c cannot know how to copy the data referenced by parserSetupArg,
372 : * and it would often be inappropriate to do so anyway. When using that
373 : * option, it is caller's responsibility that the referenced data remains
374 : * valid for as long as the CachedPlanSource exists.
375 : *
376 : * If the CachedPlanSource is a "oneshot" plan, then no querytree copying
377 : * occurs at all, and querytree_context is ignored; it is caller's
378 : * responsibility that the passed querytree_list is sufficiently long-lived.
379 : *
380 : * plansource: structure returned by CreateCachedPlan
381 : * querytree_list: analyzed-and-rewritten form of query (list of Query nodes)
382 : * querytree_context: memory context containing querytree_list,
383 : * or NULL to copy querytree_list into a fresh context
384 : * param_types: array of fixed parameter type OIDs, or NULL if none
385 : * num_params: number of fixed parameters
386 : * parserSetup: alternate method for handling query parameters
387 : * parserSetupArg: data to pass to parserSetup
388 : * cursor_options: options bitmask to pass to planner
389 : * fixed_result: true to disallow future changes in query's result tupdesc
390 : */
391 : void
392 78006 : CompleteCachedPlan(CachedPlanSource *plansource,
393 : List *querytree_list,
394 : MemoryContext querytree_context,
395 : Oid *param_types,
396 : int num_params,
397 : ParserSetupHook parserSetup,
398 : void *parserSetupArg,
399 : int cursor_options,
400 : bool fixed_result)
401 : {
402 78006 : MemoryContext source_context = plansource->context;
403 78006 : MemoryContext oldcxt = CurrentMemoryContext;
404 :
405 : /* Assert caller is doing things in a sane order */
406 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
407 : Assert(!plansource->is_complete);
408 :
409 : /*
410 : * If caller supplied a querytree_context, reparent it underneath the
411 : * CachedPlanSource's context; otherwise, create a suitable context and
412 : * copy the querytree_list into it. But no data copying should be done
413 : * for one-shot plans; for those, assume the passed querytree_list is
414 : * sufficiently long-lived.
415 : */
416 78006 : if (plansource->is_oneshot)
417 : {
418 19760 : querytree_context = CurrentMemoryContext;
419 : }
420 58246 : else if (querytree_context != NULL)
421 : {
422 6744 : MemoryContextSetParent(querytree_context, source_context);
423 6744 : MemoryContextSwitchTo(querytree_context);
424 : }
425 : else
426 : {
427 : /* Again, it's a good bet the querytree_context can be small */
428 51502 : querytree_context = AllocSetContextCreate(source_context,
429 : "CachedPlanQuery",
430 : ALLOCSET_START_SMALL_SIZES);
431 51502 : MemoryContextSwitchTo(querytree_context);
432 51502 : querytree_list = copyObject(querytree_list);
433 : }
434 :
435 78006 : plansource->query_context = querytree_context;
436 78006 : plansource->query_list = querytree_list;
437 :
438 78006 : if (!plansource->is_oneshot && StmtPlanRequiresRevalidation(plansource))
439 : {
440 : /*
441 : * Use the planner machinery to extract dependencies. Data is saved
442 : * in query_context. (We assume that not a lot of extra cruft is
443 : * created by this call.) We can skip this for one-shot plans, and
444 : * plans not needing revalidation have no such dependencies anyway.
445 : */
446 56234 : extract_query_dependencies((Node *) querytree_list,
447 : &plansource->relationOids,
448 : &plansource->invalItems,
449 : &plansource->dependsOnRLS);
450 :
451 : /* Update RLS info as well. */
452 56234 : plansource->rewriteRoleId = GetUserId();
453 56234 : plansource->rewriteRowSecurity = row_security;
454 :
455 : /*
456 : * Also save the current search_path in the query_context. (This
457 : * should not generate much extra cruft either, since almost certainly
458 : * the path is already valid.) Again, we don't really need this for
459 : * one-shot plans; and we *must* skip this for transaction control
460 : * commands, because this could result in catalog accesses.
461 : */
462 56234 : plansource->search_path = GetSearchPathMatcher(querytree_context);
463 : }
464 :
465 : /*
466 : * Save the final parameter types (or other parameter specification data)
467 : * into the source_context, as well as our other parameters. Also save
468 : * the result tuple descriptor.
469 : */
470 78006 : MemoryContextSwitchTo(source_context);
471 :
472 78006 : if (num_params > 0)
473 : {
474 14360 : plansource->param_types = (Oid *) palloc(num_params * sizeof(Oid));
475 14360 : memcpy(plansource->param_types, param_types, num_params * sizeof(Oid));
476 : }
477 : else
478 63646 : plansource->param_types = NULL;
479 78006 : plansource->num_params = num_params;
480 78006 : plansource->parserSetup = parserSetup;
481 78006 : plansource->parserSetupArg = parserSetupArg;
482 78006 : plansource->cursor_options = cursor_options;
483 78006 : plansource->fixed_result = fixed_result;
484 78006 : plansource->resultDesc = PlanCacheComputeResultDesc(querytree_list);
485 :
486 78006 : MemoryContextSwitchTo(oldcxt);
487 :
488 78006 : plansource->is_complete = true;
489 78006 : plansource->is_valid = true;
490 78006 : }
491 :
492 : /*
493 : * SetPostRewriteHook: set a hook to modify post-rewrite query trees
494 : *
495 : * Some callers have a need to modify the query trees between rewriting and
496 : * planning. In the initial call to CompleteCachedPlan, it's assumed such
497 : * work was already done on the querytree_list. However, if we're forced
498 : * to replan, it will need to be done over. The caller can set this hook
499 : * to provide code to make that happen.
500 : *
501 : * postRewriteArg is just passed verbatim to the hook. As with parserSetupArg,
502 : * it is caller's responsibility that the referenced data remains
503 : * valid for as long as the CachedPlanSource exists.
504 : */
505 : void
506 2194 : SetPostRewriteHook(CachedPlanSource *plansource,
507 : PostRewriteHook postRewrite,
508 : void *postRewriteArg)
509 : {
510 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
511 2194 : plansource->postRewrite = postRewrite;
512 2194 : plansource->postRewriteArg = postRewriteArg;
513 2194 : }
514 :
515 : /*
516 : * SaveCachedPlan: save a cached plan permanently
517 : *
518 : * This function moves the cached plan underneath CacheMemoryContext (making
519 : * it live for the life of the backend, unless explicitly dropped), and adds
520 : * it to the list of cached plans that are checked for invalidation when an
521 : * sinval event occurs.
522 : *
523 : * This is guaranteed not to throw error, except for the caller-error case
524 : * of trying to save a one-shot plan. Callers typically depend on that
525 : * since this is called just before or just after adding a pointer to the
526 : * CachedPlanSource to some permanent data structure of their own. Up until
527 : * this is done, a CachedPlanSource is just transient data that will go away
528 : * automatically on transaction abort.
529 : */
530 : void
531 47298 : SaveCachedPlan(CachedPlanSource *plansource)
532 : {
533 : /* Assert caller is doing things in a sane order */
534 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
535 : Assert(plansource->is_complete);
536 : Assert(!plansource->is_saved);
537 :
538 : /* This seems worth a real test, though */
539 47298 : if (plansource->is_oneshot)
540 0 : elog(ERROR, "cannot save one-shot cached plan");
541 :
542 : /*
543 : * In typical use, this function would be called before generating any
544 : * plans from the CachedPlanSource. If there is a generic plan, moving it
545 : * into CacheMemoryContext would be pretty risky since it's unclear
546 : * whether the caller has taken suitable care with making references
547 : * long-lived. Best thing to do seems to be to discard the plan.
548 : */
549 47298 : ReleaseGenericPlan(plansource);
550 :
551 : /*
552 : * Reparent the source memory context under CacheMemoryContext so that it
553 : * will live indefinitely. The query_context follows along since it's
554 : * already a child of the other one.
555 : */
556 47298 : MemoryContextSetParent(plansource->context, CacheMemoryContext);
557 :
558 : /*
559 : * Add the entry to the global list of cached plans.
560 : */
561 47298 : dlist_push_tail(&saved_plan_list, &plansource->node);
562 :
563 47298 : plansource->is_saved = true;
564 47298 : }
565 :
566 : /*
567 : * DropCachedPlan: destroy a cached plan.
568 : *
569 : * Actually this only destroys the CachedPlanSource: any referenced CachedPlan
570 : * is released, but not destroyed until its refcount goes to zero. That
571 : * handles the situation where DropCachedPlan is called while the plan is
572 : * still in use.
573 : */
574 : void
575 18232 : DropCachedPlan(CachedPlanSource *plansource)
576 : {
577 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
578 :
579 : /* If it's been saved, remove it from the list */
580 18232 : if (plansource->is_saved)
581 : {
582 18042 : dlist_delete(&plansource->node);
583 18042 : plansource->is_saved = false;
584 : }
585 :
586 : /* Decrement generic CachedPlan's refcount and drop if no longer needed */
587 18232 : ReleaseGenericPlan(plansource);
588 :
589 : /* Mark it no longer valid */
590 18232 : plansource->magic = 0;
591 :
592 : /*
593 : * Remove the CachedPlanSource and all subsidiary data (including the
594 : * query_context if any). But if it's a one-shot we can't free anything.
595 : */
596 18232 : if (!plansource->is_oneshot)
597 18232 : MemoryContextDelete(plansource->context);
598 18232 : }
599 :
600 : /*
601 : * ReleaseGenericPlan: release a CachedPlanSource's generic plan, if any.
602 : */
603 : static void
604 121742 : ReleaseGenericPlan(CachedPlanSource *plansource)
605 : {
606 : /* Be paranoid about the possibility that ReleaseCachedPlan fails */
607 121742 : if (plansource->gplan)
608 : {
609 15836 : CachedPlan *plan = plansource->gplan;
610 :
611 : Assert(plan->magic == CACHEDPLAN_MAGIC);
612 15836 : plansource->gplan = NULL;
613 15836 : ReleaseCachedPlan(plan, NULL);
614 : }
615 121742 : }
616 :
617 : /*
618 : * We must skip "overhead" operations that involve database access when the
619 : * cached plan's subject statement is a transaction control command or one
620 : * that requires a snapshot not to be set yet (such as SET or LOCK). More
621 : * generally, statements that do not require parse analysis/rewrite/plan
622 : * activity never need to be revalidated, so we can treat them all like that.
623 : * For the convenience of postgres.c, treat empty statements that way too.
624 : */
625 : static bool
626 33866354 : StmtPlanRequiresRevalidation(CachedPlanSource *plansource)
627 : {
628 33866354 : if (plansource->raw_parse_tree != NULL)
629 33369058 : return stmt_requires_parse_analysis(plansource->raw_parse_tree);
630 497296 : else if (plansource->analyzed_parse_tree != NULL)
631 497290 : return query_requires_rewrite_plan(plansource->analyzed_parse_tree);
632 : /* empty query never needs revalidation */
633 6 : return false;
634 : }
635 :
636 : /*
637 : * Determine if creating a plan for this CachedPlanSource requires a snapshot.
638 : * In fact this function matches StmtPlanRequiresRevalidation(), but we want
639 : * to preserve the distinction between stmt_requires_parse_analysis() and
640 : * analyze_requires_snapshot().
641 : */
642 : static bool
643 1064 : BuildingPlanRequiresSnapshot(CachedPlanSource *plansource)
644 : {
645 1064 : if (plansource->raw_parse_tree != NULL)
646 1064 : return analyze_requires_snapshot(plansource->raw_parse_tree);
647 0 : else if (plansource->analyzed_parse_tree != NULL)
648 0 : return query_requires_rewrite_plan(plansource->analyzed_parse_tree);
649 : /* empty query never needs a snapshot */
650 0 : return false;
651 : }
652 :
653 : /*
654 : * RevalidateCachedQuery: ensure validity of analyzed-and-rewritten query tree.
655 : *
656 : * What we do here is re-acquire locks and redo parse analysis if necessary.
657 : * On return, the query_list is valid and we have sufficient locks to begin
658 : * planning.
659 : *
660 : * If any parse analysis activity is required, the caller's memory context is
661 : * used for that work.
662 : *
663 : * The result value is the transient analyzed-and-rewritten query tree if we
664 : * had to do re-analysis, and NIL otherwise. (This is returned just to save
665 : * a tree copying step in a subsequent BuildCachedPlan call.)
666 : *
667 : * This also releases and drops the generic plan (plansource->gplan), if any,
668 : * as most callers will typically build a new CachedPlan for the plansource
669 : * right after this. However, when called from UpdateCachedPlan(), the
670 : * function does not release the generic plan, as UpdateCachedPlan() updates
671 : * an existing CachedPlan in place.
672 : */
673 : static List *
674 313612 : RevalidateCachedQuery(CachedPlanSource *plansource,
675 : QueryEnvironment *queryEnv,
676 : bool release_generic)
677 : {
678 : bool snapshot_set;
679 : List *tlist; /* transient query-tree list */
680 : List *qlist; /* permanent query-tree list */
681 : TupleDesc resultDesc;
682 : MemoryContext querytree_context;
683 : MemoryContext oldcxt;
684 :
685 : /*
686 : * For one-shot plans, we do not support revalidation checking; it's
687 : * assumed the query is parsed, planned, and executed in one transaction,
688 : * so that no lock re-acquisition is necessary. Also, if the statement
689 : * type can't require revalidation, we needn't do anything (and we mustn't
690 : * risk catalog accesses when handling, eg, transaction control commands).
691 : */
692 313612 : if (plansource->is_oneshot || !StmtPlanRequiresRevalidation(plansource))
693 : {
694 : Assert(plansource->is_valid);
695 42540 : return NIL;
696 : }
697 :
698 : /*
699 : * If the query is currently valid, we should have a saved search_path ---
700 : * check to see if that matches the current environment. If not, we want
701 : * to force replan. (We could almost ignore this consideration when
702 : * working from an analyzed parse tree; but there are scenarios where
703 : * planning can have search_path-dependent results, for example if it
704 : * inlines an old-style SQL function.)
705 : */
706 271072 : if (plansource->is_valid)
707 : {
708 : Assert(plansource->search_path != NULL);
709 264310 : if (!SearchPathMatchesCurrentEnvironment(plansource->search_path))
710 : {
711 : /* Invalidate the querytree and generic plan */
712 86 : plansource->is_valid = false;
713 86 : if (plansource->gplan)
714 60 : plansource->gplan->is_valid = false;
715 : }
716 : }
717 :
718 : /*
719 : * If the query rewrite phase had a possible RLS dependency, we must redo
720 : * it if either the role or the row_security setting has changed.
721 : */
722 271366 : if (plansource->is_valid && plansource->dependsOnRLS &&
723 294 : (plansource->rewriteRoleId != GetUserId() ||
724 210 : plansource->rewriteRowSecurity != row_security))
725 108 : plansource->is_valid = false;
726 :
727 : /*
728 : * If the query is currently valid, acquire locks on the referenced
729 : * objects; then check again. We need to do it this way to cover the race
730 : * condition that an invalidation message arrives before we get the locks.
731 : */
732 271072 : if (plansource->is_valid)
733 : {
734 264116 : AcquirePlannerLocks(plansource->query_list, true);
735 :
736 : /*
737 : * By now, if any invalidation has happened, the inval callback
738 : * functions will have marked the query invalid.
739 : */
740 264116 : if (plansource->is_valid)
741 : {
742 : /* Successfully revalidated and locked the query. */
743 264084 : return NIL;
744 : }
745 :
746 : /* Oops, the race case happened. Release useless locks. */
747 32 : AcquirePlannerLocks(plansource->query_list, false);
748 : }
749 :
750 : /*
751 : * Discard the no-longer-useful rewritten query tree. (Note: we don't
752 : * want to do this any earlier, else we'd not have been able to release
753 : * locks correctly in the race condition case.)
754 : */
755 6988 : plansource->is_valid = false;
756 6988 : plansource->query_list = NIL;
757 6988 : plansource->relationOids = NIL;
758 6988 : plansource->invalItems = NIL;
759 6988 : plansource->search_path = NULL;
760 :
761 : /*
762 : * Free the query_context. We don't really expect MemoryContextDelete to
763 : * fail, but just in case, make sure the CachedPlanSource is left in a
764 : * reasonably sane state. (The generic plan won't get unlinked yet, but
765 : * that's acceptable.)
766 : */
767 6988 : if (plansource->query_context)
768 : {
769 6958 : MemoryContext qcxt = plansource->query_context;
770 :
771 6958 : plansource->query_context = NULL;
772 6958 : MemoryContextDelete(qcxt);
773 : }
774 :
775 : /* Drop the generic plan reference, if any, and if requested */
776 6988 : if (release_generic)
777 6988 : ReleaseGenericPlan(plansource);
778 :
779 : /*
780 : * Now re-do parse analysis and rewrite. This not incidentally acquires
781 : * the locks we need to do planning safely.
782 : */
783 : Assert(plansource->is_complete);
784 :
785 : /*
786 : * If a snapshot is already set (the normal case), we can just use that
787 : * for parsing/planning. But if it isn't, install one. Note: no point in
788 : * checking whether parse analysis requires a snapshot; utility commands
789 : * don't have invalidatable plans, so we'd not get here for such a
790 : * command.
791 : */
792 6988 : snapshot_set = false;
793 6988 : if (!ActiveSnapshotSet())
794 : {
795 22 : PushActiveSnapshot(GetTransactionSnapshot());
796 22 : snapshot_set = true;
797 : }
798 :
799 : /*
800 : * Run parse analysis (if needed) and rule rewriting.
801 : */
802 6988 : if (plansource->raw_parse_tree != NULL)
803 : {
804 : /* Source is raw parse tree */
805 : RawStmt *rawtree;
806 :
807 : /*
808 : * The parser tends to scribble on its input, so we must copy the raw
809 : * parse tree to prevent corruption of the cache.
810 : */
811 6726 : rawtree = copyObject(plansource->raw_parse_tree);
812 6726 : if (plansource->parserSetup != NULL)
813 6354 : tlist = pg_analyze_and_rewrite_withcb(rawtree,
814 : plansource->query_string,
815 : plansource->parserSetup,
816 : plansource->parserSetupArg,
817 : queryEnv);
818 : else
819 372 : tlist = pg_analyze_and_rewrite_fixedparams(rawtree,
820 : plansource->query_string,
821 372 : plansource->param_types,
822 : plansource->num_params,
823 : queryEnv);
824 : }
825 262 : else if (plansource->analyzed_parse_tree != NULL)
826 : {
827 : /* Source is pre-analyzed query, so we only need to rewrite */
828 : Query *analyzed_tree;
829 :
830 : /* The rewriter scribbles on its input, too, so copy */
831 262 : analyzed_tree = copyObject(plansource->analyzed_parse_tree);
832 : /* Acquire locks needed before rewriting ... */
833 262 : AcquireRewriteLocks(analyzed_tree, true, false);
834 : /* ... and do it */
835 262 : tlist = pg_rewrite_query(analyzed_tree);
836 : }
837 : else
838 : {
839 : /* Empty query, nothing to do */
840 0 : tlist = NIL;
841 : }
842 :
843 : /* Apply post-rewrite callback if there is one */
844 6948 : if (plansource->postRewrite != NULL)
845 382 : plansource->postRewrite(tlist, plansource->postRewriteArg);
846 :
847 : /* Release snapshot if we got one */
848 6948 : if (snapshot_set)
849 22 : PopActiveSnapshot();
850 :
851 : /*
852 : * Check or update the result tupdesc.
853 : *
854 : * We assume the parameter types didn't change from the first time, so no
855 : * need to update that.
856 : */
857 6948 : resultDesc = PlanCacheComputeResultDesc(tlist);
858 6948 : if (resultDesc == NULL && plansource->resultDesc == NULL)
859 : {
860 : /* OK, doesn't return tuples */
861 : }
862 6768 : else if (resultDesc == NULL || plansource->resultDesc == NULL ||
863 6768 : !equalRowTypes(resultDesc, plansource->resultDesc))
864 : {
865 : /* can we give a better error message? */
866 58 : if (plansource->fixed_result)
867 12 : ereport(ERROR,
868 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
869 : errmsg("cached plan must not change result type")));
870 46 : oldcxt = MemoryContextSwitchTo(plansource->context);
871 46 : if (resultDesc)
872 46 : resultDesc = CreateTupleDescCopy(resultDesc);
873 46 : if (plansource->resultDesc)
874 46 : FreeTupleDesc(plansource->resultDesc);
875 46 : plansource->resultDesc = resultDesc;
876 46 : MemoryContextSwitchTo(oldcxt);
877 : }
878 :
879 : /*
880 : * Allocate new query_context and copy the completed querytree into it.
881 : * It's transient until we complete the copying and dependency extraction.
882 : */
883 6936 : querytree_context = AllocSetContextCreate(CurrentMemoryContext,
884 : "CachedPlanQuery",
885 : ALLOCSET_START_SMALL_SIZES);
886 6936 : oldcxt = MemoryContextSwitchTo(querytree_context);
887 :
888 6936 : qlist = copyObject(tlist);
889 :
890 : /*
891 : * Use the planner machinery to extract dependencies. Data is saved in
892 : * query_context. (We assume that not a lot of extra cruft is created by
893 : * this call.)
894 : */
895 6936 : extract_query_dependencies((Node *) qlist,
896 : &plansource->relationOids,
897 : &plansource->invalItems,
898 : &plansource->dependsOnRLS);
899 :
900 : /* Update RLS info as well. */
901 6936 : plansource->rewriteRoleId = GetUserId();
902 6936 : plansource->rewriteRowSecurity = row_security;
903 :
904 : /*
905 : * Also save the current search_path in the query_context. (This should
906 : * not generate much extra cruft either, since almost certainly the path
907 : * is already valid.)
908 : */
909 6936 : plansource->search_path = GetSearchPathMatcher(querytree_context);
910 :
911 6936 : MemoryContextSwitchTo(oldcxt);
912 :
913 : /* Now reparent the finished query_context and save the links */
914 6936 : MemoryContextSetParent(querytree_context, plansource->context);
915 :
916 6936 : plansource->query_context = querytree_context;
917 6936 : plansource->query_list = qlist;
918 :
919 : /*
920 : * Note: we do not reset generic_cost or total_custom_cost, although we
921 : * could choose to do so. If the DDL or statistics change that prompted
922 : * the invalidation meant a significant change in the cost estimates, it
923 : * would be better to reset those variables and start fresh; but often it
924 : * doesn't, and we're better retaining our hard-won knowledge about the
925 : * relative costs.
926 : */
927 :
928 6936 : plansource->is_valid = true;
929 :
930 : /* Return transient copy of querytrees for possible use in planning */
931 6936 : return tlist;
932 : }
933 :
934 : /*
935 : * CheckCachedPlan: see if the CachedPlanSource's generic plan is valid.
936 : *
937 : * Caller must have already called RevalidateCachedQuery to verify that the
938 : * querytree is up to date.
939 : *
940 : * On a "true" return, we have acquired locks on the "unprunableRelids" set
941 : * for all plans in plansource->stmt_list. However, the plans are not fully
942 : * race-condition-free until the executor acquires locks on the prunable
943 : * relations that survive initial runtime pruning during InitPlan().
944 : */
945 : static bool
946 241228 : CheckCachedPlan(CachedPlanSource *plansource)
947 : {
948 241228 : CachedPlan *plan = plansource->gplan;
949 :
950 : /* Assert that caller checked the querytree */
951 : Assert(plansource->is_valid);
952 :
953 : /* If there's no generic plan, just say "false" */
954 241228 : if (!plan)
955 49126 : return false;
956 :
957 : Assert(plan->magic == CACHEDPLAN_MAGIC);
958 : /* Generic plans are never one-shot */
959 : Assert(!plan->is_oneshot);
960 :
961 : /*
962 : * If plan isn't valid for current role, we can't use it.
963 : */
964 192140 : if (plan->is_valid && plan->dependsOnRole &&
965 38 : plan->planRoleId != GetUserId())
966 36 : plan->is_valid = false;
967 :
968 : /*
969 : * If it appears valid, acquire locks and recheck; this is much the same
970 : * logic as in RevalidateCachedQuery, but for a plan.
971 : */
972 192102 : if (plan->is_valid)
973 : {
974 : /*
975 : * Plan must have positive refcount because it is referenced by
976 : * plansource; so no need to fear it disappears under us here.
977 : */
978 : Assert(plan->refcount > 0);
979 :
980 192024 : AcquireExecutorLocks(plan->stmt_list, true);
981 :
982 : /*
983 : * If plan was transient, check to see if TransactionXmin has
984 : * advanced, and if so invalidate it.
985 : */
986 192024 : if (plan->is_valid &&
987 192024 : TransactionIdIsValid(plan->saved_xmin) &&
988 0 : !TransactionIdEquals(plan->saved_xmin, TransactionXmin))
989 0 : plan->is_valid = false;
990 :
991 : /*
992 : * By now, if any invalidation has happened, the inval callback
993 : * functions will have marked the plan invalid.
994 : */
995 192024 : if (plan->is_valid)
996 : {
997 : /* Successfully revalidated and locked the query. */
998 192024 : return true;
999 : }
1000 :
1001 : /* Oops, the race case happened. Release useless locks. */
1002 0 : AcquireExecutorLocks(plan->stmt_list, false);
1003 : }
1004 :
1005 : /*
1006 : * Plan has been invalidated, so unlink it from the parent and release it.
1007 : */
1008 78 : ReleaseGenericPlan(plansource);
1009 :
1010 78 : return false;
1011 : }
1012 :
1013 : /*
1014 : * BuildCachedPlan: construct a new CachedPlan from a CachedPlanSource.
1015 : *
1016 : * qlist should be the result value from a previous RevalidateCachedQuery,
1017 : * or it can be set to NIL if we need to re-copy the plansource's query_list.
1018 : *
1019 : * To build a generic, parameter-value-independent plan, pass NULL for
1020 : * boundParams. To build a custom plan, pass the actual parameter values via
1021 : * boundParams. For best effect, the PARAM_FLAG_CONST flag should be set on
1022 : * each parameter value; otherwise the planner will treat the value as a
1023 : * hint rather than a hard constant.
1024 : *
1025 : * Planning work is done in the caller's memory context. The finished plan
1026 : * is in a child memory context, which typically should get reparented
1027 : * (unless this is a one-shot plan, in which case we don't copy the plan).
1028 : *
1029 : * Note: When changing this, you should also look at UpdateCachedPlan().
1030 : */
1031 : static CachedPlan *
1032 101772 : BuildCachedPlan(CachedPlanSource *plansource, List *qlist,
1033 : ParamListInfo boundParams, QueryEnvironment *queryEnv)
1034 : {
1035 : CachedPlan *plan;
1036 : List *plist;
1037 : bool snapshot_set;
1038 : bool is_transient;
1039 : MemoryContext plan_context;
1040 101772 : MemoryContext stmt_context = NULL;
1041 101772 : MemoryContext oldcxt = CurrentMemoryContext;
1042 : ListCell *lc;
1043 :
1044 : /*
1045 : * Normally the querytree should be valid already, but if it's not,
1046 : * rebuild it.
1047 : *
1048 : * NOTE: GetCachedPlan should have called RevalidateCachedQuery first, so
1049 : * we ought to be holding sufficient locks to prevent any invalidation.
1050 : * However, if we're building a custom plan after having built and
1051 : * rejected a generic plan, it's possible to reach here with is_valid
1052 : * false due to an invalidation while making the generic plan. In theory
1053 : * the invalidation must be a false positive, perhaps a consequence of an
1054 : * sinval reset event or the debug_discard_caches code. But for safety,
1055 : * let's treat it as real and redo the RevalidateCachedQuery call.
1056 : */
1057 101772 : if (!plansource->is_valid)
1058 0 : qlist = RevalidateCachedQuery(plansource, queryEnv, true);
1059 :
1060 : /*
1061 : * If we don't already have a copy of the querytree list that can be
1062 : * scribbled on by the planner, make one. For a one-shot plan, we assume
1063 : * it's okay to scribble on the original query_list.
1064 : */
1065 101772 : if (qlist == NIL)
1066 : {
1067 94840 : if (!plansource->is_oneshot)
1068 75086 : qlist = copyObject(plansource->query_list);
1069 : else
1070 19754 : qlist = plansource->query_list;
1071 : }
1072 :
1073 : /*
1074 : * If a snapshot is already set (the normal case), we can just use that
1075 : * for planning. But if it isn't, and we need one, install one.
1076 : */
1077 101772 : snapshot_set = false;
1078 102836 : if (!ActiveSnapshotSet() &&
1079 1064 : BuildingPlanRequiresSnapshot(plansource))
1080 : {
1081 286 : PushActiveSnapshot(GetTransactionSnapshot());
1082 286 : snapshot_set = true;
1083 : }
1084 :
1085 : /*
1086 : * Generate the plan.
1087 : */
1088 101772 : plist = pg_plan_queries(qlist, plansource->query_string,
1089 : plansource->cursor_options, boundParams);
1090 :
1091 : /* Release snapshot if we got one */
1092 101562 : if (snapshot_set)
1093 280 : PopActiveSnapshot();
1094 :
1095 : /*
1096 : * Normally, we create a dedicated memory context for the CachedPlan and
1097 : * its subsidiary data. Although it's usually not very large, the context
1098 : * is designed to allow growth if necessary.
1099 : *
1100 : * The PlannedStmts are stored in a separate child context (stmt_context)
1101 : * of the CachedPlan's memory context. This separation allows
1102 : * UpdateCachedPlan() to free and replace the PlannedStmts without
1103 : * affecting the CachedPlan structure or its stmt_list List.
1104 : *
1105 : * For one-shot plans, we instead use the caller's memory context, as the
1106 : * CachedPlan will not persist. stmt_context will be set to NULL in this
1107 : * case, because UpdateCachedPlan() should never get called on a one-shot
1108 : * plan.
1109 : */
1110 101562 : if (!plansource->is_oneshot)
1111 : {
1112 81884 : plan_context = AllocSetContextCreate(CurrentMemoryContext,
1113 : "CachedPlan",
1114 : ALLOCSET_START_SMALL_SIZES);
1115 81884 : MemoryContextCopyAndSetIdentifier(plan_context, plansource->query_string);
1116 :
1117 81884 : stmt_context = AllocSetContextCreate(CurrentMemoryContext,
1118 : "CachedPlan PlannedStmts",
1119 : ALLOCSET_START_SMALL_SIZES);
1120 81884 : MemoryContextCopyAndSetIdentifier(stmt_context, plansource->query_string);
1121 81884 : MemoryContextSetParent(stmt_context, plan_context);
1122 :
1123 81884 : MemoryContextSwitchTo(stmt_context);
1124 81884 : plist = copyObject(plist);
1125 :
1126 81884 : MemoryContextSwitchTo(plan_context);
1127 81884 : plist = list_copy(plist);
1128 : }
1129 : else
1130 19678 : plan_context = CurrentMemoryContext;
1131 :
1132 : /*
1133 : * Create and fill the CachedPlan struct within the new context.
1134 : */
1135 101562 : plan = (CachedPlan *) palloc(sizeof(CachedPlan));
1136 101562 : plan->magic = CACHEDPLAN_MAGIC;
1137 101562 : plan->stmt_list = plist;
1138 :
1139 : /*
1140 : * CachedPlan is dependent on role either if RLS affected the rewrite
1141 : * phase or if a role dependency was injected during planning. And it's
1142 : * transient if any plan is marked so.
1143 : */
1144 101562 : plan->planRoleId = GetUserId();
1145 101562 : plan->dependsOnRole = plansource->dependsOnRLS;
1146 101562 : is_transient = false;
1147 203130 : foreach(lc, plist)
1148 : {
1149 101568 : PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1150 :
1151 101568 : if (plannedstmt->commandType == CMD_UTILITY)
1152 20306 : continue; /* Ignore utility statements */
1153 :
1154 81262 : if (plannedstmt->transientPlan)
1155 132 : is_transient = true;
1156 81262 : if (plannedstmt->dependsOnRole)
1157 72 : plan->dependsOnRole = true;
1158 : }
1159 101562 : if (is_transient)
1160 : {
1161 : Assert(TransactionIdIsNormal(TransactionXmin));
1162 132 : plan->saved_xmin = TransactionXmin;
1163 : }
1164 : else
1165 101430 : plan->saved_xmin = InvalidTransactionId;
1166 101562 : plan->refcount = 0;
1167 101562 : plan->context = plan_context;
1168 101562 : plan->stmt_context = stmt_context;
1169 101562 : plan->is_oneshot = plansource->is_oneshot;
1170 101562 : plan->is_saved = false;
1171 101562 : plan->is_reused = false;
1172 101562 : plan->is_valid = true;
1173 :
1174 : /* assign generation number to new plan */
1175 101562 : plan->generation = ++(plansource->generation);
1176 :
1177 101562 : MemoryContextSwitchTo(oldcxt);
1178 :
1179 101562 : return plan;
1180 : }
1181 :
1182 : /*
1183 : * UpdateCachedPlan
1184 : * Create fresh plans for all queries in the CachedPlanSource, replacing
1185 : * those in the generic plan's stmt_list, and return the plan for the
1186 : * query_index'th query.
1187 : *
1188 : * This function is primarily used by ExecutorStartCachedPlan() to handle
1189 : * cases where the original generic CachedPlan becomes invalid. Such
1190 : * invalidation may occur when prunable relations in the old plan for the
1191 : * query_index'th query are locked in preparation for execution.
1192 : *
1193 : * Note that invalidations received during the execution of the query_index'th
1194 : * query can affect both the queries that have already finished execution
1195 : * (e.g., due to concurrent modifications on prunable relations that were not
1196 : * locked during their execution) and also the queries that have not yet been
1197 : * executed. As a result, this function updates all plans to ensure
1198 : * CachedPlan.is_valid is safely set to true.
1199 : *
1200 : * The old PlannedStmts in plansource->gplan->stmt_list are freed here, so
1201 : * the caller and any of its callers must not rely on them remaining accessible
1202 : * after this function is called.
1203 : */
1204 : PlannedStmt *
1205 0 : UpdateCachedPlan(CachedPlanSource *plansource, int query_index,
1206 : QueryEnvironment *queryEnv)
1207 : {
1208 0 : List *query_list = plansource->query_list,
1209 : *plan_list;
1210 : ListCell *l1,
1211 : *l2;
1212 0 : CachedPlan *plan = plansource->gplan;
1213 : MemoryContext oldcxt;
1214 :
1215 : Assert(ActiveSnapshotSet());
1216 :
1217 : /* Sanity checks (XXX can be Asserts?) */
1218 0 : if (plan == NULL)
1219 0 : elog(ERROR, "UpdateCachedPlan() called in the wrong context: plansource->gplan is NULL");
1220 0 : else if (plan->is_valid)
1221 0 : elog(ERROR, "UpdateCachedPlan() called in the wrong context: plansource->gplan->is_valid is true");
1222 0 : else if (plan->is_oneshot)
1223 0 : elog(ERROR, "UpdateCachedPlan() called in the wrong context: plansource->gplan->is_oneshot is true");
1224 :
1225 : /*
1226 : * The plansource might have become invalid since GetCachedPlan() returned
1227 : * the CachedPlan. See the comment in BuildCachedPlan() for details on why
1228 : * this might happen. Although invalidation is likely a false positive as
1229 : * stated there, we make the plan valid to ensure the query list used for
1230 : * planning is up to date.
1231 : *
1232 : * The risk of catching an invalidation is higher here than when
1233 : * BuildCachedPlan() is called from GetCachedPlan(), because this function
1234 : * is normally called long after GetCachedPlan() returns the CachedPlan,
1235 : * so much more processing could have occurred including things that mark
1236 : * the CachedPlanSource invalid.
1237 : *
1238 : * Note: Do not release plansource->gplan, because the upstream callers
1239 : * (such as the callers of ExecutorStartCachedPlan()) would still be
1240 : * referencing it.
1241 : */
1242 0 : if (!plansource->is_valid)
1243 0 : query_list = RevalidateCachedQuery(plansource, queryEnv, false);
1244 : Assert(query_list != NIL);
1245 :
1246 : /*
1247 : * Build a new generic plan for all the queries after making a copy to be
1248 : * scribbled on by the planner.
1249 : */
1250 0 : query_list = copyObject(query_list);
1251 :
1252 : /*
1253 : * Planning work is done in the caller's memory context. The resulting
1254 : * PlannedStmt is then copied into plan->stmt_context after throwing away
1255 : * the old ones.
1256 : */
1257 0 : plan_list = pg_plan_queries(query_list, plansource->query_string,
1258 : plansource->cursor_options, NULL);
1259 : Assert(list_length(plan_list) == list_length(plan->stmt_list));
1260 :
1261 0 : MemoryContextReset(plan->stmt_context);
1262 0 : oldcxt = MemoryContextSwitchTo(plan->stmt_context);
1263 0 : forboth(l1, plan_list, l2, plan->stmt_list)
1264 : {
1265 0 : PlannedStmt *plannedstmt = lfirst(l1);
1266 :
1267 0 : lfirst(l2) = copyObject(plannedstmt);
1268 : }
1269 0 : MemoryContextSwitchTo(oldcxt);
1270 :
1271 : /*
1272 : * XXX Should this also (re)set the properties of the CachedPlan that are
1273 : * set in BuildCachedPlan() after creating the fresh plans such as
1274 : * planRoleId, dependsOnRole, and saved_xmin?
1275 : */
1276 :
1277 : /*
1278 : * We've updated all the plans that might have been invalidated, so mark
1279 : * the CachedPlan as valid.
1280 : */
1281 0 : plan->is_valid = true;
1282 :
1283 : /* Also update generic_cost because we just created a new generic plan. */
1284 0 : plansource->generic_cost = cached_plan_cost(plan, false);
1285 :
1286 0 : return list_nth_node(PlannedStmt, plan->stmt_list, query_index);
1287 : }
1288 :
1289 : /*
1290 : * choose_custom_plan: choose whether to use custom or generic plan
1291 : *
1292 : * This defines the policy followed by GetCachedPlan.
1293 : */
1294 : static bool
1295 342872 : choose_custom_plan(CachedPlanSource *plansource, ParamListInfo boundParams)
1296 : {
1297 : double avg_custom_cost;
1298 :
1299 : /* One-shot plans will always be considered custom */
1300 342872 : if (plansource->is_oneshot)
1301 19754 : return true;
1302 :
1303 : /* Otherwise, never any point in a custom plan if there's no parameters */
1304 323118 : if (boundParams == NULL)
1305 149556 : return false;
1306 : /* ... nor when planning would be a no-op */
1307 173562 : if (!StmtPlanRequiresRevalidation(plansource))
1308 0 : return false;
1309 :
1310 : /* Let settings force the decision */
1311 173562 : if (plan_cache_mode == PLAN_CACHE_MODE_FORCE_GENERIC_PLAN)
1312 2836 : return false;
1313 170726 : if (plan_cache_mode == PLAN_CACHE_MODE_FORCE_CUSTOM_PLAN)
1314 24 : return true;
1315 :
1316 : /* See if caller wants to force the decision */
1317 170702 : if (plansource->cursor_options & CURSOR_OPT_GENERIC_PLAN)
1318 0 : return false;
1319 170702 : if (plansource->cursor_options & CURSOR_OPT_CUSTOM_PLAN)
1320 0 : return true;
1321 :
1322 : /* Generate custom plans until we have done at least 5 (arbitrary) */
1323 170702 : if (plansource->num_custom_plans < 5)
1324 28858 : return true;
1325 :
1326 141844 : avg_custom_cost = plansource->total_custom_cost / plansource->num_custom_plans;
1327 :
1328 : /*
1329 : * Prefer generic plan if it's less expensive than the average custom
1330 : * plan. (Because we include a charge for cost of planning in the
1331 : * custom-plan costs, this means the generic plan only has to be less
1332 : * expensive than the execution cost plus replan cost of the custom
1333 : * plans.)
1334 : *
1335 : * Note that if generic_cost is -1 (indicating we've not yet determined
1336 : * the generic plan cost), we'll always prefer generic at this point.
1337 : */
1338 141844 : if (plansource->generic_cost < avg_custom_cost)
1339 137912 : return false;
1340 :
1341 3932 : return true;
1342 : }
1343 :
1344 : /*
1345 : * cached_plan_cost: calculate estimated cost of a plan
1346 : *
1347 : * If include_planner is true, also include the estimated cost of constructing
1348 : * the plan. (We must factor that into the cost of using a custom plan, but
1349 : * we don't count it for a generic plan.)
1350 : */
1351 : static double
1352 101562 : cached_plan_cost(CachedPlan *plan, bool include_planner)
1353 : {
1354 101562 : double result = 0;
1355 : ListCell *lc;
1356 :
1357 203130 : foreach(lc, plan->stmt_list)
1358 : {
1359 101568 : PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1360 :
1361 101568 : if (plannedstmt->commandType == CMD_UTILITY)
1362 20306 : continue; /* Ignore utility statements */
1363 :
1364 81262 : result += plannedstmt->planTree->total_cost;
1365 :
1366 81262 : if (include_planner)
1367 : {
1368 : /*
1369 : * Currently we use a very crude estimate of planning effort based
1370 : * on the number of relations in the finished plan's rangetable.
1371 : * Join planning effort actually scales much worse than linearly
1372 : * in the number of relations --- but only until the join collapse
1373 : * limits kick in. Also, while inheritance child relations surely
1374 : * add to planning effort, they don't make the join situation
1375 : * worse. So the actual shape of the planning cost curve versus
1376 : * number of relations isn't all that obvious. It will take
1377 : * considerable work to arrive at a less crude estimate, and for
1378 : * now it's not clear that's worth doing.
1379 : *
1380 : * The other big difficulty here is that we don't have any very
1381 : * good model of how planning cost compares to execution costs.
1382 : * The current multiplier of 1000 * cpu_operator_cost is probably
1383 : * on the low side, but we'll try this for awhile before making a
1384 : * more aggressive correction.
1385 : *
1386 : * If we ever do write a more complicated estimator, it should
1387 : * probably live in src/backend/optimizer/ not here.
1388 : */
1389 43270 : int nrelations = list_length(plannedstmt->rtable);
1390 :
1391 43270 : result += 1000.0 * cpu_operator_cost * (nrelations + 1);
1392 : }
1393 : }
1394 :
1395 101562 : return result;
1396 : }
1397 :
1398 : /*
1399 : * GetCachedPlan: get a cached plan from a CachedPlanSource.
1400 : *
1401 : * This function hides the logic that decides whether to use a generic
1402 : * plan or a custom plan for the given parameters: the caller does not know
1403 : * which it will get.
1404 : *
1405 : * On return, the plan is valid, but if it is a reused generic plan, not all
1406 : * locks are acquired. In such cases, CheckCachedPlan() does not take locks
1407 : * on relations subject to initial runtime pruning; instead, these locks are
1408 : * deferred until execution startup, when ExecDoInitialPruning() performs
1409 : * initial pruning. The plan's "is_reused" flag is set to indicate that
1410 : * CachedPlanRequiresLocking() should return true when called by
1411 : * ExecDoInitialPruning().
1412 : *
1413 : * On return, the refcount of the plan has been incremented; a later
1414 : * ReleaseCachedPlan() call is expected. If "owner" is not NULL then
1415 : * the refcount has been reported to that ResourceOwner (note that this
1416 : * is only supported for "saved" CachedPlanSources).
1417 : *
1418 : * Note: if any replanning activity is required, the caller's memory context
1419 : * is used for that work.
1420 : */
1421 : CachedPlan *
1422 293778 : GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams,
1423 : ResourceOwner owner, QueryEnvironment *queryEnv)
1424 : {
1425 293778 : CachedPlan *plan = NULL;
1426 : List *qlist;
1427 : bool customplan;
1428 :
1429 : /* Assert caller is doing things in a sane order */
1430 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1431 : Assert(plansource->is_complete);
1432 : /* This seems worth a real test, though */
1433 293778 : if (owner && !plansource->is_saved)
1434 0 : elog(ERROR, "cannot apply ResourceOwner to non-saved cached plan");
1435 :
1436 : /* Make sure the querytree list is valid and we have parse-time locks */
1437 293778 : qlist = RevalidateCachedQuery(plansource, queryEnv, true);
1438 :
1439 : /* Decide whether to use a custom plan */
1440 293726 : customplan = choose_custom_plan(plansource, boundParams);
1441 :
1442 293726 : if (!customplan)
1443 : {
1444 241228 : if (CheckCachedPlan(plansource))
1445 : {
1446 : /* We want a generic plan, and we already have a valid one */
1447 192024 : plan = plansource->gplan;
1448 : Assert(plan->magic == CACHEDPLAN_MAGIC);
1449 : /* Reusing the existing plan, so not all locks may be acquired. */
1450 192024 : plan->is_reused = true;
1451 : }
1452 : else
1453 : {
1454 : /* Build a new generic plan */
1455 49204 : plan = BuildCachedPlan(plansource, qlist, NULL, queryEnv);
1456 : /* Just make real sure plansource->gplan is clear */
1457 49146 : ReleaseGenericPlan(plansource);
1458 : /* Link the new generic plan into the plansource */
1459 49146 : plansource->gplan = plan;
1460 49146 : plan->refcount++;
1461 : /* Immediately reparent into appropriate context */
1462 49146 : if (plansource->is_saved)
1463 : {
1464 : /* saved plans all live under CacheMemoryContext */
1465 38216 : MemoryContextSetParent(plan->context, CacheMemoryContext);
1466 38216 : plan->is_saved = true;
1467 : }
1468 : else
1469 : {
1470 : /* otherwise, it should be a sibling of the plansource */
1471 10930 : MemoryContextSetParent(plan->context,
1472 : MemoryContextGetParent(plansource->context));
1473 : }
1474 : /* Update generic_cost whenever we make a new generic plan */
1475 49146 : plansource->generic_cost = cached_plan_cost(plan, false);
1476 :
1477 : /*
1478 : * If, based on the now-known value of generic_cost, we'd not have
1479 : * chosen to use a generic plan, then forget it and make a custom
1480 : * plan. This is a bit of a wart but is necessary to avoid a
1481 : * glitch in behavior when the custom plans are consistently big
1482 : * winners; at some point we'll experiment with a generic plan and
1483 : * find it's a loser, but we don't want to actually execute that
1484 : * plan.
1485 : */
1486 49146 : customplan = choose_custom_plan(plansource, boundParams);
1487 :
1488 : /*
1489 : * If we choose to plan again, we need to re-copy the query_list,
1490 : * since the planner probably scribbled on it. We can force
1491 : * BuildCachedPlan to do that by passing NIL.
1492 : */
1493 49146 : qlist = NIL;
1494 : }
1495 : }
1496 :
1497 293668 : if (customplan)
1498 : {
1499 : /* Build a custom plan */
1500 52568 : plan = BuildCachedPlan(plansource, qlist, boundParams, queryEnv);
1501 : /* Accumulate total costs of custom plans */
1502 52416 : plansource->total_custom_cost += cached_plan_cost(plan, true);
1503 :
1504 52416 : plansource->num_custom_plans++;
1505 : }
1506 : else
1507 : {
1508 241100 : plansource->num_generic_plans++;
1509 : }
1510 :
1511 : Assert(plan != NULL);
1512 :
1513 : /* Flag the plan as in use by caller */
1514 293516 : if (owner)
1515 218624 : ResourceOwnerEnlarge(owner);
1516 293516 : plan->refcount++;
1517 293516 : if (owner)
1518 218624 : ResourceOwnerRememberPlanCacheRef(owner, plan);
1519 :
1520 : /*
1521 : * Saved plans should be under CacheMemoryContext so they will not go away
1522 : * until their reference count goes to zero. In the generic-plan cases we
1523 : * already took care of that, but for a custom plan, do it as soon as we
1524 : * have created a reference-counted link.
1525 : */
1526 293516 : if (customplan && plansource->is_saved)
1527 : {
1528 32726 : MemoryContextSetParent(plan->context, CacheMemoryContext);
1529 32726 : plan->is_saved = true;
1530 : }
1531 :
1532 293516 : return plan;
1533 : }
1534 :
1535 : /*
1536 : * ReleaseCachedPlan: release active use of a cached plan.
1537 : *
1538 : * This decrements the reference count, and frees the plan if the count
1539 : * has thereby gone to zero. If "owner" is not NULL, it is assumed that
1540 : * the reference count is managed by that ResourceOwner.
1541 : *
1542 : * Note: owner == NULL is used for releasing references that are in
1543 : * persistent data structures, such as the parent CachedPlanSource or a
1544 : * Portal. Transient references should be protected by a resource owner.
1545 : */
1546 : void
1547 389238 : ReleaseCachedPlan(CachedPlan *plan, ResourceOwner owner)
1548 : {
1549 : Assert(plan->magic == CACHEDPLAN_MAGIC);
1550 389238 : if (owner)
1551 : {
1552 : Assert(plan->is_saved);
1553 208474 : ResourceOwnerForgetPlanCacheRef(owner, plan);
1554 : }
1555 : Assert(plan->refcount > 0);
1556 389238 : plan->refcount--;
1557 389238 : if (plan->refcount == 0)
1558 : {
1559 : /* Mark it no longer valid */
1560 68080 : plan->magic = 0;
1561 :
1562 : /* One-shot plans do not own their context, so we can't free them */
1563 68080 : if (!plan->is_oneshot)
1564 48574 : MemoryContextDelete(plan->context);
1565 : }
1566 389238 : }
1567 :
1568 : /*
1569 : * CachedPlanAllowsSimpleValidityCheck: can we use CachedPlanIsSimplyValid?
1570 : *
1571 : * This function, together with CachedPlanIsSimplyValid, provides a fast path
1572 : * for revalidating "simple" generic plans. The core requirement to be simple
1573 : * is that the plan must not require taking any locks, which translates to
1574 : * not touching any tables; this happens to match up well with an important
1575 : * use-case in PL/pgSQL. This function tests whether that's true, along
1576 : * with checking some other corner cases that we'd rather not bother with
1577 : * handling in the fast path. (Note that it's still possible for such a plan
1578 : * to be invalidated, for example due to a change in a function that was
1579 : * inlined into the plan.)
1580 : *
1581 : * If the plan is simply valid, and "owner" is not NULL, record a refcount on
1582 : * the plan in that resowner before returning. It is caller's responsibility
1583 : * to be sure that a refcount is held on any plan that's being actively used.
1584 : *
1585 : * This must only be called on known-valid generic plans (eg, ones just
1586 : * returned by GetCachedPlan). If it returns true, the caller may re-use
1587 : * the cached plan as long as CachedPlanIsSimplyValid returns true; that
1588 : * check is much cheaper than the full revalidation done by GetCachedPlan.
1589 : * Nonetheless, no required checks are omitted.
1590 : */
1591 : bool
1592 29552 : CachedPlanAllowsSimpleValidityCheck(CachedPlanSource *plansource,
1593 : CachedPlan *plan, ResourceOwner owner)
1594 : {
1595 : ListCell *lc;
1596 :
1597 : /*
1598 : * Sanity-check that the caller gave us a validated generic plan. Notice
1599 : * that we *don't* assert plansource->is_valid as you might expect; that's
1600 : * because it's possible that that's already false when GetCachedPlan
1601 : * returns, e.g. because ResetPlanCache happened partway through. We
1602 : * should accept the plan as long as plan->is_valid is true, and expect to
1603 : * replan after the next CachedPlanIsSimplyValid call.
1604 : */
1605 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1606 : Assert(plan->magic == CACHEDPLAN_MAGIC);
1607 : Assert(plan->is_valid);
1608 : Assert(plan == plansource->gplan);
1609 : Assert(plansource->search_path != NULL);
1610 : Assert(SearchPathMatchesCurrentEnvironment(plansource->search_path));
1611 :
1612 : /* We don't support oneshot plans here. */
1613 29552 : if (plansource->is_oneshot)
1614 0 : return false;
1615 : Assert(!plan->is_oneshot);
1616 :
1617 : /*
1618 : * If the plan is dependent on RLS considerations, or it's transient,
1619 : * reject. These things probably can't ever happen for table-free
1620 : * queries, but for safety's sake let's check.
1621 : */
1622 29552 : if (plansource->dependsOnRLS)
1623 0 : return false;
1624 29552 : if (plan->dependsOnRole)
1625 0 : return false;
1626 29552 : if (TransactionIdIsValid(plan->saved_xmin))
1627 0 : return false;
1628 :
1629 : /*
1630 : * Reject if AcquirePlannerLocks would have anything to do. This is
1631 : * simplistic, but there's no need to inquire any more carefully; indeed,
1632 : * for current callers it shouldn't even be possible to hit any of these
1633 : * checks.
1634 : */
1635 59104 : foreach(lc, plansource->query_list)
1636 : {
1637 29552 : Query *query = lfirst_node(Query, lc);
1638 :
1639 29552 : if (query->commandType == CMD_UTILITY)
1640 0 : return false;
1641 29552 : if (query->rtable || query->cteList || query->hasSubLinks)
1642 0 : return false;
1643 : }
1644 :
1645 : /*
1646 : * Reject if AcquireExecutorLocks would have anything to do. This is
1647 : * probably unnecessary given the previous check, but let's be safe.
1648 : */
1649 59104 : foreach(lc, plan->stmt_list)
1650 : {
1651 29552 : PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1652 : ListCell *lc2;
1653 :
1654 29552 : if (plannedstmt->commandType == CMD_UTILITY)
1655 0 : return false;
1656 :
1657 : /*
1658 : * We have to grovel through the rtable because it's likely to contain
1659 : * an RTE_RESULT relation, rather than being totally empty.
1660 : */
1661 59104 : foreach(lc2, plannedstmt->rtable)
1662 : {
1663 29552 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
1664 :
1665 29552 : if (rte->rtekind == RTE_RELATION)
1666 0 : return false;
1667 : }
1668 : }
1669 :
1670 : /*
1671 : * Okay, it's simple. Note that what we've primarily established here is
1672 : * that no locks need be taken before checking the plan's is_valid flag.
1673 : */
1674 :
1675 : /* Bump refcount if requested. */
1676 29552 : if (owner)
1677 : {
1678 29552 : ResourceOwnerEnlarge(owner);
1679 29552 : plan->refcount++;
1680 29552 : ResourceOwnerRememberPlanCacheRef(owner, plan);
1681 : }
1682 :
1683 29552 : return true;
1684 : }
1685 :
1686 : /*
1687 : * CachedPlanIsSimplyValid: quick check for plan still being valid
1688 : *
1689 : * This function must not be used unless CachedPlanAllowsSimpleValidityCheck
1690 : * previously said it was OK.
1691 : *
1692 : * If the plan is valid, and "owner" is not NULL, record a refcount on
1693 : * the plan in that resowner before returning. It is caller's responsibility
1694 : * to be sure that a refcount is held on any plan that's being actively used.
1695 : *
1696 : * The code here is unconditionally safe as long as the only use of this
1697 : * CachedPlanSource is in connection with the particular CachedPlan pointer
1698 : * that's passed in. If the plansource were being used for other purposes,
1699 : * it's possible that its generic plan could be invalidated and regenerated
1700 : * while the current caller wasn't looking, and then there could be a chance
1701 : * collision of address between this caller's now-stale plan pointer and the
1702 : * actual address of the new generic plan. For current uses, that scenario
1703 : * can't happen; but with a plansource shared across multiple uses, it'd be
1704 : * advisable to also save plan->generation and verify that that still matches.
1705 : */
1706 : bool
1707 317726 : CachedPlanIsSimplyValid(CachedPlanSource *plansource, CachedPlan *plan,
1708 : ResourceOwner owner)
1709 : {
1710 : /*
1711 : * Careful here: since the caller doesn't necessarily hold a refcount on
1712 : * the plan to start with, it's possible that "plan" is a dangling
1713 : * pointer. Don't dereference it until we've verified that it still
1714 : * matches the plansource's gplan (which is either valid or NULL).
1715 : */
1716 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1717 :
1718 : /*
1719 : * Has cache invalidation fired on this plan? We can check this right
1720 : * away since there are no locks that we'd need to acquire first. Note
1721 : * that here we *do* check plansource->is_valid, so as to force plan
1722 : * rebuild if that's become false.
1723 : */
1724 317726 : if (!plansource->is_valid ||
1725 312214 : plan == NULL || plan != plansource->gplan ||
1726 312214 : !plan->is_valid)
1727 5524 : return false;
1728 :
1729 : Assert(plan->magic == CACHEDPLAN_MAGIC);
1730 :
1731 : /* Is the search_path still the same as when we made it? */
1732 : Assert(plansource->search_path != NULL);
1733 312202 : if (!SearchPathMatchesCurrentEnvironment(plansource->search_path))
1734 32 : return false;
1735 :
1736 : /* It's still good. Bump refcount if requested. */
1737 312170 : if (owner)
1738 : {
1739 50654 : ResourceOwnerEnlarge(owner);
1740 50654 : plan->refcount++;
1741 50654 : ResourceOwnerRememberPlanCacheRef(owner, plan);
1742 : }
1743 :
1744 312170 : return true;
1745 : }
1746 :
1747 : /*
1748 : * CachedPlanSetParentContext: move a CachedPlanSource to a new memory context
1749 : *
1750 : * This can only be applied to unsaved plans; once saved, a plan always
1751 : * lives underneath CacheMemoryContext.
1752 : */
1753 : void
1754 33252 : CachedPlanSetParentContext(CachedPlanSource *plansource,
1755 : MemoryContext newcontext)
1756 : {
1757 : /* Assert caller is doing things in a sane order */
1758 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1759 : Assert(plansource->is_complete);
1760 :
1761 : /* These seem worth real tests, though */
1762 33252 : if (plansource->is_saved)
1763 0 : elog(ERROR, "cannot move a saved cached plan to another context");
1764 33252 : if (plansource->is_oneshot)
1765 0 : elog(ERROR, "cannot move a one-shot cached plan to another context");
1766 :
1767 : /* OK, let the caller keep the plan where he wishes */
1768 33252 : MemoryContextSetParent(plansource->context, newcontext);
1769 :
1770 : /*
1771 : * The query_context needs no special handling, since it's a child of
1772 : * plansource->context. But if there's a generic plan, it should be
1773 : * maintained as a sibling of plansource->context.
1774 : */
1775 33252 : if (plansource->gplan)
1776 : {
1777 : Assert(plansource->gplan->magic == CACHEDPLAN_MAGIC);
1778 0 : MemoryContextSetParent(plansource->gplan->context, newcontext);
1779 : }
1780 33252 : }
1781 :
1782 : /*
1783 : * CopyCachedPlan: make a copy of a CachedPlanSource
1784 : *
1785 : * This is a convenience routine that does the equivalent of
1786 : * CreateCachedPlan + CompleteCachedPlan, using the data stored in the
1787 : * input CachedPlanSource. The result is therefore "unsaved" (regardless
1788 : * of the state of the source), and we don't copy any generic plan either.
1789 : * The result will be currently valid, or not, the same as the source.
1790 : */
1791 : CachedPlanSource *
1792 0 : CopyCachedPlan(CachedPlanSource *plansource)
1793 : {
1794 : CachedPlanSource *newsource;
1795 : MemoryContext source_context;
1796 : MemoryContext querytree_context;
1797 : MemoryContext oldcxt;
1798 :
1799 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1800 : Assert(plansource->is_complete);
1801 :
1802 : /*
1803 : * One-shot plans can't be copied, because we haven't taken care that
1804 : * parsing/planning didn't scribble on the raw parse tree or querytrees.
1805 : */
1806 0 : if (plansource->is_oneshot)
1807 0 : elog(ERROR, "cannot copy a one-shot cached plan");
1808 :
1809 0 : source_context = AllocSetContextCreate(CurrentMemoryContext,
1810 : "CachedPlanSource",
1811 : ALLOCSET_START_SMALL_SIZES);
1812 :
1813 0 : oldcxt = MemoryContextSwitchTo(source_context);
1814 :
1815 0 : newsource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
1816 0 : newsource->magic = CACHEDPLANSOURCE_MAGIC;
1817 0 : newsource->raw_parse_tree = copyObject(plansource->raw_parse_tree);
1818 0 : newsource->analyzed_parse_tree = copyObject(plansource->analyzed_parse_tree);
1819 0 : newsource->query_string = pstrdup(plansource->query_string);
1820 0 : MemoryContextSetIdentifier(source_context, newsource->query_string);
1821 0 : newsource->commandTag = plansource->commandTag;
1822 0 : if (plansource->num_params > 0)
1823 : {
1824 0 : newsource->param_types = (Oid *)
1825 0 : palloc(plansource->num_params * sizeof(Oid));
1826 0 : memcpy(newsource->param_types, plansource->param_types,
1827 0 : plansource->num_params * sizeof(Oid));
1828 : }
1829 : else
1830 0 : newsource->param_types = NULL;
1831 0 : newsource->num_params = plansource->num_params;
1832 0 : newsource->parserSetup = plansource->parserSetup;
1833 0 : newsource->parserSetupArg = plansource->parserSetupArg;
1834 0 : newsource->postRewrite = plansource->postRewrite;
1835 0 : newsource->postRewriteArg = plansource->postRewriteArg;
1836 0 : newsource->cursor_options = plansource->cursor_options;
1837 0 : newsource->fixed_result = plansource->fixed_result;
1838 0 : if (plansource->resultDesc)
1839 0 : newsource->resultDesc = CreateTupleDescCopy(plansource->resultDesc);
1840 : else
1841 0 : newsource->resultDesc = NULL;
1842 0 : newsource->context = source_context;
1843 :
1844 0 : querytree_context = AllocSetContextCreate(source_context,
1845 : "CachedPlanQuery",
1846 : ALLOCSET_START_SMALL_SIZES);
1847 0 : MemoryContextSwitchTo(querytree_context);
1848 0 : newsource->query_list = copyObject(plansource->query_list);
1849 0 : newsource->relationOids = copyObject(plansource->relationOids);
1850 0 : newsource->invalItems = copyObject(plansource->invalItems);
1851 0 : if (plansource->search_path)
1852 0 : newsource->search_path = CopySearchPathMatcher(plansource->search_path);
1853 0 : newsource->query_context = querytree_context;
1854 0 : newsource->rewriteRoleId = plansource->rewriteRoleId;
1855 0 : newsource->rewriteRowSecurity = plansource->rewriteRowSecurity;
1856 0 : newsource->dependsOnRLS = plansource->dependsOnRLS;
1857 :
1858 0 : newsource->gplan = NULL;
1859 :
1860 0 : newsource->is_oneshot = false;
1861 0 : newsource->is_complete = true;
1862 0 : newsource->is_saved = false;
1863 0 : newsource->is_valid = plansource->is_valid;
1864 0 : newsource->generation = plansource->generation;
1865 :
1866 : /* We may as well copy any acquired cost knowledge */
1867 0 : newsource->generic_cost = plansource->generic_cost;
1868 0 : newsource->total_custom_cost = plansource->total_custom_cost;
1869 0 : newsource->num_generic_plans = plansource->num_generic_plans;
1870 0 : newsource->num_custom_plans = plansource->num_custom_plans;
1871 :
1872 0 : MemoryContextSwitchTo(oldcxt);
1873 :
1874 0 : return newsource;
1875 : }
1876 :
1877 : /*
1878 : * CachedPlanIsValid: test whether the rewritten querytree within a
1879 : * CachedPlanSource is currently valid (that is, not marked as being in need
1880 : * of revalidation).
1881 : *
1882 : * This result is only trustworthy (ie, free from race conditions) if
1883 : * the caller has acquired locks on all the relations used in the plan.
1884 : */
1885 : bool
1886 3580 : CachedPlanIsValid(CachedPlanSource *plansource)
1887 : {
1888 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1889 3580 : return plansource->is_valid;
1890 : }
1891 :
1892 : /*
1893 : * CachedPlanGetTargetList: return tlist, if any, describing plan's output
1894 : *
1895 : * The result is guaranteed up-to-date. However, it is local storage
1896 : * within the cached plan, and may disappear next time the plan is updated.
1897 : */
1898 : List *
1899 19834 : CachedPlanGetTargetList(CachedPlanSource *plansource,
1900 : QueryEnvironment *queryEnv)
1901 : {
1902 : Query *pstmt;
1903 :
1904 : /* Assert caller is doing things in a sane order */
1905 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1906 : Assert(plansource->is_complete);
1907 :
1908 : /*
1909 : * No work needed if statement doesn't return tuples (we assume this
1910 : * feature cannot be changed by an invalidation)
1911 : */
1912 19834 : if (plansource->resultDesc == NULL)
1913 0 : return NIL;
1914 :
1915 : /* Make sure the querytree list is valid and we have parse-time locks */
1916 19834 : RevalidateCachedQuery(plansource, queryEnv, true);
1917 :
1918 : /* Get the primary statement and find out what it returns */
1919 19834 : pstmt = QueryListGetPrimaryStmt(plansource->query_list);
1920 :
1921 19834 : return FetchStatementTargetList((Node *) pstmt);
1922 : }
1923 :
1924 : /*
1925 : * GetCachedExpression: construct a CachedExpression for an expression.
1926 : *
1927 : * This performs the same transformations on the expression as
1928 : * expression_planner(), ie, convert an expression as emitted by parse
1929 : * analysis to be ready to pass to the executor.
1930 : *
1931 : * The result is stashed in a private, long-lived memory context.
1932 : * (Note that this might leak a good deal of memory in the caller's
1933 : * context before that.) The passed-in expr tree is not modified.
1934 : */
1935 : CachedExpression *
1936 346 : GetCachedExpression(Node *expr)
1937 : {
1938 : CachedExpression *cexpr;
1939 : List *relationOids;
1940 : List *invalItems;
1941 : MemoryContext cexpr_context;
1942 : MemoryContext oldcxt;
1943 :
1944 : /*
1945 : * Pass the expression through the planner, and collect dependencies.
1946 : * Everything built here is leaked in the caller's context; that's
1947 : * intentional to minimize the size of the permanent data structure.
1948 : */
1949 346 : expr = (Node *) expression_planner_with_deps((Expr *) expr,
1950 : &relationOids,
1951 : &invalItems);
1952 :
1953 : /*
1954 : * Make a private memory context, and copy what we need into that. To
1955 : * avoid leaking a long-lived context if we fail while copying data, we
1956 : * initially make the context under the caller's context.
1957 : */
1958 346 : cexpr_context = AllocSetContextCreate(CurrentMemoryContext,
1959 : "CachedExpression",
1960 : ALLOCSET_SMALL_SIZES);
1961 :
1962 346 : oldcxt = MemoryContextSwitchTo(cexpr_context);
1963 :
1964 346 : cexpr = (CachedExpression *) palloc(sizeof(CachedExpression));
1965 346 : cexpr->magic = CACHEDEXPR_MAGIC;
1966 346 : cexpr->expr = copyObject(expr);
1967 346 : cexpr->is_valid = true;
1968 346 : cexpr->relationOids = copyObject(relationOids);
1969 346 : cexpr->invalItems = copyObject(invalItems);
1970 346 : cexpr->context = cexpr_context;
1971 :
1972 346 : MemoryContextSwitchTo(oldcxt);
1973 :
1974 : /*
1975 : * Reparent the expr's memory context under CacheMemoryContext so that it
1976 : * will live indefinitely.
1977 : */
1978 346 : MemoryContextSetParent(cexpr_context, CacheMemoryContext);
1979 :
1980 : /*
1981 : * Add the entry to the global list of cached expressions.
1982 : */
1983 346 : dlist_push_tail(&cached_expression_list, &cexpr->node);
1984 :
1985 346 : return cexpr;
1986 : }
1987 :
1988 : /*
1989 : * FreeCachedExpression
1990 : * Delete a CachedExpression.
1991 : */
1992 : void
1993 36 : FreeCachedExpression(CachedExpression *cexpr)
1994 : {
1995 : /* Sanity check */
1996 : Assert(cexpr->magic == CACHEDEXPR_MAGIC);
1997 : /* Unlink from global list */
1998 36 : dlist_delete(&cexpr->node);
1999 : /* Free all storage associated with CachedExpression */
2000 36 : MemoryContextDelete(cexpr->context);
2001 36 : }
2002 :
2003 : /*
2004 : * QueryListGetPrimaryStmt
2005 : * Get the "primary" stmt within a list, ie, the one marked canSetTag.
2006 : *
2007 : * Returns NULL if no such stmt. If multiple queries within the list are
2008 : * marked canSetTag, returns the first one. Neither of these cases should
2009 : * occur in present usages of this function.
2010 : */
2011 : static Query *
2012 20138 : QueryListGetPrimaryStmt(List *stmts)
2013 : {
2014 : ListCell *lc;
2015 :
2016 20138 : foreach(lc, stmts)
2017 : {
2018 20138 : Query *stmt = lfirst_node(Query, lc);
2019 :
2020 20138 : if (stmt->canSetTag)
2021 20138 : return stmt;
2022 : }
2023 0 : return NULL;
2024 : }
2025 :
2026 : /*
2027 : * AcquireExecutorLocks: acquire locks needed for execution of a cached plan;
2028 : * or release them if acquire is false.
2029 : */
2030 : static void
2031 192024 : AcquireExecutorLocks(List *stmt_list, bool acquire)
2032 : {
2033 : ListCell *lc1;
2034 :
2035 384048 : foreach(lc1, stmt_list)
2036 : {
2037 192024 : PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc1);
2038 : int rtindex;
2039 :
2040 192024 : if (plannedstmt->commandType == CMD_UTILITY)
2041 : {
2042 : /*
2043 : * Ignore utility statements, except those (such as EXPLAIN) that
2044 : * contain a parsed-but-not-planned query. Note: it's okay to use
2045 : * ScanQueryForLocks, even though the query hasn't been through
2046 : * rule rewriting, because rewriting doesn't change the query
2047 : * representation.
2048 : */
2049 20816 : Query *query = UtilityContainsQuery(plannedstmt->utilityStmt);
2050 :
2051 20816 : if (query)
2052 6 : ScanQueryForLocks(query, acquire);
2053 20816 : continue;
2054 : }
2055 :
2056 171208 : rtindex = -1;
2057 244334 : while ((rtindex = bms_next_member(plannedstmt->unprunableRelids,
2058 : rtindex)) >= 0)
2059 : {
2060 73126 : RangeTblEntry *rte = list_nth_node(RangeTblEntry,
2061 : plannedstmt->rtable,
2062 : rtindex - 1);
2063 :
2064 : Assert(rte->rtekind == RTE_RELATION ||
2065 : (rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid)));
2066 :
2067 : /*
2068 : * Acquire the appropriate type of lock on each relation OID. Note
2069 : * that we don't actually try to open the rel, and hence will not
2070 : * fail if it's been dropped entirely --- we'll just transiently
2071 : * acquire a non-conflicting lock.
2072 : */
2073 73126 : if (acquire)
2074 73126 : LockRelationOid(rte->relid, rte->rellockmode);
2075 : else
2076 0 : UnlockRelationOid(rte->relid, rte->rellockmode);
2077 : }
2078 : }
2079 192024 : }
2080 :
2081 : /*
2082 : * AcquirePlannerLocks: acquire locks needed for planning of a querytree list;
2083 : * or release them if acquire is false.
2084 : *
2085 : * Note that we don't actually try to open the relations, and hence will not
2086 : * fail if one has been dropped entirely --- we'll just transiently acquire
2087 : * a non-conflicting lock.
2088 : */
2089 : static void
2090 264148 : AcquirePlannerLocks(List *stmt_list, bool acquire)
2091 : {
2092 : ListCell *lc;
2093 :
2094 528296 : foreach(lc, stmt_list)
2095 : {
2096 264148 : Query *query = lfirst_node(Query, lc);
2097 :
2098 264148 : if (query->commandType == CMD_UTILITY)
2099 : {
2100 : /* Ignore utility statements, unless they contain a Query */
2101 10036 : query = UtilityContainsQuery(query->utilityStmt);
2102 10036 : if (query)
2103 9776 : ScanQueryForLocks(query, acquire);
2104 10036 : continue;
2105 : }
2106 :
2107 254112 : ScanQueryForLocks(query, acquire);
2108 : }
2109 264148 : }
2110 :
2111 : /*
2112 : * ScanQueryForLocks: recursively scan one Query for AcquirePlannerLocks.
2113 : */
2114 : static void
2115 286820 : ScanQueryForLocks(Query *parsetree, bool acquire)
2116 : {
2117 : ListCell *lc;
2118 :
2119 : /* Shouldn't get called on utility commands */
2120 : Assert(parsetree->commandType != CMD_UTILITY);
2121 :
2122 : /*
2123 : * First, process RTEs of the current query level.
2124 : */
2125 489172 : foreach(lc, parsetree->rtable)
2126 : {
2127 202352 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
2128 :
2129 202352 : switch (rte->rtekind)
2130 : {
2131 146622 : case RTE_RELATION:
2132 : /* Acquire or release the appropriate type of lock */
2133 146622 : if (acquire)
2134 146590 : LockRelationOid(rte->relid, rte->rellockmode);
2135 : else
2136 32 : UnlockRelationOid(rte->relid, rte->rellockmode);
2137 146622 : break;
2138 :
2139 17502 : case RTE_SUBQUERY:
2140 : /* If this was a view, must lock/unlock the view */
2141 17502 : if (OidIsValid(rte->relid))
2142 : {
2143 4496 : if (acquire)
2144 4496 : LockRelationOid(rte->relid, rte->rellockmode);
2145 : else
2146 0 : UnlockRelationOid(rte->relid, rte->rellockmode);
2147 : }
2148 : /* Recurse into subquery-in-FROM */
2149 17502 : ScanQueryForLocks(rte->subquery, acquire);
2150 17502 : break;
2151 :
2152 38228 : default:
2153 : /* ignore other types of RTEs */
2154 38228 : break;
2155 : }
2156 : }
2157 :
2158 : /* Recurse into subquery-in-WITH */
2159 286916 : foreach(lc, parsetree->cteList)
2160 : {
2161 96 : CommonTableExpr *cte = lfirst_node(CommonTableExpr, lc);
2162 :
2163 96 : ScanQueryForLocks(castNode(Query, cte->ctequery), acquire);
2164 : }
2165 :
2166 : /*
2167 : * Recurse into sublink subqueries, too. But we already did the ones in
2168 : * the rtable and cteList.
2169 : */
2170 286820 : if (parsetree->hasSubLinks)
2171 : {
2172 5162 : query_tree_walker(parsetree, ScanQueryWalker, &acquire,
2173 : QTW_IGNORE_RC_SUBQUERIES);
2174 : }
2175 286820 : }
2176 :
2177 : /*
2178 : * Walker to find sublink subqueries for ScanQueryForLocks
2179 : */
2180 : static bool
2181 141438 : ScanQueryWalker(Node *node, bool *acquire)
2182 : {
2183 141438 : if (node == NULL)
2184 63488 : return false;
2185 77950 : if (IsA(node, SubLink))
2186 : {
2187 5328 : SubLink *sub = (SubLink *) node;
2188 :
2189 : /* Do what we came for */
2190 5328 : ScanQueryForLocks(castNode(Query, sub->subselect), *acquire);
2191 : /* Fall through to process lefthand args of SubLink */
2192 : }
2193 :
2194 : /*
2195 : * Do NOT recurse into Query nodes, because ScanQueryForLocks already
2196 : * processed subselects of subselects for us.
2197 : */
2198 77950 : return expression_tree_walker(node, ScanQueryWalker, acquire);
2199 : }
2200 :
2201 : /*
2202 : * PlanCacheComputeResultDesc: given a list of analyzed-and-rewritten Queries,
2203 : * determine the result tupledesc it will produce. Returns NULL if the
2204 : * execution will not return tuples.
2205 : *
2206 : * Note: the result is created or copied into current memory context.
2207 : */
2208 : static TupleDesc
2209 84954 : PlanCacheComputeResultDesc(List *stmt_list)
2210 : {
2211 : Query *query;
2212 :
2213 84954 : switch (ChoosePortalStrategy(stmt_list))
2214 : {
2215 56538 : case PORTAL_ONE_SELECT:
2216 : case PORTAL_ONE_MOD_WITH:
2217 56538 : query = linitial_node(Query, stmt_list);
2218 56538 : return ExecCleanTypeFromTL(query->targetList);
2219 :
2220 304 : case PORTAL_ONE_RETURNING:
2221 304 : query = QueryListGetPrimaryStmt(stmt_list);
2222 : Assert(query->returningList);
2223 304 : return ExecCleanTypeFromTL(query->returningList);
2224 :
2225 10050 : case PORTAL_UTIL_SELECT:
2226 10050 : query = linitial_node(Query, stmt_list);
2227 : Assert(query->utilityStmt);
2228 10050 : return UtilityTupleDescriptor(query->utilityStmt);
2229 :
2230 18062 : case PORTAL_MULTI_QUERY:
2231 : /* will not return tuples */
2232 18062 : break;
2233 : }
2234 18062 : return NULL;
2235 : }
2236 :
2237 : /*
2238 : * PlanCacheRelCallback
2239 : * Relcache inval callback function
2240 : *
2241 : * Invalidate all plans mentioning the given rel, or all plans mentioning
2242 : * any rel at all if relid == InvalidOid.
2243 : */
2244 : static void
2245 2800680 : PlanCacheRelCallback(Datum arg, Oid relid)
2246 : {
2247 : dlist_iter iter;
2248 :
2249 58188434 : dlist_foreach(iter, &saved_plan_list)
2250 : {
2251 55387754 : CachedPlanSource *plansource = dlist_container(CachedPlanSource,
2252 : node, iter.cur);
2253 :
2254 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
2255 :
2256 : /* No work if it's already invalidated */
2257 55387754 : if (!plansource->is_valid)
2258 31608902 : continue;
2259 :
2260 : /* Never invalidate if parse/plan would be a no-op anyway */
2261 23778852 : if (!StmtPlanRequiresRevalidation(plansource))
2262 328326 : continue;
2263 :
2264 : /*
2265 : * Check the dependency list for the rewritten querytree.
2266 : */
2267 46901038 : if ((relid == InvalidOid) ? plansource->relationOids != NIL :
2268 23450512 : list_member_oid(plansource->relationOids, relid))
2269 : {
2270 : /* Invalidate the querytree and generic plan */
2271 3610 : plansource->is_valid = false;
2272 3610 : if (plansource->gplan)
2273 1152 : plansource->gplan->is_valid = false;
2274 : }
2275 :
2276 : /*
2277 : * The generic plan, if any, could have more dependencies than the
2278 : * querytree does, so we have to check it too.
2279 : */
2280 23450526 : if (plansource->gplan && plansource->gplan->is_valid)
2281 : {
2282 : ListCell *lc;
2283 :
2284 44704498 : foreach(lc, plansource->gplan->stmt_list)
2285 : {
2286 22352288 : PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
2287 :
2288 22352288 : if (plannedstmt->commandType == CMD_UTILITY)
2289 3700 : continue; /* Ignore utility statements */
2290 44697176 : if ((relid == InvalidOid) ? plannedstmt->relationOids != NIL :
2291 22348588 : list_member_oid(plannedstmt->relationOids, relid))
2292 : {
2293 : /* Invalidate the generic plan only */
2294 78 : plansource->gplan->is_valid = false;
2295 78 : break; /* out of stmt_list scan */
2296 : }
2297 : }
2298 : }
2299 : }
2300 :
2301 : /* Likewise check cached expressions */
2302 3111052 : dlist_foreach(iter, &cached_expression_list)
2303 : {
2304 310372 : CachedExpression *cexpr = dlist_container(CachedExpression,
2305 : node, iter.cur);
2306 :
2307 : Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2308 :
2309 : /* No work if it's already invalidated */
2310 310372 : if (!cexpr->is_valid)
2311 110348 : continue;
2312 :
2313 400048 : if ((relid == InvalidOid) ? cexpr->relationOids != NIL :
2314 200024 : list_member_oid(cexpr->relationOids, relid))
2315 : {
2316 0 : cexpr->is_valid = false;
2317 : }
2318 : }
2319 2800680 : }
2320 :
2321 : /*
2322 : * PlanCacheObjectCallback
2323 : * Syscache inval callback function for PROCOID and TYPEOID caches
2324 : *
2325 : * Invalidate all plans mentioning the object with the specified hash value,
2326 : * or all plans mentioning any member of this cache if hashvalue == 0.
2327 : */
2328 : static void
2329 1030932 : PlanCacheObjectCallback(Datum arg, int cacheid, uint32 hashvalue)
2330 : {
2331 : dlist_iter iter;
2332 :
2333 22984174 : dlist_foreach(iter, &saved_plan_list)
2334 : {
2335 21953242 : CachedPlanSource *plansource = dlist_container(CachedPlanSource,
2336 : node, iter.cur);
2337 : ListCell *lc;
2338 :
2339 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
2340 :
2341 : /* No work if it's already invalidated */
2342 21953242 : if (!plansource->is_valid)
2343 12413300 : continue;
2344 :
2345 : /* Never invalidate if parse/plan would be a no-op anyway */
2346 9539942 : if (!StmtPlanRequiresRevalidation(plansource))
2347 82498 : continue;
2348 :
2349 : /*
2350 : * Check the dependency list for the rewritten querytree.
2351 : */
2352 9561604 : foreach(lc, plansource->invalItems)
2353 : {
2354 104310 : PlanInvalItem *item = (PlanInvalItem *) lfirst(lc);
2355 :
2356 104310 : if (item->cacheId != cacheid)
2357 69728 : continue;
2358 34582 : if (hashvalue == 0 ||
2359 34580 : item->hashValue == hashvalue)
2360 : {
2361 : /* Invalidate the querytree and generic plan */
2362 150 : plansource->is_valid = false;
2363 150 : if (plansource->gplan)
2364 144 : plansource->gplan->is_valid = false;
2365 150 : break;
2366 : }
2367 : }
2368 :
2369 : /*
2370 : * The generic plan, if any, could have more dependencies than the
2371 : * querytree does, so we have to check it too.
2372 : */
2373 9457444 : if (plansource->gplan && plansource->gplan->is_valid)
2374 : {
2375 17921852 : foreach(lc, plansource->gplan->stmt_list)
2376 : {
2377 8960938 : PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
2378 : ListCell *lc3;
2379 :
2380 8960938 : if (plannedstmt->commandType == CMD_UTILITY)
2381 2214 : continue; /* Ignore utility statements */
2382 9056126 : foreach(lc3, plannedstmt->invalItems)
2383 : {
2384 97426 : PlanInvalItem *item = (PlanInvalItem *) lfirst(lc3);
2385 :
2386 97426 : if (item->cacheId != cacheid)
2387 64960 : continue;
2388 32466 : if (hashvalue == 0 ||
2389 32466 : item->hashValue == hashvalue)
2390 : {
2391 : /* Invalidate the generic plan only */
2392 24 : plansource->gplan->is_valid = false;
2393 24 : break; /* out of invalItems scan */
2394 : }
2395 : }
2396 8958724 : if (!plansource->gplan->is_valid)
2397 24 : break; /* out of stmt_list scan */
2398 : }
2399 : }
2400 : }
2401 :
2402 : /* Likewise check cached expressions */
2403 1174236 : dlist_foreach(iter, &cached_expression_list)
2404 : {
2405 143304 : CachedExpression *cexpr = dlist_container(CachedExpression,
2406 : node, iter.cur);
2407 : ListCell *lc;
2408 :
2409 : Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2410 :
2411 : /* No work if it's already invalidated */
2412 143304 : if (!cexpr->is_valid)
2413 44408 : continue;
2414 :
2415 98936 : foreach(lc, cexpr->invalItems)
2416 : {
2417 46 : PlanInvalItem *item = (PlanInvalItem *) lfirst(lc);
2418 :
2419 46 : if (item->cacheId != cacheid)
2420 28 : continue;
2421 18 : if (hashvalue == 0 ||
2422 18 : item->hashValue == hashvalue)
2423 : {
2424 6 : cexpr->is_valid = false;
2425 6 : break;
2426 : }
2427 : }
2428 : }
2429 1030932 : }
2430 :
2431 : /*
2432 : * PlanCacheSysCallback
2433 : * Syscache inval callback function for other caches
2434 : *
2435 : * Just invalidate everything...
2436 : */
2437 : static void
2438 57554 : PlanCacheSysCallback(Datum arg, int cacheid, uint32 hashvalue)
2439 : {
2440 57554 : ResetPlanCache();
2441 57554 : }
2442 :
2443 : /*
2444 : * ResetPlanCache: invalidate all cached plans.
2445 : */
2446 : void
2447 58450 : ResetPlanCache(void)
2448 : {
2449 : dlist_iter iter;
2450 :
2451 293770 : dlist_foreach(iter, &saved_plan_list)
2452 : {
2453 235320 : CachedPlanSource *plansource = dlist_container(CachedPlanSource,
2454 : node, iter.cur);
2455 :
2456 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
2457 :
2458 : /* No work if it's already invalidated */
2459 235320 : if (!plansource->is_valid)
2460 213426 : continue;
2461 :
2462 : /*
2463 : * We *must not* mark transaction control statements as invalid,
2464 : * particularly not ROLLBACK, because they may need to be executed in
2465 : * aborted transactions when we can't revalidate them (cf bug #5269).
2466 : * In general there's no point in invalidating statements for which a
2467 : * new parse analysis/rewrite/plan cycle would certainly give the same
2468 : * results.
2469 : */
2470 21894 : if (!StmtPlanRequiresRevalidation(plansource))
2471 7258 : continue;
2472 :
2473 14636 : plansource->is_valid = false;
2474 14636 : if (plansource->gplan)
2475 13154 : plansource->gplan->is_valid = false;
2476 : }
2477 :
2478 : /* Likewise invalidate cached expressions */
2479 59420 : dlist_foreach(iter, &cached_expression_list)
2480 : {
2481 970 : CachedExpression *cexpr = dlist_container(CachedExpression,
2482 : node, iter.cur);
2483 :
2484 : Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2485 :
2486 970 : cexpr->is_valid = false;
2487 : }
2488 58450 : }
2489 :
2490 : /*
2491 : * Release all CachedPlans remembered by 'owner'
2492 : */
2493 : void
2494 16400 : ReleaseAllPlanCacheRefsInOwner(ResourceOwner owner)
2495 : {
2496 16400 : ResourceOwnerReleaseAllOfKind(owner, &planref_resowner_desc);
2497 16400 : }
2498 :
2499 : /* ResourceOwner callbacks */
2500 :
2501 : static void
2502 90356 : ResOwnerReleaseCachedPlan(Datum res)
2503 : {
2504 90356 : ReleaseCachedPlan((CachedPlan *) DatumGetPointer(res), NULL);
2505 90356 : }
|