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 296720 : ResourceOwnerRememberPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
127 : {
128 296720 : ResourceOwnerRemember(owner, PointerGetDatum(plan), &planref_resowner_desc);
129 296720 : }
130 : static inline void
131 206206 : ResourceOwnerForgetPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
132 : {
133 206206 : ResourceOwnerForget(owner, PointerGetDatum(plan), &planref_resowner_desc);
134 206206 : }
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 36004 : InitPlanCache(void)
147 : {
148 36004 : CacheRegisterRelcacheCallback(PlanCacheRelCallback, (Datum) 0);
149 36004 : CacheRegisterSyscacheCallback(PROCOID, PlanCacheObjectCallback, (Datum) 0);
150 36004 : CacheRegisterSyscacheCallback(TYPEOID, PlanCacheObjectCallback, (Datum) 0);
151 36004 : CacheRegisterSyscacheCallback(NAMESPACEOID, PlanCacheSysCallback, (Datum) 0);
152 36004 : CacheRegisterSyscacheCallback(OPEROID, PlanCacheSysCallback, (Datum) 0);
153 36004 : CacheRegisterSyscacheCallback(AMOPOPID, PlanCacheSysCallback, (Datum) 0);
154 36004 : CacheRegisterSyscacheCallback(FOREIGNSERVEROID, PlanCacheSysCallback, (Datum) 0);
155 36004 : CacheRegisterSyscacheCallback(FOREIGNDATAWRAPPEROID, PlanCacheSysCallback, (Datum) 0);
156 36004 : }
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 57832 : 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 57832 : 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 57832 : oldcxt = MemoryContextSwitchTo(source_context);
209 :
210 57832 : plansource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
211 57832 : plansource->magic = CACHEDPLANSOURCE_MAGIC;
212 57832 : plansource->raw_parse_tree = copyObject(raw_parse_tree);
213 57832 : plansource->analyzed_parse_tree = NULL;
214 57832 : plansource->query_string = pstrdup(query_string);
215 57832 : MemoryContextSetIdentifier(source_context, plansource->query_string);
216 57832 : plansource->commandTag = commandTag;
217 57832 : plansource->param_types = NULL;
218 57832 : plansource->num_params = 0;
219 57832 : plansource->parserSetup = NULL;
220 57832 : plansource->parserSetupArg = NULL;
221 57832 : plansource->postRewrite = NULL;
222 57832 : plansource->postRewriteArg = NULL;
223 57832 : plansource->cursor_options = 0;
224 57832 : plansource->fixed_result = false;
225 57832 : plansource->resultDesc = NULL;
226 57832 : plansource->context = source_context;
227 57832 : plansource->query_list = NIL;
228 57832 : plansource->relationOids = NIL;
229 57832 : plansource->invalItems = NIL;
230 57832 : plansource->search_path = NULL;
231 57832 : plansource->query_context = NULL;
232 57832 : plansource->rewriteRoleId = InvalidOid;
233 57832 : plansource->rewriteRowSecurity = false;
234 57832 : plansource->dependsOnRLS = false;
235 57832 : plansource->gplan = NULL;
236 57832 : plansource->is_oneshot = false;
237 57832 : plansource->is_complete = false;
238 57832 : plansource->is_saved = false;
239 57832 : plansource->is_valid = false;
240 57832 : plansource->generation = 0;
241 57832 : plansource->generic_cost = -1;
242 57832 : plansource->total_custom_cost = 0;
243 57832 : plansource->num_generic_plans = 0;
244 57832 : plansource->num_custom_plans = 0;
245 :
246 57832 : MemoryContextSwitchTo(oldcxt);
247 :
248 57832 : 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 778 : 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 778 : plansource = CreateCachedPlan(NULL, query_string, commandTag);
272 778 : oldcxt = MemoryContextSwitchTo(plansource->context);
273 778 : plansource->analyzed_parse_tree = copyObject(analyzed_parse_tree);
274 778 : MemoryContextSwitchTo(oldcxt);
275 :
276 778 : 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 77476 : 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 77476 : MemoryContext source_context = plansource->context;
402 77476 : 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 77476 : if (plansource->is_oneshot)
416 : {
417 19776 : querytree_context = CurrentMemoryContext;
418 : }
419 57700 : else if (querytree_context != NULL)
420 : {
421 6654 : MemoryContextSetParent(querytree_context, source_context);
422 6654 : MemoryContextSwitchTo(querytree_context);
423 : }
424 : else
425 : {
426 : /* Again, it's a good bet the querytree_context can be small */
427 51046 : querytree_context = AllocSetContextCreate(source_context,
428 : "CachedPlanQuery",
429 : ALLOCSET_START_SMALL_SIZES);
430 51046 : MemoryContextSwitchTo(querytree_context);
431 51046 : querytree_list = copyObject(querytree_list);
432 : }
433 :
434 77476 : plansource->query_context = querytree_context;
435 77476 : plansource->query_list = querytree_list;
436 :
437 77476 : 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 55770 : extract_query_dependencies((Node *) querytree_list,
446 : &plansource->relationOids,
447 : &plansource->invalItems,
448 : &plansource->dependsOnRLS);
449 :
450 : /* Update RLS info as well. */
451 55770 : plansource->rewriteRoleId = GetUserId();
452 55770 : 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 55770 : plansource->search_path = GetSearchPathMatcher(querytree_context);
462 : }
463 :
464 : /*
465 : * Save the final parameter types (or other parameter specification data)
466 : * into the source_context, as well as our other parameters.
467 : */
468 77476 : MemoryContextSwitchTo(source_context);
469 :
470 77476 : if (num_params > 0)
471 : {
472 14062 : plansource->param_types = (Oid *) palloc(num_params * sizeof(Oid));
473 14062 : memcpy(plansource->param_types, param_types, num_params * sizeof(Oid));
474 : }
475 : else
476 63414 : plansource->param_types = NULL;
477 77476 : plansource->num_params = num_params;
478 77476 : plansource->parserSetup = parserSetup;
479 77476 : plansource->parserSetupArg = parserSetupArg;
480 77476 : plansource->cursor_options = cursor_options;
481 77476 : plansource->fixed_result = fixed_result;
482 :
483 : /*
484 : * Also save the result tuple descriptor. PlanCacheComputeResultDesc may
485 : * leak some cruft; normally we just accept that to save a copy step, but
486 : * in USE_VALGRIND mode be tidy by running it in the caller's context.
487 : */
488 : #ifdef USE_VALGRIND
489 : MemoryContextSwitchTo(oldcxt);
490 : plansource->resultDesc = PlanCacheComputeResultDesc(querytree_list);
491 : if (plansource->resultDesc)
492 : {
493 : MemoryContextSwitchTo(source_context);
494 : plansource->resultDesc = CreateTupleDescCopy(plansource->resultDesc);
495 : MemoryContextSwitchTo(oldcxt);
496 : }
497 : #else
498 77476 : plansource->resultDesc = PlanCacheComputeResultDesc(querytree_list);
499 77476 : MemoryContextSwitchTo(oldcxt);
500 : #endif
501 :
502 77476 : plansource->is_complete = true;
503 77476 : plansource->is_valid = true;
504 77476 : }
505 :
506 : /*
507 : * SetPostRewriteHook: set a hook to modify post-rewrite query trees
508 : *
509 : * Some callers have a need to modify the query trees between rewriting and
510 : * planning. In the initial call to CompleteCachedPlan, it's assumed such
511 : * work was already done on the querytree_list. However, if we're forced
512 : * to replan, it will need to be done over. The caller can set this hook
513 : * to provide code to make that happen.
514 : *
515 : * postRewriteArg is just passed verbatim to the hook. As with parserSetupArg,
516 : * it is caller's responsibility that the referenced data remains
517 : * valid for as long as the CachedPlanSource exists.
518 : */
519 : void
520 2104 : SetPostRewriteHook(CachedPlanSource *plansource,
521 : PostRewriteHook postRewrite,
522 : void *postRewriteArg)
523 : {
524 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
525 2104 : plansource->postRewrite = postRewrite;
526 2104 : plansource->postRewriteArg = postRewriteArg;
527 2104 : }
528 :
529 : /*
530 : * SaveCachedPlan: save a cached plan permanently
531 : *
532 : * This function moves the cached plan underneath CacheMemoryContext (making
533 : * it live for the life of the backend, unless explicitly dropped), and adds
534 : * it to the list of cached plans that are checked for invalidation when an
535 : * sinval event occurs.
536 : *
537 : * This is guaranteed not to throw error, except for the caller-error case
538 : * of trying to save a one-shot plan. Callers typically depend on that
539 : * since this is called just before or just after adding a pointer to the
540 : * CachedPlanSource to some permanent data structure of their own. Up until
541 : * this is done, a CachedPlanSource is just transient data that will go away
542 : * automatically on transaction abort.
543 : */
544 : void
545 46762 : SaveCachedPlan(CachedPlanSource *plansource)
546 : {
547 : /* Assert caller is doing things in a sane order */
548 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
549 : Assert(plansource->is_complete);
550 : Assert(!plansource->is_saved);
551 :
552 : /* This seems worth a real test, though */
553 46762 : if (plansource->is_oneshot)
554 0 : elog(ERROR, "cannot save one-shot cached plan");
555 :
556 : /*
557 : * In typical use, this function would be called before generating any
558 : * plans from the CachedPlanSource. If there is a generic plan, moving it
559 : * into CacheMemoryContext would be pretty risky since it's unclear
560 : * whether the caller has taken suitable care with making references
561 : * long-lived. Best thing to do seems to be to discard the plan.
562 : */
563 46762 : ReleaseGenericPlan(plansource);
564 :
565 : /*
566 : * Reparent the source memory context under CacheMemoryContext so that it
567 : * will live indefinitely. The query_context follows along since it's
568 : * already a child of the other one.
569 : */
570 46762 : MemoryContextSetParent(plansource->context, CacheMemoryContext);
571 :
572 : /*
573 : * Add the entry to the global list of cached plans.
574 : */
575 46762 : dlist_push_tail(&saved_plan_list, &plansource->node);
576 :
577 46762 : plansource->is_saved = true;
578 46762 : }
579 :
580 : /*
581 : * DropCachedPlan: destroy a cached plan.
582 : *
583 : * Actually this only destroys the CachedPlanSource: any referenced CachedPlan
584 : * is released, but not destroyed until its refcount goes to zero. That
585 : * handles the situation where DropCachedPlan is called while the plan is
586 : * still in use.
587 : */
588 : void
589 18146 : DropCachedPlan(CachedPlanSource *plansource)
590 : {
591 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
592 :
593 : /* If it's been saved, remove it from the list */
594 18146 : if (plansource->is_saved)
595 : {
596 17956 : dlist_delete(&plansource->node);
597 17956 : plansource->is_saved = false;
598 : }
599 :
600 : /* Decrement generic CachedPlan's refcount and drop if no longer needed */
601 18146 : ReleaseGenericPlan(plansource);
602 :
603 : /* Mark it no longer valid */
604 18146 : plansource->magic = 0;
605 :
606 : /*
607 : * Remove the CachedPlanSource and all subsidiary data (including the
608 : * query_context if any). But if it's a one-shot we can't free anything.
609 : */
610 18146 : if (!plansource->is_oneshot)
611 18146 : MemoryContextDelete(plansource->context);
612 18146 : }
613 :
614 : /*
615 : * ReleaseGenericPlan: release a CachedPlanSource's generic plan, if any.
616 : */
617 : static void
618 119360 : ReleaseGenericPlan(CachedPlanSource *plansource)
619 : {
620 : /* Be paranoid about the possibility that ReleaseCachedPlan fails */
621 119360 : if (plansource->gplan)
622 : {
623 14954 : CachedPlan *plan = plansource->gplan;
624 :
625 : Assert(plan->magic == CACHEDPLAN_MAGIC);
626 14954 : plansource->gplan = NULL;
627 14954 : ReleaseCachedPlan(plan, NULL);
628 : }
629 119360 : }
630 :
631 : /*
632 : * We must skip "overhead" operations that involve database access when the
633 : * cached plan's subject statement is a transaction control command or one
634 : * that requires a snapshot not to be set yet (such as SET or LOCK). More
635 : * generally, statements that do not require parse analysis/rewrite/plan
636 : * activity never need to be revalidated, so we can treat them all like that.
637 : * For the convenience of postgres.c, treat empty statements that way too.
638 : */
639 : static bool
640 37007512 : StmtPlanRequiresRevalidation(CachedPlanSource *plansource)
641 : {
642 37007512 : if (plansource->raw_parse_tree != NULL)
643 36482700 : return stmt_requires_parse_analysis(plansource->raw_parse_tree);
644 524812 : else if (plansource->analyzed_parse_tree != NULL)
645 524806 : return query_requires_rewrite_plan(plansource->analyzed_parse_tree);
646 : /* empty query never needs revalidation */
647 6 : return false;
648 : }
649 :
650 : /*
651 : * Determine if creating a plan for this CachedPlanSource requires a snapshot.
652 : * In fact this function matches StmtPlanRequiresRevalidation(), but we want
653 : * to preserve the distinction between stmt_requires_parse_analysis() and
654 : * analyze_requires_snapshot().
655 : */
656 : static bool
657 994 : BuildingPlanRequiresSnapshot(CachedPlanSource *plansource)
658 : {
659 994 : if (plansource->raw_parse_tree != NULL)
660 994 : return analyze_requires_snapshot(plansource->raw_parse_tree);
661 0 : else if (plansource->analyzed_parse_tree != NULL)
662 0 : return query_requires_rewrite_plan(plansource->analyzed_parse_tree);
663 : /* empty query never needs a snapshot */
664 0 : return false;
665 : }
666 :
667 : /*
668 : * RevalidateCachedQuery: ensure validity of analyzed-and-rewritten query tree.
669 : *
670 : * What we do here is re-acquire locks and redo parse analysis if necessary.
671 : * On return, the query_list is valid and we have sufficient locks to begin
672 : * planning.
673 : *
674 : * If any parse analysis activity is required, the caller's memory context is
675 : * used for that work.
676 : *
677 : * The result value is the transient analyzed-and-rewritten query tree if we
678 : * had to do re-analysis, and NIL otherwise. (This is returned just to save
679 : * a tree copying step in a subsequent BuildCachedPlan call.)
680 : */
681 : static List *
682 304372 : RevalidateCachedQuery(CachedPlanSource *plansource,
683 : QueryEnvironment *queryEnv)
684 : {
685 : bool snapshot_set;
686 : List *tlist; /* transient query-tree list */
687 : List *qlist; /* permanent query-tree list */
688 : TupleDesc resultDesc;
689 : MemoryContext querytree_context;
690 : MemoryContext oldcxt;
691 :
692 : /*
693 : * For one-shot plans, we do not support revalidation checking; it's
694 : * assumed the query is parsed, planned, and executed in one transaction,
695 : * so that no lock re-acquisition is necessary. Also, if the statement
696 : * type can't require revalidation, we needn't do anything (and we mustn't
697 : * risk catalog accesses when handling, eg, transaction control commands).
698 : */
699 304372 : if (plansource->is_oneshot || !StmtPlanRequiresRevalidation(plansource))
700 : {
701 : Assert(plansource->is_valid);
702 42340 : return NIL;
703 : }
704 :
705 : /*
706 : * If the query is currently valid, we should have a saved search_path ---
707 : * check to see if that matches the current environment. If not, we want
708 : * to force replan. (We could almost ignore this consideration when
709 : * working from an analyzed parse tree; but there are scenarios where
710 : * planning can have search_path-dependent results, for example if it
711 : * inlines an old-style SQL function.)
712 : */
713 262032 : if (plansource->is_valid)
714 : {
715 : Assert(plansource->search_path != NULL);
716 256038 : if (!SearchPathMatchesCurrentEnvironment(plansource->search_path))
717 : {
718 : /* Invalidate the querytree and generic plan */
719 86 : plansource->is_valid = false;
720 86 : if (plansource->gplan)
721 62 : plansource->gplan->is_valid = false;
722 : }
723 : }
724 :
725 : /*
726 : * If the query rewrite phase had a possible RLS dependency, we must redo
727 : * it if either the role or the row_security setting has changed.
728 : */
729 262332 : if (plansource->is_valid && plansource->dependsOnRLS &&
730 300 : (plansource->rewriteRoleId != GetUserId() ||
731 210 : plansource->rewriteRowSecurity != row_security))
732 114 : plansource->is_valid = false;
733 :
734 : /*
735 : * If the query is currently valid, acquire locks on the referenced
736 : * objects; then check again. We need to do it this way to cover the race
737 : * condition that an invalidation message arrives before we get the locks.
738 : */
739 262032 : if (plansource->is_valid)
740 : {
741 255838 : AcquirePlannerLocks(plansource->query_list, true);
742 :
743 : /*
744 : * By now, if any invalidation has happened, the inval callback
745 : * functions will have marked the query invalid.
746 : */
747 255838 : if (plansource->is_valid)
748 : {
749 : /* Successfully revalidated and locked the query. */
750 255818 : return NIL;
751 : }
752 :
753 : /* Oops, the race case happened. Release useless locks. */
754 20 : AcquirePlannerLocks(plansource->query_list, false);
755 : }
756 :
757 : /*
758 : * Discard the no-longer-useful rewritten query tree. (Note: we don't
759 : * want to do this any earlier, else we'd not have been able to release
760 : * locks correctly in the race condition case.)
761 : */
762 6214 : plansource->is_valid = false;
763 6214 : plansource->query_list = NIL;
764 6214 : plansource->relationOids = NIL;
765 6214 : plansource->invalItems = NIL;
766 6214 : plansource->search_path = NULL;
767 :
768 : /*
769 : * Free the query_context. We don't really expect MemoryContextDelete to
770 : * fail, but just in case, make sure the CachedPlanSource is left in a
771 : * reasonably sane state. (The generic plan won't get unlinked yet, but
772 : * that's acceptable.)
773 : */
774 6214 : if (plansource->query_context)
775 : {
776 6184 : MemoryContext qcxt = plansource->query_context;
777 :
778 6184 : plansource->query_context = NULL;
779 6184 : MemoryContextDelete(qcxt);
780 : }
781 :
782 : /* Drop the generic plan reference if any */
783 6214 : ReleaseGenericPlan(plansource);
784 :
785 : /*
786 : * Now re-do parse analysis and rewrite. This not incidentally acquires
787 : * the locks we need to do planning safely.
788 : */
789 : Assert(plansource->is_complete);
790 :
791 : /*
792 : * If a snapshot is already set (the normal case), we can just use that
793 : * for parsing/planning. But if it isn't, install one. Note: no point in
794 : * checking whether parse analysis requires a snapshot; utility commands
795 : * don't have invalidatable plans, so we'd not get here for such a
796 : * command.
797 : */
798 6214 : snapshot_set = false;
799 6214 : if (!ActiveSnapshotSet())
800 : {
801 20 : PushActiveSnapshot(GetTransactionSnapshot());
802 20 : snapshot_set = true;
803 : }
804 :
805 : /*
806 : * Run parse analysis (if needed) and rule rewriting.
807 : */
808 6214 : if (plansource->raw_parse_tree != NULL)
809 : {
810 : /* Source is raw parse tree */
811 : RawStmt *rawtree;
812 :
813 : /*
814 : * The parser tends to scribble on its input, so we must copy the raw
815 : * parse tree to prevent corruption of the cache.
816 : */
817 5948 : rawtree = copyObject(plansource->raw_parse_tree);
818 5948 : if (plansource->parserSetup != NULL)
819 5538 : tlist = pg_analyze_and_rewrite_withcb(rawtree,
820 : plansource->query_string,
821 : plansource->parserSetup,
822 : plansource->parserSetupArg,
823 : queryEnv);
824 : else
825 410 : tlist = pg_analyze_and_rewrite_fixedparams(rawtree,
826 : plansource->query_string,
827 410 : plansource->param_types,
828 : plansource->num_params,
829 : queryEnv);
830 : }
831 266 : else if (plansource->analyzed_parse_tree != NULL)
832 : {
833 : /* Source is pre-analyzed query, so we only need to rewrite */
834 : Query *analyzed_tree;
835 :
836 : /* The rewriter scribbles on its input, too, so copy */
837 266 : analyzed_tree = copyObject(plansource->analyzed_parse_tree);
838 : /* Acquire locks needed before rewriting ... */
839 266 : AcquireRewriteLocks(analyzed_tree, true, false);
840 : /* ... and do it */
841 266 : tlist = pg_rewrite_query(analyzed_tree);
842 : }
843 : else
844 : {
845 : /* Empty query, nothing to do */
846 0 : tlist = NIL;
847 : }
848 :
849 : /* Apply post-rewrite callback if there is one */
850 6174 : if (plansource->postRewrite != NULL)
851 410 : plansource->postRewrite(tlist, plansource->postRewriteArg);
852 :
853 : /* Release snapshot if we got one */
854 6174 : if (snapshot_set)
855 20 : PopActiveSnapshot();
856 :
857 : /*
858 : * Check or update the result tupdesc.
859 : *
860 : * We assume the parameter types didn't change from the first time, so no
861 : * need to update that.
862 : */
863 6174 : resultDesc = PlanCacheComputeResultDesc(tlist);
864 6174 : if (resultDesc == NULL && plansource->resultDesc == NULL)
865 : {
866 : /* OK, doesn't return tuples */
867 : }
868 6016 : else if (resultDesc == NULL || plansource->resultDesc == NULL ||
869 6016 : !equalRowTypes(resultDesc, plansource->resultDesc))
870 : {
871 : /* can we give a better error message? */
872 58 : if (plansource->fixed_result)
873 12 : ereport(ERROR,
874 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
875 : errmsg("cached plan must not change result type")));
876 46 : oldcxt = MemoryContextSwitchTo(plansource->context);
877 46 : if (resultDesc)
878 46 : resultDesc = CreateTupleDescCopy(resultDesc);
879 46 : if (plansource->resultDesc)
880 46 : FreeTupleDesc(plansource->resultDesc);
881 46 : plansource->resultDesc = resultDesc;
882 46 : MemoryContextSwitchTo(oldcxt);
883 : }
884 :
885 : /*
886 : * Allocate new query_context and copy the completed querytree into it.
887 : * It's transient until we complete the copying and dependency extraction.
888 : */
889 6162 : querytree_context = AllocSetContextCreate(CurrentMemoryContext,
890 : "CachedPlanQuery",
891 : ALLOCSET_START_SMALL_SIZES);
892 6162 : oldcxt = MemoryContextSwitchTo(querytree_context);
893 :
894 6162 : qlist = copyObject(tlist);
895 :
896 : /*
897 : * Use the planner machinery to extract dependencies. Data is saved in
898 : * query_context. (We assume that not a lot of extra cruft is created by
899 : * this call.)
900 : */
901 6162 : extract_query_dependencies((Node *) qlist,
902 : &plansource->relationOids,
903 : &plansource->invalItems,
904 : &plansource->dependsOnRLS);
905 :
906 : /* Update RLS info as well. */
907 6162 : plansource->rewriteRoleId = GetUserId();
908 6162 : plansource->rewriteRowSecurity = row_security;
909 :
910 : /*
911 : * Also save the current search_path in the query_context. (This should
912 : * not generate much extra cruft either, since almost certainly the path
913 : * is already valid.)
914 : */
915 6162 : plansource->search_path = GetSearchPathMatcher(querytree_context);
916 :
917 6162 : MemoryContextSwitchTo(oldcxt);
918 :
919 : /* Now reparent the finished query_context and save the links */
920 6162 : MemoryContextSetParent(querytree_context, plansource->context);
921 :
922 6162 : plansource->query_context = querytree_context;
923 6162 : plansource->query_list = qlist;
924 :
925 : /*
926 : * Note: we do not reset generic_cost or total_custom_cost, although we
927 : * could choose to do so. If the DDL or statistics change that prompted
928 : * the invalidation meant a significant change in the cost estimates, it
929 : * would be better to reset those variables and start fresh; but often it
930 : * doesn't, and we're better retaining our hard-won knowledge about the
931 : * relative costs.
932 : */
933 :
934 6162 : plansource->is_valid = true;
935 :
936 : /* Return transient copy of querytrees for possible use in planning */
937 6162 : return tlist;
938 : }
939 :
940 : /*
941 : * CheckCachedPlan: see if the CachedPlanSource's generic plan is valid.
942 : *
943 : * Caller must have already called RevalidateCachedQuery to verify that the
944 : * querytree is up to date.
945 : *
946 : * On a "true" return, we have acquired the locks needed to run the plan.
947 : * (We must do this for the "true" result to be race-condition-free.)
948 : */
949 : static bool
950 236688 : CheckCachedPlan(CachedPlanSource *plansource)
951 : {
952 236688 : CachedPlan *plan = plansource->gplan;
953 :
954 : /* Assert that caller checked the querytree */
955 : Assert(plansource->is_valid);
956 :
957 : /* If there's no generic plan, just say "false" */
958 236688 : if (!plan)
959 48140 : return false;
960 :
961 : Assert(plan->magic == CACHEDPLAN_MAGIC);
962 : /* Generic plans are never one-shot */
963 : Assert(!plan->is_oneshot);
964 :
965 : /*
966 : * If plan isn't valid for current role, we can't use it.
967 : */
968 188588 : if (plan->is_valid && plan->dependsOnRole &&
969 40 : plan->planRoleId != GetUserId())
970 36 : plan->is_valid = false;
971 :
972 : /*
973 : * If it appears valid, acquire locks and recheck; this is much the same
974 : * logic as in RevalidateCachedQuery, but for a plan.
975 : */
976 188548 : if (plan->is_valid)
977 : {
978 : /*
979 : * Plan must have positive refcount because it is referenced by
980 : * plansource; so no need to fear it disappears under us here.
981 : */
982 : Assert(plan->refcount > 0);
983 :
984 188470 : AcquireExecutorLocks(plan->stmt_list, true);
985 :
986 : /*
987 : * If plan was transient, check to see if TransactionXmin has
988 : * advanced, and if so invalidate it.
989 : */
990 188470 : if (plan->is_valid &&
991 188470 : TransactionIdIsValid(plan->saved_xmin) &&
992 0 : !TransactionIdEquals(plan->saved_xmin, TransactionXmin))
993 0 : plan->is_valid = false;
994 :
995 : /*
996 : * By now, if any invalidation has happened, the inval callback
997 : * functions will have marked the plan invalid.
998 : */
999 188470 : if (plan->is_valid)
1000 : {
1001 : /* Successfully revalidated and locked the query. */
1002 188470 : return true;
1003 : }
1004 :
1005 : /* Oops, the race case happened. Release useless locks. */
1006 0 : AcquireExecutorLocks(plan->stmt_list, false);
1007 : }
1008 :
1009 : /*
1010 : * Plan has been invalidated, so unlink it from the parent and release it.
1011 : */
1012 78 : ReleaseGenericPlan(plansource);
1013 :
1014 78 : return false;
1015 : }
1016 :
1017 : /*
1018 : * BuildCachedPlan: construct a new CachedPlan from a CachedPlanSource.
1019 : *
1020 : * qlist should be the result value from a previous RevalidateCachedQuery,
1021 : * or it can be set to NIL if we need to re-copy the plansource's query_list.
1022 : *
1023 : * To build a generic, parameter-value-independent plan, pass NULL for
1024 : * boundParams. To build a custom plan, pass the actual parameter values via
1025 : * boundParams. For best effect, the PARAM_FLAG_CONST flag should be set on
1026 : * each parameter value; otherwise the planner will treat the value as a
1027 : * hint rather than a hard constant.
1028 : *
1029 : * Planning work is done in the caller's memory context. The finished plan
1030 : * is in a child memory context, which typically should get reparented
1031 : * (unless this is a one-shot plan, in which case we don't copy the plan).
1032 : */
1033 : static CachedPlan *
1034 100090 : BuildCachedPlan(CachedPlanSource *plansource, List *qlist,
1035 : ParamListInfo boundParams, QueryEnvironment *queryEnv)
1036 : {
1037 : CachedPlan *plan;
1038 : List *plist;
1039 : bool snapshot_set;
1040 : bool is_transient;
1041 : MemoryContext plan_context;
1042 100090 : MemoryContext oldcxt = CurrentMemoryContext;
1043 : ListCell *lc;
1044 :
1045 : /*
1046 : * Normally the querytree should be valid already, but if it's not,
1047 : * rebuild it.
1048 : *
1049 : * NOTE: GetCachedPlan should have called RevalidateCachedQuery first, so
1050 : * we ought to be holding sufficient locks to prevent any invalidation.
1051 : * However, if we're building a custom plan after having built and
1052 : * rejected a generic plan, it's possible to reach here with is_valid
1053 : * false due to an invalidation while making the generic plan. In theory
1054 : * the invalidation must be a false positive, perhaps a consequence of an
1055 : * sinval reset event or the debug_discard_caches code. But for safety,
1056 : * let's treat it as real and redo the RevalidateCachedQuery call.
1057 : */
1058 100090 : if (!plansource->is_valid)
1059 0 : qlist = RevalidateCachedQuery(plansource, queryEnv);
1060 :
1061 : /*
1062 : * If we don't already have a copy of the querytree list that can be
1063 : * scribbled on by the planner, make one. For a one-shot plan, we assume
1064 : * it's okay to scribble on the original query_list.
1065 : */
1066 100090 : if (qlist == NIL)
1067 : {
1068 93930 : if (!plansource->is_oneshot)
1069 74160 : qlist = copyObject(plansource->query_list);
1070 : else
1071 19770 : qlist = plansource->query_list;
1072 : }
1073 :
1074 : /*
1075 : * If a snapshot is already set (the normal case), we can just use that
1076 : * for planning. But if it isn't, and we need one, install one.
1077 : */
1078 100090 : snapshot_set = false;
1079 101084 : if (!ActiveSnapshotSet() &&
1080 994 : BuildingPlanRequiresSnapshot(plansource))
1081 : {
1082 286 : PushActiveSnapshot(GetTransactionSnapshot());
1083 286 : snapshot_set = true;
1084 : }
1085 :
1086 : /*
1087 : * Generate the plan.
1088 : */
1089 100090 : plist = pg_plan_queries(qlist, plansource->query_string,
1090 : plansource->cursor_options, boundParams);
1091 :
1092 : /* Release snapshot if we got one */
1093 99880 : if (snapshot_set)
1094 280 : PopActiveSnapshot();
1095 :
1096 : /*
1097 : * Normally we make a dedicated memory context for the CachedPlan and its
1098 : * subsidiary data. (It's probably not going to be large, but just in
1099 : * case, allow it to grow large. It's transient for the moment.) But for
1100 : * a one-shot plan, we just leave it in the caller's memory context.
1101 : */
1102 99880 : if (!plansource->is_oneshot)
1103 : {
1104 80186 : plan_context = AllocSetContextCreate(CurrentMemoryContext,
1105 : "CachedPlan",
1106 : ALLOCSET_START_SMALL_SIZES);
1107 80186 : MemoryContextCopyAndSetIdentifier(plan_context, plansource->query_string);
1108 :
1109 : /*
1110 : * Copy plan into the new context.
1111 : */
1112 80186 : MemoryContextSwitchTo(plan_context);
1113 :
1114 80186 : plist = copyObject(plist);
1115 : }
1116 : else
1117 19694 : plan_context = CurrentMemoryContext;
1118 :
1119 : /*
1120 : * Create and fill the CachedPlan struct within the new context.
1121 : */
1122 99880 : plan = (CachedPlan *) palloc(sizeof(CachedPlan));
1123 99880 : plan->magic = CACHEDPLAN_MAGIC;
1124 99880 : plan->stmt_list = plist;
1125 :
1126 : /*
1127 : * CachedPlan is dependent on role either if RLS affected the rewrite
1128 : * phase or if a role dependency was injected during planning. And it's
1129 : * transient if any plan is marked so.
1130 : */
1131 99880 : plan->planRoleId = GetUserId();
1132 99880 : plan->dependsOnRole = plansource->dependsOnRLS;
1133 99880 : is_transient = false;
1134 199766 : foreach(lc, plist)
1135 : {
1136 99886 : PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1137 :
1138 99886 : if (plannedstmt->commandType == CMD_UTILITY)
1139 20252 : continue; /* Ignore utility statements */
1140 :
1141 79634 : if (plannedstmt->transientPlan)
1142 126 : is_transient = true;
1143 79634 : if (plannedstmt->dependsOnRole)
1144 72 : plan->dependsOnRole = true;
1145 : }
1146 99880 : if (is_transient)
1147 : {
1148 : Assert(TransactionIdIsNormal(TransactionXmin));
1149 126 : plan->saved_xmin = TransactionXmin;
1150 : }
1151 : else
1152 99754 : plan->saved_xmin = InvalidTransactionId;
1153 99880 : plan->refcount = 0;
1154 99880 : plan->context = plan_context;
1155 99880 : plan->is_oneshot = plansource->is_oneshot;
1156 99880 : plan->is_saved = false;
1157 99880 : plan->is_valid = true;
1158 :
1159 : /* assign generation number to new plan */
1160 99880 : plan->generation = ++(plansource->generation);
1161 :
1162 99880 : MemoryContextSwitchTo(oldcxt);
1163 :
1164 99880 : return plan;
1165 : }
1166 :
1167 : /*
1168 : * choose_custom_plan: choose whether to use custom or generic plan
1169 : *
1170 : * This defines the policy followed by GetCachedPlan.
1171 : */
1172 : static bool
1173 336656 : choose_custom_plan(CachedPlanSource *plansource, ParamListInfo boundParams)
1174 : {
1175 : double avg_custom_cost;
1176 :
1177 : /* One-shot plans will always be considered custom */
1178 336656 : if (plansource->is_oneshot)
1179 19770 : return true;
1180 :
1181 : /* Otherwise, never any point in a custom plan if there's no parameters */
1182 316886 : if (boundParams == NULL)
1183 147572 : return false;
1184 : /* ... nor when planning would be a no-op */
1185 169314 : if (!StmtPlanRequiresRevalidation(plansource))
1186 0 : return false;
1187 :
1188 : /* Let settings force the decision */
1189 169314 : if (plan_cache_mode == PLAN_CACHE_MODE_FORCE_GENERIC_PLAN)
1190 2854 : return false;
1191 166460 : if (plan_cache_mode == PLAN_CACHE_MODE_FORCE_CUSTOM_PLAN)
1192 40 : return true;
1193 :
1194 : /* See if caller wants to force the decision */
1195 166420 : if (plansource->cursor_options & CURSOR_OPT_GENERIC_PLAN)
1196 0 : return false;
1197 166420 : if (plansource->cursor_options & CURSOR_OPT_CUSTOM_PLAN)
1198 0 : return true;
1199 :
1200 : /* Generate custom plans until we have done at least 5 (arbitrary) */
1201 166420 : if (plansource->num_custom_plans < 5)
1202 28224 : return true;
1203 :
1204 138196 : avg_custom_cost = plansource->total_custom_cost / plansource->num_custom_plans;
1205 :
1206 : /*
1207 : * Prefer generic plan if it's less expensive than the average custom
1208 : * plan. (Because we include a charge for cost of planning in the
1209 : * custom-plan costs, this means the generic plan only has to be less
1210 : * expensive than the execution cost plus replan cost of the custom
1211 : * plans.)
1212 : *
1213 : * Note that if generic_cost is -1 (indicating we've not yet determined
1214 : * the generic plan cost), we'll always prefer generic at this point.
1215 : */
1216 138196 : if (plansource->generic_cost < avg_custom_cost)
1217 134358 : return false;
1218 :
1219 3838 : return true;
1220 : }
1221 :
1222 : /*
1223 : * cached_plan_cost: calculate estimated cost of a plan
1224 : *
1225 : * If include_planner is true, also include the estimated cost of constructing
1226 : * the plan. (We must factor that into the cost of using a custom plan, but
1227 : * we don't count it for a generic plan.)
1228 : */
1229 : static double
1230 99880 : cached_plan_cost(CachedPlan *plan, bool include_planner)
1231 : {
1232 99880 : double result = 0;
1233 : ListCell *lc;
1234 :
1235 199766 : foreach(lc, plan->stmt_list)
1236 : {
1237 99886 : PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1238 :
1239 99886 : if (plannedstmt->commandType == CMD_UTILITY)
1240 20252 : continue; /* Ignore utility statements */
1241 :
1242 79634 : result += plannedstmt->planTree->total_cost;
1243 :
1244 79634 : if (include_planner)
1245 : {
1246 : /*
1247 : * Currently we use a very crude estimate of planning effort based
1248 : * on the number of relations in the finished plan's rangetable.
1249 : * Join planning effort actually scales much worse than linearly
1250 : * in the number of relations --- but only until the join collapse
1251 : * limits kick in. Also, while inheritance child relations surely
1252 : * add to planning effort, they don't make the join situation
1253 : * worse. So the actual shape of the planning cost curve versus
1254 : * number of relations isn't all that obvious. It will take
1255 : * considerable work to arrive at a less crude estimate, and for
1256 : * now it's not clear that's worth doing.
1257 : *
1258 : * The other big difficulty here is that we don't have any very
1259 : * good model of how planning cost compares to execution costs.
1260 : * The current multiplier of 1000 * cpu_operator_cost is probably
1261 : * on the low side, but we'll try this for awhile before making a
1262 : * more aggressive correction.
1263 : *
1264 : * If we ever do write a more complicated estimator, it should
1265 : * probably live in src/backend/optimizer/ not here.
1266 : */
1267 42564 : int nrelations = list_length(plannedstmt->rtable);
1268 :
1269 42564 : result += 1000.0 * cpu_operator_cost * (nrelations + 1);
1270 : }
1271 : }
1272 :
1273 99880 : return result;
1274 : }
1275 :
1276 : /*
1277 : * GetCachedPlan: get a cached plan from a CachedPlanSource.
1278 : *
1279 : * This function hides the logic that decides whether to use a generic
1280 : * plan or a custom plan for the given parameters: the caller does not know
1281 : * which it will get.
1282 : *
1283 : * On return, the plan is valid and we have sufficient locks to begin
1284 : * execution.
1285 : *
1286 : * On return, the refcount of the plan has been incremented; a later
1287 : * ReleaseCachedPlan() call is expected. If "owner" is not NULL then
1288 : * the refcount has been reported to that ResourceOwner (note that this
1289 : * is only supported for "saved" CachedPlanSources).
1290 : *
1291 : * Note: if any replanning activity is required, the caller's memory context
1292 : * is used for that work.
1293 : */
1294 : CachedPlan *
1295 288548 : GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams,
1296 : ResourceOwner owner, QueryEnvironment *queryEnv)
1297 : {
1298 288548 : CachedPlan *plan = NULL;
1299 : List *qlist;
1300 : bool customplan;
1301 : ListCell *lc;
1302 :
1303 : /* Assert caller is doing things in a sane order */
1304 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1305 : Assert(plansource->is_complete);
1306 : /* This seems worth a real test, though */
1307 288548 : if (owner && !plansource->is_saved)
1308 0 : elog(ERROR, "cannot apply ResourceOwner to non-saved cached plan");
1309 :
1310 : /* Make sure the querytree list is valid and we have parse-time locks */
1311 288548 : qlist = RevalidateCachedQuery(plansource, queryEnv);
1312 :
1313 : /* Decide whether to use a custom plan */
1314 288496 : customplan = choose_custom_plan(plansource, boundParams);
1315 :
1316 288496 : if (!customplan)
1317 : {
1318 236688 : if (CheckCachedPlan(plansource))
1319 : {
1320 : /* We want a generic plan, and we already have a valid one */
1321 188470 : plan = plansource->gplan;
1322 : Assert(plan->magic == CACHEDPLAN_MAGIC);
1323 : }
1324 : else
1325 : {
1326 : /* Build a new generic plan */
1327 48218 : plan = BuildCachedPlan(plansource, qlist, NULL, queryEnv);
1328 : /* Just make real sure plansource->gplan is clear */
1329 48160 : ReleaseGenericPlan(plansource);
1330 : /* Link the new generic plan into the plansource */
1331 48160 : plansource->gplan = plan;
1332 48160 : plan->refcount++;
1333 : /* Immediately reparent into appropriate context */
1334 48160 : if (plansource->is_saved)
1335 : {
1336 : /* saved plans all live under CacheMemoryContext */
1337 37240 : MemoryContextSetParent(plan->context, CacheMemoryContext);
1338 37240 : plan->is_saved = true;
1339 : }
1340 : else
1341 : {
1342 : /* otherwise, it should be a sibling of the plansource */
1343 10920 : MemoryContextSetParent(plan->context,
1344 : MemoryContextGetParent(plansource->context));
1345 : }
1346 : /* Update generic_cost whenever we make a new generic plan */
1347 48160 : plansource->generic_cost = cached_plan_cost(plan, false);
1348 :
1349 : /*
1350 : * If, based on the now-known value of generic_cost, we'd not have
1351 : * chosen to use a generic plan, then forget it and make a custom
1352 : * plan. This is a bit of a wart but is necessary to avoid a
1353 : * glitch in behavior when the custom plans are consistently big
1354 : * winners; at some point we'll experiment with a generic plan and
1355 : * find it's a loser, but we don't want to actually execute that
1356 : * plan.
1357 : */
1358 48160 : customplan = choose_custom_plan(plansource, boundParams);
1359 :
1360 : /*
1361 : * If we choose to plan again, we need to re-copy the query_list,
1362 : * since the planner probably scribbled on it. We can force
1363 : * BuildCachedPlan to do that by passing NIL.
1364 : */
1365 48160 : qlist = NIL;
1366 : }
1367 : }
1368 :
1369 288438 : if (customplan)
1370 : {
1371 : /* Build a custom plan */
1372 51872 : plan = BuildCachedPlan(plansource, qlist, boundParams, queryEnv);
1373 : /* Accumulate total costs of custom plans */
1374 51720 : plansource->total_custom_cost += cached_plan_cost(plan, true);
1375 :
1376 51720 : plansource->num_custom_plans++;
1377 : }
1378 : else
1379 : {
1380 236566 : plansource->num_generic_plans++;
1381 : }
1382 :
1383 : Assert(plan != NULL);
1384 :
1385 : /* Flag the plan as in use by caller */
1386 288286 : if (owner)
1387 217000 : ResourceOwnerEnlarge(owner);
1388 288286 : plan->refcount++;
1389 288286 : if (owner)
1390 217000 : ResourceOwnerRememberPlanCacheRef(owner, plan);
1391 :
1392 : /*
1393 : * Saved plans should be under CacheMemoryContext so they will not go away
1394 : * until their reference count goes to zero. In the generic-plan cases we
1395 : * already took care of that, but for a custom plan, do it as soon as we
1396 : * have created a reference-counted link.
1397 : */
1398 288286 : if (customplan && plansource->is_saved)
1399 : {
1400 32014 : MemoryContextSetParent(plan->context, CacheMemoryContext);
1401 32014 : plan->is_saved = true;
1402 : }
1403 :
1404 576578 : foreach(lc, plan->stmt_list)
1405 : {
1406 288292 : PlannedStmt *pstmt = (PlannedStmt *) lfirst(lc);
1407 :
1408 288292 : pstmt->planOrigin = customplan ? PLAN_STMT_CACHE_CUSTOM : PLAN_STMT_CACHE_GENERIC;
1409 : }
1410 :
1411 288286 : return plan;
1412 : }
1413 :
1414 : /*
1415 : * ReleaseCachedPlan: release active use of a cached plan.
1416 : *
1417 : * This decrements the reference count, and frees the plan if the count
1418 : * has thereby gone to zero. If "owner" is not NULL, it is assumed that
1419 : * the reference count is managed by that ResourceOwner.
1420 : *
1421 : * Note: owner == NULL is used for releasing references that are in
1422 : * persistent data structures, such as the parent CachedPlanSource or a
1423 : * Portal. Transient references should be protected by a resource owner.
1424 : */
1425 : void
1426 382640 : ReleaseCachedPlan(CachedPlan *plan, ResourceOwner owner)
1427 : {
1428 : Assert(plan->magic == CACHEDPLAN_MAGIC);
1429 382640 : if (owner)
1430 : {
1431 : Assert(plan->is_saved);
1432 206206 : ResourceOwnerForgetPlanCacheRef(owner, plan);
1433 : }
1434 : Assert(plan->refcount > 0);
1435 382640 : plan->refcount--;
1436 382640 : if (plan->refcount == 0)
1437 : {
1438 : /* Mark it no longer valid */
1439 66502 : plan->magic = 0;
1440 :
1441 : /* One-shot plans do not own their context, so we can't free them */
1442 66502 : if (!plan->is_oneshot)
1443 46980 : MemoryContextDelete(plan->context);
1444 : }
1445 382640 : }
1446 :
1447 : /*
1448 : * CachedPlanAllowsSimpleValidityCheck: can we use CachedPlanIsSimplyValid?
1449 : *
1450 : * This function, together with CachedPlanIsSimplyValid, provides a fast path
1451 : * for revalidating "simple" generic plans. The core requirement to be simple
1452 : * is that the plan must not require taking any locks, which translates to
1453 : * not touching any tables; this happens to match up well with an important
1454 : * use-case in PL/pgSQL. This function tests whether that's true, along
1455 : * with checking some other corner cases that we'd rather not bother with
1456 : * handling in the fast path. (Note that it's still possible for such a plan
1457 : * to be invalidated, for example due to a change in a function that was
1458 : * inlined into the plan.)
1459 : *
1460 : * If the plan is simply valid, and "owner" is not NULL, record a refcount on
1461 : * the plan in that resowner before returning. It is caller's responsibility
1462 : * to be sure that a refcount is held on any plan that's being actively used.
1463 : *
1464 : * This must only be called on known-valid generic plans (eg, ones just
1465 : * returned by GetCachedPlan). If it returns true, the caller may re-use
1466 : * the cached plan as long as CachedPlanIsSimplyValid returns true; that
1467 : * check is much cheaper than the full revalidation done by GetCachedPlan.
1468 : * Nonetheless, no required checks are omitted.
1469 : */
1470 : bool
1471 28688 : CachedPlanAllowsSimpleValidityCheck(CachedPlanSource *plansource,
1472 : CachedPlan *plan, ResourceOwner owner)
1473 : {
1474 : ListCell *lc;
1475 :
1476 : /*
1477 : * Sanity-check that the caller gave us a validated generic plan. Notice
1478 : * that we *don't* assert plansource->is_valid as you might expect; that's
1479 : * because it's possible that that's already false when GetCachedPlan
1480 : * returns, e.g. because ResetPlanCache happened partway through. We
1481 : * should accept the plan as long as plan->is_valid is true, and expect to
1482 : * replan after the next CachedPlanIsSimplyValid call.
1483 : */
1484 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1485 : Assert(plan->magic == CACHEDPLAN_MAGIC);
1486 : Assert(plan->is_valid);
1487 : Assert(plan == plansource->gplan);
1488 : Assert(plansource->search_path != NULL);
1489 : Assert(SearchPathMatchesCurrentEnvironment(plansource->search_path));
1490 :
1491 : /* We don't support oneshot plans here. */
1492 28688 : if (plansource->is_oneshot)
1493 0 : return false;
1494 : Assert(!plan->is_oneshot);
1495 :
1496 : /*
1497 : * If the plan is dependent on RLS considerations, or it's transient,
1498 : * reject. These things probably can't ever happen for table-free
1499 : * queries, but for safety's sake let's check.
1500 : */
1501 28688 : if (plansource->dependsOnRLS)
1502 0 : return false;
1503 28688 : if (plan->dependsOnRole)
1504 0 : return false;
1505 28688 : if (TransactionIdIsValid(plan->saved_xmin))
1506 0 : return false;
1507 :
1508 : /*
1509 : * Reject if AcquirePlannerLocks would have anything to do. This is
1510 : * simplistic, but there's no need to inquire any more carefully; indeed,
1511 : * for current callers it shouldn't even be possible to hit any of these
1512 : * checks.
1513 : */
1514 57376 : foreach(lc, plansource->query_list)
1515 : {
1516 28688 : Query *query = lfirst_node(Query, lc);
1517 :
1518 28688 : if (query->commandType == CMD_UTILITY)
1519 0 : return false;
1520 28688 : if (query->rtable || query->cteList || query->hasSubLinks)
1521 0 : return false;
1522 : }
1523 :
1524 : /*
1525 : * Reject if AcquireExecutorLocks would have anything to do. This is
1526 : * probably unnecessary given the previous check, but let's be safe.
1527 : */
1528 57376 : foreach(lc, plan->stmt_list)
1529 : {
1530 28688 : PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1531 : ListCell *lc2;
1532 :
1533 28688 : if (plannedstmt->commandType == CMD_UTILITY)
1534 0 : return false;
1535 :
1536 : /*
1537 : * We have to grovel through the rtable because it's likely to contain
1538 : * an RTE_RESULT relation, rather than being totally empty.
1539 : */
1540 57376 : foreach(lc2, plannedstmt->rtable)
1541 : {
1542 28688 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
1543 :
1544 28688 : if (rte->rtekind == RTE_RELATION)
1545 0 : return false;
1546 : }
1547 : }
1548 :
1549 : /*
1550 : * Okay, it's simple. Note that what we've primarily established here is
1551 : * that no locks need be taken before checking the plan's is_valid flag.
1552 : */
1553 :
1554 : /* Bump refcount if requested. */
1555 28688 : if (owner)
1556 : {
1557 28688 : ResourceOwnerEnlarge(owner);
1558 28688 : plan->refcount++;
1559 28688 : ResourceOwnerRememberPlanCacheRef(owner, plan);
1560 : }
1561 :
1562 28688 : return true;
1563 : }
1564 :
1565 : /*
1566 : * CachedPlanIsSimplyValid: quick check for plan still being valid
1567 : *
1568 : * This function must not be used unless CachedPlanAllowsSimpleValidityCheck
1569 : * previously said it was OK.
1570 : *
1571 : * If the plan is valid, and "owner" is not NULL, record a refcount on
1572 : * the plan in that resowner before returning. It is caller's responsibility
1573 : * to be sure that a refcount is held on any plan that's being actively used.
1574 : *
1575 : * The code here is unconditionally safe as long as the only use of this
1576 : * CachedPlanSource is in connection with the particular CachedPlan pointer
1577 : * that's passed in. If the plansource were being used for other purposes,
1578 : * it's possible that its generic plan could be invalidated and regenerated
1579 : * while the current caller wasn't looking, and then there could be a chance
1580 : * collision of address between this caller's now-stale plan pointer and the
1581 : * actual address of the new generic plan. For current uses, that scenario
1582 : * can't happen; but with a plansource shared across multiple uses, it'd be
1583 : * advisable to also save plan->generation and verify that that still matches.
1584 : */
1585 : bool
1586 319674 : CachedPlanIsSimplyValid(CachedPlanSource *plansource, CachedPlan *plan,
1587 : ResourceOwner owner)
1588 : {
1589 : /*
1590 : * Careful here: since the caller doesn't necessarily hold a refcount on
1591 : * the plan to start with, it's possible that "plan" is a dangling
1592 : * pointer. Don't dereference it until we've verified that it still
1593 : * matches the plansource's gplan (which is either valid or NULL).
1594 : */
1595 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1596 :
1597 : /*
1598 : * Has cache invalidation fired on this plan? We can check this right
1599 : * away since there are no locks that we'd need to acquire first. Note
1600 : * that here we *do* check plansource->is_valid, so as to force plan
1601 : * rebuild if that's become false.
1602 : */
1603 319674 : if (!plansource->is_valid ||
1604 315010 : plan == NULL || plan != plansource->gplan ||
1605 315010 : !plan->is_valid)
1606 4676 : return false;
1607 :
1608 : Assert(plan->magic == CACHEDPLAN_MAGIC);
1609 :
1610 : /* Is the search_path still the same as when we made it? */
1611 : Assert(plansource->search_path != NULL);
1612 314998 : if (!SearchPathMatchesCurrentEnvironment(plansource->search_path))
1613 32 : return false;
1614 :
1615 : /* It's still good. Bump refcount if requested. */
1616 314966 : if (owner)
1617 : {
1618 51032 : ResourceOwnerEnlarge(owner);
1619 51032 : plan->refcount++;
1620 51032 : ResourceOwnerRememberPlanCacheRef(owner, plan);
1621 : }
1622 :
1623 314966 : return true;
1624 : }
1625 :
1626 : /*
1627 : * CachedPlanSetParentContext: move a CachedPlanSource to a new memory context
1628 : *
1629 : * This can only be applied to unsaved plans; once saved, a plan always
1630 : * lives underneath CacheMemoryContext.
1631 : */
1632 : void
1633 33216 : CachedPlanSetParentContext(CachedPlanSource *plansource,
1634 : MemoryContext newcontext)
1635 : {
1636 : /* Assert caller is doing things in a sane order */
1637 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1638 : Assert(plansource->is_complete);
1639 :
1640 : /* These seem worth real tests, though */
1641 33216 : if (plansource->is_saved)
1642 0 : elog(ERROR, "cannot move a saved cached plan to another context");
1643 33216 : if (plansource->is_oneshot)
1644 0 : elog(ERROR, "cannot move a one-shot cached plan to another context");
1645 :
1646 : /* OK, let the caller keep the plan where he wishes */
1647 33216 : MemoryContextSetParent(plansource->context, newcontext);
1648 :
1649 : /*
1650 : * The query_context needs no special handling, since it's a child of
1651 : * plansource->context. But if there's a generic plan, it should be
1652 : * maintained as a sibling of plansource->context.
1653 : */
1654 33216 : if (plansource->gplan)
1655 : {
1656 : Assert(plansource->gplan->magic == CACHEDPLAN_MAGIC);
1657 0 : MemoryContextSetParent(plansource->gplan->context, newcontext);
1658 : }
1659 33216 : }
1660 :
1661 : /*
1662 : * CopyCachedPlan: make a copy of a CachedPlanSource
1663 : *
1664 : * This is a convenience routine that does the equivalent of
1665 : * CreateCachedPlan + CompleteCachedPlan, using the data stored in the
1666 : * input CachedPlanSource. The result is therefore "unsaved" (regardless
1667 : * of the state of the source), and we don't copy any generic plan either.
1668 : * The result will be currently valid, or not, the same as the source.
1669 : */
1670 : CachedPlanSource *
1671 0 : CopyCachedPlan(CachedPlanSource *plansource)
1672 : {
1673 : CachedPlanSource *newsource;
1674 : MemoryContext source_context;
1675 : MemoryContext querytree_context;
1676 : MemoryContext oldcxt;
1677 :
1678 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1679 : Assert(plansource->is_complete);
1680 :
1681 : /*
1682 : * One-shot plans can't be copied, because we haven't taken care that
1683 : * parsing/planning didn't scribble on the raw parse tree or querytrees.
1684 : */
1685 0 : if (plansource->is_oneshot)
1686 0 : elog(ERROR, "cannot copy a one-shot cached plan");
1687 :
1688 0 : source_context = AllocSetContextCreate(CurrentMemoryContext,
1689 : "CachedPlanSource",
1690 : ALLOCSET_START_SMALL_SIZES);
1691 :
1692 0 : oldcxt = MemoryContextSwitchTo(source_context);
1693 :
1694 0 : newsource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
1695 0 : newsource->magic = CACHEDPLANSOURCE_MAGIC;
1696 0 : newsource->raw_parse_tree = copyObject(plansource->raw_parse_tree);
1697 0 : newsource->analyzed_parse_tree = copyObject(plansource->analyzed_parse_tree);
1698 0 : newsource->query_string = pstrdup(plansource->query_string);
1699 0 : MemoryContextSetIdentifier(source_context, newsource->query_string);
1700 0 : newsource->commandTag = plansource->commandTag;
1701 0 : if (plansource->num_params > 0)
1702 : {
1703 0 : newsource->param_types = (Oid *)
1704 0 : palloc(plansource->num_params * sizeof(Oid));
1705 0 : memcpy(newsource->param_types, plansource->param_types,
1706 0 : plansource->num_params * sizeof(Oid));
1707 : }
1708 : else
1709 0 : newsource->param_types = NULL;
1710 0 : newsource->num_params = plansource->num_params;
1711 0 : newsource->parserSetup = plansource->parserSetup;
1712 0 : newsource->parserSetupArg = plansource->parserSetupArg;
1713 0 : newsource->postRewrite = plansource->postRewrite;
1714 0 : newsource->postRewriteArg = plansource->postRewriteArg;
1715 0 : newsource->cursor_options = plansource->cursor_options;
1716 0 : newsource->fixed_result = plansource->fixed_result;
1717 0 : if (plansource->resultDesc)
1718 0 : newsource->resultDesc = CreateTupleDescCopy(plansource->resultDesc);
1719 : else
1720 0 : newsource->resultDesc = NULL;
1721 0 : newsource->context = source_context;
1722 :
1723 0 : querytree_context = AllocSetContextCreate(source_context,
1724 : "CachedPlanQuery",
1725 : ALLOCSET_START_SMALL_SIZES);
1726 0 : MemoryContextSwitchTo(querytree_context);
1727 0 : newsource->query_list = copyObject(plansource->query_list);
1728 0 : newsource->relationOids = copyObject(plansource->relationOids);
1729 0 : newsource->invalItems = copyObject(plansource->invalItems);
1730 0 : if (plansource->search_path)
1731 0 : newsource->search_path = CopySearchPathMatcher(plansource->search_path);
1732 0 : newsource->query_context = querytree_context;
1733 0 : newsource->rewriteRoleId = plansource->rewriteRoleId;
1734 0 : newsource->rewriteRowSecurity = plansource->rewriteRowSecurity;
1735 0 : newsource->dependsOnRLS = plansource->dependsOnRLS;
1736 :
1737 0 : newsource->gplan = NULL;
1738 :
1739 0 : newsource->is_oneshot = false;
1740 0 : newsource->is_complete = true;
1741 0 : newsource->is_saved = false;
1742 0 : newsource->is_valid = plansource->is_valid;
1743 0 : newsource->generation = plansource->generation;
1744 :
1745 : /* We may as well copy any acquired cost knowledge */
1746 0 : newsource->generic_cost = plansource->generic_cost;
1747 0 : newsource->total_custom_cost = plansource->total_custom_cost;
1748 0 : newsource->num_generic_plans = plansource->num_generic_plans;
1749 0 : newsource->num_custom_plans = plansource->num_custom_plans;
1750 :
1751 0 : MemoryContextSwitchTo(oldcxt);
1752 :
1753 0 : return newsource;
1754 : }
1755 :
1756 : /*
1757 : * CachedPlanIsValid: test whether the rewritten querytree within a
1758 : * CachedPlanSource is currently valid (that is, not marked as being in need
1759 : * of revalidation).
1760 : *
1761 : * This result is only trustworthy (ie, free from race conditions) if
1762 : * the caller has acquired locks on all the relations used in the plan.
1763 : */
1764 : bool
1765 3628 : CachedPlanIsValid(CachedPlanSource *plansource)
1766 : {
1767 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1768 3628 : return plansource->is_valid;
1769 : }
1770 :
1771 : /*
1772 : * CachedPlanGetTargetList: return tlist, if any, describing plan's output
1773 : *
1774 : * The result is guaranteed up-to-date. However, it is local storage
1775 : * within the cached plan, and may disappear next time the plan is updated.
1776 : */
1777 : List *
1778 15824 : CachedPlanGetTargetList(CachedPlanSource *plansource,
1779 : QueryEnvironment *queryEnv)
1780 : {
1781 : Query *pstmt;
1782 :
1783 : /* Assert caller is doing things in a sane order */
1784 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1785 : Assert(plansource->is_complete);
1786 :
1787 : /*
1788 : * No work needed if statement doesn't return tuples (we assume this
1789 : * feature cannot be changed by an invalidation)
1790 : */
1791 15824 : if (plansource->resultDesc == NULL)
1792 0 : return NIL;
1793 :
1794 : /* Make sure the querytree list is valid and we have parse-time locks */
1795 15824 : RevalidateCachedQuery(plansource, queryEnv);
1796 :
1797 : /* Get the primary statement and find out what it returns */
1798 15824 : pstmt = QueryListGetPrimaryStmt(plansource->query_list);
1799 :
1800 15824 : return FetchStatementTargetList((Node *) pstmt);
1801 : }
1802 :
1803 : /*
1804 : * GetCachedExpression: construct a CachedExpression for an expression.
1805 : *
1806 : * This performs the same transformations on the expression as
1807 : * expression_planner(), ie, convert an expression as emitted by parse
1808 : * analysis to be ready to pass to the executor.
1809 : *
1810 : * The result is stashed in a private, long-lived memory context.
1811 : * (Note that this might leak a good deal of memory in the caller's
1812 : * context before that.) The passed-in expr tree is not modified.
1813 : */
1814 : CachedExpression *
1815 364 : GetCachedExpression(Node *expr)
1816 : {
1817 : CachedExpression *cexpr;
1818 : List *relationOids;
1819 : List *invalItems;
1820 : MemoryContext cexpr_context;
1821 : MemoryContext oldcxt;
1822 :
1823 : /*
1824 : * Pass the expression through the planner, and collect dependencies.
1825 : * Everything built here is leaked in the caller's context; that's
1826 : * intentional to minimize the size of the permanent data structure.
1827 : */
1828 364 : expr = (Node *) expression_planner_with_deps((Expr *) expr,
1829 : &relationOids,
1830 : &invalItems);
1831 :
1832 : /*
1833 : * Make a private memory context, and copy what we need into that. To
1834 : * avoid leaking a long-lived context if we fail while copying data, we
1835 : * initially make the context under the caller's context.
1836 : */
1837 364 : cexpr_context = AllocSetContextCreate(CurrentMemoryContext,
1838 : "CachedExpression",
1839 : ALLOCSET_SMALL_SIZES);
1840 :
1841 364 : oldcxt = MemoryContextSwitchTo(cexpr_context);
1842 :
1843 364 : cexpr = (CachedExpression *) palloc(sizeof(CachedExpression));
1844 364 : cexpr->magic = CACHEDEXPR_MAGIC;
1845 364 : cexpr->expr = copyObject(expr);
1846 364 : cexpr->is_valid = true;
1847 364 : cexpr->relationOids = copyObject(relationOids);
1848 364 : cexpr->invalItems = copyObject(invalItems);
1849 364 : cexpr->context = cexpr_context;
1850 :
1851 364 : MemoryContextSwitchTo(oldcxt);
1852 :
1853 : /*
1854 : * Reparent the expr's memory context under CacheMemoryContext so that it
1855 : * will live indefinitely.
1856 : */
1857 364 : MemoryContextSetParent(cexpr_context, CacheMemoryContext);
1858 :
1859 : /*
1860 : * Add the entry to the global list of cached expressions.
1861 : */
1862 364 : dlist_push_tail(&cached_expression_list, &cexpr->node);
1863 :
1864 364 : return cexpr;
1865 : }
1866 :
1867 : /*
1868 : * FreeCachedExpression
1869 : * Delete a CachedExpression.
1870 : */
1871 : void
1872 54 : FreeCachedExpression(CachedExpression *cexpr)
1873 : {
1874 : /* Sanity check */
1875 : Assert(cexpr->magic == CACHEDEXPR_MAGIC);
1876 : /* Unlink from global list */
1877 54 : dlist_delete(&cexpr->node);
1878 : /* Free all storage associated with CachedExpression */
1879 54 : MemoryContextDelete(cexpr->context);
1880 54 : }
1881 :
1882 : /*
1883 : * QueryListGetPrimaryStmt
1884 : * Get the "primary" stmt within a list, ie, the one marked canSetTag.
1885 : *
1886 : * Returns NULL if no such stmt. If multiple queries within the list are
1887 : * marked canSetTag, returns the first one. Neither of these cases should
1888 : * occur in present usages of this function.
1889 : */
1890 : static Query *
1891 16126 : QueryListGetPrimaryStmt(List *stmts)
1892 : {
1893 : ListCell *lc;
1894 :
1895 16126 : foreach(lc, stmts)
1896 : {
1897 16126 : Query *stmt = lfirst_node(Query, lc);
1898 :
1899 16126 : if (stmt->canSetTag)
1900 16126 : return stmt;
1901 : }
1902 0 : return NULL;
1903 : }
1904 :
1905 : /*
1906 : * AcquireExecutorLocks: acquire locks needed for execution of a cached plan;
1907 : * or release them if acquire is false.
1908 : */
1909 : static void
1910 188470 : AcquireExecutorLocks(List *stmt_list, bool acquire)
1911 : {
1912 : ListCell *lc1;
1913 :
1914 376940 : foreach(lc1, stmt_list)
1915 : {
1916 188470 : PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc1);
1917 : ListCell *lc2;
1918 :
1919 188470 : if (plannedstmt->commandType == CMD_UTILITY)
1920 20680 : {
1921 : /*
1922 : * Ignore utility statements, except those (such as EXPLAIN) that
1923 : * contain a parsed-but-not-planned query. Note: it's okay to use
1924 : * ScanQueryForLocks, even though the query hasn't been through
1925 : * rule rewriting, because rewriting doesn't change the query
1926 : * representation.
1927 : */
1928 20680 : Query *query = UtilityContainsQuery(plannedstmt->utilityStmt);
1929 :
1930 20680 : if (query)
1931 4 : ScanQueryForLocks(query, acquire);
1932 20680 : continue;
1933 : }
1934 :
1935 379358 : foreach(lc2, plannedstmt->rtable)
1936 : {
1937 211568 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
1938 :
1939 211568 : if (!(rte->rtekind == RTE_RELATION ||
1940 147768 : (rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid))))
1941 144552 : continue;
1942 :
1943 : /*
1944 : * Acquire the appropriate type of lock on each relation OID. Note
1945 : * that we don't actually try to open the rel, and hence will not
1946 : * fail if it's been dropped entirely --- we'll just transiently
1947 : * acquire a non-conflicting lock.
1948 : */
1949 67016 : if (acquire)
1950 67016 : LockRelationOid(rte->relid, rte->rellockmode);
1951 : else
1952 0 : UnlockRelationOid(rte->relid, rte->rellockmode);
1953 : }
1954 : }
1955 188470 : }
1956 :
1957 : /*
1958 : * AcquirePlannerLocks: acquire locks needed for planning of a querytree list;
1959 : * or release them if acquire is false.
1960 : *
1961 : * Note that we don't actually try to open the relations, and hence will not
1962 : * fail if one has been dropped entirely --- we'll just transiently acquire
1963 : * a non-conflicting lock.
1964 : */
1965 : static void
1966 255858 : AcquirePlannerLocks(List *stmt_list, bool acquire)
1967 : {
1968 : ListCell *lc;
1969 :
1970 511716 : foreach(lc, stmt_list)
1971 : {
1972 255858 : Query *query = lfirst_node(Query, lc);
1973 :
1974 255858 : if (query->commandType == CMD_UTILITY)
1975 : {
1976 : /* Ignore utility statements, unless they contain a Query */
1977 10052 : query = UtilityContainsQuery(query->utilityStmt);
1978 10052 : if (query)
1979 9792 : ScanQueryForLocks(query, acquire);
1980 10052 : continue;
1981 : }
1982 :
1983 245806 : ScanQueryForLocks(query, acquire);
1984 : }
1985 255858 : }
1986 :
1987 : /*
1988 : * ScanQueryForLocks: recursively scan one Query for AcquirePlannerLocks.
1989 : */
1990 : static void
1991 277478 : ScanQueryForLocks(Query *parsetree, bool acquire)
1992 : {
1993 : ListCell *lc;
1994 :
1995 : /* Shouldn't get called on utility commands */
1996 : Assert(parsetree->commandType != CMD_UTILITY);
1997 :
1998 : /*
1999 : * First, process RTEs of the current query level.
2000 : */
2001 458522 : foreach(lc, parsetree->rtable)
2002 : {
2003 181044 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
2004 :
2005 181044 : switch (rte->rtekind)
2006 : {
2007 130256 : case RTE_RELATION:
2008 : /* Acquire or release the appropriate type of lock */
2009 130256 : if (acquire)
2010 130236 : LockRelationOid(rte->relid, rte->rellockmode);
2011 : else
2012 20 : UnlockRelationOid(rte->relid, rte->rellockmode);
2013 130256 : break;
2014 :
2015 16866 : case RTE_SUBQUERY:
2016 : /* If this was a view, must lock/unlock the view */
2017 16866 : if (OidIsValid(rte->relid))
2018 : {
2019 3874 : if (acquire)
2020 3874 : LockRelationOid(rte->relid, rte->rellockmode);
2021 : else
2022 0 : UnlockRelationOid(rte->relid, rte->rellockmode);
2023 : }
2024 : /* Recurse into subquery-in-FROM */
2025 16866 : ScanQueryForLocks(rte->subquery, acquire);
2026 16866 : break;
2027 :
2028 33922 : default:
2029 : /* ignore other types of RTEs */
2030 33922 : break;
2031 : }
2032 : }
2033 :
2034 : /* Recurse into subquery-in-WITH */
2035 277574 : foreach(lc, parsetree->cteList)
2036 : {
2037 96 : CommonTableExpr *cte = lfirst_node(CommonTableExpr, lc);
2038 :
2039 96 : ScanQueryForLocks(castNode(Query, cte->ctequery), acquire);
2040 : }
2041 :
2042 : /*
2043 : * Recurse into sublink subqueries, too. But we already did the ones in
2044 : * the rtable and cteList.
2045 : */
2046 277478 : if (parsetree->hasSubLinks)
2047 : {
2048 4748 : query_tree_walker(parsetree, ScanQueryWalker, &acquire,
2049 : QTW_IGNORE_RC_SUBQUERIES);
2050 : }
2051 277478 : }
2052 :
2053 : /*
2054 : * Walker to find sublink subqueries for ScanQueryForLocks
2055 : */
2056 : static bool
2057 128442 : ScanQueryWalker(Node *node, bool *acquire)
2058 : {
2059 128442 : if (node == NULL)
2060 58130 : return false;
2061 70312 : if (IsA(node, SubLink))
2062 : {
2063 4914 : SubLink *sub = (SubLink *) node;
2064 :
2065 : /* Do what we came for */
2066 4914 : ScanQueryForLocks(castNode(Query, sub->subselect), *acquire);
2067 : /* Fall through to process lefthand args of SubLink */
2068 : }
2069 :
2070 : /*
2071 : * Do NOT recurse into Query nodes, because ScanQueryForLocks already
2072 : * processed subselects of subselects for us.
2073 : */
2074 70312 : return expression_tree_walker(node, ScanQueryWalker, acquire);
2075 : }
2076 :
2077 : /*
2078 : * PlanCacheComputeResultDesc: given a list of analyzed-and-rewritten Queries,
2079 : * determine the result tupledesc it will produce. Returns NULL if the
2080 : * execution will not return tuples.
2081 : *
2082 : * Note: the result is created or copied into current memory context.
2083 : */
2084 : static TupleDesc
2085 83650 : PlanCacheComputeResultDesc(List *stmt_list)
2086 : {
2087 : Query *query;
2088 :
2089 83650 : switch (ChoosePortalStrategy(stmt_list))
2090 : {
2091 55304 : case PORTAL_ONE_SELECT:
2092 : case PORTAL_ONE_MOD_WITH:
2093 55304 : query = linitial_node(Query, stmt_list);
2094 55304 : return ExecCleanTypeFromTL(query->targetList);
2095 :
2096 302 : case PORTAL_ONE_RETURNING:
2097 302 : query = QueryListGetPrimaryStmt(stmt_list);
2098 : Assert(query->returningList);
2099 302 : return ExecCleanTypeFromTL(query->returningList);
2100 :
2101 10056 : case PORTAL_UTIL_SELECT:
2102 10056 : query = linitial_node(Query, stmt_list);
2103 : Assert(query->utilityStmt);
2104 10056 : return UtilityTupleDescriptor(query->utilityStmt);
2105 :
2106 17988 : case PORTAL_MULTI_QUERY:
2107 : /* will not return tuples */
2108 17988 : break;
2109 : }
2110 17988 : return NULL;
2111 : }
2112 :
2113 : /*
2114 : * PlanCacheRelCallback
2115 : * Relcache inval callback function
2116 : *
2117 : * Invalidate all plans mentioning the given rel, or all plans mentioning
2118 : * any rel at all if relid == InvalidOid.
2119 : */
2120 : static void
2121 3041950 : PlanCacheRelCallback(Datum arg, Oid relid)
2122 : {
2123 : dlist_iter iter;
2124 :
2125 59059152 : dlist_foreach(iter, &saved_plan_list)
2126 : {
2127 56017202 : CachedPlanSource *plansource = dlist_container(CachedPlanSource,
2128 : node, iter.cur);
2129 :
2130 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
2131 :
2132 : /* No work if it's already invalidated */
2133 56017202 : if (!plansource->is_valid)
2134 30489100 : continue;
2135 :
2136 : /* Never invalidate if parse/plan would be a no-op anyway */
2137 25528102 : if (!StmtPlanRequiresRevalidation(plansource))
2138 349852 : continue;
2139 :
2140 : /*
2141 : * Check the dependency list for the rewritten querytree.
2142 : */
2143 50356488 : if ((relid == InvalidOid) ? plansource->relationOids != NIL :
2144 25178238 : list_member_oid(plansource->relationOids, relid))
2145 : {
2146 : /* Invalidate the querytree and generic plan */
2147 3690 : plansource->is_valid = false;
2148 3690 : if (plansource->gplan)
2149 1168 : plansource->gplan->is_valid = false;
2150 : }
2151 :
2152 : /*
2153 : * The generic plan, if any, could have more dependencies than the
2154 : * querytree does, so we have to check it too.
2155 : */
2156 25178250 : if (plansource->gplan && plansource->gplan->is_valid)
2157 : {
2158 : ListCell *lc;
2159 :
2160 47561422 : foreach(lc, plansource->gplan->stmt_list)
2161 : {
2162 23780752 : PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
2163 :
2164 23780752 : if (plannedstmt->commandType == CMD_UTILITY)
2165 4596 : continue; /* Ignore utility statements */
2166 47552312 : if ((relid == InvalidOid) ? plannedstmt->relationOids != NIL :
2167 23776156 : list_member_oid(plannedstmt->relationOids, relid))
2168 : {
2169 : /* Invalidate the generic plan only */
2170 82 : plansource->gplan->is_valid = false;
2171 82 : break; /* out of stmt_list scan */
2172 : }
2173 : }
2174 : }
2175 : }
2176 :
2177 : /* Likewise check cached expressions */
2178 3368454 : dlist_foreach(iter, &cached_expression_list)
2179 : {
2180 326504 : CachedExpression *cexpr = dlist_container(CachedExpression,
2181 : node, iter.cur);
2182 :
2183 : Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2184 :
2185 : /* No work if it's already invalidated */
2186 326504 : if (!cexpr->is_valid)
2187 111072 : continue;
2188 :
2189 430864 : if ((relid == InvalidOid) ? cexpr->relationOids != NIL :
2190 215432 : list_member_oid(cexpr->relationOids, relid))
2191 : {
2192 0 : cexpr->is_valid = false;
2193 : }
2194 : }
2195 3041950 : }
2196 :
2197 : /*
2198 : * PlanCacheObjectCallback
2199 : * Syscache inval callback function for PROCOID and TYPEOID caches
2200 : *
2201 : * Invalidate all plans mentioning the object with the specified hash value,
2202 : * or all plans mentioning any member of this cache if hashvalue == 0.
2203 : */
2204 : static void
2205 1156122 : PlanCacheObjectCallback(Datum arg, int cacheid, uint32 hashvalue)
2206 : {
2207 : dlist_iter iter;
2208 :
2209 22759722 : dlist_foreach(iter, &saved_plan_list)
2210 : {
2211 21603600 : CachedPlanSource *plansource = dlist_container(CachedPlanSource,
2212 : node, iter.cur);
2213 : ListCell *lc;
2214 :
2215 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
2216 :
2217 : /* No work if it's already invalidated */
2218 21603600 : if (!plansource->is_valid)
2219 10655050 : continue;
2220 :
2221 : /* Never invalidate if parse/plan would be a no-op anyway */
2222 10948550 : if (!StmtPlanRequiresRevalidation(plansource))
2223 92874 : continue;
2224 :
2225 : /*
2226 : * Check the dependency list for the rewritten querytree.
2227 : */
2228 11090422 : foreach(lc, plansource->invalItems)
2229 : {
2230 234894 : PlanInvalItem *item = (PlanInvalItem *) lfirst(lc);
2231 :
2232 234894 : if (item->cacheId != cacheid)
2233 150844 : continue;
2234 84050 : if (hashvalue == 0 ||
2235 84050 : item->hashValue == hashvalue)
2236 : {
2237 : /* Invalidate the querytree and generic plan */
2238 148 : plansource->is_valid = false;
2239 148 : if (plansource->gplan)
2240 144 : plansource->gplan->is_valid = false;
2241 148 : break;
2242 : }
2243 : }
2244 :
2245 : /*
2246 : * The generic plan, if any, could have more dependencies than the
2247 : * querytree does, so we have to check it too.
2248 : */
2249 10855676 : if (plansource->gplan && plansource->gplan->is_valid)
2250 : {
2251 20389104 : foreach(lc, plansource->gplan->stmt_list)
2252 : {
2253 10194564 : PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
2254 : ListCell *lc3;
2255 :
2256 10194564 : if (plannedstmt->commandType == CMD_UTILITY)
2257 2902 : continue; /* Ignore utility statements */
2258 10417228 : foreach(lc3, plannedstmt->invalItems)
2259 : {
2260 225590 : PlanInvalItem *item = (PlanInvalItem *) lfirst(lc3);
2261 :
2262 225590 : if (item->cacheId != cacheid)
2263 143212 : continue;
2264 82378 : if (hashvalue == 0 ||
2265 82378 : item->hashValue == hashvalue)
2266 : {
2267 : /* Invalidate the generic plan only */
2268 24 : plansource->gplan->is_valid = false;
2269 24 : break; /* out of invalItems scan */
2270 : }
2271 : }
2272 10191662 : if (!plansource->gplan->is_valid)
2273 24 : break; /* out of stmt_list scan */
2274 : }
2275 : }
2276 : }
2277 :
2278 : /* Likewise check cached expressions */
2279 1299598 : dlist_foreach(iter, &cached_expression_list)
2280 : {
2281 143476 : CachedExpression *cexpr = dlist_container(CachedExpression,
2282 : node, iter.cur);
2283 : ListCell *lc;
2284 :
2285 : Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2286 :
2287 : /* No work if it's already invalidated */
2288 143476 : if (!cexpr->is_valid)
2289 41962 : continue;
2290 :
2291 101530 : foreach(lc, cexpr->invalItems)
2292 : {
2293 22 : PlanInvalItem *item = (PlanInvalItem *) lfirst(lc);
2294 :
2295 22 : if (item->cacheId != cacheid)
2296 4 : continue;
2297 18 : if (hashvalue == 0 ||
2298 18 : item->hashValue == hashvalue)
2299 : {
2300 6 : cexpr->is_valid = false;
2301 6 : break;
2302 : }
2303 : }
2304 : }
2305 1156122 : }
2306 :
2307 : /*
2308 : * PlanCacheSysCallback
2309 : * Syscache inval callback function for other caches
2310 : *
2311 : * Just invalidate everything...
2312 : */
2313 : static void
2314 77240 : PlanCacheSysCallback(Datum arg, int cacheid, uint32 hashvalue)
2315 : {
2316 77240 : ResetPlanCache();
2317 77240 : }
2318 :
2319 : /*
2320 : * ResetPlanCache: invalidate all cached plans.
2321 : */
2322 : void
2323 78340 : ResetPlanCache(void)
2324 : {
2325 : dlist_iter iter;
2326 :
2327 300800 : dlist_foreach(iter, &saved_plan_list)
2328 : {
2329 222460 : CachedPlanSource *plansource = dlist_container(CachedPlanSource,
2330 : node, iter.cur);
2331 :
2332 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
2333 :
2334 : /* No work if it's already invalidated */
2335 222460 : if (!plansource->is_valid)
2336 203216 : continue;
2337 :
2338 : /*
2339 : * We *must not* mark transaction control statements as invalid,
2340 : * particularly not ROLLBACK, because they may need to be executed in
2341 : * aborted transactions when we can't revalidate them (cf bug #5269).
2342 : * In general there's no point in invalidating statements for which a
2343 : * new parse analysis/rewrite/plan cycle would certainly give the same
2344 : * results.
2345 : */
2346 19244 : if (!StmtPlanRequiresRevalidation(plansource))
2347 6396 : continue;
2348 :
2349 12848 : plansource->is_valid = false;
2350 12848 : if (plansource->gplan)
2351 11568 : plansource->gplan->is_valid = false;
2352 : }
2353 :
2354 : /* Likewise invalidate cached expressions */
2355 79512 : dlist_foreach(iter, &cached_expression_list)
2356 : {
2357 1172 : CachedExpression *cexpr = dlist_container(CachedExpression,
2358 : node, iter.cur);
2359 :
2360 : Assert(cexpr->magic == CACHEDEXPR_MAGIC);
2361 :
2362 1172 : cexpr->is_valid = false;
2363 : }
2364 78340 : }
2365 :
2366 : /*
2367 : * Release all CachedPlans remembered by 'owner'
2368 : */
2369 : void
2370 16420 : ReleaseAllPlanCacheRefsInOwner(ResourceOwner owner)
2371 : {
2372 16420 : ResourceOwnerReleaseAllOfKind(owner, &planref_resowner_desc);
2373 16420 : }
2374 :
2375 : /* ResourceOwner callbacks */
2376 :
2377 : static void
2378 90514 : ResOwnerReleaseCachedPlan(Datum res)
2379 : {
2380 90514 : ReleaseCachedPlan((CachedPlan *) DatumGetPointer(res), NULL);
2381 90514 : }
|