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