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