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