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