Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * plancache.c
4 : * Plan cache management.
5 : *
6 : * The plan cache manager has two principal responsibilities: deciding when
7 : * to use a generic plan versus a custom (parameter-value-specific) plan,
8 : * and tracking whether cached plans need to be invalidated because of schema
9 : * changes in the objects they depend on.
10 : *
11 : * The logic for choosing generic or custom plans is in choose_custom_plan,
12 : * which see for comments.
13 : *
14 : * Cache invalidation is driven off sinval events. Any CachedPlanSource
15 : * that matches the event is marked invalid, as is its generic CachedPlan
16 : * if it has one. When (and if) the next demand for a cached plan occurs,
17 : * parse analysis and/or rewrite is repeated to build a new valid query tree,
18 : * and then planning is performed as normal. We also force re-analysis and
19 : * re-planning if the active search_path is different from the previous time
20 : * or, if RLS is involved, if the user changes or the RLS environment changes.
21 : *
22 : * Note that if the sinval was a result of user DDL actions, parse analysis
23 : * could throw an error, for example if a column referenced by the query is
24 : * no longer present. Another possibility is for the query's output tupdesc
25 : * to change (for instance "SELECT *" might expand differently than before).
26 : * The creator of a cached plan can specify whether it is allowable for the
27 : * query to change output tupdesc on replan --- if so, it's up to the
28 : * caller to notice changes and cope with them.
29 : *
30 : * Currently, we track exactly the dependencies of plans on relations,
31 : * user-defined functions, and domains. On relcache invalidation events or
32 : * pg_proc or pg_type syscache invalidation events, we invalidate just those
33 : * plans that depend on the particular object being modified. (Note: this
34 : * scheme assumes that any table modification that requires replanning will
35 : * generate a relcache inval event.) We also watch for inval events on
36 : * certain other system catalogs, such as pg_namespace; but for them, our
37 : * response is just to invalidate all plans. We expect updates on those
38 : * catalogs to be infrequent enough that more-detailed tracking is not worth
39 : * the effort.
40 : *
41 : * In addition to full-fledged query plans, we provide a facility for
42 : * detecting invalidations of simple scalar expressions. This is fairly
43 : * bare-bones; it's the caller's responsibility to build a new expression
44 : * if the old one gets invalidated.
45 : *
46 : *
47 : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
48 : * Portions Copyright (c) 1994, Regents of the University of California
49 : *
50 : * IDENTIFICATION
51 : * src/backend/utils/cache/plancache.c
52 : *
53 : *-------------------------------------------------------------------------
54 : */
55 : #include "postgres.h"
56 :
57 : #include <limits.h>
58 :
59 : #include "access/transam.h"
60 : #include "catalog/namespace.h"
61 : #include "executor/executor.h"
62 : #include "miscadmin.h"
63 : #include "nodes/nodeFuncs.h"
64 : #include "optimizer/optimizer.h"
65 : #include "parser/analyze.h"
66 : #include "rewrite/rewriteHandler.h"
67 : #include "storage/lmgr.h"
68 : #include "tcop/pquery.h"
69 : #include "tcop/utility.h"
70 : #include "utils/inval.h"
71 : #include "utils/memutils.h"
72 : #include "utils/resowner.h"
73 : #include "utils/rls.h"
74 : #include "utils/snapmgr.h"
75 : #include "utils/syscache.h"
76 :
77 :
78 : /*
79 : * This is the head of the backend's list of "saved" CachedPlanSources (i.e.,
80 : * those that are in long-lived storage and are examined for sinval events).
81 : * We use a dlist instead of separate List cells so that we can guarantee
82 : * to save a CachedPlanSource without error.
83 : */
84 : static dlist_head saved_plan_list = DLIST_STATIC_INIT(saved_plan_list);
85 :
86 : /*
87 : * This is the head of the backend's list of CachedExpressions.
88 : */
89 : static dlist_head cached_expression_list = DLIST_STATIC_INIT(cached_expression_list);
90 :
91 : static void ReleaseGenericPlan(CachedPlanSource *plansource);
92 : static bool StmtPlanRequiresRevalidation(CachedPlanSource *plansource);
93 : static bool BuildingPlanRequiresSnapshot(CachedPlanSource *plansource);
94 : static List *RevalidateCachedQuery(CachedPlanSource *plansource,
95 : QueryEnvironment *queryEnv);
96 : static bool CheckCachedPlan(CachedPlanSource *plansource);
97 : static CachedPlan *BuildCachedPlan(CachedPlanSource *plansource, List *qlist,
98 : ParamListInfo boundParams, QueryEnvironment *queryEnv);
99 : static bool choose_custom_plan(CachedPlanSource *plansource,
100 : ParamListInfo boundParams);
101 : static double cached_plan_cost(CachedPlan *plan, bool include_planner);
102 : static Query *QueryListGetPrimaryStmt(List *stmts);
103 : static void AcquireExecutorLocks(List *stmt_list, bool acquire);
104 : static void AcquirePlannerLocks(List *stmt_list, bool acquire);
105 : static void ScanQueryForLocks(Query *parsetree, bool acquire);
106 : static bool ScanQueryWalker(Node *node, bool *acquire);
107 : static TupleDesc PlanCacheComputeResultDesc(List *stmt_list);
108 : static void PlanCacheRelCallback(Datum arg, Oid relid);
109 : static void PlanCacheObjectCallback(Datum arg, 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 293920 : ResourceOwnerRememberPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
127 : {
128 293920 : ResourceOwnerRemember(owner, PointerGetDatum(plan), &planref_resowner_desc);
129 293920 : }
130 : static inline void
131 201428 : ResourceOwnerForgetPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
132 : {
133 201428 : ResourceOwnerForget(owner, PointerGetDatum(plan), &planref_resowner_desc);
134 201428 : }
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 36504 : InitPlanCache(void)
147 : {
148 36504 : CacheRegisterRelcacheCallback(PlanCacheRelCallback, (Datum) 0);
149 36504 : CacheRegisterSyscacheCallback(PROCOID, PlanCacheObjectCallback, (Datum) 0);
150 36504 : CacheRegisterSyscacheCallback(TYPEOID, PlanCacheObjectCallback, (Datum) 0);
151 36504 : CacheRegisterSyscacheCallback(NAMESPACEOID, PlanCacheSysCallback, (Datum) 0);
152 36504 : CacheRegisterSyscacheCallback(OPEROID, PlanCacheSysCallback, (Datum) 0);
153 36504 : CacheRegisterSyscacheCallback(AMOPOPID, PlanCacheSysCallback, (Datum) 0);
154 36504 : CacheRegisterSyscacheCallback(FOREIGNSERVEROID, PlanCacheSysCallback, (Datum) 0);
155 36504 : CacheRegisterSyscacheCallback(FOREIGNDATAWRAPPEROID, PlanCacheSysCallback, (Datum) 0);
156 36504 : }
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 58962 : 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 58962 : 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 58962 : oldcxt = MemoryContextSwitchTo(source_context);
209 :
210 58962 : plansource = palloc0_object(CachedPlanSource);
211 58962 : plansource->magic = CACHEDPLANSOURCE_MAGIC;
212 58962 : plansource->raw_parse_tree = copyObject(raw_parse_tree);
213 58962 : plansource->analyzed_parse_tree = NULL;
214 58962 : plansource->query_string = pstrdup(query_string);
215 58962 : MemoryContextSetIdentifier(source_context, plansource->query_string);
216 58962 : plansource->commandTag = commandTag;
217 58962 : plansource->param_types = NULL;
218 58962 : plansource->num_params = 0;
219 58962 : plansource->parserSetup = NULL;
220 58962 : plansource->parserSetupArg = NULL;
221 58962 : plansource->postRewrite = NULL;
222 58962 : plansource->postRewriteArg = NULL;
223 58962 : plansource->cursor_options = 0;
224 58962 : plansource->fixed_result = false;
225 58962 : plansource->resultDesc = NULL;
226 58962 : plansource->context = source_context;
227 58962 : plansource->query_list = NIL;
228 58962 : plansource->relationOids = NIL;
229 58962 : plansource->invalItems = NIL;
230 58962 : plansource->search_path = NULL;
231 58962 : plansource->query_context = NULL;
232 58962 : plansource->rewriteRoleId = InvalidOid;
233 58962 : plansource->rewriteRowSecurity = false;
234 58962 : plansource->dependsOnRLS = false;
235 58962 : plansource->gplan = NULL;
236 58962 : plansource->is_oneshot = false;
237 58962 : plansource->is_complete = false;
238 58962 : plansource->is_saved = false;
239 58962 : plansource->is_valid = false;
240 58962 : plansource->generation = 0;
241 58962 : plansource->generic_cost = -1;
242 58962 : plansource->total_custom_cost = 0;
243 58962 : plansource->num_generic_plans = 0;
244 58962 : plansource->num_custom_plans = 0;
245 :
246 58962 : MemoryContextSwitchTo(oldcxt);
247 :
248 58962 : 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 812 : 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 812 : plansource = CreateCachedPlan(NULL, query_string, commandTag);
272 812 : oldcxt = MemoryContextSwitchTo(plansource->context);
273 812 : plansource->analyzed_parse_tree = copyObject(analyzed_parse_tree);
274 812 : MemoryContextSwitchTo(oldcxt);
275 :
276 812 : 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 19844 : 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 19844 : plansource = palloc0_object(CachedPlanSource);
311 19844 : plansource->magic = CACHEDPLANSOURCE_MAGIC;
312 19844 : plansource->raw_parse_tree = raw_parse_tree;
313 19844 : plansource->analyzed_parse_tree = NULL;
314 19844 : plansource->query_string = query_string;
315 19844 : plansource->commandTag = commandTag;
316 19844 : plansource->param_types = NULL;
317 19844 : plansource->num_params = 0;
318 19844 : plansource->parserSetup = NULL;
319 19844 : plansource->parserSetupArg = NULL;
320 19844 : plansource->postRewrite = NULL;
321 19844 : plansource->postRewriteArg = NULL;
322 19844 : plansource->cursor_options = 0;
323 19844 : plansource->fixed_result = false;
324 19844 : plansource->resultDesc = NULL;
325 19844 : plansource->context = CurrentMemoryContext;
326 19844 : plansource->query_list = NIL;
327 19844 : plansource->relationOids = NIL;
328 19844 : plansource->invalItems = NIL;
329 19844 : plansource->search_path = NULL;
330 19844 : plansource->query_context = NULL;
331 19844 : plansource->rewriteRoleId = InvalidOid;
332 19844 : plansource->rewriteRowSecurity = false;
333 19844 : plansource->dependsOnRLS = false;
334 19844 : plansource->gplan = NULL;
335 19844 : plansource->is_oneshot = true;
336 19844 : plansource->is_complete = false;
337 19844 : plansource->is_saved = false;
338 19844 : plansource->is_valid = false;
339 19844 : plansource->generation = 0;
340 19844 : plansource->generic_cost = -1;
341 19844 : plansource->total_custom_cost = 0;
342 19844 : plansource->num_generic_plans = 0;
343 19844 : plansource->num_custom_plans = 0;
344 :
345 19844 : 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 78652 : 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 78652 : MemoryContext source_context = plansource->context;
402 78652 : 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 78652 : if (plansource->is_oneshot)
416 : {
417 19828 : querytree_context = CurrentMemoryContext;
418 : }
419 58824 : else if (querytree_context != NULL)
420 : {
421 6740 : MemoryContextSetParent(querytree_context, source_context);
422 6740 : MemoryContextSwitchTo(querytree_context);
423 : }
424 : else
425 : {
426 : /* Again, it's a good bet the querytree_context can be small */
427 52084 : querytree_context = AllocSetContextCreate(source_context,
428 : "CachedPlanQuery",
429 : ALLOCSET_START_SMALL_SIZES);
430 52084 : MemoryContextSwitchTo(querytree_context);
431 52084 : querytree_list = copyObject(querytree_list);
432 : }
433 :
434 78652 : plansource->query_context = querytree_context;
435 78652 : plansource->query_list = querytree_list;
436 :
437 78652 : 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 56858 : extract_query_dependencies((Node *) querytree_list,
446 : &plansource->relationOids,
447 : &plansource->invalItems,
448 : &plansource->dependsOnRLS);
449 :
450 : /* Update RLS info as well. */
451 56858 : plansource->rewriteRoleId = GetUserId();
452 56858 : 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 56858 : 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 78652 : MemoryContextSwitchTo(source_context);
469 :
470 78652 : if (num_params > 0)
471 : {
472 14314 : plansource->param_types = palloc_array(Oid, num_params);
473 14314 : memcpy(plansource->param_types, param_types, num_params * sizeof(Oid));
474 : }
475 : else
476 64338 : plansource->param_types = NULL;
477 78652 : plansource->num_params = num_params;
478 78652 : plansource->parserSetup = parserSetup;
479 78652 : plansource->parserSetupArg = parserSetupArg;
480 78652 : plansource->cursor_options = cursor_options;
481 78652 : 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 78652 : plansource->resultDesc = PlanCacheComputeResultDesc(querytree_list);
499 78652 : MemoryContextSwitchTo(oldcxt);
500 : #endif
501 :
502 78652 : plansource->is_complete = true;
503 78652 : plansource->is_valid = true;
504 78652 : }
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 2140 : SetPostRewriteHook(CachedPlanSource *plansource,
521 : PostRewriteHook postRewrite,
522 : void *postRewriteArg)
523 : {
524 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
525 2140 : plansource->postRewrite = postRewrite;
526 2140 : plansource->postRewriteArg = postRewriteArg;
527 2140 : }
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 47856 : 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 47856 : 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 47856 : 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 47856 : MemoryContextSetParent(plansource->context, CacheMemoryContext);
571 :
572 : /*
573 : * Add the entry to the global list of cached plans.
574 : */
575 47856 : dlist_push_tail(&saved_plan_list, &plansource->node);
576 :
577 47856 : plansource->is_saved = true;
578 47856 : }
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 18480 : DropCachedPlan(CachedPlanSource *plansource)
590 : {
591 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
592 :
593 : /* If it's been saved, remove it from the list */
594 18480 : if (plansource->is_saved)
595 : {
596 18290 : dlist_delete(&plansource->node);
597 18290 : plansource->is_saved = false;
598 : }
599 :
600 : /* Decrement generic CachedPlan's refcount and drop if no longer needed */
601 18480 : ReleaseGenericPlan(plansource);
602 :
603 : /* Mark it no longer valid */
604 18480 : 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 18480 : if (!plansource->is_oneshot)
611 18480 : MemoryContextDelete(plansource->context);
612 18480 : }
613 :
614 : /*
615 : * ReleaseGenericPlan: release a CachedPlanSource's generic plan, if any.
616 : */
617 : static void
618 122944 : ReleaseGenericPlan(CachedPlanSource *plansource)
619 : {
620 : /* Be paranoid about the possibility that ReleaseCachedPlan fails */
621 122944 : if (plansource->gplan)
622 : {
623 15800 : CachedPlan *plan = plansource->gplan;
624 :
625 : Assert(plan->magic == CACHEDPLAN_MAGIC);
626 15800 : plansource->gplan = NULL;
627 15800 : ReleaseCachedPlan(plan, NULL);
628 : }
629 122944 : }
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 27212666 : StmtPlanRequiresRevalidation(CachedPlanSource *plansource)
641 : {
642 27212666 : if (plansource->raw_parse_tree != NULL)
643 26648106 : return stmt_requires_parse_analysis(plansource->raw_parse_tree);
644 564560 : else if (plansource->analyzed_parse_tree != NULL)
645 564554 : 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 299934 : 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 299934 : if (plansource->is_oneshot || !StmtPlanRequiresRevalidation(plansource))
700 : {
701 : Assert(plansource->is_valid);
702 42758 : 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 257176 : if (plansource->is_valid)
714 : {
715 : Assert(plansource->search_path != NULL);
716 250484 : if (!SearchPathMatchesCurrentEnvironment(plansource->search_path))
717 : {
718 : /* Invalidate the querytree and generic plan */
719 72 : plansource->is_valid = false;
720 72 : if (plansource->gplan)
721 46 : 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 257474 : if (plansource->is_valid && plansource->dependsOnRLS &&
730 298 : (plansource->rewriteRoleId != GetUserId() ||
731 210 : plansource->rewriteRowSecurity != row_security))
732 112 : 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 257176 : if (plansource->is_valid)
740 : {
741 250300 : 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 250300 : if (plansource->is_valid)
748 : {
749 : /* Successfully revalidated and locked the query. */
750 250276 : return NIL;
751 : }
752 :
753 : /* Oops, the race case happened. Release useless locks. */
754 24 : 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 6900 : plansource->is_valid = false;
763 6900 : plansource->query_list = NIL;
764 6900 : plansource->relationOids = NIL;
765 6900 : plansource->invalItems = NIL;
766 6900 : 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 6900 : if (plansource->query_context)
775 : {
776 6870 : MemoryContext qcxt = plansource->query_context;
777 :
778 6870 : plansource->query_context = NULL;
779 6870 : MemoryContextDelete(qcxt);
780 : }
781 :
782 : /* Drop the generic plan reference if any */
783 6900 : 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 6900 : snapshot_set = false;
799 6900 : if (!ActiveSnapshotSet())
800 : {
801 20 : PushActiveSnapshot(GetTransactionSnapshot());
802 20 : snapshot_set = true;
803 : }
804 :
805 : /*
806 : * Run parse analysis (if needed) and rule rewriting.
807 : */
808 6900 : 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 6596 : rawtree = copyObject(plansource->raw_parse_tree);
818 6596 : if (plansource->parserSetup != NULL)
819 6108 : tlist = pg_analyze_and_rewrite_withcb(rawtree,
820 : plansource->query_string,
821 : plansource->parserSetup,
822 : plansource->parserSetupArg,
823 : queryEnv);
824 : else
825 488 : tlist = pg_analyze_and_rewrite_fixedparams(rawtree,
826 : plansource->query_string,
827 488 : plansource->param_types,
828 : plansource->num_params,
829 : queryEnv);
830 : }
831 304 : 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 304 : analyzed_tree = copyObject(plansource->analyzed_parse_tree);
838 : /* Acquire locks needed before rewriting ... */
839 304 : AcquireRewriteLocks(analyzed_tree, true, false);
840 : /* ... and do it */
841 304 : 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 6860 : if (plansource->postRewrite != NULL)
851 436 : plansource->postRewrite(tlist, plansource->postRewriteArg);
852 :
853 : /* Release snapshot if we got one */
854 6860 : if (snapshot_set)
855 20 : 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 6860 : resultDesc = PlanCacheComputeResultDesc(tlist);
864 6860 : if (resultDesc == NULL && plansource->resultDesc == NULL)
865 : {
866 : /* OK, doesn't return tuples */
867 : }
868 6688 : else if (resultDesc == NULL || plansource->resultDesc == NULL ||
869 6688 : !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 6848 : querytree_context = AllocSetContextCreate(CurrentMemoryContext,
890 : "CachedPlanQuery",
891 : ALLOCSET_START_SMALL_SIZES);
892 6848 : oldcxt = MemoryContextSwitchTo(querytree_context);
893 :
894 6848 : 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 6848 : extract_query_dependencies((Node *) qlist,
902 : &plansource->relationOids,
903 : &plansource->invalItems,
904 : &plansource->dependsOnRLS);
905 :
906 : /* Update RLS info as well. */
907 6848 : plansource->rewriteRoleId = GetUserId();
908 6848 : 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 6848 : plansource->search_path = GetSearchPathMatcher(querytree_context);
916 :
917 6848 : MemoryContextSwitchTo(oldcxt);
918 :
919 : /* Now reparent the finished query_context and save the links */
920 6848 : MemoryContextSetParent(querytree_context, plansource->context);
921 :
922 6848 : plansource->query_context = querytree_context;
923 6848 : 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 6848 : plansource->is_valid = true;
935 :
936 : /* Return transient copy of querytrees for possible use in planning */
937 6848 : 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 231816 : CheckCachedPlan(CachedPlanSource *plansource)
951 : {
952 231816 : 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 231816 : if (!plan)
959 49610 : 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 182246 : 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 182206 : 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 182128 : 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 182128 : if (plan->is_valid &&
991 182128 : 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 182128 : if (plan->is_valid)
1000 : {
1001 : /* Successfully revalidated and locked the query. */
1002 182128 : 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 102016 : 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 102016 : 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 102016 : 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 102016 : if (qlist == NIL)
1067 : {
1068 95170 : if (!plansource->is_oneshot)
1069 75348 : qlist = copyObject(plansource->query_list);
1070 : else
1071 19822 : 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 102016 : snapshot_set = false;
1079 103010 : 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 102016 : plist = pg_plan_queries(qlist, plansource->query_string,
1090 : plansource->cursor_options, boundParams);
1091 :
1092 : /* Release snapshot if we got one */
1093 101806 : 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 101806 : if (!plansource->is_oneshot)
1103 : {
1104 82060 : plan_context = AllocSetContextCreate(CurrentMemoryContext,
1105 : "CachedPlan",
1106 : ALLOCSET_START_SMALL_SIZES);
1107 82060 : MemoryContextCopyAndSetIdentifier(plan_context, plansource->query_string);
1108 :
1109 : /*
1110 : * Copy plan into the new context.
1111 : */
1112 82060 : MemoryContextSwitchTo(plan_context);
1113 :
1114 82060 : plist = copyObject(plist);
1115 : }
1116 : else
1117 19746 : plan_context = CurrentMemoryContext;
1118 :
1119 : /*
1120 : * Create and fill the CachedPlan struct within the new context.
1121 : */
1122 101806 : plan = palloc_object(CachedPlan);
1123 101806 : plan->magic = CACHEDPLAN_MAGIC;
1124 101806 : 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 101806 : plan->planRoleId = GetUserId();
1132 101806 : plan->dependsOnRole = plansource->dependsOnRLS;
1133 101806 : is_transient = false;
1134 203618 : foreach(lc, plist)
1135 : {
1136 101812 : PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1137 :
1138 101812 : if (plannedstmt->commandType == CMD_UTILITY)
1139 20340 : continue; /* Ignore utility statements */
1140 :
1141 81472 : if (plannedstmt->transientPlan)
1142 132 : is_transient = true;
1143 81472 : if (plannedstmt->dependsOnRole)
1144 72 : plan->dependsOnRole = true;
1145 : }
1146 101806 : if (is_transient)
1147 : {
1148 : Assert(TransactionIdIsNormal(TransactionXmin));
1149 132 : plan->saved_xmin = TransactionXmin;
1150 : }
1151 : else
1152 101674 : plan->saved_xmin = InvalidTransactionId;
1153 101806 : plan->refcount = 0;
1154 101806 : plan->context = plan_context;
1155 101806 : plan->is_oneshot = plansource->is_oneshot;
1156 101806 : plan->is_saved = false;
1157 101806 : plan->is_valid = true;
1158 :
1159 : /* assign generation number to new plan */
1160 101806 : plan->generation = ++(plansource->generation);
1161 :
1162 101806 : MemoryContextSwitchTo(oldcxt);
1163 :
1164 101806 : 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 333698 : choose_custom_plan(CachedPlanSource *plansource, ParamListInfo boundParams)
1174 : {
1175 : double avg_custom_cost;
1176 :
1177 : /* One-shot plans will always be considered custom */
1178 333698 : if (plansource->is_oneshot)
1179 19822 : return true;
1180 :
1181 : /* Otherwise, never any point in a custom plan if there's no parameters */
1182 313876 : if (boundParams == NULL)
1183 150878 : return false;
1184 : /* ... nor when planning would be a no-op */
1185 162998 : if (!StmtPlanRequiresRevalidation(plansource))
1186 0 : return false;
1187 :
1188 : /* Let settings force the decision */
1189 162998 : if (plan_cache_mode == PLAN_CACHE_MODE_FORCE_GENERIC_PLAN)
1190 2876 : return false;
1191 160122 : 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 160082 : if (plansource->cursor_options & CURSOR_OPT_GENERIC_PLAN)
1196 0 : return false;
1197 160082 : 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 160082 : if (plansource->num_custom_plans < 5)
1202 28580 : return true;
1203 :
1204 131502 : 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 131502 : if (plansource->generic_cost < avg_custom_cost)
1217 127616 : return false;
1218 :
1219 3886 : 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 101806 : cached_plan_cost(CachedPlan *plan, bool include_planner)
1231 : {
1232 101806 : double result = 0;
1233 : ListCell *lc;
1234 :
1235 203618 : foreach(lc, plan->stmt_list)
1236 : {
1237 101812 : PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1238 :
1239 101812 : if (plannedstmt->commandType == CMD_UTILITY)
1240 20340 : continue; /* Ignore utility statements */
1241 :
1242 81472 : result += plannedstmt->planTree->total_cost;
1243 :
1244 81472 : 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 42982 : int nrelations = list_length(plannedstmt->rtable);
1268 :
1269 42982 : result += 1000.0 * cpu_operator_cost * (nrelations + 1);
1270 : }
1271 : }
1272 :
1273 101806 : 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 284120 : GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams,
1296 : ResourceOwner owner, QueryEnvironment *queryEnv)
1297 : {
1298 284120 : 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 284120 : 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 284120 : qlist = RevalidateCachedQuery(plansource, queryEnv);
1312 :
1313 : /* Decide whether to use a custom plan */
1314 284068 : customplan = choose_custom_plan(plansource, boundParams);
1315 :
1316 284068 : if (!customplan)
1317 : {
1318 231816 : if (CheckCachedPlan(plansource))
1319 : {
1320 : /* We want a generic plan, and we already have a valid one */
1321 182128 : plan = plansource->gplan;
1322 : Assert(plan->magic == CACHEDPLAN_MAGIC);
1323 : }
1324 : else
1325 : {
1326 : /* Build a new generic plan */
1327 49688 : plan = BuildCachedPlan(plansource, qlist, NULL, queryEnv);
1328 : /* Just make real sure plansource->gplan is clear */
1329 49630 : ReleaseGenericPlan(plansource);
1330 : /* Link the new generic plan into the plansource */
1331 49630 : plansource->gplan = plan;
1332 49630 : plan->refcount++;
1333 : /* Immediately reparent into appropriate context */
1334 49630 : if (plansource->is_saved)
1335 : {
1336 : /* saved plans all live under CacheMemoryContext */
1337 38680 : MemoryContextSetParent(plan->context, CacheMemoryContext);
1338 38680 : plan->is_saved = true;
1339 : }
1340 : else
1341 : {
1342 : /* otherwise, it should be a sibling of the plansource */
1343 10950 : MemoryContextSetParent(plan->context,
1344 : MemoryContextGetParent(plansource->context));
1345 : }
1346 : /* Update generic_cost whenever we make a new generic plan */
1347 49630 : 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 49630 : 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 49630 : qlist = NIL;
1366 : }
1367 : }
1368 :
1369 284010 : if (customplan)
1370 : {
1371 : /* Build a custom plan */
1372 52328 : plan = BuildCachedPlan(plansource, qlist, boundParams, queryEnv);
1373 : /* Accumulate total costs of custom plans */
1374 52176 : plansource->total_custom_cost += cached_plan_cost(plan, true);
1375 :
1376 52176 : plansource->num_custom_plans++;
1377 : }
1378 : else
1379 : {
1380 231682 : plansource->num_generic_plans++;
1381 : }
1382 :
1383 : Assert(plan != NULL);
1384 :
1385 : /* Flag the plan as in use by caller */
1386 283858 : if (owner)
1387 212144 : ResourceOwnerEnlarge(owner);
1388 283858 : plan->refcount++;
1389 283858 : if (owner)
1390 212144 : 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 283858 : if (customplan && plansource->is_saved)
1399 : {
1400 32418 : MemoryContextSetParent(plan->context, CacheMemoryContext);
1401 32418 : plan->is_saved = true;
1402 : }
1403 :
1404 567722 : foreach(lc, plan->stmt_list)
1405 : {
1406 283864 : PlannedStmt *pstmt = (PlannedStmt *) lfirst(lc);
1407 :
1408 283864 : pstmt->planOrigin = customplan ? PLAN_STMT_CACHE_CUSTOM : PLAN_STMT_CACHE_GENERIC;
1409 : }
1410 :
1411 283858 : 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 381090 : ReleaseCachedPlan(CachedPlan *plan, ResourceOwner owner)
1427 : {
1428 : Assert(plan->magic == CACHEDPLAN_MAGIC);
1429 381090 : if (owner)
1430 : {
1431 : Assert(plan->is_saved);
1432 201428 : ResourceOwnerForgetPlanCacheRef(owner, plan);
1433 : }
1434 : Assert(plan->refcount > 0);
1435 381090 : plan->refcount--;
1436 381090 : if (plan->refcount == 0)
1437 : {
1438 : /* Mark it no longer valid */
1439 67780 : plan->magic = 0;
1440 :
1441 : /* One-shot plans do not own their context, so we can't free them */
1442 67780 : if (!plan->is_oneshot)
1443 48230 : MemoryContextDelete(plan->context);
1444 : }
1445 381090 : }
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 29948 : 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 29948 : 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 29948 : if (plansource->dependsOnRLS)
1502 0 : return false;
1503 29948 : if (plan->dependsOnRole)
1504 0 : return false;
1505 29948 : 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 59896 : foreach(lc, plansource->query_list)
1515 : {
1516 29948 : Query *query = lfirst_node(Query, lc);
1517 :
1518 29948 : if (query->commandType == CMD_UTILITY)
1519 0 : return false;
1520 29948 : 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 59896 : foreach(lc, plan->stmt_list)
1529 : {
1530 29948 : PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1531 : ListCell *lc2;
1532 :
1533 29948 : 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 59896 : foreach(lc2, plannedstmt->rtable)
1541 : {
1542 29948 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
1543 :
1544 29948 : 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 29948 : if (owner)
1556 : {
1557 29948 : ResourceOwnerEnlarge(owner);
1558 29948 : plan->refcount++;
1559 29948 : ResourceOwnerRememberPlanCacheRef(owner, plan);
1560 : }
1561 :
1562 29948 : 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 324960 : 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 324960 : if (!plansource->is_valid ||
1604 319750 : plan == NULL || plan != plansource->gplan ||
1605 319750 : !plan->is_valid)
1606 5222 : 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 319738 : if (!SearchPathMatchesCurrentEnvironment(plansource->search_path))
1613 18 : return false;
1614 :
1615 : /* It's still good. Bump refcount if requested. */
1616 319720 : if (owner)
1617 : {
1618 51828 : ResourceOwnerEnlarge(owner);
1619 51828 : plan->refcount++;
1620 51828 : ResourceOwnerRememberPlanCacheRef(owner, plan);
1621 : }
1622 :
1623 319720 : 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 34192 : 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 34192 : if (plansource->is_saved)
1642 0 : elog(ERROR, "cannot move a saved cached plan to another context");
1643 34192 : 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 34192 : 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 34192 : if (plansource->gplan)
1655 : {
1656 : Assert(plansource->gplan->magic == CACHEDPLAN_MAGIC);
1657 0 : MemoryContextSetParent(plansource->gplan->context, newcontext);
1658 : }
1659 34192 : }
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 3700 : CachedPlanIsValid(CachedPlanSource *plansource)
1765 : {
1766 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1767 3700 : 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 15814 : 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 15814 : if (plansource->resultDesc == NULL)
1791 0 : return NIL;
1792 :
1793 : /* Make sure the querytree list is valid and we have parse-time locks */
1794 15814 : RevalidateCachedQuery(plansource, queryEnv);
1795 :
1796 : /* Get the primary statement and find out what it returns */
1797 15814 : pstmt = QueryListGetPrimaryStmt(plansource->query_list);
1798 :
1799 15814 : 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 376 : 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 376 : 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 376 : cexpr_context = AllocSetContextCreate(CurrentMemoryContext,
1837 : "CachedExpression",
1838 : ALLOCSET_SMALL_SIZES);
1839 :
1840 376 : oldcxt = MemoryContextSwitchTo(cexpr_context);
1841 :
1842 376 : cexpr = palloc_object(CachedExpression);
1843 376 : cexpr->magic = CACHEDEXPR_MAGIC;
1844 376 : cexpr->expr = copyObject(expr);
1845 376 : cexpr->is_valid = true;
1846 376 : cexpr->relationOids = copyObject(relationOids);
1847 376 : cexpr->invalItems = copyObject(invalItems);
1848 376 : cexpr->context = cexpr_context;
1849 :
1850 376 : MemoryContextSwitchTo(oldcxt);
1851 :
1852 : /*
1853 : * Reparent the expr's memory context under CacheMemoryContext so that it
1854 : * will live indefinitely.
1855 : */
1856 376 : MemoryContextSetParent(cexpr_context, CacheMemoryContext);
1857 :
1858 : /*
1859 : * Add the entry to the global list of cached expressions.
1860 : */
1861 376 : dlist_push_tail(&cached_expression_list, &cexpr->node);
1862 :
1863 376 : return cexpr;
1864 : }
1865 :
1866 : /*
1867 : * FreeCachedExpression
1868 : * Delete a CachedExpression.
1869 : */
1870 : void
1871 56 : FreeCachedExpression(CachedExpression *cexpr)
1872 : {
1873 : /* Sanity check */
1874 : Assert(cexpr->magic == CACHEDEXPR_MAGIC);
1875 : /* Unlink from global list */
1876 56 : dlist_delete(&cexpr->node);
1877 : /* Free all storage associated with CachedExpression */
1878 56 : MemoryContextDelete(cexpr->context);
1879 56 : }
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 16132 : QueryListGetPrimaryStmt(List *stmts)
1891 : {
1892 : ListCell *lc;
1893 :
1894 16132 : foreach(lc, stmts)
1895 : {
1896 16132 : Query *stmt = lfirst_node(Query, lc);
1897 :
1898 16132 : if (stmt->canSetTag)
1899 16132 : 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 182128 : AcquireExecutorLocks(List *stmt_list, bool acquire)
1910 : {
1911 : ListCell *lc1;
1912 :
1913 364256 : foreach(lc1, stmt_list)
1914 : {
1915 182128 : PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc1);
1916 : ListCell *lc2;
1917 :
1918 182128 : if (plannedstmt->commandType == CMD_UTILITY)
1919 21012 : {
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 21012 : Query *query = UtilityContainsQuery(plannedstmt->utilityStmt);
1928 :
1929 21012 : if (query)
1930 6 : ScanQueryForLocks(query, acquire);
1931 21012 : continue;
1932 : }
1933 :
1934 366764 : foreach(lc2, plannedstmt->rtable)
1935 : {
1936 205648 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
1937 :
1938 205648 : if (!(rte->rtekind == RTE_RELATION ||
1939 140982 : (rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid))))
1940 137788 : 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 67860 : if (acquire)
1949 67860 : LockRelationOid(rte->relid, rte->rellockmode);
1950 : else
1951 0 : UnlockRelationOid(rte->relid, rte->rellockmode);
1952 : }
1953 : }
1954 182128 : }
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 250324 : AcquirePlannerLocks(List *stmt_list, bool acquire)
1966 : {
1967 : ListCell *lc;
1968 :
1969 500648 : foreach(lc, stmt_list)
1970 : {
1971 250324 : Query *query = lfirst_node(Query, lc);
1972 :
1973 250324 : 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 240248 : ScanQueryForLocks(query, acquire);
1983 : }
1984 250324 : }
1985 :
1986 : /*
1987 : * ScanQueryForLocks: recursively scan one Query for AcquirePlannerLocks.
1988 : */
1989 : static void
1990 272010 : 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 454318 : foreach(lc, parsetree->rtable)
2001 : {
2002 182308 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
2003 :
2004 182308 : switch (rte->rtekind)
2005 : {
2006 131404 : case RTE_RELATION:
2007 : /* Acquire or release the appropriate type of lock */
2008 131404 : if (acquire)
2009 131372 : LockRelationOid(rte->relid, rte->rellockmode);
2010 : else
2011 32 : UnlockRelationOid(rte->relid, rte->rellockmode);
2012 131404 : break;
2013 :
2014 16916 : case RTE_SUBQUERY:
2015 : /* If this was a view, must lock/unlock the view */
2016 16916 : if (OidIsValid(rte->relid))
2017 : {
2018 3860 : if (acquire)
2019 3860 : LockRelationOid(rte->relid, rte->rellockmode);
2020 : else
2021 0 : UnlockRelationOid(rte->relid, rte->rellockmode);
2022 : }
2023 : /* Recurse into subquery-in-FROM */
2024 16916 : ScanQueryForLocks(rte->subquery, acquire);
2025 16916 : break;
2026 :
2027 33988 : default:
2028 : /* ignore other types of RTEs */
2029 33988 : break;
2030 : }
2031 : }
2032 :
2033 : /* Recurse into subquery-in-WITH */
2034 272106 : 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 272010 : if (parsetree->hasSubLinks)
2046 : {
2047 4794 : query_tree_walker(parsetree, ScanQueryWalker, &acquire,
2048 : QTW_IGNORE_RC_SUBQUERIES);
2049 : }
2050 272010 : }
2051 :
2052 : /*
2053 : * Walker to find sublink subqueries for ScanQueryForLocks
2054 : */
2055 : static bool
2056 128866 : ScanQueryWalker(Node *node, bool *acquire)
2057 : {
2058 128866 : if (node == NULL)
2059 58524 : return false;
2060 70342 : if (IsA(node, SubLink))
2061 : {
2062 4928 : SubLink *sub = (SubLink *) node;
2063 :
2064 : /* Do what we came for */
2065 4928 : 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 70342 : 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 85512 : PlanCacheComputeResultDesc(List *stmt_list)
2085 : {
2086 : Query *query;
2087 :
2088 85512 : switch (ChoosePortalStrategy(stmt_list))
2089 : {
2090 57014 : case PORTAL_ONE_SELECT:
2091 : case PORTAL_ONE_MOD_WITH:
2092 57014 : query = linitial_node(Query, stmt_list);
2093 57014 : return ExecCleanTypeFromTL(query->targetList);
2094 :
2095 318 : case PORTAL_ONE_RETURNING:
2096 318 : query = QueryListGetPrimaryStmt(stmt_list);
2097 : Assert(query->returningList);
2098 318 : 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 18104 : case PORTAL_MULTI_QUERY:
2106 : /* will not return tuples */
2107 18104 : break;
2108 : }
2109 18104 : 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 3386382 : PlanCacheRelCallback(Datum arg, Oid relid)
2121 : {
2122 : dlist_iter iter;
2123 :
2124 61611500 : dlist_foreach(iter, &saved_plan_list)
2125 : {
2126 58225118 : 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 58225118 : if (!plansource->is_valid)
2133 39284982 : continue;
2134 :
2135 : /* Never invalidate if parse/plan would be a no-op anyway */
2136 18940136 : if (!StmtPlanRequiresRevalidation(plansource))
2137 361602 : continue;
2138 :
2139 : /*
2140 : * Check the dependency list for the rewritten querytree.
2141 : */
2142 37157052 : if ((relid == InvalidOid) ? plansource->relationOids != NIL :
2143 18578518 : list_member_oid(plansource->relationOids, relid))
2144 : {
2145 : /* Invalidate the querytree and generic plan */
2146 3808 : plansource->is_valid = false;
2147 3808 : if (plansource->gplan)
2148 1184 : 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 18578534 : if (plansource->gplan && plansource->gplan->is_valid)
2156 : {
2157 : ListCell *lc;
2158 :
2159 34829788 : foreach(lc, plansource->gplan->stmt_list)
2160 : {
2161 17414932 : PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
2162 :
2163 17414932 : if (plannedstmt->commandType == CMD_UTILITY)
2164 4428 : continue; /* Ignore utility statements */
2165 34821008 : if ((relid == InvalidOid) ? plannedstmt->relationOids != NIL :
2166 17410504 : list_member_oid(plannedstmt->relationOids, relid))
2167 : {
2168 : /* Invalidate the generic plan only */
2169 76 : plansource->gplan->is_valid = false;
2170 76 : break; /* out of stmt_list scan */
2171 : }
2172 : }
2173 : }
2174 : }
2175 :
2176 : /* Likewise check cached expressions */
2177 3695988 : dlist_foreach(iter, &cached_expression_list)
2178 : {
2179 309606 : 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 309606 : if (!cexpr->is_valid)
2186 141534 : continue;
2187 :
2188 336144 : if ((relid == InvalidOid) ? cexpr->relationOids != NIL :
2189 168072 : list_member_oid(cexpr->relationOids, relid))
2190 : {
2191 0 : cexpr->is_valid = false;
2192 : }
2193 : }
2194 3386382 : }
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 1278074 : PlanCacheObjectCallback(Datum arg, int cacheid, uint32 hashvalue)
2205 : {
2206 : dlist_iter iter;
2207 :
2208 23653074 : dlist_foreach(iter, &saved_plan_list)
2209 : {
2210 22375000 : 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 22375000 : if (!plansource->is_valid)
2218 14626478 : continue;
2219 :
2220 : /* Never invalidate if parse/plan would be a no-op anyway */
2221 7748522 : if (!StmtPlanRequiresRevalidation(plansource))
2222 96524 : continue;
2223 :
2224 : /*
2225 : * Check the dependency list for the rewritten querytree.
2226 : */
2227 7788306 : foreach(lc, plansource->invalItems)
2228 : {
2229 136462 : PlanInvalItem *item = (PlanInvalItem *) lfirst(lc);
2230 :
2231 136462 : if (item->cacheId != cacheid)
2232 93102 : continue;
2233 43360 : if (hashvalue == 0 ||
2234 43354 : item->hashValue == hashvalue)
2235 : {
2236 : /* Invalidate the querytree and generic plan */
2237 154 : plansource->is_valid = false;
2238 154 : if (plansource->gplan)
2239 148 : 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 7651998 : if (plansource->gplan && plansource->gplan->is_valid)
2249 : {
2250 14280896 : foreach(lc, plansource->gplan->stmt_list)
2251 : {
2252 7140460 : PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
2253 : ListCell *lc3;
2254 :
2255 7140460 : if (plannedstmt->commandType == CMD_UTILITY)
2256 2636 : continue; /* Ignore utility statements */
2257 7266212 : foreach(lc3, plannedstmt->invalItems)
2258 : {
2259 128412 : PlanInvalItem *item = (PlanInvalItem *) lfirst(lc3);
2260 :
2261 128412 : if (item->cacheId != cacheid)
2262 86964 : continue;
2263 41448 : if (hashvalue == 0 ||
2264 41448 : 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 7137824 : if (!plansource->gplan->is_valid)
2272 24 : break; /* out of stmt_list scan */
2273 : }
2274 : }
2275 : }
2276 :
2277 : /* Likewise check cached expressions */
2278 1421008 : dlist_foreach(iter, &cached_expression_list)
2279 : {
2280 142934 : 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 142934 : if (!cexpr->is_valid)
2288 54450 : continue;
2289 :
2290 88500 : foreach(lc, cexpr->invalItems)
2291 : {
2292 22 : PlanInvalItem *item = (PlanInvalItem *) lfirst(lc);
2293 :
2294 22 : if (item->cacheId != cacheid)
2295 4 : 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 1278074 : }
2305 :
2306 : /*
2307 : * PlanCacheSysCallback
2308 : * Syscache inval callback function for other caches
2309 : *
2310 : * Just invalidate everything...
2311 : */
2312 : static void
2313 79950 : PlanCacheSysCallback(Datum arg, int cacheid, uint32 hashvalue)
2314 : {
2315 79950 : ResetPlanCache();
2316 79950 : }
2317 :
2318 : /*
2319 : * ResetPlanCache: invalidate all cached plans.
2320 : */
2321 : void
2322 81092 : ResetPlanCache(void)
2323 : {
2324 : dlist_iter iter;
2325 :
2326 324116 : dlist_foreach(iter, &saved_plan_list)
2327 : {
2328 243024 : 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 243024 : if (!plansource->is_valid)
2335 220950 : 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 22074 : if (!StmtPlanRequiresRevalidation(plansource))
2346 6304 : continue;
2347 :
2348 15770 : plansource->is_valid = false;
2349 15770 : if (plansource->gplan)
2350 14214 : plansource->gplan->is_valid = false;
2351 : }
2352 :
2353 : /* Likewise invalidate cached expressions */
2354 82384 : dlist_foreach(iter, &cached_expression_list)
2355 : {
2356 1292 : CachedExpression *cexpr = dlist_container(CachedExpression,
2357 : node, iter.cur);
2358 :
2359 : Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2360 :
2361 1292 : cexpr->is_valid = false;
2362 : }
2363 81092 : }
2364 :
2365 : /*
2366 : * Release all CachedPlans remembered by 'owner'
2367 : */
2368 : void
2369 16834 : ReleaseAllPlanCacheRefsInOwner(ResourceOwner owner)
2370 : {
2371 16834 : ResourceOwnerReleaseAllOfKind(owner, &planref_resowner_desc);
2372 16834 : }
2373 :
2374 : /* ResourceOwner callbacks */
2375 :
2376 : static void
2377 92492 : ResOwnerReleaseCachedPlan(Datum res)
2378 : {
2379 92492 : ReleaseCachedPlan((CachedPlan *) DatumGetPointer(res), NULL);
2380 92492 : }
|