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