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