LCOV - code coverage report
Current view: top level - src/backend/utils/cache - plancache.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 88.4 % 688 608
Test Date: 2026-03-10 05:14:54 Functions: 97.5 % 40 39
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.0-1