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