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 288600 : ResourceOwnerRememberPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
127 : {
128 288600 : ResourceOwnerRemember(owner, PointerGetDatum(plan), &planref_resowner_desc);
129 288600 : }
130 : static inline void
131 198232 : ResourceOwnerForgetPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
132 : {
133 198232 : ResourceOwnerForget(owner, PointerGetDatum(plan), &planref_resowner_desc);
134 198232 : }
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 34394 : InitPlanCache(void)
147 : {
148 34394 : CacheRegisterRelcacheCallback(PlanCacheRelCallback, (Datum) 0);
149 34394 : CacheRegisterSyscacheCallback(PROCOID, PlanCacheObjectCallback, (Datum) 0);
150 34394 : CacheRegisterSyscacheCallback(TYPEOID, PlanCacheObjectCallback, (Datum) 0);
151 34394 : CacheRegisterSyscacheCallback(NAMESPACEOID, PlanCacheSysCallback, (Datum) 0);
152 34394 : CacheRegisterSyscacheCallback(OPEROID, PlanCacheSysCallback, (Datum) 0);
153 34394 : CacheRegisterSyscacheCallback(AMOPOPID, PlanCacheSysCallback, (Datum) 0);
154 34394 : CacheRegisterSyscacheCallback(FOREIGNSERVEROID, PlanCacheSysCallback, (Datum) 0);
155 34394 : CacheRegisterSyscacheCallback(FOREIGNDATAWRAPPEROID, PlanCacheSysCallback, (Datum) 0);
156 34394 : }
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 58418 : 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 58418 : 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 58418 : oldcxt = MemoryContextSwitchTo(source_context);
209 :
210 58418 : plansource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
211 58418 : plansource->magic = CACHEDPLANSOURCE_MAGIC;
212 58418 : plansource->raw_parse_tree = copyObject(raw_parse_tree);
213 58418 : plansource->analyzed_parse_tree = NULL;
214 58418 : plansource->query_string = pstrdup(query_string);
215 58418 : MemoryContextSetIdentifier(source_context, plansource->query_string);
216 58418 : plansource->commandTag = commandTag;
217 58418 : plansource->param_types = NULL;
218 58418 : plansource->num_params = 0;
219 58418 : plansource->parserSetup = NULL;
220 58418 : plansource->parserSetupArg = NULL;
221 58418 : plansource->postRewrite = NULL;
222 58418 : plansource->postRewriteArg = NULL;
223 58418 : plansource->cursor_options = 0;
224 58418 : plansource->fixed_result = false;
225 58418 : plansource->resultDesc = NULL;
226 58418 : plansource->context = source_context;
227 58418 : plansource->query_list = NIL;
228 58418 : plansource->relationOids = NIL;
229 58418 : plansource->invalItems = NIL;
230 58418 : plansource->search_path = NULL;
231 58418 : plansource->query_context = NULL;
232 58418 : plansource->rewriteRoleId = InvalidOid;
233 58418 : plansource->rewriteRowSecurity = false;
234 58418 : plansource->dependsOnRLS = false;
235 58418 : plansource->gplan = NULL;
236 58418 : plansource->is_oneshot = false;
237 58418 : plansource->is_complete = false;
238 58418 : plansource->is_saved = false;
239 58418 : plansource->is_valid = false;
240 58418 : plansource->generation = 0;
241 58418 : plansource->generic_cost = -1;
242 58418 : plansource->total_custom_cost = 0;
243 58418 : plansource->num_generic_plans = 0;
244 58418 : plansource->num_custom_plans = 0;
245 :
246 58418 : MemoryContextSwitchTo(oldcxt);
247 :
248 58418 : 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 886 : 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 886 : plansource = CreateCachedPlan(NULL, query_string, commandTag);
272 886 : oldcxt = MemoryContextSwitchTo(plansource->context);
273 886 : plansource->analyzed_parse_tree = copyObject(analyzed_parse_tree);
274 886 : MemoryContextSwitchTo(oldcxt);
275 :
276 886 : 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 78064 : 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 78064 : MemoryContext source_context = plansource->context;
402 78064 : 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 78064 : if (plansource->is_oneshot)
416 : {
417 19776 : querytree_context = CurrentMemoryContext;
418 : }
419 58288 : else if (querytree_context != NULL)
420 : {
421 6746 : MemoryContextSetParent(querytree_context, source_context);
422 6746 : MemoryContextSwitchTo(querytree_context);
423 : }
424 : else
425 : {
426 : /* Again, it's a good bet the querytree_context can be small */
427 51542 : querytree_context = AllocSetContextCreate(source_context,
428 : "CachedPlanQuery",
429 : ALLOCSET_START_SMALL_SIZES);
430 51542 : MemoryContextSwitchTo(querytree_context);
431 51542 : querytree_list = copyObject(querytree_list);
432 : }
433 :
434 78064 : plansource->query_context = querytree_context;
435 78064 : plansource->query_list = querytree_list;
436 :
437 78064 : 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 56272 : extract_query_dependencies((Node *) querytree_list,
446 : &plansource->relationOids,
447 : &plansource->invalItems,
448 : &plansource->dependsOnRLS);
449 :
450 : /* Update RLS info as well. */
451 56272 : plansource->rewriteRoleId = GetUserId();
452 56272 : 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 56272 : 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 78064 : MemoryContextSwitchTo(source_context);
470 :
471 78064 : if (num_params > 0)
472 : {
473 14436 : plansource->param_types = (Oid *) palloc(num_params * sizeof(Oid));
474 14436 : memcpy(plansource->param_types, param_types, num_params * sizeof(Oid));
475 : }
476 : else
477 63628 : plansource->param_types = NULL;
478 78064 : plansource->num_params = num_params;
479 78064 : plansource->parserSetup = parserSetup;
480 78064 : plansource->parserSetupArg = parserSetupArg;
481 78064 : plansource->cursor_options = cursor_options;
482 78064 : plansource->fixed_result = fixed_result;
483 78064 : plansource->resultDesc = PlanCacheComputeResultDesc(querytree_list);
484 :
485 78064 : MemoryContextSwitchTo(oldcxt);
486 :
487 78064 : plansource->is_complete = true;
488 78064 : plansource->is_valid = true;
489 78064 : }
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 2190 : SetPostRewriteHook(CachedPlanSource *plansource,
506 : PostRewriteHook postRewrite,
507 : void *postRewriteArg)
508 : {
509 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
510 2190 : plansource->postRewrite = postRewrite;
511 2190 : plansource->postRewriteArg = postRewriteArg;
512 2190 : }
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 47316 : 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 47316 : 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 47316 : 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 47316 : MemoryContextSetParent(plansource->context, CacheMemoryContext);
556 :
557 : /*
558 : * Add the entry to the global list of cached plans.
559 : */
560 47316 : dlist_push_tail(&saved_plan_list, &plansource->node);
561 :
562 47316 : plansource->is_saved = true;
563 47316 : }
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 18266 : DropCachedPlan(CachedPlanSource *plansource)
575 : {
576 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
577 :
578 : /* If it's been saved, remove it from the list */
579 18266 : if (plansource->is_saved)
580 : {
581 18076 : dlist_delete(&plansource->node);
582 18076 : plansource->is_saved = false;
583 : }
584 :
585 : /* Decrement generic CachedPlan's refcount and drop if no longer needed */
586 18266 : ReleaseGenericPlan(plansource);
587 :
588 : /* Mark it no longer valid */
589 18266 : 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 18266 : if (!plansource->is_oneshot)
596 18266 : MemoryContextDelete(plansource->context);
597 18266 : }
598 :
599 : /*
600 : * ReleaseGenericPlan: release a CachedPlanSource's generic plan, if any.
601 : */
602 : static void
603 119140 : ReleaseGenericPlan(CachedPlanSource *plansource)
604 : {
605 : /* Be paranoid about the possibility that ReleaseCachedPlan fails */
606 119140 : if (plansource->gplan)
607 : {
608 14546 : CachedPlan *plan = plansource->gplan;
609 :
610 : Assert(plan->magic == CACHEDPLAN_MAGIC);
611 14546 : plansource->gplan = NULL;
612 14546 : ReleaseCachedPlan(plan, NULL);
613 : }
614 119140 : }
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 29639854 : StmtPlanRequiresRevalidation(CachedPlanSource *plansource)
626 : {
627 29639854 : if (plansource->raw_parse_tree != NULL)
628 29148148 : return stmt_requires_parse_analysis(plansource->raw_parse_tree);
629 491706 : else if (plansource->analyzed_parse_tree != NULL)
630 491700 : 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 1064 : BuildingPlanRequiresSnapshot(CachedPlanSource *plansource)
643 : {
644 1064 : if (plansource->raw_parse_tree != NULL)
645 1064 : 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 304772 : 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 304772 : if (plansource->is_oneshot || !StmtPlanRequiresRevalidation(plansource))
685 : {
686 : Assert(plansource->is_valid);
687 42592 : 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 262180 : if (plansource->is_valid)
699 : {
700 : Assert(plansource->search_path != NULL);
701 256770 : if (!SearchPathMatchesCurrentEnvironment(plansource->search_path))
702 : {
703 : /* Invalidate the querytree and generic plan */
704 98 : plansource->is_valid = false;
705 98 : if (plansource->gplan)
706 80 : 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 262480 : if (plansource->is_valid && plansource->dependsOnRLS &&
715 300 : (plansource->rewriteRoleId != GetUserId() ||
716 210 : plansource->rewriteRowSecurity != row_security))
717 114 : 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 262180 : if (plansource->is_valid)
725 : {
726 256558 : 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 256558 : if (plansource->is_valid)
733 : {
734 : /* Successfully revalidated and locked the query. */
735 256542 : return NIL;
736 : }
737 :
738 : /* Oops, the race case happened. Release useless locks. */
739 16 : 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 5638 : plansource->is_valid = false;
748 5638 : plansource->query_list = NIL;
749 5638 : plansource->relationOids = NIL;
750 5638 : plansource->invalItems = NIL;
751 5638 : 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 5638 : if (plansource->query_context)
760 : {
761 5608 : MemoryContext qcxt = plansource->query_context;
762 :
763 5608 : plansource->query_context = NULL;
764 5608 : MemoryContextDelete(qcxt);
765 : }
766 :
767 : /* Drop the generic plan reference if any */
768 5638 : 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 5638 : snapshot_set = false;
784 5638 : 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 5638 : 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 5402 : rawtree = copyObject(plansource->raw_parse_tree);
803 5402 : if (plansource->parserSetup != NULL)
804 5010 : tlist = pg_analyze_and_rewrite_withcb(rawtree,
805 : plansource->query_string,
806 : plansource->parserSetup,
807 : plansource->parserSetupArg,
808 : queryEnv);
809 : else
810 392 : tlist = pg_analyze_and_rewrite_fixedparams(rawtree,
811 : plansource->query_string,
812 392 : plansource->param_types,
813 : plansource->num_params,
814 : queryEnv);
815 : }
816 236 : 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 236 : analyzed_tree = copyObject(plansource->analyzed_parse_tree);
823 : /* Acquire locks needed before rewriting ... */
824 236 : AcquireRewriteLocks(analyzed_tree, true, false);
825 : /* ... and do it */
826 236 : 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 5598 : if (plansource->postRewrite != NULL)
836 322 : plansource->postRewrite(tlist, plansource->postRewriteArg);
837 :
838 : /* Release snapshot if we got one */
839 5598 : 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 5598 : resultDesc = PlanCacheComputeResultDesc(tlist);
849 5598 : if (resultDesc == NULL && plansource->resultDesc == NULL)
850 : {
851 : /* OK, doesn't return tuples */
852 : }
853 5432 : else if (resultDesc == NULL || plansource->resultDesc == NULL ||
854 5432 : !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 5586 : querytree_context = AllocSetContextCreate(CurrentMemoryContext,
875 : "CachedPlanQuery",
876 : ALLOCSET_START_SMALL_SIZES);
877 5586 : oldcxt = MemoryContextSwitchTo(querytree_context);
878 :
879 5586 : 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 5586 : extract_query_dependencies((Node *) qlist,
887 : &plansource->relationOids,
888 : &plansource->invalItems,
889 : &plansource->dependsOnRLS);
890 :
891 : /* Update RLS info as well. */
892 5586 : plansource->rewriteRoleId = GetUserId();
893 5586 : 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 5586 : plansource->search_path = GetSearchPathMatcher(querytree_context);
901 :
902 5586 : MemoryContextSwitchTo(oldcxt);
903 :
904 : /* Now reparent the finished query_context and save the links */
905 5586 : MemoryContextSetParent(querytree_context, plansource->context);
906 :
907 5586 : plansource->query_context = querytree_context;
908 5586 : 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 5586 : plansource->is_valid = true;
920 :
921 : /* Return transient copy of querytrees for possible use in planning */
922 5586 : 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 232256 : CheckCachedPlan(CachedPlanSource *plansource)
936 : {
937 232256 : 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 232256 : if (!plan)
944 47822 : 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 184472 : if (plan->is_valid && plan->dependsOnRole &&
954 38 : 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 184434 : 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 184356 : 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 184356 : if (plan->is_valid &&
976 184356 : 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 184356 : if (plan->is_valid)
985 : {
986 : /* Successfully revalidated and locked the query. */
987 184356 : 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 100600 : 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 100600 : 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 100600 : 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 100600 : if (qlist == NIL)
1052 : {
1053 95016 : if (!plansource->is_oneshot)
1054 75246 : 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 100600 : snapshot_set = false;
1064 101664 : if (!ActiveSnapshotSet() &&
1065 1064 : BuildingPlanRequiresSnapshot(plansource))
1066 : {
1067 286 : PushActiveSnapshot(GetTransactionSnapshot());
1068 286 : snapshot_set = true;
1069 : }
1070 :
1071 : /*
1072 : * Generate the plan.
1073 : */
1074 100600 : plist = pg_plan_queries(qlist, plansource->query_string,
1075 : plansource->cursor_options, boundParams);
1076 :
1077 : /* Release snapshot if we got one */
1078 100390 : 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 100390 : if (!plansource->is_oneshot)
1088 : {
1089 80696 : plan_context = AllocSetContextCreate(CurrentMemoryContext,
1090 : "CachedPlan",
1091 : ALLOCSET_START_SMALL_SIZES);
1092 80696 : MemoryContextCopyAndSetIdentifier(plan_context, plansource->query_string);
1093 :
1094 : /*
1095 : * Copy plan into the new context.
1096 : */
1097 80696 : MemoryContextSwitchTo(plan_context);
1098 :
1099 80696 : 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 100390 : plan = (CachedPlan *) palloc(sizeof(CachedPlan));
1108 100390 : plan->magic = CACHEDPLAN_MAGIC;
1109 100390 : 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 100390 : plan->planRoleId = GetUserId();
1117 100390 : plan->dependsOnRole = plansource->dependsOnRLS;
1118 100390 : is_transient = false;
1119 200786 : foreach(lc, plist)
1120 : {
1121 100396 : PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1122 :
1123 100396 : if (plannedstmt->commandType == CMD_UTILITY)
1124 20322 : continue; /* Ignore utility statements */
1125 :
1126 80074 : if (plannedstmt->transientPlan)
1127 88 : is_transient = true;
1128 80074 : if (plannedstmt->dependsOnRole)
1129 72 : plan->dependsOnRole = true;
1130 : }
1131 100390 : if (is_transient)
1132 : {
1133 : Assert(TransactionIdIsNormal(TransactionXmin));
1134 88 : plan->saved_xmin = TransactionXmin;
1135 : }
1136 : else
1137 100302 : plan->saved_xmin = InvalidTransactionId;
1138 100390 : plan->refcount = 0;
1139 100390 : plan->context = plan_context;
1140 100390 : plan->is_oneshot = plansource->is_oneshot;
1141 100390 : plan->is_saved = false;
1142 100390 : plan->is_valid = true;
1143 :
1144 : /* assign generation number to new plan */
1145 100390 : plan->generation = ++(plansource->generation);
1146 :
1147 100390 : MemoryContextSwitchTo(oldcxt);
1148 :
1149 100390 : 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 332728 : choose_custom_plan(CachedPlanSource *plansource, ParamListInfo boundParams)
1159 : {
1160 : double avg_custom_cost;
1161 :
1162 : /* One-shot plans will always be considered custom */
1163 332728 : if (plansource->is_oneshot)
1164 19770 : return true;
1165 :
1166 : /* Otherwise, never any point in a custom plan if there's no parameters */
1167 312958 : if (boundParams == NULL)
1168 147014 : return false;
1169 : /* ... nor when planning would be a no-op */
1170 165944 : if (!StmtPlanRequiresRevalidation(plansource))
1171 0 : return false;
1172 :
1173 : /* Let settings force the decision */
1174 165944 : if (plan_cache_mode == PLAN_CACHE_MODE_FORCE_GENERIC_PLAN)
1175 2826 : return false;
1176 163118 : 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 163094 : if (plansource->cursor_options & CURSOR_OPT_GENERIC_PLAN)
1181 0 : return false;
1182 163094 : 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 163094 : if (plansource->num_custom_plans < 5)
1187 28972 : return true;
1188 :
1189 134122 : 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 134122 : if (plansource->generic_cost < avg_custom_cost)
1202 130188 : return false;
1203 :
1204 3934 : 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 100390 : cached_plan_cost(CachedPlan *plan, bool include_planner)
1216 : {
1217 100390 : double result = 0;
1218 : ListCell *lc;
1219 :
1220 200786 : foreach(lc, plan->stmt_list)
1221 : {
1222 100396 : PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1223 :
1224 100396 : if (plannedstmt->commandType == CMD_UTILITY)
1225 20322 : continue; /* Ignore utility statements */
1226 :
1227 80074 : result += plannedstmt->planTree->total_cost;
1228 :
1229 80074 : 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 43394 : int nrelations = list_length(plannedstmt->rtable);
1253 :
1254 43394 : result += 1000.0 * cpu_operator_cost * (nrelations + 1);
1255 : }
1256 : }
1257 :
1258 100390 : 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 284938 : GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams,
1281 : ResourceOwner owner, QueryEnvironment *queryEnv)
1282 : {
1283 284938 : CachedPlan *plan = NULL;
1284 : List *qlist;
1285 : bool customplan;
1286 :
1287 : /* Assert caller is doing things in a sane order */
1288 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1289 : Assert(plansource->is_complete);
1290 : /* This seems worth a real test, though */
1291 284938 : if (owner && !plansource->is_saved)
1292 0 : elog(ERROR, "cannot apply ResourceOwner to non-saved cached plan");
1293 :
1294 : /* Make sure the querytree list is valid and we have parse-time locks */
1295 284938 : qlist = RevalidateCachedQuery(plansource, queryEnv);
1296 :
1297 : /* Decide whether to use a custom plan */
1298 284886 : customplan = choose_custom_plan(plansource, boundParams);
1299 :
1300 284886 : if (!customplan)
1301 : {
1302 232256 : if (CheckCachedPlan(plansource))
1303 : {
1304 : /* We want a generic plan, and we already have a valid one */
1305 184356 : plan = plansource->gplan;
1306 : Assert(plan->magic == CACHEDPLAN_MAGIC);
1307 : }
1308 : else
1309 : {
1310 : /* Build a new generic plan */
1311 47900 : plan = BuildCachedPlan(plansource, qlist, NULL, queryEnv);
1312 : /* Just make real sure plansource->gplan is clear */
1313 47842 : ReleaseGenericPlan(plansource);
1314 : /* Link the new generic plan into the plansource */
1315 47842 : plansource->gplan = plan;
1316 47842 : plan->refcount++;
1317 : /* Immediately reparent into appropriate context */
1318 47842 : if (plansource->is_saved)
1319 : {
1320 : /* saved plans all live under CacheMemoryContext */
1321 36888 : MemoryContextSetParent(plan->context, CacheMemoryContext);
1322 36888 : plan->is_saved = true;
1323 : }
1324 : else
1325 : {
1326 : /* otherwise, it should be a sibling of the plansource */
1327 10954 : MemoryContextSetParent(plan->context,
1328 : MemoryContextGetParent(plansource->context));
1329 : }
1330 : /* Update generic_cost whenever we make a new generic plan */
1331 47842 : plansource->generic_cost = cached_plan_cost(plan, false);
1332 :
1333 : /*
1334 : * If, based on the now-known value of generic_cost, we'd not have
1335 : * chosen to use a generic plan, then forget it and make a custom
1336 : * plan. This is a bit of a wart but is necessary to avoid a
1337 : * glitch in behavior when the custom plans are consistently big
1338 : * winners; at some point we'll experiment with a generic plan and
1339 : * find it's a loser, but we don't want to actually execute that
1340 : * plan.
1341 : */
1342 47842 : customplan = choose_custom_plan(plansource, boundParams);
1343 :
1344 : /*
1345 : * If we choose to plan again, we need to re-copy the query_list,
1346 : * since the planner probably scribbled on it. We can force
1347 : * BuildCachedPlan to do that by passing NIL.
1348 : */
1349 47842 : qlist = NIL;
1350 : }
1351 : }
1352 :
1353 284828 : if (customplan)
1354 : {
1355 : /* Build a custom plan */
1356 52700 : plan = BuildCachedPlan(plansource, qlist, boundParams, queryEnv);
1357 : /* Accumulate total costs of custom plans */
1358 52548 : plansource->total_custom_cost += cached_plan_cost(plan, true);
1359 :
1360 52548 : plansource->num_custom_plans++;
1361 : }
1362 : else
1363 : {
1364 232128 : plansource->num_generic_plans++;
1365 : }
1366 :
1367 : Assert(plan != NULL);
1368 :
1369 : /* Flag the plan as in use by caller */
1370 284676 : if (owner)
1371 209530 : ResourceOwnerEnlarge(owner);
1372 284676 : plan->refcount++;
1373 284676 : if (owner)
1374 209530 : ResourceOwnerRememberPlanCacheRef(owner, plan);
1375 :
1376 : /*
1377 : * Saved plans should be under CacheMemoryContext so they will not go away
1378 : * until their reference count goes to zero. In the generic-plan cases we
1379 : * already took care of that, but for a custom plan, do it as soon as we
1380 : * have created a reference-counted link.
1381 : */
1382 284676 : if (customplan && plansource->is_saved)
1383 : {
1384 32842 : MemoryContextSetParent(plan->context, CacheMemoryContext);
1385 32842 : plan->is_saved = true;
1386 : }
1387 :
1388 284676 : return plan;
1389 : }
1390 :
1391 : /*
1392 : * ReleaseCachedPlan: release active use of a cached plan.
1393 : *
1394 : * This decrements the reference count, and frees the plan if the count
1395 : * has thereby gone to zero. If "owner" is not NULL, it is assumed that
1396 : * the reference count is managed by that ResourceOwner.
1397 : *
1398 : * Note: owner == NULL is used for releasing references that are in
1399 : * persistent data structures, such as the parent CachedPlanSource or a
1400 : * Portal. Transient references should be protected by a resource owner.
1401 : */
1402 : void
1403 377972 : ReleaseCachedPlan(CachedPlan *plan, ResourceOwner owner)
1404 : {
1405 : Assert(plan->magic == CACHEDPLAN_MAGIC);
1406 377972 : if (owner)
1407 : {
1408 : Assert(plan->is_saved);
1409 198232 : ResourceOwnerForgetPlanCacheRef(owner, plan);
1410 : }
1411 : Assert(plan->refcount > 0);
1412 377972 : plan->refcount--;
1413 377972 : if (plan->refcount == 0)
1414 : {
1415 : /* Mark it no longer valid */
1416 66922 : plan->magic = 0;
1417 :
1418 : /* One-shot plans do not own their context, so we can't free them */
1419 66922 : if (!plan->is_oneshot)
1420 47400 : MemoryContextDelete(plan->context);
1421 : }
1422 377972 : }
1423 :
1424 : /*
1425 : * CachedPlanAllowsSimpleValidityCheck: can we use CachedPlanIsSimplyValid?
1426 : *
1427 : * This function, together with CachedPlanIsSimplyValid, provides a fast path
1428 : * for revalidating "simple" generic plans. The core requirement to be simple
1429 : * is that the plan must not require taking any locks, which translates to
1430 : * not touching any tables; this happens to match up well with an important
1431 : * use-case in PL/pgSQL. This function tests whether that's true, along
1432 : * with checking some other corner cases that we'd rather not bother with
1433 : * handling in the fast path. (Note that it's still possible for such a plan
1434 : * to be invalidated, for example due to a change in a function that was
1435 : * inlined into the plan.)
1436 : *
1437 : * If the plan is simply valid, and "owner" is not NULL, record a refcount on
1438 : * the plan in that resowner before returning. It is caller's responsibility
1439 : * to be sure that a refcount is held on any plan that's being actively used.
1440 : *
1441 : * This must only be called on known-valid generic plans (eg, ones just
1442 : * returned by GetCachedPlan). If it returns true, the caller may re-use
1443 : * the cached plan as long as CachedPlanIsSimplyValid returns true; that
1444 : * check is much cheaper than the full revalidation done by GetCachedPlan.
1445 : * Nonetheless, no required checks are omitted.
1446 : */
1447 : bool
1448 28206 : CachedPlanAllowsSimpleValidityCheck(CachedPlanSource *plansource,
1449 : CachedPlan *plan, ResourceOwner owner)
1450 : {
1451 : ListCell *lc;
1452 :
1453 : /*
1454 : * Sanity-check that the caller gave us a validated generic plan. Notice
1455 : * that we *don't* assert plansource->is_valid as you might expect; that's
1456 : * because it's possible that that's already false when GetCachedPlan
1457 : * returns, e.g. because ResetPlanCache happened partway through. We
1458 : * should accept the plan as long as plan->is_valid is true, and expect to
1459 : * replan after the next CachedPlanIsSimplyValid call.
1460 : */
1461 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1462 : Assert(plan->magic == CACHEDPLAN_MAGIC);
1463 : Assert(plan->is_valid);
1464 : Assert(plan == plansource->gplan);
1465 : Assert(plansource->search_path != NULL);
1466 : Assert(SearchPathMatchesCurrentEnvironment(plansource->search_path));
1467 :
1468 : /* We don't support oneshot plans here. */
1469 28206 : if (plansource->is_oneshot)
1470 0 : return false;
1471 : Assert(!plan->is_oneshot);
1472 :
1473 : /*
1474 : * If the plan is dependent on RLS considerations, or it's transient,
1475 : * reject. These things probably can't ever happen for table-free
1476 : * queries, but for safety's sake let's check.
1477 : */
1478 28206 : if (plansource->dependsOnRLS)
1479 0 : return false;
1480 28206 : if (plan->dependsOnRole)
1481 0 : return false;
1482 28206 : if (TransactionIdIsValid(plan->saved_xmin))
1483 0 : return false;
1484 :
1485 : /*
1486 : * Reject if AcquirePlannerLocks would have anything to do. This is
1487 : * simplistic, but there's no need to inquire any more carefully; indeed,
1488 : * for current callers it shouldn't even be possible to hit any of these
1489 : * checks.
1490 : */
1491 56412 : foreach(lc, plansource->query_list)
1492 : {
1493 28206 : Query *query = lfirst_node(Query, lc);
1494 :
1495 28206 : if (query->commandType == CMD_UTILITY)
1496 0 : return false;
1497 28206 : if (query->rtable || query->cteList || query->hasSubLinks)
1498 0 : return false;
1499 : }
1500 :
1501 : /*
1502 : * Reject if AcquireExecutorLocks would have anything to do. This is
1503 : * probably unnecessary given the previous check, but let's be safe.
1504 : */
1505 56412 : foreach(lc, plan->stmt_list)
1506 : {
1507 28206 : PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1508 : ListCell *lc2;
1509 :
1510 28206 : if (plannedstmt->commandType == CMD_UTILITY)
1511 0 : return false;
1512 :
1513 : /*
1514 : * We have to grovel through the rtable because it's likely to contain
1515 : * an RTE_RESULT relation, rather than being totally empty.
1516 : */
1517 56412 : foreach(lc2, plannedstmt->rtable)
1518 : {
1519 28206 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
1520 :
1521 28206 : if (rte->rtekind == RTE_RELATION)
1522 0 : return false;
1523 : }
1524 : }
1525 :
1526 : /*
1527 : * Okay, it's simple. Note that what we've primarily established here is
1528 : * that no locks need be taken before checking the plan's is_valid flag.
1529 : */
1530 :
1531 : /* Bump refcount if requested. */
1532 28206 : if (owner)
1533 : {
1534 28206 : ResourceOwnerEnlarge(owner);
1535 28206 : plan->refcount++;
1536 28206 : ResourceOwnerRememberPlanCacheRef(owner, plan);
1537 : }
1538 :
1539 28206 : return true;
1540 : }
1541 :
1542 : /*
1543 : * CachedPlanIsSimplyValid: quick check for plan still being valid
1544 : *
1545 : * This function must not be used unless CachedPlanAllowsSimpleValidityCheck
1546 : * previously said it was OK.
1547 : *
1548 : * If the plan is valid, and "owner" is not NULL, record a refcount on
1549 : * the plan in that resowner before returning. It is caller's responsibility
1550 : * to be sure that a refcount is held on any plan that's being actively used.
1551 : *
1552 : * The code here is unconditionally safe as long as the only use of this
1553 : * CachedPlanSource is in connection with the particular CachedPlan pointer
1554 : * that's passed in. If the plansource were being used for other purposes,
1555 : * it's possible that its generic plan could be invalidated and regenerated
1556 : * while the current caller wasn't looking, and then there could be a chance
1557 : * collision of address between this caller's now-stale plan pointer and the
1558 : * actual address of the new generic plan. For current uses, that scenario
1559 : * can't happen; but with a plansource shared across multiple uses, it'd be
1560 : * advisable to also save plan->generation and verify that that still matches.
1561 : */
1562 : bool
1563 317812 : CachedPlanIsSimplyValid(CachedPlanSource *plansource, CachedPlan *plan,
1564 : ResourceOwner owner)
1565 : {
1566 : /*
1567 : * Careful here: since the caller doesn't necessarily hold a refcount on
1568 : * the plan to start with, it's possible that "plan" is a dangling
1569 : * pointer. Don't dereference it until we've verified that it still
1570 : * matches the plansource's gplan (which is either valid or NULL).
1571 : */
1572 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1573 :
1574 : /*
1575 : * Has cache invalidation fired on this plan? We can check this right
1576 : * away since there are no locks that we'd need to acquire first. Note
1577 : * that here we *do* check plansource->is_valid, so as to force plan
1578 : * rebuild if that's become false.
1579 : */
1580 317812 : if (!plansource->is_valid ||
1581 313642 : plan == NULL || plan != plansource->gplan ||
1582 313640 : !plan->is_valid)
1583 4184 : return false;
1584 :
1585 : Assert(plan->magic == CACHEDPLAN_MAGIC);
1586 :
1587 : /* Is the search_path still the same as when we made it? */
1588 : Assert(plansource->search_path != NULL);
1589 313628 : if (!SearchPathMatchesCurrentEnvironment(plansource->search_path))
1590 50 : return false;
1591 :
1592 : /* It's still good. Bump refcount if requested. */
1593 313578 : if (owner)
1594 : {
1595 50864 : ResourceOwnerEnlarge(owner);
1596 50864 : plan->refcount++;
1597 50864 : ResourceOwnerRememberPlanCacheRef(owner, plan);
1598 : }
1599 :
1600 313578 : return true;
1601 : }
1602 :
1603 : /*
1604 : * CachedPlanSetParentContext: move a CachedPlanSource to a new memory context
1605 : *
1606 : * This can only be applied to unsaved plans; once saved, a plan always
1607 : * lives underneath CacheMemoryContext.
1608 : */
1609 : void
1610 33296 : CachedPlanSetParentContext(CachedPlanSource *plansource,
1611 : MemoryContext newcontext)
1612 : {
1613 : /* Assert caller is doing things in a sane order */
1614 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1615 : Assert(plansource->is_complete);
1616 :
1617 : /* These seem worth real tests, though */
1618 33296 : if (plansource->is_saved)
1619 0 : elog(ERROR, "cannot move a saved cached plan to another context");
1620 33296 : if (plansource->is_oneshot)
1621 0 : elog(ERROR, "cannot move a one-shot cached plan to another context");
1622 :
1623 : /* OK, let the caller keep the plan where he wishes */
1624 33296 : MemoryContextSetParent(plansource->context, newcontext);
1625 :
1626 : /*
1627 : * The query_context needs no special handling, since it's a child of
1628 : * plansource->context. But if there's a generic plan, it should be
1629 : * maintained as a sibling of plansource->context.
1630 : */
1631 33296 : if (plansource->gplan)
1632 : {
1633 : Assert(plansource->gplan->magic == CACHEDPLAN_MAGIC);
1634 0 : MemoryContextSetParent(plansource->gplan->context, newcontext);
1635 : }
1636 33296 : }
1637 :
1638 : /*
1639 : * CopyCachedPlan: make a copy of a CachedPlanSource
1640 : *
1641 : * This is a convenience routine that does the equivalent of
1642 : * CreateCachedPlan + CompleteCachedPlan, using the data stored in the
1643 : * input CachedPlanSource. The result is therefore "unsaved" (regardless
1644 : * of the state of the source), and we don't copy any generic plan either.
1645 : * The result will be currently valid, or not, the same as the source.
1646 : */
1647 : CachedPlanSource *
1648 0 : CopyCachedPlan(CachedPlanSource *plansource)
1649 : {
1650 : CachedPlanSource *newsource;
1651 : MemoryContext source_context;
1652 : MemoryContext querytree_context;
1653 : MemoryContext oldcxt;
1654 :
1655 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1656 : Assert(plansource->is_complete);
1657 :
1658 : /*
1659 : * One-shot plans can't be copied, because we haven't taken care that
1660 : * parsing/planning didn't scribble on the raw parse tree or querytrees.
1661 : */
1662 0 : if (plansource->is_oneshot)
1663 0 : elog(ERROR, "cannot copy a one-shot cached plan");
1664 :
1665 0 : source_context = AllocSetContextCreate(CurrentMemoryContext,
1666 : "CachedPlanSource",
1667 : ALLOCSET_START_SMALL_SIZES);
1668 :
1669 0 : oldcxt = MemoryContextSwitchTo(source_context);
1670 :
1671 0 : newsource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
1672 0 : newsource->magic = CACHEDPLANSOURCE_MAGIC;
1673 0 : newsource->raw_parse_tree = copyObject(plansource->raw_parse_tree);
1674 0 : newsource->analyzed_parse_tree = copyObject(plansource->analyzed_parse_tree);
1675 0 : newsource->query_string = pstrdup(plansource->query_string);
1676 0 : MemoryContextSetIdentifier(source_context, newsource->query_string);
1677 0 : newsource->commandTag = plansource->commandTag;
1678 0 : if (plansource->num_params > 0)
1679 : {
1680 0 : newsource->param_types = (Oid *)
1681 0 : palloc(plansource->num_params * sizeof(Oid));
1682 0 : memcpy(newsource->param_types, plansource->param_types,
1683 0 : plansource->num_params * sizeof(Oid));
1684 : }
1685 : else
1686 0 : newsource->param_types = NULL;
1687 0 : newsource->num_params = plansource->num_params;
1688 0 : newsource->parserSetup = plansource->parserSetup;
1689 0 : newsource->parserSetupArg = plansource->parserSetupArg;
1690 0 : newsource->postRewrite = plansource->postRewrite;
1691 0 : newsource->postRewriteArg = plansource->postRewriteArg;
1692 0 : newsource->cursor_options = plansource->cursor_options;
1693 0 : newsource->fixed_result = plansource->fixed_result;
1694 0 : if (plansource->resultDesc)
1695 0 : newsource->resultDesc = CreateTupleDescCopy(plansource->resultDesc);
1696 : else
1697 0 : newsource->resultDesc = NULL;
1698 0 : newsource->context = source_context;
1699 :
1700 0 : querytree_context = AllocSetContextCreate(source_context,
1701 : "CachedPlanQuery",
1702 : ALLOCSET_START_SMALL_SIZES);
1703 0 : MemoryContextSwitchTo(querytree_context);
1704 0 : newsource->query_list = copyObject(plansource->query_list);
1705 0 : newsource->relationOids = copyObject(plansource->relationOids);
1706 0 : newsource->invalItems = copyObject(plansource->invalItems);
1707 0 : if (plansource->search_path)
1708 0 : newsource->search_path = CopySearchPathMatcher(plansource->search_path);
1709 0 : newsource->query_context = querytree_context;
1710 0 : newsource->rewriteRoleId = plansource->rewriteRoleId;
1711 0 : newsource->rewriteRowSecurity = plansource->rewriteRowSecurity;
1712 0 : newsource->dependsOnRLS = plansource->dependsOnRLS;
1713 :
1714 0 : newsource->gplan = NULL;
1715 :
1716 0 : newsource->is_oneshot = false;
1717 0 : newsource->is_complete = true;
1718 0 : newsource->is_saved = false;
1719 0 : newsource->is_valid = plansource->is_valid;
1720 0 : newsource->generation = plansource->generation;
1721 :
1722 : /* We may as well copy any acquired cost knowledge */
1723 0 : newsource->generic_cost = plansource->generic_cost;
1724 0 : newsource->total_custom_cost = plansource->total_custom_cost;
1725 0 : newsource->num_generic_plans = plansource->num_generic_plans;
1726 0 : newsource->num_custom_plans = plansource->num_custom_plans;
1727 :
1728 0 : MemoryContextSwitchTo(oldcxt);
1729 :
1730 0 : return newsource;
1731 : }
1732 :
1733 : /*
1734 : * CachedPlanIsValid: test whether the rewritten querytree within a
1735 : * CachedPlanSource is currently valid (that is, not marked as being in need
1736 : * of revalidation).
1737 : *
1738 : * This result is only trustworthy (ie, free from race conditions) if
1739 : * the caller has acquired locks on all the relations used in the plan.
1740 : */
1741 : bool
1742 3630 : CachedPlanIsValid(CachedPlanSource *plansource)
1743 : {
1744 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1745 3630 : return plansource->is_valid;
1746 : }
1747 :
1748 : /*
1749 : * CachedPlanGetTargetList: return tlist, if any, describing plan's output
1750 : *
1751 : * The result is guaranteed up-to-date. However, it is local storage
1752 : * within the cached plan, and may disappear next time the plan is updated.
1753 : */
1754 : List *
1755 19834 : CachedPlanGetTargetList(CachedPlanSource *plansource,
1756 : QueryEnvironment *queryEnv)
1757 : {
1758 : Query *pstmt;
1759 :
1760 : /* Assert caller is doing things in a sane order */
1761 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1762 : Assert(plansource->is_complete);
1763 :
1764 : /*
1765 : * No work needed if statement doesn't return tuples (we assume this
1766 : * feature cannot be changed by an invalidation)
1767 : */
1768 19834 : if (plansource->resultDesc == NULL)
1769 0 : return NIL;
1770 :
1771 : /* Make sure the querytree list is valid and we have parse-time locks */
1772 19834 : RevalidateCachedQuery(plansource, queryEnv);
1773 :
1774 : /* Get the primary statement and find out what it returns */
1775 19834 : pstmt = QueryListGetPrimaryStmt(plansource->query_list);
1776 :
1777 19834 : return FetchStatementTargetList((Node *) pstmt);
1778 : }
1779 :
1780 : /*
1781 : * GetCachedExpression: construct a CachedExpression for an expression.
1782 : *
1783 : * This performs the same transformations on the expression as
1784 : * expression_planner(), ie, convert an expression as emitted by parse
1785 : * analysis to be ready to pass to the executor.
1786 : *
1787 : * The result is stashed in a private, long-lived memory context.
1788 : * (Note that this might leak a good deal of memory in the caller's
1789 : * context before that.) The passed-in expr tree is not modified.
1790 : */
1791 : CachedExpression *
1792 364 : GetCachedExpression(Node *expr)
1793 : {
1794 : CachedExpression *cexpr;
1795 : List *relationOids;
1796 : List *invalItems;
1797 : MemoryContext cexpr_context;
1798 : MemoryContext oldcxt;
1799 :
1800 : /*
1801 : * Pass the expression through the planner, and collect dependencies.
1802 : * Everything built here is leaked in the caller's context; that's
1803 : * intentional to minimize the size of the permanent data structure.
1804 : */
1805 364 : expr = (Node *) expression_planner_with_deps((Expr *) expr,
1806 : &relationOids,
1807 : &invalItems);
1808 :
1809 : /*
1810 : * Make a private memory context, and copy what we need into that. To
1811 : * avoid leaking a long-lived context if we fail while copying data, we
1812 : * initially make the context under the caller's context.
1813 : */
1814 364 : cexpr_context = AllocSetContextCreate(CurrentMemoryContext,
1815 : "CachedExpression",
1816 : ALLOCSET_SMALL_SIZES);
1817 :
1818 364 : oldcxt = MemoryContextSwitchTo(cexpr_context);
1819 :
1820 364 : cexpr = (CachedExpression *) palloc(sizeof(CachedExpression));
1821 364 : cexpr->magic = CACHEDEXPR_MAGIC;
1822 364 : cexpr->expr = copyObject(expr);
1823 364 : cexpr->is_valid = true;
1824 364 : cexpr->relationOids = copyObject(relationOids);
1825 364 : cexpr->invalItems = copyObject(invalItems);
1826 364 : cexpr->context = cexpr_context;
1827 :
1828 364 : MemoryContextSwitchTo(oldcxt);
1829 :
1830 : /*
1831 : * Reparent the expr's memory context under CacheMemoryContext so that it
1832 : * will live indefinitely.
1833 : */
1834 364 : MemoryContextSetParent(cexpr_context, CacheMemoryContext);
1835 :
1836 : /*
1837 : * Add the entry to the global list of cached expressions.
1838 : */
1839 364 : dlist_push_tail(&cached_expression_list, &cexpr->node);
1840 :
1841 364 : return cexpr;
1842 : }
1843 :
1844 : /*
1845 : * FreeCachedExpression
1846 : * Delete a CachedExpression.
1847 : */
1848 : void
1849 54 : FreeCachedExpression(CachedExpression *cexpr)
1850 : {
1851 : /* Sanity check */
1852 : Assert(cexpr->magic == CACHEDEXPR_MAGIC);
1853 : /* Unlink from global list */
1854 54 : dlist_delete(&cexpr->node);
1855 : /* Free all storage associated with CachedExpression */
1856 54 : MemoryContextDelete(cexpr->context);
1857 54 : }
1858 :
1859 : /*
1860 : * QueryListGetPrimaryStmt
1861 : * Get the "primary" stmt within a list, ie, the one marked canSetTag.
1862 : *
1863 : * Returns NULL if no such stmt. If multiple queries within the list are
1864 : * marked canSetTag, returns the first one. Neither of these cases should
1865 : * occur in present usages of this function.
1866 : */
1867 : static Query *
1868 20136 : QueryListGetPrimaryStmt(List *stmts)
1869 : {
1870 : ListCell *lc;
1871 :
1872 20136 : foreach(lc, stmts)
1873 : {
1874 20136 : Query *stmt = lfirst_node(Query, lc);
1875 :
1876 20136 : if (stmt->canSetTag)
1877 20136 : return stmt;
1878 : }
1879 0 : return NULL;
1880 : }
1881 :
1882 : /*
1883 : * AcquireExecutorLocks: acquire locks needed for execution of a cached plan;
1884 : * or release them if acquire is false.
1885 : */
1886 : static void
1887 184356 : AcquireExecutorLocks(List *stmt_list, bool acquire)
1888 : {
1889 : ListCell *lc1;
1890 :
1891 368712 : foreach(lc1, stmt_list)
1892 : {
1893 184356 : PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc1);
1894 : ListCell *lc2;
1895 :
1896 184356 : if (plannedstmt->commandType == CMD_UTILITY)
1897 20846 : {
1898 : /*
1899 : * Ignore utility statements, except those (such as EXPLAIN) that
1900 : * contain a parsed-but-not-planned query. Note: it's okay to use
1901 : * ScanQueryForLocks, even though the query hasn't been through
1902 : * rule rewriting, because rewriting doesn't change the query
1903 : * representation.
1904 : */
1905 20846 : Query *query = UtilityContainsQuery(plannedstmt->utilityStmt);
1906 :
1907 20846 : if (query)
1908 4 : ScanQueryForLocks(query, acquire);
1909 20846 : continue;
1910 : }
1911 :
1912 374158 : foreach(lc2, plannedstmt->rtable)
1913 : {
1914 210648 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
1915 :
1916 210648 : if (!(rte->rtekind == RTE_RELATION ||
1917 140388 : (rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid))))
1918 137088 : continue;
1919 :
1920 : /*
1921 : * Acquire the appropriate type of lock on each relation OID. Note
1922 : * that we don't actually try to open the rel, and hence will not
1923 : * fail if it's been dropped entirely --- we'll just transiently
1924 : * acquire a non-conflicting lock.
1925 : */
1926 73560 : if (acquire)
1927 73560 : LockRelationOid(rte->relid, rte->rellockmode);
1928 : else
1929 0 : UnlockRelationOid(rte->relid, rte->rellockmode);
1930 : }
1931 : }
1932 184356 : }
1933 :
1934 : /*
1935 : * AcquirePlannerLocks: acquire locks needed for planning of a querytree list;
1936 : * or release them if acquire is false.
1937 : *
1938 : * Note that we don't actually try to open the relations, and hence will not
1939 : * fail if one has been dropped entirely --- we'll just transiently acquire
1940 : * a non-conflicting lock.
1941 : */
1942 : static void
1943 256574 : AcquirePlannerLocks(List *stmt_list, bool acquire)
1944 : {
1945 : ListCell *lc;
1946 :
1947 513148 : foreach(lc, stmt_list)
1948 : {
1949 256574 : Query *query = lfirst_node(Query, lc);
1950 :
1951 256574 : if (query->commandType == CMD_UTILITY)
1952 : {
1953 : /* Ignore utility statements, unless they contain a Query */
1954 10036 : query = UtilityContainsQuery(query->utilityStmt);
1955 10036 : if (query)
1956 9776 : ScanQueryForLocks(query, acquire);
1957 10036 : continue;
1958 : }
1959 :
1960 246538 : ScanQueryForLocks(query, acquire);
1961 : }
1962 256574 : }
1963 :
1964 : /*
1965 : * ScanQueryForLocks: recursively scan one Query for AcquirePlannerLocks.
1966 : */
1967 : static void
1968 279320 : ScanQueryForLocks(Query *parsetree, bool acquire)
1969 : {
1970 : ListCell *lc;
1971 :
1972 : /* Shouldn't get called on utility commands */
1973 : Assert(parsetree->commandType != CMD_UTILITY);
1974 :
1975 : /*
1976 : * First, process RTEs of the current query level.
1977 : */
1978 482046 : foreach(lc, parsetree->rtable)
1979 : {
1980 202726 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
1981 :
1982 202726 : switch (rte->rtekind)
1983 : {
1984 146800 : case RTE_RELATION:
1985 : /* Acquire or release the appropriate type of lock */
1986 146800 : if (acquire)
1987 146784 : LockRelationOid(rte->relid, rte->rellockmode);
1988 : else
1989 16 : UnlockRelationOid(rte->relid, rte->rellockmode);
1990 146800 : break;
1991 :
1992 17574 : case RTE_SUBQUERY:
1993 : /* If this was a view, must lock/unlock the view */
1994 17574 : if (OidIsValid(rte->relid))
1995 : {
1996 4566 : if (acquire)
1997 4566 : LockRelationOid(rte->relid, rte->rellockmode);
1998 : else
1999 0 : UnlockRelationOid(rte->relid, rte->rellockmode);
2000 : }
2001 : /* Recurse into subquery-in-FROM */
2002 17574 : ScanQueryForLocks(rte->subquery, acquire);
2003 17574 : break;
2004 :
2005 38352 : default:
2006 : /* ignore other types of RTEs */
2007 38352 : break;
2008 : }
2009 : }
2010 :
2011 : /* Recurse into subquery-in-WITH */
2012 279416 : foreach(lc, parsetree->cteList)
2013 : {
2014 96 : CommonTableExpr *cte = lfirst_node(CommonTableExpr, lc);
2015 :
2016 96 : ScanQueryForLocks(castNode(Query, cte->ctequery), acquire);
2017 : }
2018 :
2019 : /*
2020 : * Recurse into sublink subqueries, too. But we already did the ones in
2021 : * the rtable and cteList.
2022 : */
2023 279320 : if (parsetree->hasSubLinks)
2024 : {
2025 5166 : query_tree_walker(parsetree, ScanQueryWalker, &acquire,
2026 : QTW_IGNORE_RC_SUBQUERIES);
2027 : }
2028 279320 : }
2029 :
2030 : /*
2031 : * Walker to find sublink subqueries for ScanQueryForLocks
2032 : */
2033 : static bool
2034 141432 : ScanQueryWalker(Node *node, bool *acquire)
2035 : {
2036 141432 : if (node == NULL)
2037 63526 : return false;
2038 77906 : if (IsA(node, SubLink))
2039 : {
2040 5332 : SubLink *sub = (SubLink *) node;
2041 :
2042 : /* Do what we came for */
2043 5332 : ScanQueryForLocks(castNode(Query, sub->subselect), *acquire);
2044 : /* Fall through to process lefthand args of SubLink */
2045 : }
2046 :
2047 : /*
2048 : * Do NOT recurse into Query nodes, because ScanQueryForLocks already
2049 : * processed subselects of subselects for us.
2050 : */
2051 77906 : return expression_tree_walker(node, ScanQueryWalker, acquire);
2052 : }
2053 :
2054 : /*
2055 : * PlanCacheComputeResultDesc: given a list of analyzed-and-rewritten Queries,
2056 : * determine the result tupledesc it will produce. Returns NULL if the
2057 : * execution will not return tuples.
2058 : *
2059 : * Note: the result is created or copied into current memory context.
2060 : */
2061 : static TupleDesc
2062 83662 : PlanCacheComputeResultDesc(List *stmt_list)
2063 : {
2064 : Query *query;
2065 :
2066 83662 : switch (ChoosePortalStrategy(stmt_list))
2067 : {
2068 55264 : case PORTAL_ONE_SELECT:
2069 : case PORTAL_ONE_MOD_WITH:
2070 55264 : query = linitial_node(Query, stmt_list);
2071 55264 : return ExecCleanTypeFromTL(query->targetList);
2072 :
2073 302 : case PORTAL_ONE_RETURNING:
2074 302 : query = QueryListGetPrimaryStmt(stmt_list);
2075 : Assert(query->returningList);
2076 302 : return ExecCleanTypeFromTL(query->returningList);
2077 :
2078 10050 : case PORTAL_UTIL_SELECT:
2079 10050 : query = linitial_node(Query, stmt_list);
2080 : Assert(query->utilityStmt);
2081 10050 : return UtilityTupleDescriptor(query->utilityStmt);
2082 :
2083 18046 : case PORTAL_MULTI_QUERY:
2084 : /* will not return tuples */
2085 18046 : break;
2086 : }
2087 18046 : return NULL;
2088 : }
2089 :
2090 : /*
2091 : * PlanCacheRelCallback
2092 : * Relcache inval callback function
2093 : *
2094 : * Invalidate all plans mentioning the given rel, or all plans mentioning
2095 : * any rel at all if relid == InvalidOid.
2096 : */
2097 : static void
2098 3065868 : PlanCacheRelCallback(Datum arg, Oid relid)
2099 : {
2100 : dlist_iter iter;
2101 :
2102 58275248 : dlist_foreach(iter, &saved_plan_list)
2103 : {
2104 55209380 : CachedPlanSource *plansource = dlist_container(CachedPlanSource,
2105 : node, iter.cur);
2106 :
2107 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
2108 :
2109 : /* No work if it's already invalidated */
2110 55209380 : if (!plansource->is_valid)
2111 34665198 : continue;
2112 :
2113 : /* Never invalidate if parse/plan would be a no-op anyway */
2114 20544182 : if (!StmtPlanRequiresRevalidation(plansource))
2115 339634 : continue;
2116 :
2117 : /*
2118 : * Check the dependency list for the rewritten querytree.
2119 : */
2120 40409084 : if ((relid == InvalidOid) ? plansource->relationOids != NIL :
2121 20204536 : list_member_oid(plansource->relationOids, relid))
2122 : {
2123 : /* Invalidate the querytree and generic plan */
2124 3714 : plansource->is_valid = false;
2125 3714 : if (plansource->gplan)
2126 1186 : plansource->gplan->is_valid = false;
2127 : }
2128 :
2129 : /*
2130 : * The generic plan, if any, could have more dependencies than the
2131 : * querytree does, so we have to check it too.
2132 : */
2133 20204548 : if (plansource->gplan && plansource->gplan->is_valid)
2134 : {
2135 : ListCell *lc;
2136 :
2137 38177874 : foreach(lc, plansource->gplan->stmt_list)
2138 : {
2139 19088978 : PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
2140 :
2141 19088978 : if (plannedstmt->commandType == CMD_UTILITY)
2142 4348 : continue; /* Ignore utility statements */
2143 38169260 : if ((relid == InvalidOid) ? plannedstmt->relationOids != NIL :
2144 19084630 : list_member_oid(plannedstmt->relationOids, relid))
2145 : {
2146 : /* Invalidate the generic plan only */
2147 82 : plansource->gplan->is_valid = false;
2148 82 : break; /* out of stmt_list scan */
2149 : }
2150 : }
2151 : }
2152 : }
2153 :
2154 : /* Likewise check cached expressions */
2155 3373218 : dlist_foreach(iter, &cached_expression_list)
2156 : {
2157 307350 : CachedExpression *cexpr = dlist_container(CachedExpression,
2158 : node, iter.cur);
2159 :
2160 : Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2161 :
2162 : /* No work if it's already invalidated */
2163 307350 : if (!cexpr->is_valid)
2164 145852 : continue;
2165 :
2166 322996 : if ((relid == InvalidOid) ? cexpr->relationOids != NIL :
2167 161498 : list_member_oid(cexpr->relationOids, relid))
2168 : {
2169 0 : cexpr->is_valid = false;
2170 : }
2171 : }
2172 3065868 : }
2173 :
2174 : /*
2175 : * PlanCacheObjectCallback
2176 : * Syscache inval callback function for PROCOID and TYPEOID caches
2177 : *
2178 : * Invalidate all plans mentioning the object with the specified hash value,
2179 : * or all plans mentioning any member of this cache if hashvalue == 0.
2180 : */
2181 : static void
2182 1143840 : PlanCacheObjectCallback(Datum arg, int cacheid, uint32 hashvalue)
2183 : {
2184 : dlist_iter iter;
2185 :
2186 22804696 : dlist_foreach(iter, &saved_plan_list)
2187 : {
2188 21660856 : CachedPlanSource *plansource = dlist_container(CachedPlanSource,
2189 : node, iter.cur);
2190 : ListCell *lc;
2191 :
2192 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
2193 :
2194 : /* No work if it's already invalidated */
2195 21660856 : if (!plansource->is_valid)
2196 13093032 : continue;
2197 :
2198 : /* Never invalidate if parse/plan would be a no-op anyway */
2199 8567824 : if (!StmtPlanRequiresRevalidation(plansource))
2200 86560 : continue;
2201 :
2202 : /*
2203 : * Check the dependency list for the rewritten querytree.
2204 : */
2205 8624568 : foreach(lc, plansource->invalItems)
2206 : {
2207 143452 : PlanInvalItem *item = (PlanInvalItem *) lfirst(lc);
2208 :
2209 143452 : if (item->cacheId != cacheid)
2210 96630 : continue;
2211 46822 : if (hashvalue == 0 ||
2212 46822 : item->hashValue == hashvalue)
2213 : {
2214 : /* Invalidate the querytree and generic plan */
2215 148 : plansource->is_valid = false;
2216 148 : if (plansource->gplan)
2217 144 : plansource->gplan->is_valid = false;
2218 148 : break;
2219 : }
2220 : }
2221 :
2222 : /*
2223 : * The generic plan, if any, could have more dependencies than the
2224 : * querytree does, so we have to check it too.
2225 : */
2226 8481264 : if (plansource->gplan && plansource->gplan->is_valid)
2227 : {
2228 15896612 : foreach(lc, plansource->gplan->stmt_list)
2229 : {
2230 7948318 : PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
2231 : ListCell *lc3;
2232 :
2233 7948318 : if (plannedstmt->commandType == CMD_UTILITY)
2234 2628 : continue; /* Ignore utility statements */
2235 8082442 : foreach(lc3, plannedstmt->invalItems)
2236 : {
2237 136776 : PlanInvalItem *item = (PlanInvalItem *) lfirst(lc3);
2238 :
2239 136776 : if (item->cacheId != cacheid)
2240 91544 : continue;
2241 45232 : if (hashvalue == 0 ||
2242 45232 : item->hashValue == hashvalue)
2243 : {
2244 : /* Invalidate the generic plan only */
2245 24 : plansource->gplan->is_valid = false;
2246 24 : break; /* out of invalItems scan */
2247 : }
2248 : }
2249 7945690 : if (!plansource->gplan->is_valid)
2250 24 : break; /* out of stmt_list scan */
2251 : }
2252 : }
2253 : }
2254 :
2255 : /* Likewise check cached expressions */
2256 1290158 : dlist_foreach(iter, &cached_expression_list)
2257 : {
2258 146318 : CachedExpression *cexpr = dlist_container(CachedExpression,
2259 : node, iter.cur);
2260 : ListCell *lc;
2261 :
2262 : Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2263 :
2264 : /* No work if it's already invalidated */
2265 146318 : if (!cexpr->is_valid)
2266 57180 : continue;
2267 :
2268 89158 : foreach(lc, cexpr->invalItems)
2269 : {
2270 26 : PlanInvalItem *item = (PlanInvalItem *) lfirst(lc);
2271 :
2272 26 : if (item->cacheId != cacheid)
2273 8 : continue;
2274 18 : if (hashvalue == 0 ||
2275 18 : item->hashValue == hashvalue)
2276 : {
2277 6 : cexpr->is_valid = false;
2278 6 : break;
2279 : }
2280 : }
2281 : }
2282 1143840 : }
2283 :
2284 : /*
2285 : * PlanCacheSysCallback
2286 : * Syscache inval callback function for other caches
2287 : *
2288 : * Just invalidate everything...
2289 : */
2290 : static void
2291 68790 : PlanCacheSysCallback(Datum arg, int cacheid, uint32 hashvalue)
2292 : {
2293 68790 : ResetPlanCache();
2294 68790 : }
2295 :
2296 : /*
2297 : * ResetPlanCache: invalidate all cached plans.
2298 : */
2299 : void
2300 69724 : ResetPlanCache(void)
2301 : {
2302 : dlist_iter iter;
2303 :
2304 287018 : dlist_foreach(iter, &saved_plan_list)
2305 : {
2306 217294 : CachedPlanSource *plansource = dlist_container(CachedPlanSource,
2307 : node, iter.cur);
2308 :
2309 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
2310 :
2311 : /* No work if it's already invalidated */
2312 217294 : if (!plansource->is_valid)
2313 198680 : continue;
2314 :
2315 : /*
2316 : * We *must not* mark transaction control statements as invalid,
2317 : * particularly not ROLLBACK, because they may need to be executed in
2318 : * aborted transactions when we can't revalidate them (cf bug #5269).
2319 : * In general there's no point in invalidating statements for which a
2320 : * new parse analysis/rewrite/plan cycle would certainly give the same
2321 : * results.
2322 : */
2323 18614 : if (!StmtPlanRequiresRevalidation(plansource))
2324 5052 : continue;
2325 :
2326 13562 : plansource->is_valid = false;
2327 13562 : if (plansource->gplan)
2328 12242 : plansource->gplan->is_valid = false;
2329 : }
2330 :
2331 : /* Likewise invalidate cached expressions */
2332 70810 : dlist_foreach(iter, &cached_expression_list)
2333 : {
2334 1086 : CachedExpression *cexpr = dlist_container(CachedExpression,
2335 : node, iter.cur);
2336 :
2337 : Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2338 :
2339 1086 : cexpr->is_valid = false;
2340 : }
2341 69724 : }
2342 :
2343 : /*
2344 : * Release all CachedPlans remembered by 'owner'
2345 : */
2346 : void
2347 16386 : ReleaseAllPlanCacheRefsInOwner(ResourceOwner owner)
2348 : {
2349 16386 : ResourceOwnerReleaseAllOfKind(owner, &planref_resowner_desc);
2350 16386 : }
2351 :
2352 : /* ResourceOwner callbacks */
2353 :
2354 : static void
2355 90368 : ResOwnerReleaseCachedPlan(Datum res)
2356 : {
2357 90368 : ReleaseCachedPlan((CachedPlan *) DatumGetPointer(res), NULL);
2358 90368 : }
|