Don't use 'return' where you should use 'PG_RETURN_xxx'.
[PostgreSQL.git] / src / backend / utils / cache / plancache.c
bloba400dbff2277d97fb59104da70033037f35dc94d
1 /*-------------------------------------------------------------------------
3 * plancache.c
4 * Plan cache management.
6 * We can store a cached plan in either fully-planned format, or just
7 * parsed-and-rewritten if the caller wishes to postpone planning until
8 * actual parameter values are available. CachedPlanSource has the same
9 * contents either way, but CachedPlan contains a list of PlannedStmts
10 * and bare utility statements in the first case, or a list of Query nodes
11 * in the second case.
13 * The plan cache manager itself is principally responsible for tracking
14 * whether cached plans should be invalidated because of schema changes in
15 * the objects they depend on. When (and if) the next demand for a cached
16 * plan occurs, the query will be replanned. Note that this could result
17 * in an error, for example if a column referenced by the query is no
18 * longer present. The creator of a cached plan can specify whether it
19 * is allowable for the query to change output tupdesc on replan (this
20 * could happen with "SELECT *" for example) --- if so, it's up to the
21 * caller to notice changes and cope with them.
23 * Currently, we track exactly the dependencies of plans on relations and
24 * user-defined functions. On relcache invalidation events or pg_proc
25 * syscache invalidation events, we invalidate just those plans that depend
26 * on the particular object being modified. (Note: this scheme assumes
27 * that any table modification that requires replanning will generate a
28 * relcache inval event.) We also watch for inval events on certain other
29 * system catalogs, such as pg_namespace; but for them, our response is
30 * just to invalidate all plans. We expect updates on those catalogs to
31 * be infrequent enough that more-detailed tracking is not worth the effort.
34 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
35 * Portions Copyright (c) 1994, Regents of the University of California
37 * IDENTIFICATION
38 * $PostgreSQL$
40 *-------------------------------------------------------------------------
42 #include "postgres.h"
44 #include "utils/plancache.h"
45 #include "access/transam.h"
46 #include "catalog/namespace.h"
47 #include "executor/executor.h"
48 #include "nodes/nodeFuncs.h"
49 #include "optimizer/planmain.h"
50 #include "storage/lmgr.h"
51 #include "tcop/pquery.h"
52 #include "tcop/tcopprot.h"
53 #include "tcop/utility.h"
54 #include "utils/inval.h"
55 #include "utils/memutils.h"
56 #include "utils/resowner.h"
57 #include "utils/snapmgr.h"
58 #include "utils/syscache.h"
61 static List *cached_plans_list = NIL;
63 static void StoreCachedPlan(CachedPlanSource *plansource, List *stmt_list,
64 MemoryContext plan_context);
65 static void AcquireExecutorLocks(List *stmt_list, bool acquire);
66 static void AcquirePlannerLocks(List *stmt_list, bool acquire);
67 static void ScanQueryForLocks(Query *parsetree, bool acquire);
68 static bool ScanQueryWalker(Node *node, bool *acquire);
69 static bool rowmark_member(List *rowMarks, int rt_index);
70 static bool plan_list_is_transient(List *stmt_list);
71 static void PlanCacheRelCallback(Datum arg, Oid relid);
72 static void PlanCacheFuncCallback(Datum arg, int cacheid, ItemPointer tuplePtr);
73 static void PlanCacheSysCallback(Datum arg, int cacheid, ItemPointer tuplePtr);
77 * InitPlanCache: initialize module during InitPostgres.
79 * All we need to do is hook into inval.c's callback lists.
81 void
82 InitPlanCache(void)
84 CacheRegisterRelcacheCallback(PlanCacheRelCallback, (Datum) 0);
85 CacheRegisterSyscacheCallback(PROCOID, PlanCacheFuncCallback, (Datum) 0);
86 CacheRegisterSyscacheCallback(NAMESPACEOID, PlanCacheSysCallback, (Datum) 0);
87 CacheRegisterSyscacheCallback(OPEROID, PlanCacheSysCallback, (Datum) 0);
88 CacheRegisterSyscacheCallback(AMOPOPID, PlanCacheSysCallback, (Datum) 0);
92 * CreateCachedPlan: initially create a plan cache entry.
94 * The caller must already have successfully parsed/planned the query;
95 * about all that we do here is copy it into permanent storage.
97 * raw_parse_tree: output of raw_parser()
98 * query_string: original query text (as of PG 8.4, must not be NULL)
99 * commandTag: compile-time-constant tag for query, or NULL if empty query
100 * param_types: array of parameter type OIDs, or NULL if none
101 * num_params: number of parameters
102 * cursor_options: options bitmask that was/will be passed to planner
103 * stmt_list: list of PlannedStmts/utility stmts, or list of Query trees
104 * fully_planned: are we caching planner or rewriter output?
105 * fixed_result: TRUE to disallow changes in result tupdesc
107 CachedPlanSource *
108 CreateCachedPlan(Node *raw_parse_tree,
109 const char *query_string,
110 const char *commandTag,
111 Oid *param_types,
112 int num_params,
113 int cursor_options,
114 List *stmt_list,
115 bool fully_planned,
116 bool fixed_result)
118 CachedPlanSource *plansource;
119 OverrideSearchPath *search_path;
120 MemoryContext source_context;
121 MemoryContext oldcxt;
123 Assert(query_string != NULL); /* required as of 8.4 */
126 * Make a dedicated memory context for the CachedPlanSource and its
127 * subsidiary data. We expect it can be pretty small.
129 source_context = AllocSetContextCreate(CacheMemoryContext,
130 "CachedPlanSource",
131 ALLOCSET_SMALL_MINSIZE,
132 ALLOCSET_SMALL_INITSIZE,
133 ALLOCSET_SMALL_MAXSIZE);
136 * Fetch current search_path into new context, but do any recalculation
137 * work required in caller's context.
139 search_path = GetOverrideSearchPath(source_context);
142 * Create and fill the CachedPlanSource struct within the new context.
144 oldcxt = MemoryContextSwitchTo(source_context);
145 plansource = (CachedPlanSource *) palloc(sizeof(CachedPlanSource));
146 plansource->raw_parse_tree = copyObject(raw_parse_tree);
147 plansource->query_string = pstrdup(query_string);
148 plansource->commandTag = commandTag; /* no copying needed */
149 if (num_params > 0)
151 plansource->param_types = (Oid *) palloc(num_params * sizeof(Oid));
152 memcpy(plansource->param_types, param_types, num_params * sizeof(Oid));
154 else
155 plansource->param_types = NULL;
156 plansource->num_params = num_params;
157 plansource->cursor_options = cursor_options;
158 plansource->fully_planned = fully_planned;
159 plansource->fixed_result = fixed_result;
160 plansource->search_path = search_path;
161 plansource->generation = 0; /* StoreCachedPlan will increment */
162 plansource->resultDesc = PlanCacheComputeResultDesc(stmt_list);
163 plansource->plan = NULL;
164 plansource->context = source_context;
165 plansource->orig_plan = NULL;
168 * Copy the current output plans into the plancache entry.
170 StoreCachedPlan(plansource, stmt_list, NULL);
173 * Now we can add the entry to the list of cached plans. The List nodes
174 * live in CacheMemoryContext.
176 MemoryContextSwitchTo(CacheMemoryContext);
178 cached_plans_list = lappend(cached_plans_list, plansource);
180 MemoryContextSwitchTo(oldcxt);
182 return plansource;
186 * FastCreateCachedPlan: create a plan cache entry with minimal data copying.
188 * For plans that aren't expected to live very long, the copying overhead of
189 * CreateCachedPlan is annoying. We provide this variant entry point in which
190 * the caller has already placed all the data in a suitable memory context.
191 * The source data and completed plan are in the same context, since this
192 * avoids extra copy steps during plan construction. If the query ever does
193 * need replanning, we'll generate a separate new CachedPlan at that time, but
194 * the CachedPlanSource and the initial CachedPlan share the caller-provided
195 * context and go away together when neither is needed any longer. (Because
196 * the parser and planner generate extra cruft in addition to their real
197 * output, this approach means that the context probably contains a bunch of
198 * useless junk as well as the useful trees. Hence, this method is a
199 * space-for-time tradeoff, which is worth making for plans expected to be
200 * short-lived.)
202 * raw_parse_tree, query_string, param_types, and stmt_list must reside in the
203 * given context, which must have adequate lifespan (recommendation: make it a
204 * child of CacheMemoryContext). Otherwise the API is the same as
205 * CreateCachedPlan.
207 CachedPlanSource *
208 FastCreateCachedPlan(Node *raw_parse_tree,
209 char *query_string,
210 const char *commandTag,
211 Oid *param_types,
212 int num_params,
213 int cursor_options,
214 List *stmt_list,
215 bool fully_planned,
216 bool fixed_result,
217 MemoryContext context)
219 CachedPlanSource *plansource;
220 OverrideSearchPath *search_path;
221 MemoryContext oldcxt;
223 Assert(query_string != NULL); /* required as of 8.4 */
226 * Fetch current search_path into given context, but do any recalculation
227 * work required in caller's context.
229 search_path = GetOverrideSearchPath(context);
232 * Create and fill the CachedPlanSource struct within the given context.
234 oldcxt = MemoryContextSwitchTo(context);
235 plansource = (CachedPlanSource *) palloc(sizeof(CachedPlanSource));
236 plansource->raw_parse_tree = raw_parse_tree;
237 plansource->query_string = query_string;
238 plansource->commandTag = commandTag; /* no copying needed */
239 plansource->param_types = param_types;
240 plansource->num_params = num_params;
241 plansource->cursor_options = cursor_options;
242 plansource->fully_planned = fully_planned;
243 plansource->fixed_result = fixed_result;
244 plansource->search_path = search_path;
245 plansource->generation = 0; /* StoreCachedPlan will increment */
246 plansource->resultDesc = PlanCacheComputeResultDesc(stmt_list);
247 plansource->plan = NULL;
248 plansource->context = context;
249 plansource->orig_plan = NULL;
252 * Store the current output plans into the plancache entry.
254 StoreCachedPlan(plansource, stmt_list, context);
257 * Since the context is owned by the CachedPlan, advance its refcount.
259 plansource->orig_plan = plansource->plan;
260 plansource->orig_plan->refcount++;
263 * Now we can add the entry to the list of cached plans. The List nodes
264 * live in CacheMemoryContext.
266 MemoryContextSwitchTo(CacheMemoryContext);
268 cached_plans_list = lappend(cached_plans_list, plansource);
270 MemoryContextSwitchTo(oldcxt);
272 return plansource;
276 * StoreCachedPlan: store a built or rebuilt plan into a plancache entry.
278 * Common subroutine for CreateCachedPlan and RevalidateCachedPlan.
280 static void
281 StoreCachedPlan(CachedPlanSource *plansource,
282 List *stmt_list,
283 MemoryContext plan_context)
285 CachedPlan *plan;
286 MemoryContext oldcxt;
288 if (plan_context == NULL)
291 * Make a dedicated memory context for the CachedPlan and its
292 * subsidiary data. It's probably not going to be large, but just in
293 * case, use the default maxsize parameter.
295 plan_context = AllocSetContextCreate(CacheMemoryContext,
296 "CachedPlan",
297 ALLOCSET_SMALL_MINSIZE,
298 ALLOCSET_SMALL_INITSIZE,
299 ALLOCSET_DEFAULT_MAXSIZE);
302 * Copy supplied data into the new context.
304 oldcxt = MemoryContextSwitchTo(plan_context);
306 stmt_list = (List *) copyObject(stmt_list);
308 else
310 /* Assume subsidiary data is in the given context */
311 oldcxt = MemoryContextSwitchTo(plan_context);
315 * Create and fill the CachedPlan struct within the new context.
317 plan = (CachedPlan *) palloc(sizeof(CachedPlan));
318 plan->stmt_list = stmt_list;
319 plan->fully_planned = plansource->fully_planned;
320 plan->dead = false;
321 if (plansource->fully_planned && plan_list_is_transient(stmt_list))
323 Assert(TransactionIdIsNormal(TransactionXmin));
324 plan->saved_xmin = TransactionXmin;
326 else
327 plan->saved_xmin = InvalidTransactionId;
328 plan->refcount = 1; /* for the parent's link */
329 plan->generation = ++(plansource->generation);
330 plan->context = plan_context;
331 if (plansource->fully_planned)
333 /* Planner already extracted dependencies, we don't have to */
334 plan->relationOids = plan->invalItems = NIL;
336 else
338 /* Use the planner machinery to extract dependencies */
339 extract_query_dependencies(stmt_list,
340 &plan->relationOids,
341 &plan->invalItems);
344 Assert(plansource->plan == NULL);
345 plansource->plan = plan;
347 MemoryContextSwitchTo(oldcxt);
351 * DropCachedPlan: destroy a cached plan.
353 * Actually this only destroys the CachedPlanSource: the referenced CachedPlan
354 * is released, but not destroyed until its refcount goes to zero. That
355 * handles the situation where DropCachedPlan is called while the plan is
356 * still in use.
358 void
359 DropCachedPlan(CachedPlanSource *plansource)
361 /* Validity check that we were given a CachedPlanSource */
362 Assert(list_member_ptr(cached_plans_list, plansource));
364 /* Remove it from the list */
365 cached_plans_list = list_delete_ptr(cached_plans_list, plansource);
367 /* Decrement child CachePlan's refcount and drop if no longer needed */
368 if (plansource->plan)
369 ReleaseCachedPlan(plansource->plan, false);
372 * If CachedPlanSource has independent storage, just drop it. Otherwise
373 * decrement the refcount on the CachePlan that owns the storage.
375 if (plansource->orig_plan == NULL)
377 /* Remove the CachedPlanSource and all subsidiary data */
378 MemoryContextDelete(plansource->context);
380 else
382 Assert(plansource->context == plansource->orig_plan->context);
383 ReleaseCachedPlan(plansource->orig_plan, false);
388 * RevalidateCachedPlan: prepare for re-use of a previously cached plan.
390 * What we do here is re-acquire locks and rebuild the plan if necessary.
391 * On return, the plan is valid and we have sufficient locks to begin
392 * execution (or planning, if not fully_planned).
394 * On return, the refcount of the plan has been incremented; a later
395 * ReleaseCachedPlan() call is expected. The refcount has been reported
396 * to the CurrentResourceOwner if useResOwner is true.
398 * Note: if any replanning activity is required, the caller's memory context
399 * is used for that work.
401 CachedPlan *
402 RevalidateCachedPlan(CachedPlanSource *plansource, bool useResOwner)
404 CachedPlan *plan;
406 /* Validity check that we were given a CachedPlanSource */
407 Assert(list_member_ptr(cached_plans_list, plansource));
410 * If the plan currently appears valid, acquire locks on the referenced
411 * objects; then check again. We need to do it this way to cover the race
412 * condition that an invalidation message arrives before we get the lock.
414 plan = plansource->plan;
415 if (plan && !plan->dead)
418 * Plan must have positive refcount because it is referenced by
419 * plansource; so no need to fear it disappears under us here.
421 Assert(plan->refcount > 0);
423 if (plan->fully_planned)
424 AcquireExecutorLocks(plan->stmt_list, true);
425 else
426 AcquirePlannerLocks(plan->stmt_list, true);
429 * If plan was transient, check to see if TransactionXmin has
430 * advanced, and if so invalidate it.
432 if (!plan->dead &&
433 TransactionIdIsValid(plan->saved_xmin) &&
434 !TransactionIdEquals(plan->saved_xmin, TransactionXmin))
435 plan->dead = true;
438 * By now, if any invalidation has happened, the inval callback
439 * functions will have marked the plan dead.
441 if (plan->dead)
443 /* Ooops, the race case happened. Release useless locks. */
444 if (plan->fully_planned)
445 AcquireExecutorLocks(plan->stmt_list, false);
446 else
447 AcquirePlannerLocks(plan->stmt_list, false);
452 * If plan has been invalidated, unlink it from the parent and release it.
454 if (plan && plan->dead)
456 plansource->plan = NULL;
457 ReleaseCachedPlan(plan, false);
458 plan = NULL;
462 * Build a new plan if needed.
464 if (!plan)
466 bool snapshot_set = false;
467 List *slist;
468 TupleDesc resultDesc;
471 * Restore the search_path that was in use when the plan was made.
472 * (XXX is there anything else we really need to restore?)
474 PushOverrideSearchPath(plansource->search_path);
477 * If a snapshot is already set (the normal case), we can just use
478 * that for parsing/planning. But if it isn't, install one. Note: no
479 * point in checking whether parse analysis requires a snapshot;
480 * utility commands don't have invalidatable plans, so we'd not get
481 * here for such a command.
483 if (!ActiveSnapshotSet())
485 PushActiveSnapshot(GetTransactionSnapshot());
486 snapshot_set = true;
490 * Run parse analysis and rule rewriting. The parser tends to
491 * scribble on its input, so we must copy the raw parse tree to
492 * prevent corruption of the cache. Note that we do not use
493 * parse_analyze_varparams(), assuming that the caller never wants the
494 * parameter types to change from the original values.
496 slist = pg_analyze_and_rewrite(copyObject(plansource->raw_parse_tree),
497 plansource->query_string,
498 plansource->param_types,
499 plansource->num_params);
501 if (plansource->fully_planned)
504 * Generate plans for queries.
506 slist = pg_plan_queries(slist, plansource->cursor_options, NULL);
510 * Check or update the result tupdesc. XXX should we use a weaker
511 * condition than equalTupleDescs() here?
513 resultDesc = PlanCacheComputeResultDesc(slist);
514 if (resultDesc == NULL && plansource->resultDesc == NULL)
516 /* OK, doesn't return tuples */
518 else if (resultDesc == NULL || plansource->resultDesc == NULL ||
519 !equalTupleDescs(resultDesc, plansource->resultDesc))
521 MemoryContext oldcxt;
523 /* can we give a better error message? */
524 if (plansource->fixed_result)
525 ereport(ERROR,
526 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
527 errmsg("cached plan must not change result type")));
528 oldcxt = MemoryContextSwitchTo(plansource->context);
529 if (resultDesc)
530 resultDesc = CreateTupleDescCopy(resultDesc);
531 if (plansource->resultDesc)
532 FreeTupleDesc(plansource->resultDesc);
533 plansource->resultDesc = resultDesc;
534 MemoryContextSwitchTo(oldcxt);
537 /* Release snapshot if we got one */
538 if (snapshot_set)
539 PopActiveSnapshot();
541 /* Now we can restore current search path */
542 PopOverrideSearchPath();
545 * Store the plans into the plancache entry, advancing the generation
546 * count.
548 StoreCachedPlan(plansource, slist, NULL);
550 plan = plansource->plan;
554 * Last step: flag the plan as in use by caller.
556 if (useResOwner)
557 ResourceOwnerEnlargePlanCacheRefs(CurrentResourceOwner);
558 plan->refcount++;
559 if (useResOwner)
560 ResourceOwnerRememberPlanCacheRef(CurrentResourceOwner, plan);
562 return plan;
566 * ReleaseCachedPlan: release active use of a cached plan.
568 * This decrements the reference count, and frees the plan if the count
569 * has thereby gone to zero. If useResOwner is true, it is assumed that
570 * the reference count is managed by the CurrentResourceOwner.
572 * Note: useResOwner = false is used for releasing references that are in
573 * persistent data structures, such as the parent CachedPlanSource or a
574 * Portal. Transient references should be protected by a resource owner.
576 void
577 ReleaseCachedPlan(CachedPlan *plan, bool useResOwner)
579 if (useResOwner)
580 ResourceOwnerForgetPlanCacheRef(CurrentResourceOwner, plan);
581 Assert(plan->refcount > 0);
582 plan->refcount--;
583 if (plan->refcount == 0)
584 MemoryContextDelete(plan->context);
588 * CachedPlanIsValid: test whether the plan within a CachedPlanSource is
589 * currently valid (that is, not marked as being in need of revalidation).
591 * This result is only trustworthy (ie, free from race conditions) if
592 * the caller has acquired locks on all the relations used in the plan.
594 bool
595 CachedPlanIsValid(CachedPlanSource *plansource)
597 CachedPlan *plan;
599 /* Validity check that we were given a CachedPlanSource */
600 Assert(list_member_ptr(cached_plans_list, plansource));
602 plan = plansource->plan;
603 if (plan && !plan->dead)
606 * Plan must have positive refcount because it is referenced by
607 * plansource; so no need to fear it disappears under us here.
609 Assert(plan->refcount > 0);
612 * Although we don't want to acquire locks here, it still seems useful
613 * to check for expiration of a transient plan.
615 if (TransactionIdIsValid(plan->saved_xmin) &&
616 !TransactionIdEquals(plan->saved_xmin, TransactionXmin))
617 plan->dead = true;
618 else
619 return true;
622 return false;
626 * AcquireExecutorLocks: acquire locks needed for execution of a fully-planned
627 * cached plan; or release them if acquire is false.
629 static void
630 AcquireExecutorLocks(List *stmt_list, bool acquire)
632 ListCell *lc1;
634 foreach(lc1, stmt_list)
636 PlannedStmt *plannedstmt = (PlannedStmt *) lfirst(lc1);
637 int rt_index;
638 ListCell *lc2;
640 Assert(!IsA(plannedstmt, Query));
641 if (!IsA(plannedstmt, PlannedStmt))
642 continue; /* Ignore utility statements */
644 rt_index = 0;
645 foreach(lc2, plannedstmt->rtable)
647 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
648 LOCKMODE lockmode;
650 rt_index++;
652 if (rte->rtekind != RTE_RELATION)
653 continue;
656 * Acquire the appropriate type of lock on each relation OID. Note
657 * that we don't actually try to open the rel, and hence will not
658 * fail if it's been dropped entirely --- we'll just transiently
659 * acquire a non-conflicting lock.
661 if (list_member_int(plannedstmt->resultRelations, rt_index))
662 lockmode = RowExclusiveLock;
663 else if (rowmark_member(plannedstmt->rowMarks, rt_index))
664 lockmode = RowShareLock;
665 else
666 lockmode = AccessShareLock;
668 if (acquire)
669 LockRelationOid(rte->relid, lockmode);
670 else
671 UnlockRelationOid(rte->relid, lockmode);
677 * AcquirePlannerLocks: acquire locks needed for planning and execution of a
678 * not-fully-planned cached plan; or release them if acquire is false.
680 * Note that we don't actually try to open the relations, and hence will not
681 * fail if one has been dropped entirely --- we'll just transiently acquire
682 * a non-conflicting lock.
684 static void
685 AcquirePlannerLocks(List *stmt_list, bool acquire)
687 ListCell *lc;
689 foreach(lc, stmt_list)
691 Query *query = (Query *) lfirst(lc);
693 Assert(IsA(query, Query));
694 ScanQueryForLocks(query, acquire);
699 * ScanQueryForLocks: recursively scan one Query for AcquirePlannerLocks.
701 static void
702 ScanQueryForLocks(Query *parsetree, bool acquire)
704 ListCell *lc;
705 int rt_index;
708 * First, process RTEs of the current query level.
710 rt_index = 0;
711 foreach(lc, parsetree->rtable)
713 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
714 LOCKMODE lockmode;
716 rt_index++;
717 switch (rte->rtekind)
719 case RTE_RELATION:
720 /* Acquire or release the appropriate type of lock */
721 if (rt_index == parsetree->resultRelation)
722 lockmode = RowExclusiveLock;
723 else if (rowmark_member(parsetree->rowMarks, rt_index))
724 lockmode = RowShareLock;
725 else
726 lockmode = AccessShareLock;
727 if (acquire)
728 LockRelationOid(rte->relid, lockmode);
729 else
730 UnlockRelationOid(rte->relid, lockmode);
731 break;
733 case RTE_SUBQUERY:
734 /* Recurse into subquery-in-FROM */
735 ScanQueryForLocks(rte->subquery, acquire);
736 break;
738 default:
739 /* ignore other types of RTEs */
740 break;
744 /* Recurse into subquery-in-WITH */
745 foreach(lc, parsetree->cteList)
747 CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
749 ScanQueryForLocks((Query *) cte->ctequery, acquire);
753 * Recurse into sublink subqueries, too. But we already did the ones in
754 * the rtable and cteList.
756 if (parsetree->hasSubLinks)
758 query_tree_walker(parsetree, ScanQueryWalker,
759 (void *) &acquire,
760 QTW_IGNORE_RC_SUBQUERIES);
765 * Walker to find sublink subqueries for ScanQueryForLocks
767 static bool
768 ScanQueryWalker(Node *node, bool *acquire)
770 if (node == NULL)
771 return false;
772 if (IsA(node, SubLink))
774 SubLink *sub = (SubLink *) node;
776 /* Do what we came for */
777 ScanQueryForLocks((Query *) sub->subselect, *acquire);
778 /* Fall through to process lefthand args of SubLink */
782 * Do NOT recurse into Query nodes, because ScanQueryForLocks already
783 * processed subselects of subselects for us.
785 return expression_tree_walker(node, ScanQueryWalker,
786 (void *) acquire);
790 * rowmark_member: check whether an RT index appears in a RowMarkClause list.
792 static bool
793 rowmark_member(List *rowMarks, int rt_index)
795 ListCell *l;
797 foreach(l, rowMarks)
799 RowMarkClause *rc = (RowMarkClause *) lfirst(l);
801 if (rc->rti == rt_index)
802 return true;
804 return false;
808 * plan_list_is_transient: check if any of the plans in the list are transient.
810 static bool
811 plan_list_is_transient(List *stmt_list)
813 ListCell *lc;
815 foreach(lc, stmt_list)
817 PlannedStmt *plannedstmt = (PlannedStmt *) lfirst(lc);
819 if (!IsA(plannedstmt, PlannedStmt))
820 continue; /* Ignore utility statements */
822 if (plannedstmt->transientPlan)
823 return true;
826 return false;
830 * PlanCacheComputeResultDesc: given a list of either fully-planned statements
831 * or Queries, determine the result tupledesc it will produce. Returns NULL
832 * if the execution will not return tuples.
834 * Note: the result is created or copied into current memory context.
836 TupleDesc
837 PlanCacheComputeResultDesc(List *stmt_list)
839 Node *node;
840 Query *query;
841 PlannedStmt *pstmt;
843 switch (ChoosePortalStrategy(stmt_list))
845 case PORTAL_ONE_SELECT:
846 node = (Node *) linitial(stmt_list);
847 if (IsA(node, Query))
849 query = (Query *) node;
850 return ExecCleanTypeFromTL(query->targetList, false);
852 if (IsA(node, PlannedStmt))
854 pstmt = (PlannedStmt *) node;
855 return ExecCleanTypeFromTL(pstmt->planTree->targetlist, false);
857 /* other cases shouldn't happen, but return NULL */
858 break;
860 case PORTAL_ONE_RETURNING:
861 node = PortalListGetPrimaryStmt(stmt_list);
862 if (IsA(node, Query))
864 query = (Query *) node;
865 Assert(query->returningList);
866 return ExecCleanTypeFromTL(query->returningList, false);
868 if (IsA(node, PlannedStmt))
870 pstmt = (PlannedStmt *) node;
871 Assert(pstmt->returningLists);
872 return ExecCleanTypeFromTL((List *) linitial(pstmt->returningLists), false);
874 /* other cases shouldn't happen, but return NULL */
875 break;
877 case PORTAL_UTIL_SELECT:
878 node = (Node *) linitial(stmt_list);
879 if (IsA(node, Query))
881 query = (Query *) node;
882 Assert(query->utilityStmt);
883 return UtilityTupleDescriptor(query->utilityStmt);
885 /* else it's a bare utility statement */
886 return UtilityTupleDescriptor(node);
888 case PORTAL_MULTI_QUERY:
889 /* will not return tuples */
890 break;
892 return NULL;
896 * PlanCacheRelCallback
897 * Relcache inval callback function
899 * Invalidate all plans mentioning the given rel, or all plans mentioning
900 * any rel at all if relid == InvalidOid.
902 static void
903 PlanCacheRelCallback(Datum arg, Oid relid)
905 ListCell *lc1;
907 foreach(lc1, cached_plans_list)
909 CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc1);
910 CachedPlan *plan = plansource->plan;
912 /* No work if it's already invalidated */
913 if (!plan || plan->dead)
914 continue;
915 if (plan->fully_planned)
917 /* Have to check the per-PlannedStmt relid lists */
918 ListCell *lc2;
920 foreach(lc2, plan->stmt_list)
922 PlannedStmt *plannedstmt = (PlannedStmt *) lfirst(lc2);
924 Assert(!IsA(plannedstmt, Query));
925 if (!IsA(plannedstmt, PlannedStmt))
926 continue; /* Ignore utility statements */
927 if ((relid == InvalidOid) ? plannedstmt->relationOids != NIL :
928 list_member_oid(plannedstmt->relationOids, relid))
930 /* Invalidate the plan! */
931 plan->dead = true;
932 break; /* out of stmt_list scan */
936 else
938 /* Otherwise check the single list we built ourselves */
939 if ((relid == InvalidOid) ? plan->relationOids != NIL :
940 list_member_oid(plan->relationOids, relid))
941 plan->dead = true;
947 * PlanCacheFuncCallback
948 * Syscache inval callback function for PROCOID cache
950 * Invalidate all plans mentioning the given catalog entry, or all plans
951 * mentioning any member of this cache if tuplePtr == NULL.
953 * Note that the coding would support use for multiple caches, but right
954 * now only user-defined functions are tracked this way.
956 static void
957 PlanCacheFuncCallback(Datum arg, int cacheid, ItemPointer tuplePtr)
959 ListCell *lc1;
961 foreach(lc1, cached_plans_list)
963 CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc1);
964 CachedPlan *plan = plansource->plan;
966 /* No work if it's already invalidated */
967 if (!plan || plan->dead)
968 continue;
969 if (plan->fully_planned)
971 /* Have to check the per-PlannedStmt inval-item lists */
972 ListCell *lc2;
974 foreach(lc2, plan->stmt_list)
976 PlannedStmt *plannedstmt = (PlannedStmt *) lfirst(lc2);
977 ListCell *lc3;
979 Assert(!IsA(plannedstmt, Query));
980 if (!IsA(plannedstmt, PlannedStmt))
981 continue; /* Ignore utility statements */
982 foreach(lc3, plannedstmt->invalItems)
984 PlanInvalItem *item = (PlanInvalItem *) lfirst(lc3);
986 if (item->cacheId != cacheid)
987 continue;
988 if (tuplePtr == NULL ||
989 ItemPointerEquals(tuplePtr, &item->tupleId))
991 /* Invalidate the plan! */
992 plan->dead = true;
993 break; /* out of invalItems scan */
996 if (plan->dead)
997 break; /* out of stmt_list scan */
1000 else
1002 /* Otherwise check the single list we built ourselves */
1003 ListCell *lc2;
1005 foreach(lc2, plan->invalItems)
1007 PlanInvalItem *item = (PlanInvalItem *) lfirst(lc2);
1009 if (item->cacheId != cacheid)
1010 continue;
1011 if (tuplePtr == NULL ||
1012 ItemPointerEquals(tuplePtr, &item->tupleId))
1014 /* Invalidate the plan! */
1015 plan->dead = true;
1016 break;
1024 * PlanCacheSysCallback
1025 * Syscache inval callback function for other caches
1027 * Just invalidate everything...
1029 static void
1030 PlanCacheSysCallback(Datum arg, int cacheid, ItemPointer tuplePtr)
1032 ResetPlanCache();
1036 * ResetPlanCache: drop all cached plans.
1038 void
1039 ResetPlanCache(void)
1041 ListCell *lc;
1043 foreach(lc, cached_plans_list)
1045 CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
1046 CachedPlan *plan = plansource->plan;
1048 if (plan)
1049 plan->dead = true;