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