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 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 and
31 : * user-defined functions. On relcache invalidation events or pg_proc
32 : * syscache invalidation events, we invalidate just those plans that depend
33 : * on the particular object being modified. (Note: this scheme assumes
34 : * that any table modification that requires replanning will generate a
35 : * relcache inval event.) We also watch for inval events on certain other
36 : * system catalogs, such as pg_namespace; but for them, our response is
37 : * just to invalidate all plans. We expect updates on those catalogs to
38 : * be infrequent enough that more-detailed tracking is not worth the effort.
39 : *
40 : *
41 : * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
42 : * Portions Copyright (c) 1994, Regents of the University of California
43 : *
44 : * IDENTIFICATION
45 : * src/backend/utils/cache/plancache.c
46 : *
47 : *-------------------------------------------------------------------------
48 : */
49 : #include "postgres.h"
50 :
51 : #include <limits.h>
52 :
53 : #include "access/transam.h"
54 : #include "catalog/namespace.h"
55 : #include "executor/executor.h"
56 : #include "miscadmin.h"
57 : #include "nodes/nodeFuncs.h"
58 : #include "optimizer/cost.h"
59 : #include "optimizer/planmain.h"
60 : #include "optimizer/prep.h"
61 : #include "parser/analyze.h"
62 : #include "parser/parsetree.h"
63 : #include "storage/lmgr.h"
64 : #include "tcop/pquery.h"
65 : #include "tcop/utility.h"
66 : #include "utils/inval.h"
67 : #include "utils/memutils.h"
68 : #include "utils/resowner_private.h"
69 : #include "utils/rls.h"
70 : #include "utils/snapmgr.h"
71 : #include "utils/syscache.h"
72 :
73 :
74 : /*
75 : * We must skip "overhead" operations that involve database access when the
76 : * cached plan's subject statement is a transaction control command.
77 : */
78 : #define IsTransactionStmtPlan(plansource) \
79 : ((plansource)->raw_parse_tree && \
80 : IsA((plansource)->raw_parse_tree->stmt, TransactionStmt))
81 :
82 : /*
83 : * This is the head of the backend's list of "saved" CachedPlanSources (i.e.,
84 : * those that are in long-lived storage and are examined for sinval events).
85 : * We thread the structs manually instead of using List cells so that we can
86 : * guarantee to save a CachedPlanSource without error.
87 : */
88 : static CachedPlanSource *first_saved_plan = NULL;
89 :
90 : static void ReleaseGenericPlan(CachedPlanSource *plansource);
91 : static List *RevalidateCachedQuery(CachedPlanSource *plansource,
92 : QueryEnvironment *queryEnv);
93 : static bool CheckCachedPlan(CachedPlanSource *plansource);
94 : static CachedPlan *BuildCachedPlan(CachedPlanSource *plansource, List *qlist,
95 : ParamListInfo boundParams, QueryEnvironment *queryEnv);
96 : static bool choose_custom_plan(CachedPlanSource *plansource,
97 : ParamListInfo boundParams);
98 : static double cached_plan_cost(CachedPlan *plan, bool include_planner);
99 : static Query *QueryListGetPrimaryStmt(List *stmts);
100 : static void AcquireExecutorLocks(List *stmt_list, bool acquire);
101 : static void AcquirePlannerLocks(List *stmt_list, bool acquire);
102 : static void ScanQueryForLocks(Query *parsetree, bool acquire);
103 : static bool ScanQueryWalker(Node *node, bool *acquire);
104 : static TupleDesc PlanCacheComputeResultDesc(List *stmt_list);
105 : static void PlanCacheRelCallback(Datum arg, Oid relid);
106 : static void PlanCacheFuncCallback(Datum arg, int cacheid, uint32 hashvalue);
107 : static void PlanCacheSysCallback(Datum arg, int cacheid, uint32 hashvalue);
108 :
109 :
110 : /*
111 : * InitPlanCache: initialize module during InitPostgres.
112 : *
113 : * All we need to do is hook into inval.c's callback lists.
114 : */
115 : void
116 338 : InitPlanCache(void)
117 : {
118 338 : CacheRegisterRelcacheCallback(PlanCacheRelCallback, (Datum) 0);
119 338 : CacheRegisterSyscacheCallback(PROCOID, PlanCacheFuncCallback, (Datum) 0);
120 338 : CacheRegisterSyscacheCallback(NAMESPACEOID, PlanCacheSysCallback, (Datum) 0);
121 338 : CacheRegisterSyscacheCallback(OPEROID, PlanCacheSysCallback, (Datum) 0);
122 338 : CacheRegisterSyscacheCallback(AMOPOPID, PlanCacheSysCallback, (Datum) 0);
123 338 : CacheRegisterSyscacheCallback(FOREIGNSERVEROID, PlanCacheSysCallback, (Datum) 0);
124 338 : CacheRegisterSyscacheCallback(FOREIGNDATAWRAPPEROID, PlanCacheSysCallback, (Datum) 0);
125 338 : }
126 :
127 : /*
128 : * CreateCachedPlan: initially create a plan cache entry.
129 : *
130 : * Creation of a cached plan is divided into two steps, CreateCachedPlan and
131 : * CompleteCachedPlan. CreateCachedPlan should be called after running the
132 : * query through raw_parser, but before doing parse analysis and rewrite;
133 : * CompleteCachedPlan is called after that. The reason for this arrangement
134 : * is that it can save one round of copying of the raw parse tree, since
135 : * the parser will normally scribble on the raw parse tree. Callers would
136 : * otherwise need to make an extra copy of the parse tree to ensure they
137 : * still had a clean copy to present at plan cache creation time.
138 : *
139 : * All arguments presented to CreateCachedPlan are copied into a memory
140 : * context created as a child of the call-time CurrentMemoryContext, which
141 : * should be a reasonably short-lived working context that will go away in
142 : * event of an error. This ensures that the cached plan data structure will
143 : * likewise disappear if an error occurs before we have fully constructed it.
144 : * Once constructed, the cached plan can be made longer-lived, if needed,
145 : * by calling SaveCachedPlan.
146 : *
147 : * raw_parse_tree: output of raw_parser(), or NULL if empty query
148 : * query_string: original query text
149 : * commandTag: compile-time-constant tag for query, or NULL if empty query
150 : */
151 : CachedPlanSource *
152 2355 : CreateCachedPlan(RawStmt *raw_parse_tree,
153 : const char *query_string,
154 : const char *commandTag)
155 : {
156 : CachedPlanSource *plansource;
157 : MemoryContext source_context;
158 : MemoryContext oldcxt;
159 :
160 2355 : Assert(query_string != NULL); /* required as of 8.4 */
161 :
162 : /*
163 : * Make a dedicated memory context for the CachedPlanSource and its
164 : * permanent subsidiary data. It's probably not going to be large, but
165 : * just in case, allow it to grow large. Initially it's a child of the
166 : * caller's context (which we assume to be transient), so that it will be
167 : * cleaned up on error.
168 : */
169 2355 : source_context = AllocSetContextCreate(CurrentMemoryContext,
170 : "CachedPlanSource",
171 : ALLOCSET_START_SMALL_SIZES);
172 :
173 : /*
174 : * Create and fill the CachedPlanSource struct within the new context.
175 : * Most fields are just left empty for the moment.
176 : */
177 2355 : oldcxt = MemoryContextSwitchTo(source_context);
178 :
179 2355 : plansource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
180 2355 : plansource->magic = CACHEDPLANSOURCE_MAGIC;
181 2355 : plansource->raw_parse_tree = copyObject(raw_parse_tree);
182 2355 : plansource->query_string = pstrdup(query_string);
183 2355 : plansource->commandTag = commandTag;
184 2355 : plansource->param_types = NULL;
185 2355 : plansource->num_params = 0;
186 2355 : plansource->parserSetup = NULL;
187 2355 : plansource->parserSetupArg = NULL;
188 2355 : plansource->cursor_options = 0;
189 2355 : plansource->fixed_result = false;
190 2355 : plansource->resultDesc = NULL;
191 2355 : plansource->context = source_context;
192 2355 : plansource->query_list = NIL;
193 2355 : plansource->relationOids = NIL;
194 2355 : plansource->invalItems = NIL;
195 2355 : plansource->search_path = NULL;
196 2355 : plansource->query_context = NULL;
197 2355 : plansource->rewriteRoleId = InvalidOid;
198 2355 : plansource->rewriteRowSecurity = false;
199 2355 : plansource->dependsOnRLS = false;
200 2355 : plansource->gplan = NULL;
201 2355 : plansource->is_oneshot = false;
202 2355 : plansource->is_complete = false;
203 2355 : plansource->is_saved = false;
204 2355 : plansource->is_valid = false;
205 2355 : plansource->generation = 0;
206 2355 : plansource->next_saved = NULL;
207 2355 : plansource->generic_cost = -1;
208 2355 : plansource->total_custom_cost = 0;
209 2355 : plansource->num_custom_plans = 0;
210 :
211 2355 : MemoryContextSwitchTo(oldcxt);
212 :
213 2355 : return plansource;
214 : }
215 :
216 : /*
217 : * CreateOneShotCachedPlan: initially create a one-shot plan cache entry.
218 : *
219 : * This variant of CreateCachedPlan creates a plan cache entry that is meant
220 : * to be used only once. No data copying occurs: all data structures remain
221 : * in the caller's memory context (which typically should get cleared after
222 : * completing execution). The CachedPlanSource struct itself is also created
223 : * in that context.
224 : *
225 : * A one-shot plan cannot be saved or copied, since we make no effort to
226 : * preserve the raw parse tree unmodified. There is also no support for
227 : * invalidation, so plan use must be completed in the current transaction,
228 : * and DDL that might invalidate the querytree_list must be avoided as well.
229 : *
230 : * raw_parse_tree: output of raw_parser(), or NULL if empty query
231 : * query_string: original query text
232 : * commandTag: compile-time-constant tag for query, or NULL if empty query
233 : */
234 : CachedPlanSource *
235 624 : CreateOneShotCachedPlan(RawStmt *raw_parse_tree,
236 : const char *query_string,
237 : const char *commandTag)
238 : {
239 : CachedPlanSource *plansource;
240 :
241 624 : Assert(query_string != NULL); /* required as of 8.4 */
242 :
243 : /*
244 : * Create and fill the CachedPlanSource struct within the caller's memory
245 : * context. Most fields are just left empty for the moment.
246 : */
247 624 : plansource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
248 624 : plansource->magic = CACHEDPLANSOURCE_MAGIC;
249 624 : plansource->raw_parse_tree = raw_parse_tree;
250 624 : plansource->query_string = query_string;
251 624 : plansource->commandTag = commandTag;
252 624 : plansource->param_types = NULL;
253 624 : plansource->num_params = 0;
254 624 : plansource->parserSetup = NULL;
255 624 : plansource->parserSetupArg = NULL;
256 624 : plansource->cursor_options = 0;
257 624 : plansource->fixed_result = false;
258 624 : plansource->resultDesc = NULL;
259 624 : plansource->context = CurrentMemoryContext;
260 624 : plansource->query_list = NIL;
261 624 : plansource->relationOids = NIL;
262 624 : plansource->invalItems = NIL;
263 624 : plansource->search_path = NULL;
264 624 : plansource->query_context = NULL;
265 624 : plansource->rewriteRoleId = InvalidOid;
266 624 : plansource->rewriteRowSecurity = false;
267 624 : plansource->dependsOnRLS = false;
268 624 : plansource->gplan = NULL;
269 624 : plansource->is_oneshot = true;
270 624 : plansource->is_complete = false;
271 624 : plansource->is_saved = false;
272 624 : plansource->is_valid = false;
273 624 : plansource->generation = 0;
274 624 : plansource->next_saved = NULL;
275 624 : plansource->generic_cost = -1;
276 624 : plansource->total_custom_cost = 0;
277 624 : plansource->num_custom_plans = 0;
278 :
279 624 : return plansource;
280 : }
281 :
282 : /*
283 : * CompleteCachedPlan: second step of creating a plan cache entry.
284 : *
285 : * Pass in the analyzed-and-rewritten form of the query, as well as the
286 : * required subsidiary data about parameters and such. All passed values will
287 : * be copied into the CachedPlanSource's memory, except as specified below.
288 : * After this is called, GetCachedPlan can be called to obtain a plan, and
289 : * optionally the CachedPlanSource can be saved using SaveCachedPlan.
290 : *
291 : * If querytree_context is not NULL, the querytree_list must be stored in that
292 : * context (but the other parameters need not be). The querytree_list is not
293 : * copied, rather the given context is kept as the initial query_context of
294 : * the CachedPlanSource. (It should have been created as a child of the
295 : * caller's working memory context, but it will now be reparented to belong
296 : * to the CachedPlanSource.) The querytree_context is normally the context in
297 : * which the caller did raw parsing and parse analysis. This approach saves
298 : * one tree copying step compared to passing NULL, but leaves lots of extra
299 : * cruft in the query_context, namely whatever extraneous stuff parse analysis
300 : * created, as well as whatever went unused from the raw parse tree. Using
301 : * this option is a space-for-time tradeoff that is appropriate if the
302 : * CachedPlanSource is not expected to survive long.
303 : *
304 : * plancache.c cannot know how to copy the data referenced by parserSetupArg,
305 : * and it would often be inappropriate to do so anyway. When using that
306 : * option, it is caller's responsibility that the referenced data remains
307 : * valid for as long as the CachedPlanSource exists.
308 : *
309 : * If the CachedPlanSource is a "oneshot" plan, then no querytree copying
310 : * occurs at all, and querytree_context is ignored; it is caller's
311 : * responsibility that the passed querytree_list is sufficiently long-lived.
312 : *
313 : * plansource: structure returned by CreateCachedPlan
314 : * querytree_list: analyzed-and-rewritten form of query (list of Query nodes)
315 : * querytree_context: memory context containing querytree_list,
316 : * or NULL to copy querytree_list into a fresh context
317 : * param_types: array of fixed parameter type OIDs, or NULL if none
318 : * num_params: number of fixed parameters
319 : * parserSetup: alternate method for handling query parameters
320 : * parserSetupArg: data to pass to parserSetup
321 : * cursor_options: options bitmask to pass to planner
322 : * fixed_result: TRUE to disallow future changes in query's result tupdesc
323 : */
324 : void
325 2972 : CompleteCachedPlan(CachedPlanSource *plansource,
326 : List *querytree_list,
327 : MemoryContext querytree_context,
328 : Oid *param_types,
329 : int num_params,
330 : ParserSetupHook parserSetup,
331 : void *parserSetupArg,
332 : int cursor_options,
333 : bool fixed_result)
334 : {
335 2972 : MemoryContext source_context = plansource->context;
336 2972 : MemoryContext oldcxt = CurrentMemoryContext;
337 :
338 : /* Assert caller is doing things in a sane order */
339 2972 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
340 2972 : Assert(!plansource->is_complete);
341 :
342 : /*
343 : * If caller supplied a querytree_context, reparent it underneath the
344 : * CachedPlanSource's context; otherwise, create a suitable context and
345 : * copy the querytree_list into it. But no data copying should be done
346 : * for one-shot plans; for those, assume the passed querytree_list is
347 : * sufficiently long-lived.
348 : */
349 2972 : if (plansource->is_oneshot)
350 : {
351 624 : querytree_context = CurrentMemoryContext;
352 : }
353 2348 : else if (querytree_context != NULL)
354 : {
355 0 : MemoryContextSetParent(querytree_context, source_context);
356 0 : MemoryContextSwitchTo(querytree_context);
357 : }
358 : else
359 : {
360 : /* Again, it's a good bet the querytree_context can be small */
361 2348 : querytree_context = AllocSetContextCreate(source_context,
362 : "CachedPlanQuery",
363 : ALLOCSET_START_SMALL_SIZES);
364 2348 : MemoryContextSwitchTo(querytree_context);
365 2348 : querytree_list = copyObject(querytree_list);
366 : }
367 :
368 2972 : plansource->query_context = querytree_context;
369 2972 : plansource->query_list = querytree_list;
370 :
371 2972 : if (!plansource->is_oneshot && !IsTransactionStmtPlan(plansource))
372 : {
373 : /*
374 : * Use the planner machinery to extract dependencies. Data is saved
375 : * in query_context. (We assume that not a lot of extra cruft is
376 : * created by this call.) We can skip this for one-shot plans, and
377 : * transaction control commands have no such dependencies anyway.
378 : */
379 2348 : extract_query_dependencies((Node *) querytree_list,
380 : &plansource->relationOids,
381 : &plansource->invalItems,
382 : &plansource->dependsOnRLS);
383 :
384 : /* Update RLS info as well. */
385 2348 : plansource->rewriteRoleId = GetUserId();
386 2348 : plansource->rewriteRowSecurity = row_security;
387 :
388 : /*
389 : * Also save the current search_path in the query_context. (This
390 : * should not generate much extra cruft either, since almost certainly
391 : * the path is already valid.) Again, we don't really need this for
392 : * one-shot plans; and we *must* skip this for transaction control
393 : * commands, because this could result in catalog accesses.
394 : */
395 2348 : plansource->search_path = GetOverrideSearchPath(querytree_context);
396 : }
397 :
398 : /*
399 : * Save the final parameter types (or other parameter specification data)
400 : * into the source_context, as well as our other parameters. Also save
401 : * the result tuple descriptor.
402 : */
403 2972 : MemoryContextSwitchTo(source_context);
404 :
405 2972 : if (num_params > 0)
406 : {
407 182 : plansource->param_types = (Oid *) palloc(num_params * sizeof(Oid));
408 182 : memcpy(plansource->param_types, param_types, num_params * sizeof(Oid));
409 : }
410 : else
411 2790 : plansource->param_types = NULL;
412 2972 : plansource->num_params = num_params;
413 2972 : plansource->parserSetup = parserSetup;
414 2972 : plansource->parserSetupArg = parserSetupArg;
415 2972 : plansource->cursor_options = cursor_options;
416 2972 : plansource->fixed_result = fixed_result;
417 2972 : plansource->resultDesc = PlanCacheComputeResultDesc(querytree_list);
418 :
419 2972 : MemoryContextSwitchTo(oldcxt);
420 :
421 2972 : plansource->is_complete = true;
422 2972 : plansource->is_valid = true;
423 2972 : }
424 :
425 : /*
426 : * SaveCachedPlan: save a cached plan permanently
427 : *
428 : * This function moves the cached plan underneath CacheMemoryContext (making
429 : * it live for the life of the backend, unless explicitly dropped), and adds
430 : * it to the list of cached plans that are checked for invalidation when an
431 : * sinval event occurs.
432 : *
433 : * This is guaranteed not to throw error, except for the caller-error case
434 : * of trying to save a one-shot plan. Callers typically depend on that
435 : * since this is called just before or just after adding a pointer to the
436 : * CachedPlanSource to some permanent data structure of their own. Up until
437 : * this is done, a CachedPlanSource is just transient data that will go away
438 : * automatically on transaction abort.
439 : */
440 : void
441 1781 : SaveCachedPlan(CachedPlanSource *plansource)
442 : {
443 : /* Assert caller is doing things in a sane order */
444 1781 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
445 1781 : Assert(plansource->is_complete);
446 1781 : Assert(!plansource->is_saved);
447 :
448 : /* This seems worth a real test, though */
449 1781 : if (plansource->is_oneshot)
450 0 : elog(ERROR, "cannot save one-shot cached plan");
451 :
452 : /*
453 : * In typical use, this function would be called before generating any
454 : * plans from the CachedPlanSource. If there is a generic plan, moving it
455 : * into CacheMemoryContext would be pretty risky since it's unclear
456 : * whether the caller has taken suitable care with making references
457 : * long-lived. Best thing to do seems to be to discard the plan.
458 : */
459 1781 : ReleaseGenericPlan(plansource);
460 :
461 : /*
462 : * Reparent the source memory context under CacheMemoryContext so that it
463 : * will live indefinitely. The query_context follows along since it's
464 : * already a child of the other one.
465 : */
466 1781 : MemoryContextSetParent(plansource->context, CacheMemoryContext);
467 :
468 : /*
469 : * Add the entry to the global list of cached plans.
470 : */
471 1781 : plansource->next_saved = first_saved_plan;
472 1781 : first_saved_plan = plansource;
473 :
474 1781 : plansource->is_saved = true;
475 1781 : }
476 :
477 : /*
478 : * DropCachedPlan: destroy a cached plan.
479 : *
480 : * Actually this only destroys the CachedPlanSource: any referenced CachedPlan
481 : * is released, but not destroyed until its refcount goes to zero. That
482 : * handles the situation where DropCachedPlan is called while the plan is
483 : * still in use.
484 : */
485 : void
486 353 : DropCachedPlan(CachedPlanSource *plansource)
487 : {
488 353 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
489 :
490 : /* If it's been saved, remove it from the list */
491 353 : if (plansource->is_saved)
492 : {
493 329 : if (first_saved_plan == plansource)
494 131 : first_saved_plan = plansource->next_saved;
495 : else
496 : {
497 : CachedPlanSource *psrc;
498 :
499 810 : for (psrc = first_saved_plan; psrc; psrc = psrc->next_saved)
500 : {
501 810 : if (psrc->next_saved == plansource)
502 : {
503 198 : psrc->next_saved = plansource->next_saved;
504 198 : break;
505 : }
506 : }
507 : }
508 329 : plansource->is_saved = false;
509 : }
510 :
511 : /* Decrement generic CachePlan's refcount and drop if no longer needed */
512 353 : ReleaseGenericPlan(plansource);
513 :
514 : /* Mark it no longer valid */
515 353 : plansource->magic = 0;
516 :
517 : /*
518 : * Remove the CachedPlanSource and all subsidiary data (including the
519 : * query_context if any). But if it's a one-shot we can't free anything.
520 : */
521 353 : if (!plansource->is_oneshot)
522 353 : MemoryContextDelete(plansource->context);
523 353 : }
524 :
525 : /*
526 : * ReleaseGenericPlan: release a CachedPlanSource's generic plan, if any.
527 : */
528 : static void
529 5420 : ReleaseGenericPlan(CachedPlanSource *plansource)
530 : {
531 : /* Be paranoid about the possibility that ReleaseCachedPlan fails */
532 5420 : if (plansource->gplan)
533 : {
534 892 : CachedPlan *plan = plansource->gplan;
535 :
536 892 : Assert(plan->magic == CACHEDPLAN_MAGIC);
537 892 : plansource->gplan = NULL;
538 892 : ReleaseCachedPlan(plan, false);
539 : }
540 5420 : }
541 :
542 : /*
543 : * RevalidateCachedQuery: ensure validity of analyzed-and-rewritten query tree.
544 : *
545 : * What we do here is re-acquire locks and redo parse analysis if necessary.
546 : * On return, the query_list is valid and we have sufficient locks to begin
547 : * planning.
548 : *
549 : * If any parse analysis activity is required, the caller's memory context is
550 : * used for that work.
551 : *
552 : * The result value is the transient analyzed-and-rewritten query tree if we
553 : * had to do re-analysis, and NIL otherwise. (This is returned just to save
554 : * a tree copying step in a subsequent BuildCachedPlan call.)
555 : */
556 : static List *
557 33684 : RevalidateCachedQuery(CachedPlanSource *plansource,
558 : QueryEnvironment *queryEnv)
559 : {
560 : bool snapshot_set;
561 : RawStmt *rawtree;
562 : List *tlist; /* transient query-tree list */
563 : List *qlist; /* permanent query-tree list */
564 : TupleDesc resultDesc;
565 : MemoryContext querytree_context;
566 : MemoryContext oldcxt;
567 :
568 : /*
569 : * For one-shot plans, we do not support revalidation checking; it's
570 : * assumed the query is parsed, planned, and executed in one transaction,
571 : * so that no lock re-acquisition is necessary. Also, there is never any
572 : * need to revalidate plans for transaction control commands (and we
573 : * mustn't risk any catalog accesses when handling those).
574 : */
575 33684 : if (plansource->is_oneshot || IsTransactionStmtPlan(plansource))
576 : {
577 624 : Assert(plansource->is_valid);
578 624 : return NIL;
579 : }
580 :
581 : /*
582 : * If the query is currently valid, we should have a saved search_path ---
583 : * check to see if that matches the current environment. If not, we want
584 : * to force replan.
585 : */
586 33060 : if (plansource->is_valid)
587 : {
588 32471 : Assert(plansource->search_path != NULL);
589 32471 : if (!OverrideSearchPathMatchesCurrent(plansource->search_path))
590 : {
591 : /* Invalidate the querytree and generic plan */
592 4 : plansource->is_valid = false;
593 4 : if (plansource->gplan)
594 3 : plansource->gplan->is_valid = false;
595 : }
596 : }
597 :
598 : /*
599 : * If the query rewrite phase had a possible RLS dependency, we must redo
600 : * it if either the role or the row_security setting has changed.
601 : */
602 33099 : if (plansource->is_valid && plansource->dependsOnRLS &&
603 66 : (plansource->rewriteRoleId != GetUserId() ||
604 27 : plansource->rewriteRowSecurity != row_security))
605 12 : plansource->is_valid = false;
606 :
607 : /*
608 : * If the query is currently valid, acquire locks on the referenced
609 : * objects; then check again. We need to do it this way to cover the race
610 : * condition that an invalidation message arrives before we get the locks.
611 : */
612 33060 : if (plansource->is_valid)
613 : {
614 32455 : AcquirePlannerLocks(plansource->query_list, true);
615 :
616 : /*
617 : * By now, if any invalidation has happened, the inval callback
618 : * functions will have marked the query invalid.
619 : */
620 32455 : if (plansource->is_valid)
621 : {
622 : /* Successfully revalidated and locked the query. */
623 32455 : return NIL;
624 : }
625 :
626 : /* Oops, the race case happened. Release useless locks. */
627 0 : AcquirePlannerLocks(plansource->query_list, false);
628 : }
629 :
630 : /*
631 : * Discard the no-longer-useful query tree. (Note: we don't want to do
632 : * this any earlier, else we'd not have been able to release locks
633 : * correctly in the race condition case.)
634 : */
635 605 : plansource->is_valid = false;
636 605 : plansource->query_list = NIL;
637 605 : plansource->relationOids = NIL;
638 605 : plansource->invalItems = NIL;
639 605 : plansource->search_path = NULL;
640 :
641 : /*
642 : * Free the query_context. We don't really expect MemoryContextDelete to
643 : * fail, but just in case, make sure the CachedPlanSource is left in a
644 : * reasonably sane state. (The generic plan won't get unlinked yet, but
645 : * that's acceptable.)
646 : */
647 605 : if (plansource->query_context)
648 : {
649 601 : MemoryContext qcxt = plansource->query_context;
650 :
651 601 : plansource->query_context = NULL;
652 601 : MemoryContextDelete(qcxt);
653 : }
654 :
655 : /* Drop the generic plan reference if any */
656 605 : ReleaseGenericPlan(plansource);
657 :
658 : /*
659 : * Now re-do parse analysis and rewrite. This not incidentally acquires
660 : * the locks we need to do planning safely.
661 : */
662 605 : Assert(plansource->is_complete);
663 :
664 : /*
665 : * If a snapshot is already set (the normal case), we can just use that
666 : * for parsing/planning. But if it isn't, install one. Note: no point in
667 : * checking whether parse analysis requires a snapshot; utility commands
668 : * don't have invalidatable plans, so we'd not get here for such a
669 : * command.
670 : */
671 605 : snapshot_set = false;
672 605 : if (!ActiveSnapshotSet())
673 : {
674 0 : PushActiveSnapshot(GetTransactionSnapshot());
675 0 : snapshot_set = true;
676 : }
677 :
678 : /*
679 : * Run parse analysis and rule rewriting. The parser tends to scribble on
680 : * its input, so we must copy the raw parse tree to prevent corruption of
681 : * the cache.
682 : */
683 605 : rawtree = copyObject(plansource->raw_parse_tree);
684 605 : if (rawtree == NULL)
685 0 : tlist = NIL;
686 605 : else if (plansource->parserSetup != NULL)
687 568 : tlist = pg_analyze_and_rewrite_params(rawtree,
688 : plansource->query_string,
689 : plansource->parserSetup,
690 : plansource->parserSetupArg,
691 : queryEnv);
692 : else
693 37 : tlist = pg_analyze_and_rewrite(rawtree,
694 : plansource->query_string,
695 : plansource->param_types,
696 : plansource->num_params,
697 : queryEnv);
698 :
699 : /* Release snapshot if we got one */
700 601 : if (snapshot_set)
701 0 : PopActiveSnapshot();
702 :
703 : /*
704 : * Check or update the result tupdesc. XXX should we use a weaker
705 : * condition than equalTupleDescs() here?
706 : *
707 : * We assume the parameter types didn't change from the first time, so no
708 : * need to update that.
709 : */
710 601 : resultDesc = PlanCacheComputeResultDesc(tlist);
711 601 : if (resultDesc == NULL && plansource->resultDesc == NULL)
712 : {
713 : /* OK, doesn't return tuples */
714 : }
715 1164 : else if (resultDesc == NULL || plansource->resultDesc == NULL ||
716 582 : !equalTupleDescs(resultDesc, plansource->resultDesc))
717 : {
718 : /* can we give a better error message? */
719 7 : if (plansource->fixed_result)
720 2 : ereport(ERROR,
721 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
722 : errmsg("cached plan must not change result type")));
723 5 : oldcxt = MemoryContextSwitchTo(plansource->context);
724 5 : if (resultDesc)
725 5 : resultDesc = CreateTupleDescCopy(resultDesc);
726 5 : if (plansource->resultDesc)
727 5 : FreeTupleDesc(plansource->resultDesc);
728 5 : plansource->resultDesc = resultDesc;
729 5 : MemoryContextSwitchTo(oldcxt);
730 : }
731 :
732 : /*
733 : * Allocate new query_context and copy the completed querytree into it.
734 : * It's transient until we complete the copying and dependency extraction.
735 : */
736 599 : querytree_context = AllocSetContextCreate(CurrentMemoryContext,
737 : "CachedPlanQuery",
738 : ALLOCSET_START_SMALL_SIZES);
739 599 : oldcxt = MemoryContextSwitchTo(querytree_context);
740 :
741 599 : qlist = copyObject(tlist);
742 :
743 : /*
744 : * Use the planner machinery to extract dependencies. Data is saved in
745 : * query_context. (We assume that not a lot of extra cruft is created by
746 : * this call.)
747 : */
748 599 : extract_query_dependencies((Node *) qlist,
749 : &plansource->relationOids,
750 : &plansource->invalItems,
751 : &plansource->dependsOnRLS);
752 :
753 : /* Update RLS info as well. */
754 599 : plansource->rewriteRoleId = GetUserId();
755 599 : plansource->rewriteRowSecurity = row_security;
756 :
757 : /*
758 : * Also save the current search_path in the query_context. (This should
759 : * not generate much extra cruft either, since almost certainly the path
760 : * is already valid.)
761 : */
762 599 : plansource->search_path = GetOverrideSearchPath(querytree_context);
763 :
764 599 : MemoryContextSwitchTo(oldcxt);
765 :
766 : /* Now reparent the finished query_context and save the links */
767 599 : MemoryContextSetParent(querytree_context, plansource->context);
768 :
769 599 : plansource->query_context = querytree_context;
770 599 : plansource->query_list = qlist;
771 :
772 : /*
773 : * Note: we do not reset generic_cost or total_custom_cost, although we
774 : * could choose to do so. If the DDL or statistics change that prompted
775 : * the invalidation meant a significant change in the cost estimates, it
776 : * would be better to reset those variables and start fresh; but often it
777 : * doesn't, and we're better retaining our hard-won knowledge about the
778 : * relative costs.
779 : */
780 :
781 599 : plansource->is_valid = true;
782 :
783 : /* Return transient copy of querytrees for possible use in planning */
784 599 : return tlist;
785 : }
786 :
787 : /*
788 : * CheckCachedPlan: see if the CachedPlanSource's generic plan is valid.
789 : *
790 : * Caller must have already called RevalidateCachedQuery to verify that the
791 : * querytree is up to date.
792 : *
793 : * On a "true" return, we have acquired the locks needed to run the plan.
794 : * (We must do this for the "true" result to be race-condition-free.)
795 : */
796 : static bool
797 32161 : CheckCachedPlan(CachedPlanSource *plansource)
798 : {
799 32161 : CachedPlan *plan = plansource->gplan;
800 :
801 : /* Assert that caller checked the querytree */
802 32161 : Assert(plansource->is_valid);
803 :
804 : /* If there's no generic plan, just say "false" */
805 32161 : if (!plan)
806 2688 : return false;
807 :
808 29473 : Assert(plan->magic == CACHEDPLAN_MAGIC);
809 : /* Generic plans are never one-shot */
810 29473 : Assert(!plan->is_oneshot);
811 :
812 : /*
813 : * If plan isn't valid for current role, we can't use it.
814 : */
815 29473 : if (plan->is_valid && plan->dependsOnRole &&
816 0 : plan->planRoleId != GetUserId())
817 0 : plan->is_valid = false;
818 :
819 : /*
820 : * If it appears valid, acquire locks and recheck; this is much the same
821 : * logic as in RevalidateCachedQuery, but for a plan.
822 : */
823 29473 : if (plan->is_valid)
824 : {
825 : /*
826 : * Plan must have positive refcount because it is referenced by
827 : * plansource; so no need to fear it disappears under us here.
828 : */
829 29473 : Assert(plan->refcount > 0);
830 :
831 29473 : AcquireExecutorLocks(plan->stmt_list, true);
832 :
833 : /*
834 : * If plan was transient, check to see if TransactionXmin has
835 : * advanced, and if so invalidate it.
836 : */
837 58946 : if (plan->is_valid &&
838 29473 : TransactionIdIsValid(plan->saved_xmin) &&
839 0 : !TransactionIdEquals(plan->saved_xmin, TransactionXmin))
840 0 : plan->is_valid = false;
841 :
842 : /*
843 : * By now, if any invalidation has happened, the inval callback
844 : * functions will have marked the plan invalid.
845 : */
846 29473 : if (plan->is_valid)
847 : {
848 : /* Successfully revalidated and locked the query. */
849 29473 : return true;
850 : }
851 :
852 : /* Oops, the race case happened. Release useless locks. */
853 0 : AcquireExecutorLocks(plan->stmt_list, false);
854 : }
855 :
856 : /*
857 : * Plan has been invalidated, so unlink it from the parent and release it.
858 : */
859 0 : ReleaseGenericPlan(plansource);
860 :
861 0 : return false;
862 : }
863 :
864 : /*
865 : * BuildCachedPlan: construct a new CachedPlan from a CachedPlanSource.
866 : *
867 : * qlist should be the result value from a previous RevalidateCachedQuery,
868 : * or it can be set to NIL if we need to re-copy the plansource's query_list.
869 : *
870 : * To build a generic, parameter-value-independent plan, pass NULL for
871 : * boundParams. To build a custom plan, pass the actual parameter values via
872 : * boundParams. For best effect, the PARAM_FLAG_CONST flag should be set on
873 : * each parameter value; otherwise the planner will treat the value as a
874 : * hint rather than a hard constant.
875 : *
876 : * Planning work is done in the caller's memory context. The finished plan
877 : * is in a child memory context, which typically should get reparented
878 : * (unless this is a one-shot plan, in which case we don't copy the plan).
879 : */
880 : static CachedPlan *
881 4087 : BuildCachedPlan(CachedPlanSource *plansource, List *qlist,
882 : ParamListInfo boundParams, QueryEnvironment *queryEnv)
883 : {
884 : CachedPlan *plan;
885 : List *plist;
886 : bool snapshot_set;
887 : bool is_transient;
888 : MemoryContext plan_context;
889 4087 : MemoryContext oldcxt = CurrentMemoryContext;
890 : ListCell *lc;
891 :
892 : /*
893 : * Normally the querytree should be valid already, but if it's not,
894 : * rebuild it.
895 : *
896 : * NOTE: GetCachedPlan should have called RevalidateCachedQuery first, so
897 : * we ought to be holding sufficient locks to prevent any invalidation.
898 : * However, if we're building a custom plan after having built and
899 : * rejected a generic plan, it's possible to reach here with is_valid
900 : * false due to an invalidation while making the generic plan. In theory
901 : * the invalidation must be a false positive, perhaps a consequence of an
902 : * sinval reset event or the CLOBBER_CACHE_ALWAYS debug code. But for
903 : * safety, let's treat it as real and redo the RevalidateCachedQuery call.
904 : */
905 4087 : if (!plansource->is_valid)
906 0 : qlist = RevalidateCachedQuery(plansource, queryEnv);
907 :
908 : /*
909 : * If we don't already have a copy of the querytree list that can be
910 : * scribbled on by the planner, make one. For a one-shot plan, we assume
911 : * it's okay to scribble on the original query_list.
912 : */
913 4087 : if (qlist == NIL)
914 : {
915 3488 : if (!plansource->is_oneshot)
916 2864 : qlist = copyObject(plansource->query_list);
917 : else
918 624 : qlist = plansource->query_list;
919 : }
920 :
921 : /*
922 : * If a snapshot is already set (the normal case), we can just use that
923 : * for planning. But if it isn't, and we need one, install one.
924 : */
925 4087 : snapshot_set = false;
926 4087 : if (!ActiveSnapshotSet() &&
927 0 : plansource->raw_parse_tree &&
928 0 : analyze_requires_snapshot(plansource->raw_parse_tree))
929 : {
930 0 : PushActiveSnapshot(GetTransactionSnapshot());
931 0 : snapshot_set = true;
932 : }
933 :
934 : /*
935 : * Generate the plan.
936 : */
937 4087 : plist = pg_plan_queries(qlist, plansource->cursor_options, boundParams);
938 :
939 : /* Release snapshot if we got one */
940 4077 : if (snapshot_set)
941 0 : PopActiveSnapshot();
942 :
943 : /*
944 : * Normally we make a dedicated memory context for the CachedPlan and its
945 : * subsidiary data. (It's probably not going to be large, but just in
946 : * case, allow it to grow large. It's transient for the moment.) But for
947 : * a one-shot plan, we just leave it in the caller's memory context.
948 : */
949 4077 : if (!plansource->is_oneshot)
950 : {
951 3453 : plan_context = AllocSetContextCreate(CurrentMemoryContext,
952 : "CachedPlan",
953 : ALLOCSET_START_SMALL_SIZES);
954 :
955 : /*
956 : * Copy plan into the new context.
957 : */
958 3453 : MemoryContextSwitchTo(plan_context);
959 :
960 3453 : plist = copyObject(plist);
961 : }
962 : else
963 624 : plan_context = CurrentMemoryContext;
964 :
965 : /*
966 : * Create and fill the CachedPlan struct within the new context.
967 : */
968 4077 : plan = (CachedPlan *) palloc(sizeof(CachedPlan));
969 4077 : plan->magic = CACHEDPLAN_MAGIC;
970 4077 : plan->stmt_list = plist;
971 :
972 : /*
973 : * CachedPlan is dependent on role either if RLS affected the rewrite
974 : * phase or if a role dependency was injected during planning. And it's
975 : * transient if any plan is marked so.
976 : */
977 4077 : plan->planRoleId = GetUserId();
978 4077 : plan->dependsOnRole = plansource->dependsOnRLS;
979 4077 : is_transient = false;
980 8154 : foreach(lc, plist)
981 : {
982 4077 : PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
983 :
984 4077 : if (plannedstmt->commandType == CMD_UTILITY)
985 572 : continue; /* Ignore utility statements */
986 :
987 3505 : if (plannedstmt->transientPlan)
988 22 : is_transient = true;
989 3505 : if (plannedstmt->dependsOnRole)
990 0 : plan->dependsOnRole = true;
991 : }
992 4077 : if (is_transient)
993 : {
994 22 : Assert(TransactionIdIsNormal(TransactionXmin));
995 22 : plan->saved_xmin = TransactionXmin;
996 : }
997 : else
998 4055 : plan->saved_xmin = InvalidTransactionId;
999 4077 : plan->refcount = 0;
1000 4077 : plan->context = plan_context;
1001 4077 : plan->is_oneshot = plansource->is_oneshot;
1002 4077 : plan->is_saved = false;
1003 4077 : plan->is_valid = true;
1004 :
1005 : /* assign generation number to new plan */
1006 4077 : plan->generation = ++(plansource->generation);
1007 :
1008 4077 : MemoryContextSwitchTo(oldcxt);
1009 :
1010 4077 : return plan;
1011 : }
1012 :
1013 : /*
1014 : * choose_custom_plan: choose whether to use custom or generic plan
1015 : *
1016 : * This defines the policy followed by GetCachedPlan.
1017 : */
1018 : static bool
1019 36241 : choose_custom_plan(CachedPlanSource *plansource, ParamListInfo boundParams)
1020 : {
1021 : double avg_custom_cost;
1022 :
1023 : /* One-shot plans will always be considered custom */
1024 36241 : if (plansource->is_oneshot)
1025 624 : return true;
1026 :
1027 : /* Otherwise, never any point in a custom plan if there's no parameters */
1028 35617 : if (boundParams == NULL)
1029 33231 : return false;
1030 : /* ... nor for transaction control statements */
1031 2386 : if (IsTransactionStmtPlan(plansource))
1032 0 : return false;
1033 :
1034 : /* See if caller wants to force the decision */
1035 2386 : if (plansource->cursor_options & CURSOR_OPT_GENERIC_PLAN)
1036 0 : return false;
1037 2386 : if (plansource->cursor_options & CURSOR_OPT_CUSTOM_PLAN)
1038 0 : return true;
1039 :
1040 : /* Generate custom plans until we have done at least 5 (arbitrary) */
1041 2386 : if (plansource->num_custom_plans < 5)
1042 775 : return true;
1043 :
1044 1611 : avg_custom_cost = plansource->total_custom_cost / plansource->num_custom_plans;
1045 :
1046 : /*
1047 : * Prefer generic plan if it's less expensive than the average custom
1048 : * plan. (Because we include a charge for cost of planning in the
1049 : * custom-plan costs, this means the generic plan only has to be less
1050 : * expensive than the execution cost plus replan cost of the custom
1051 : * plans.)
1052 : *
1053 : * Note that if generic_cost is -1 (indicating we've not yet determined
1054 : * the generic plan cost), we'll always prefer generic at this point.
1055 : */
1056 1611 : if (plansource->generic_cost < avg_custom_cost)
1057 1611 : return false;
1058 :
1059 0 : return true;
1060 : }
1061 :
1062 : /*
1063 : * cached_plan_cost: calculate estimated cost of a plan
1064 : *
1065 : * If include_planner is true, also include the estimated cost of constructing
1066 : * the plan. (We must factor that into the cost of using a custom plan, but
1067 : * we don't count it for a generic plan.)
1068 : */
1069 : static double
1070 4077 : cached_plan_cost(CachedPlan *plan, bool include_planner)
1071 : {
1072 4077 : double result = 0;
1073 : ListCell *lc;
1074 :
1075 8154 : foreach(lc, plan->stmt_list)
1076 : {
1077 4077 : PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1078 :
1079 4077 : if (plannedstmt->commandType == CMD_UTILITY)
1080 572 : continue; /* Ignore utility statements */
1081 :
1082 3505 : result += plannedstmt->planTree->total_cost;
1083 :
1084 3505 : if (include_planner)
1085 : {
1086 : /*
1087 : * Currently we use a very crude estimate of planning effort based
1088 : * on the number of relations in the finished plan's rangetable.
1089 : * Join planning effort actually scales much worse than linearly
1090 : * in the number of relations --- but only until the join collapse
1091 : * limits kick in. Also, while inheritance child relations surely
1092 : * add to planning effort, they don't make the join situation
1093 : * worse. So the actual shape of the planning cost curve versus
1094 : * number of relations isn't all that obvious. It will take
1095 : * considerable work to arrive at a less crude estimate, and for
1096 : * now it's not clear that's worth doing.
1097 : *
1098 : * The other big difficulty here is that we don't have any very
1099 : * good model of how planning cost compares to execution costs.
1100 : * The current multiplier of 1000 * cpu_operator_cost is probably
1101 : * on the low side, but we'll try this for awhile before making a
1102 : * more aggressive correction.
1103 : *
1104 : * If we ever do write a more complicated estimator, it should
1105 : * probably live in src/backend/optimizer/ not here.
1106 : */
1107 1346 : int nrelations = list_length(plannedstmt->rtable);
1108 :
1109 1346 : result += 1000.0 * cpu_operator_cost * (nrelations + 1);
1110 : }
1111 : }
1112 :
1113 4077 : return result;
1114 : }
1115 :
1116 : /*
1117 : * GetCachedPlan: get a cached plan from a CachedPlanSource.
1118 : *
1119 : * This function hides the logic that decides whether to use a generic
1120 : * plan or a custom plan for the given parameters: the caller does not know
1121 : * which it will get.
1122 : *
1123 : * On return, the plan is valid and we have sufficient locks to begin
1124 : * execution.
1125 : *
1126 : * On return, the refcount of the plan has been incremented; a later
1127 : * ReleaseCachedPlan() call is expected. The refcount has been reported
1128 : * to the CurrentResourceOwner if useResOwner is true (note that that must
1129 : * only be true if it's a "saved" CachedPlanSource).
1130 : *
1131 : * Note: if any replanning activity is required, the caller's memory context
1132 : * is used for that work.
1133 : */
1134 : CachedPlan *
1135 33566 : GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams,
1136 : bool useResOwner, QueryEnvironment *queryEnv)
1137 : {
1138 33566 : CachedPlan *plan = NULL;
1139 : List *qlist;
1140 : bool customplan;
1141 :
1142 : /* Assert caller is doing things in a sane order */
1143 33566 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1144 33566 : Assert(plansource->is_complete);
1145 : /* This seems worth a real test, though */
1146 33566 : if (useResOwner && !plansource->is_saved)
1147 0 : elog(ERROR, "cannot apply ResourceOwner to non-saved cached plan");
1148 :
1149 : /* Make sure the querytree list is valid and we have parse-time locks */
1150 33566 : qlist = RevalidateCachedQuery(plansource, queryEnv);
1151 :
1152 : /* Decide whether to use a custom plan */
1153 33560 : customplan = choose_custom_plan(plansource, boundParams);
1154 :
1155 33560 : if (!customplan)
1156 : {
1157 32161 : if (CheckCachedPlan(plansource))
1158 : {
1159 : /* We want a generic plan, and we already have a valid one */
1160 29473 : plan = plansource->gplan;
1161 29473 : Assert(plan->magic == CACHEDPLAN_MAGIC);
1162 : }
1163 : else
1164 : {
1165 : /* Build a new generic plan */
1166 2688 : plan = BuildCachedPlan(plansource, qlist, NULL, queryEnv);
1167 : /* Just make real sure plansource->gplan is clear */
1168 2681 : ReleaseGenericPlan(plansource);
1169 : /* Link the new generic plan into the plansource */
1170 2681 : plansource->gplan = plan;
1171 2681 : plan->refcount++;
1172 : /* Immediately reparent into appropriate context */
1173 2681 : if (plansource->is_saved)
1174 : {
1175 : /* saved plans all live under CacheMemoryContext */
1176 2118 : MemoryContextSetParent(plan->context, CacheMemoryContext);
1177 2118 : plan->is_saved = true;
1178 : }
1179 : else
1180 : {
1181 : /* otherwise, it should be a sibling of the plansource */
1182 563 : MemoryContextSetParent(plan->context,
1183 : MemoryContextGetParent(plansource->context));
1184 : }
1185 : /* Update generic_cost whenever we make a new generic plan */
1186 2681 : plansource->generic_cost = cached_plan_cost(plan, false);
1187 :
1188 : /*
1189 : * If, based on the now-known value of generic_cost, we'd not have
1190 : * chosen to use a generic plan, then forget it and make a custom
1191 : * plan. This is a bit of a wart but is necessary to avoid a
1192 : * glitch in behavior when the custom plans are consistently big
1193 : * winners; at some point we'll experiment with a generic plan and
1194 : * find it's a loser, but we don't want to actually execute that
1195 : * plan.
1196 : */
1197 2681 : customplan = choose_custom_plan(plansource, boundParams);
1198 :
1199 : /*
1200 : * If we choose to plan again, we need to re-copy the query_list,
1201 : * since the planner probably scribbled on it. We can force
1202 : * BuildCachedPlan to do that by passing NIL.
1203 : */
1204 2681 : qlist = NIL;
1205 : }
1206 : }
1207 :
1208 33553 : if (customplan)
1209 : {
1210 : /* Build a custom plan */
1211 1399 : plan = BuildCachedPlan(plansource, qlist, boundParams, queryEnv);
1212 : /* Accumulate total costs of custom plans, but 'ware overflow */
1213 1396 : if (plansource->num_custom_plans < INT_MAX)
1214 : {
1215 1396 : plansource->total_custom_cost += cached_plan_cost(plan, true);
1216 1396 : plansource->num_custom_plans++;
1217 : }
1218 : }
1219 :
1220 33550 : Assert(plan != NULL);
1221 :
1222 : /* Flag the plan as in use by caller */
1223 33550 : if (useResOwner)
1224 32025 : ResourceOwnerEnlargePlanCacheRefs(CurrentResourceOwner);
1225 33550 : plan->refcount++;
1226 33550 : if (useResOwner)
1227 32025 : ResourceOwnerRememberPlanCacheRef(CurrentResourceOwner, plan);
1228 :
1229 : /*
1230 : * Saved plans should be under CacheMemoryContext so they will not go away
1231 : * until their reference count goes to zero. In the generic-plan cases we
1232 : * already took care of that, but for a custom plan, do it as soon as we
1233 : * have created a reference-counted link.
1234 : */
1235 33550 : if (customplan && plansource->is_saved)
1236 : {
1237 769 : MemoryContextSetParent(plan->context, CacheMemoryContext);
1238 769 : plan->is_saved = true;
1239 : }
1240 :
1241 33550 : return plan;
1242 : }
1243 :
1244 : /*
1245 : * ReleaseCachedPlan: release active use of a cached plan.
1246 : *
1247 : * This decrements the reference count, and frees the plan if the count
1248 : * has thereby gone to zero. If useResOwner is true, it is assumed that
1249 : * the reference count is managed by the CurrentResourceOwner.
1250 : *
1251 : * Note: useResOwner = false is used for releasing references that are in
1252 : * persistent data structures, such as the parent CachedPlanSource or a
1253 : * Portal. Transient references should be protected by a resource owner.
1254 : */
1255 : void
1256 34428 : ReleaseCachedPlan(CachedPlan *plan, bool useResOwner)
1257 : {
1258 34428 : Assert(plan->magic == CACHEDPLAN_MAGIC);
1259 34428 : if (useResOwner)
1260 : {
1261 32025 : Assert(plan->is_saved);
1262 32025 : ResourceOwnerForgetPlanCacheRef(CurrentResourceOwner, plan);
1263 : }
1264 34428 : Assert(plan->refcount > 0);
1265 34428 : plan->refcount--;
1266 34428 : if (plan->refcount == 0)
1267 : {
1268 : /* Mark it no longer valid */
1269 2274 : plan->magic = 0;
1270 :
1271 : /* One-shot plans do not own their context, so we can't free them */
1272 2274 : if (!plan->is_oneshot)
1273 1664 : MemoryContextDelete(plan->context);
1274 : }
1275 34428 : }
1276 :
1277 : /*
1278 : * CachedPlanSetParentContext: move a CachedPlanSource to a new memory context
1279 : *
1280 : * This can only be applied to unsaved plans; once saved, a plan always
1281 : * lives underneath CacheMemoryContext.
1282 : */
1283 : void
1284 1799 : CachedPlanSetParentContext(CachedPlanSource *plansource,
1285 : MemoryContext newcontext)
1286 : {
1287 : /* Assert caller is doing things in a sane order */
1288 1799 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1289 1799 : Assert(plansource->is_complete);
1290 :
1291 : /* These seem worth real tests, though */
1292 1799 : if (plansource->is_saved)
1293 0 : elog(ERROR, "cannot move a saved cached plan to another context");
1294 1799 : if (plansource->is_oneshot)
1295 0 : elog(ERROR, "cannot move a one-shot cached plan to another context");
1296 :
1297 : /* OK, let the caller keep the plan where he wishes */
1298 1799 : MemoryContextSetParent(plansource->context, newcontext);
1299 :
1300 : /*
1301 : * The query_context needs no special handling, since it's a child of
1302 : * plansource->context. But if there's a generic plan, it should be
1303 : * maintained as a sibling of plansource->context.
1304 : */
1305 1799 : if (plansource->gplan)
1306 : {
1307 0 : Assert(plansource->gplan->magic == CACHEDPLAN_MAGIC);
1308 0 : MemoryContextSetParent(plansource->gplan->context, newcontext);
1309 : }
1310 1799 : }
1311 :
1312 : /*
1313 : * CopyCachedPlan: make a copy of a CachedPlanSource
1314 : *
1315 : * This is a convenience routine that does the equivalent of
1316 : * CreateCachedPlan + CompleteCachedPlan, using the data stored in the
1317 : * input CachedPlanSource. The result is therefore "unsaved" (regardless
1318 : * of the state of the source), and we don't copy any generic plan either.
1319 : * The result will be currently valid, or not, the same as the source.
1320 : */
1321 : CachedPlanSource *
1322 0 : CopyCachedPlan(CachedPlanSource *plansource)
1323 : {
1324 : CachedPlanSource *newsource;
1325 : MemoryContext source_context;
1326 : MemoryContext querytree_context;
1327 : MemoryContext oldcxt;
1328 :
1329 0 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1330 0 : Assert(plansource->is_complete);
1331 :
1332 : /*
1333 : * One-shot plans can't be copied, because we haven't taken care that
1334 : * parsing/planning didn't scribble on the raw parse tree or querytrees.
1335 : */
1336 0 : if (plansource->is_oneshot)
1337 0 : elog(ERROR, "cannot copy a one-shot cached plan");
1338 :
1339 0 : source_context = AllocSetContextCreate(CurrentMemoryContext,
1340 : "CachedPlanSource",
1341 : ALLOCSET_START_SMALL_SIZES);
1342 :
1343 0 : oldcxt = MemoryContextSwitchTo(source_context);
1344 :
1345 0 : newsource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
1346 0 : newsource->magic = CACHEDPLANSOURCE_MAGIC;
1347 0 : newsource->raw_parse_tree = copyObject(plansource->raw_parse_tree);
1348 0 : newsource->query_string = pstrdup(plansource->query_string);
1349 0 : newsource->commandTag = plansource->commandTag;
1350 0 : if (plansource->num_params > 0)
1351 : {
1352 0 : newsource->param_types = (Oid *)
1353 0 : palloc(plansource->num_params * sizeof(Oid));
1354 0 : memcpy(newsource->param_types, plansource->param_types,
1355 0 : plansource->num_params * sizeof(Oid));
1356 : }
1357 : else
1358 0 : newsource->param_types = NULL;
1359 0 : newsource->num_params = plansource->num_params;
1360 0 : newsource->parserSetup = plansource->parserSetup;
1361 0 : newsource->parserSetupArg = plansource->parserSetupArg;
1362 0 : newsource->cursor_options = plansource->cursor_options;
1363 0 : newsource->fixed_result = plansource->fixed_result;
1364 0 : if (plansource->resultDesc)
1365 0 : newsource->resultDesc = CreateTupleDescCopy(plansource->resultDesc);
1366 : else
1367 0 : newsource->resultDesc = NULL;
1368 0 : newsource->context = source_context;
1369 :
1370 0 : querytree_context = AllocSetContextCreate(source_context,
1371 : "CachedPlanQuery",
1372 : ALLOCSET_START_SMALL_SIZES);
1373 0 : MemoryContextSwitchTo(querytree_context);
1374 0 : newsource->query_list = copyObject(plansource->query_list);
1375 0 : newsource->relationOids = copyObject(plansource->relationOids);
1376 0 : newsource->invalItems = copyObject(plansource->invalItems);
1377 0 : if (plansource->search_path)
1378 0 : newsource->search_path = CopyOverrideSearchPath(plansource->search_path);
1379 0 : newsource->query_context = querytree_context;
1380 0 : newsource->rewriteRoleId = plansource->rewriteRoleId;
1381 0 : newsource->rewriteRowSecurity = plansource->rewriteRowSecurity;
1382 0 : newsource->dependsOnRLS = plansource->dependsOnRLS;
1383 :
1384 0 : newsource->gplan = NULL;
1385 :
1386 0 : newsource->is_oneshot = false;
1387 0 : newsource->is_complete = true;
1388 0 : newsource->is_saved = false;
1389 0 : newsource->is_valid = plansource->is_valid;
1390 0 : newsource->generation = plansource->generation;
1391 0 : newsource->next_saved = NULL;
1392 :
1393 : /* We may as well copy any acquired cost knowledge */
1394 0 : newsource->generic_cost = plansource->generic_cost;
1395 0 : newsource->total_custom_cost = plansource->total_custom_cost;
1396 0 : newsource->num_custom_plans = plansource->num_custom_plans;
1397 :
1398 0 : MemoryContextSwitchTo(oldcxt);
1399 :
1400 0 : return newsource;
1401 : }
1402 :
1403 : /*
1404 : * CachedPlanIsValid: test whether the rewritten querytree within a
1405 : * CachedPlanSource is currently valid (that is, not marked as being in need
1406 : * of revalidation).
1407 : *
1408 : * This result is only trustworthy (ie, free from race conditions) if
1409 : * the caller has acquired locks on all the relations used in the plan.
1410 : */
1411 : bool
1412 276 : CachedPlanIsValid(CachedPlanSource *plansource)
1413 : {
1414 276 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1415 276 : return plansource->is_valid;
1416 : }
1417 :
1418 : /*
1419 : * CachedPlanGetTargetList: return tlist, if any, describing plan's output
1420 : *
1421 : * The result is guaranteed up-to-date. However, it is local storage
1422 : * within the cached plan, and may disappear next time the plan is updated.
1423 : */
1424 : List *
1425 118 : CachedPlanGetTargetList(CachedPlanSource *plansource,
1426 : QueryEnvironment *queryEnv)
1427 : {
1428 : Query *pstmt;
1429 :
1430 : /* Assert caller is doing things in a sane order */
1431 118 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1432 118 : Assert(plansource->is_complete);
1433 :
1434 : /*
1435 : * No work needed if statement doesn't return tuples (we assume this
1436 : * feature cannot be changed by an invalidation)
1437 : */
1438 118 : if (plansource->resultDesc == NULL)
1439 0 : return NIL;
1440 :
1441 : /* Make sure the querytree list is valid and we have parse-time locks */
1442 118 : RevalidateCachedQuery(plansource, queryEnv);
1443 :
1444 : /* Get the primary statement and find out what it returns */
1445 118 : pstmt = QueryListGetPrimaryStmt(plansource->query_list);
1446 :
1447 118 : return FetchStatementTargetList((Node *) pstmt);
1448 : }
1449 :
1450 : /*
1451 : * QueryListGetPrimaryStmt
1452 : * Get the "primary" stmt within a list, ie, the one marked canSetTag.
1453 : *
1454 : * Returns NULL if no such stmt. If multiple queries within the list are
1455 : * marked canSetTag, returns the first one. Neither of these cases should
1456 : * occur in present usages of this function.
1457 : */
1458 : static Query *
1459 125 : QueryListGetPrimaryStmt(List *stmts)
1460 : {
1461 : ListCell *lc;
1462 :
1463 125 : foreach(lc, stmts)
1464 : {
1465 125 : Query *stmt = lfirst_node(Query, lc);
1466 :
1467 125 : if (stmt->canSetTag)
1468 125 : return stmt;
1469 : }
1470 0 : return NULL;
1471 : }
1472 :
1473 : /*
1474 : * AcquireExecutorLocks: acquire locks needed for execution of a cached plan;
1475 : * or release them if acquire is false.
1476 : */
1477 : static void
1478 29473 : AcquireExecutorLocks(List *stmt_list, bool acquire)
1479 : {
1480 : ListCell *lc1;
1481 :
1482 58946 : foreach(lc1, stmt_list)
1483 : {
1484 29473 : PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc1);
1485 : int rt_index;
1486 : ListCell *lc2;
1487 :
1488 29473 : if (plannedstmt->commandType == CMD_UTILITY)
1489 : {
1490 : /*
1491 : * Ignore utility statements, except those (such as EXPLAIN) that
1492 : * contain a parsed-but-not-planned query. Note: it's okay to use
1493 : * ScanQueryForLocks, even though the query hasn't been through
1494 : * rule rewriting, because rewriting doesn't change the query
1495 : * representation.
1496 : */
1497 996 : Query *query = UtilityContainsQuery(plannedstmt->utilityStmt);
1498 :
1499 996 : if (query)
1500 1 : ScanQueryForLocks(query, acquire);
1501 996 : continue;
1502 : }
1503 :
1504 28477 : rt_index = 0;
1505 30267 : foreach(lc2, plannedstmt->rtable)
1506 : {
1507 1790 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
1508 : LOCKMODE lockmode;
1509 : PlanRowMark *rc;
1510 :
1511 1790 : rt_index++;
1512 :
1513 1790 : if (rte->rtekind != RTE_RELATION)
1514 292 : continue;
1515 :
1516 : /*
1517 : * Acquire the appropriate type of lock on each relation OID. Note
1518 : * that we don't actually try to open the rel, and hence will not
1519 : * fail if it's been dropped entirely --- we'll just transiently
1520 : * acquire a non-conflicting lock.
1521 : */
1522 2787 : if (list_member_int(plannedstmt->resultRelations, rt_index) ||
1523 1289 : list_member_int(plannedstmt->nonleafResultRelations, rt_index))
1524 209 : lockmode = RowExclusiveLock;
1525 1328 : else if ((rc = get_plan_rowmark(plannedstmt->rowMarks, rt_index)) != NULL &&
1526 39 : RowMarkRequiresRowShareLock(rc->markType))
1527 39 : lockmode = RowShareLock;
1528 : else
1529 1250 : lockmode = AccessShareLock;
1530 :
1531 1498 : if (acquire)
1532 1498 : LockRelationOid(rte->relid, lockmode);
1533 : else
1534 0 : UnlockRelationOid(rte->relid, lockmode);
1535 : }
1536 : }
1537 29473 : }
1538 :
1539 : /*
1540 : * AcquirePlannerLocks: acquire locks needed for planning of a querytree list;
1541 : * or release them if acquire is false.
1542 : *
1543 : * Note that we don't actually try to open the relations, and hence will not
1544 : * fail if one has been dropped entirely --- we'll just transiently acquire
1545 : * a non-conflicting lock.
1546 : */
1547 : static void
1548 32455 : AcquirePlannerLocks(List *stmt_list, bool acquire)
1549 : {
1550 : ListCell *lc;
1551 :
1552 64910 : foreach(lc, stmt_list)
1553 : {
1554 32455 : Query *query = lfirst_node(Query, lc);
1555 :
1556 32455 : if (query->commandType == CMD_UTILITY)
1557 : {
1558 : /* Ignore utility statements, unless they contain a Query */
1559 1518 : query = UtilityContainsQuery(query->utilityStmt);
1560 1518 : if (query)
1561 504 : ScanQueryForLocks(query, acquire);
1562 1518 : continue;
1563 : }
1564 :
1565 30937 : ScanQueryForLocks(query, acquire);
1566 : }
1567 32455 : }
1568 :
1569 : /*
1570 : * ScanQueryForLocks: recursively scan one Query for AcquirePlannerLocks.
1571 : */
1572 : static void
1573 32074 : ScanQueryForLocks(Query *parsetree, bool acquire)
1574 : {
1575 : ListCell *lc;
1576 : int rt_index;
1577 :
1578 : /* Shouldn't get called on utility commands */
1579 32074 : Assert(parsetree->commandType != CMD_UTILITY);
1580 :
1581 : /*
1582 : * First, process RTEs of the current query level.
1583 : */
1584 32074 : rt_index = 0;
1585 35604 : foreach(lc, parsetree->rtable)
1586 : {
1587 3530 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
1588 : LOCKMODE lockmode;
1589 :
1590 3530 : rt_index++;
1591 3530 : switch (rte->rtekind)
1592 : {
1593 : case RTE_RELATION:
1594 : /* Acquire or release the appropriate type of lock */
1595 2992 : if (rt_index == parsetree->resultRelation)
1596 398 : lockmode = RowExclusiveLock;
1597 2594 : else if (get_parse_rowmark(parsetree, rt_index) != NULL)
1598 345 : lockmode = RowShareLock;
1599 : else
1600 2249 : lockmode = AccessShareLock;
1601 2992 : if (acquire)
1602 2992 : LockRelationOid(rte->relid, lockmode);
1603 : else
1604 0 : UnlockRelationOid(rte->relid, lockmode);
1605 2992 : break;
1606 :
1607 : case RTE_SUBQUERY:
1608 : /* Recurse into subquery-in-FROM */
1609 57 : ScanQueryForLocks(rte->subquery, acquire);
1610 57 : break;
1611 :
1612 : default:
1613 : /* ignore other types of RTEs */
1614 481 : break;
1615 : }
1616 : }
1617 :
1618 : /* Recurse into subquery-in-WITH */
1619 32077 : foreach(lc, parsetree->cteList)
1620 : {
1621 3 : CommonTableExpr *cte = lfirst_node(CommonTableExpr, lc);
1622 :
1623 3 : ScanQueryForLocks(castNode(Query, cte->ctequery), acquire);
1624 : }
1625 :
1626 : /*
1627 : * Recurse into sublink subqueries, too. But we already did the ones in
1628 : * the rtable and cteList.
1629 : */
1630 32074 : if (parsetree->hasSubLinks)
1631 : {
1632 572 : query_tree_walker(parsetree, ScanQueryWalker,
1633 : (void *) &acquire,
1634 : QTW_IGNORE_RC_SUBQUERIES);
1635 : }
1636 32074 : }
1637 :
1638 : /*
1639 : * Walker to find sublink subqueries for ScanQueryForLocks
1640 : */
1641 : static bool
1642 8794 : ScanQueryWalker(Node *node, bool *acquire)
1643 : {
1644 8794 : if (node == NULL)
1645 5740 : return false;
1646 3054 : if (IsA(node, SubLink))
1647 : {
1648 572 : SubLink *sub = (SubLink *) node;
1649 :
1650 : /* Do what we came for */
1651 572 : ScanQueryForLocks(castNode(Query, sub->subselect), *acquire);
1652 : /* Fall through to process lefthand args of SubLink */
1653 : }
1654 :
1655 : /*
1656 : * Do NOT recurse into Query nodes, because ScanQueryForLocks already
1657 : * processed subselects of subselects for us.
1658 : */
1659 3054 : return expression_tree_walker(node, ScanQueryWalker,
1660 : (void *) acquire);
1661 : }
1662 :
1663 : /*
1664 : * PlanCacheComputeResultDesc: given a list of analyzed-and-rewritten Queries,
1665 : * determine the result tupledesc it will produce. Returns NULL if the
1666 : * execution will not return tuples.
1667 : *
1668 : * Note: the result is created or copied into current memory context.
1669 : */
1670 : static TupleDesc
1671 3573 : PlanCacheComputeResultDesc(List *stmt_list)
1672 : {
1673 : Query *query;
1674 :
1675 3573 : switch (ChoosePortalStrategy(stmt_list))
1676 : {
1677 : case PORTAL_ONE_SELECT:
1678 : case PORTAL_ONE_MOD_WITH:
1679 2871 : query = linitial_node(Query, stmt_list);
1680 2871 : return ExecCleanTypeFromTL(query->targetList, false);
1681 :
1682 : case PORTAL_ONE_RETURNING:
1683 7 : query = QueryListGetPrimaryStmt(stmt_list);
1684 7 : Assert(query->returningList);
1685 7 : return ExecCleanTypeFromTL(query->returningList, false);
1686 :
1687 : case PORTAL_UTIL_SELECT:
1688 501 : query = linitial_node(Query, stmt_list);
1689 501 : Assert(query->utilityStmt);
1690 501 : return UtilityTupleDescriptor(query->utilityStmt);
1691 :
1692 : case PORTAL_MULTI_QUERY:
1693 : /* will not return tuples */
1694 194 : break;
1695 : }
1696 194 : return NULL;
1697 : }
1698 :
1699 : /*
1700 : * PlanCacheRelCallback
1701 : * Relcache inval callback function
1702 : *
1703 : * Invalidate all plans mentioning the given rel, or all plans mentioning
1704 : * any rel at all if relid == InvalidOid.
1705 : */
1706 : static void
1707 79032 : PlanCacheRelCallback(Datum arg, Oid relid)
1708 : {
1709 : CachedPlanSource *plansource;
1710 :
1711 1451317 : for (plansource = first_saved_plan; plansource; plansource = plansource->next_saved)
1712 : {
1713 1372285 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1714 :
1715 : /* No work if it's already invalidated */
1716 1372285 : if (!plansource->is_valid)
1717 1033077 : continue;
1718 :
1719 : /* Never invalidate transaction control commands */
1720 339208 : if (IsTransactionStmtPlan(plansource))
1721 0 : continue;
1722 :
1723 : /*
1724 : * Check the dependency list for the rewritten querytree.
1725 : */
1726 678416 : if ((relid == InvalidOid) ? plansource->relationOids != NIL :
1727 339208 : list_member_oid(plansource->relationOids, relid))
1728 : {
1729 : /* Invalidate the querytree and generic plan */
1730 217 : plansource->is_valid = false;
1731 217 : if (plansource->gplan)
1732 87 : plansource->gplan->is_valid = false;
1733 : }
1734 :
1735 : /*
1736 : * The generic plan, if any, could have more dependencies than the
1737 : * querytree does, so we have to check it too.
1738 : */
1739 339208 : if (plansource->gplan && plansource->gplan->is_valid)
1740 : {
1741 : ListCell *lc;
1742 :
1743 620896 : foreach(lc, plansource->gplan->stmt_list)
1744 : {
1745 310448 : PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1746 :
1747 310448 : if (plannedstmt->commandType == CMD_UTILITY)
1748 8203 : continue; /* Ignore utility statements */
1749 604490 : if ((relid == InvalidOid) ? plannedstmt->relationOids != NIL :
1750 302245 : list_member_oid(plannedstmt->relationOids, relid))
1751 : {
1752 : /* Invalidate the generic plan only */
1753 0 : plansource->gplan->is_valid = false;
1754 0 : break; /* out of stmt_list scan */
1755 : }
1756 : }
1757 : }
1758 : }
1759 79032 : }
1760 :
1761 : /*
1762 : * PlanCacheFuncCallback
1763 : * Syscache inval callback function for PROCOID cache
1764 : *
1765 : * Invalidate all plans mentioning the object with the specified hash value,
1766 : * or all plans mentioning any member of this cache if hashvalue == 0.
1767 : *
1768 : * Note that the coding would support use for multiple caches, but right
1769 : * now only user-defined functions are tracked this way.
1770 : */
1771 : static void
1772 5714 : PlanCacheFuncCallback(Datum arg, int cacheid, uint32 hashvalue)
1773 : {
1774 : CachedPlanSource *plansource;
1775 :
1776 345901 : for (plansource = first_saved_plan; plansource; plansource = plansource->next_saved)
1777 : {
1778 : ListCell *lc;
1779 :
1780 340187 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1781 :
1782 : /* No work if it's already invalidated */
1783 340187 : if (!plansource->is_valid)
1784 217572 : continue;
1785 :
1786 : /* Never invalidate transaction control commands */
1787 122615 : if (IsTransactionStmtPlan(plansource))
1788 0 : continue;
1789 :
1790 : /*
1791 : * Check the dependency list for the rewritten querytree.
1792 : */
1793 125653 : foreach(lc, plansource->invalItems)
1794 : {
1795 3066 : PlanInvalItem *item = (PlanInvalItem *) lfirst(lc);
1796 :
1797 3066 : if (item->cacheId != cacheid)
1798 0 : continue;
1799 6113 : if (hashvalue == 0 ||
1800 3047 : item->hashValue == hashvalue)
1801 : {
1802 : /* Invalidate the querytree and generic plan */
1803 28 : plansource->is_valid = false;
1804 28 : if (plansource->gplan)
1805 27 : plansource->gplan->is_valid = false;
1806 28 : break;
1807 : }
1808 : }
1809 :
1810 : /*
1811 : * The generic plan, if any, could have more dependencies than the
1812 : * querytree does, so we have to check it too.
1813 : */
1814 122615 : if (plansource->gplan && plansource->gplan->is_valid)
1815 : {
1816 223382 : foreach(lc, plansource->gplan->stmt_list)
1817 : {
1818 111691 : PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc);
1819 : ListCell *lc3;
1820 :
1821 111691 : if (plannedstmt->commandType == CMD_UTILITY)
1822 811 : continue; /* Ignore utility statements */
1823 113917 : foreach(lc3, plannedstmt->invalItems)
1824 : {
1825 3037 : PlanInvalItem *item = (PlanInvalItem *) lfirst(lc3);
1826 :
1827 3037 : if (item->cacheId != cacheid)
1828 0 : continue;
1829 6074 : if (hashvalue == 0 ||
1830 3037 : item->hashValue == hashvalue)
1831 : {
1832 : /* Invalidate the generic plan only */
1833 0 : plansource->gplan->is_valid = false;
1834 0 : break; /* out of invalItems scan */
1835 : }
1836 : }
1837 110880 : if (!plansource->gplan->is_valid)
1838 0 : break; /* out of stmt_list scan */
1839 : }
1840 : }
1841 : }
1842 5714 : }
1843 :
1844 : /*
1845 : * PlanCacheSysCallback
1846 : * Syscache inval callback function for other caches
1847 : *
1848 : * Just invalidate everything...
1849 : */
1850 : static void
1851 2950 : PlanCacheSysCallback(Datum arg, int cacheid, uint32 hashvalue)
1852 : {
1853 2950 : ResetPlanCache();
1854 2950 : }
1855 :
1856 : /*
1857 : * ResetPlanCache: invalidate all cached plans.
1858 : */
1859 : void
1860 2951 : ResetPlanCache(void)
1861 : {
1862 : CachedPlanSource *plansource;
1863 :
1864 30470 : for (plansource = first_saved_plan; plansource; plansource = plansource->next_saved)
1865 : {
1866 : ListCell *lc;
1867 :
1868 27519 : Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
1869 :
1870 : /* No work if it's already invalidated */
1871 27519 : if (!plansource->is_valid)
1872 25978 : continue;
1873 :
1874 : /*
1875 : * We *must not* mark transaction control statements as invalid,
1876 : * particularly not ROLLBACK, because they may need to be executed in
1877 : * aborted transactions when we can't revalidate them (cf bug #5269).
1878 : */
1879 1541 : if (IsTransactionStmtPlan(plansource))
1880 0 : continue;
1881 :
1882 : /*
1883 : * In general there is no point in invalidating utility statements
1884 : * since they have no plans anyway. So invalidate it only if it
1885 : * contains at least one non-utility statement, or contains a utility
1886 : * statement that contains a pre-analyzed query (which could have
1887 : * dependencies.)
1888 : */
1889 1756 : foreach(lc, plansource->query_list)
1890 : {
1891 1541 : Query *query = lfirst_node(Query, lc);
1892 :
1893 1756 : if (query->commandType != CMD_UTILITY ||
1894 215 : UtilityContainsQuery(query->utilityStmt))
1895 : {
1896 : /* non-utility statement, so invalidate */
1897 1326 : plansource->is_valid = false;
1898 1326 : if (plansource->gplan)
1899 1242 : plansource->gplan->is_valid = false;
1900 : /* no need to look further */
1901 1326 : break;
1902 : }
1903 : }
1904 : }
1905 2951 : }
|