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