LCOV - code coverage report
Current view: top level - src/include/utils - plancache.h (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 4 4 100.0 %
Date: 2025-04-01 14:15:22 Functions: 2 2 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * plancache.h
       4             :  *    Plan cache definitions.
       5             :  *
       6             :  * See plancache.c for comments.
       7             :  *
       8             :  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
       9             :  * Portions Copyright (c) 1994, Regents of the University of California
      10             :  *
      11             :  * src/include/utils/plancache.h
      12             :  *
      13             :  *-------------------------------------------------------------------------
      14             :  */
      15             : #ifndef PLANCACHE_H
      16             : #define PLANCACHE_H
      17             : 
      18             : #include "access/tupdesc.h"
      19             : #include "lib/ilist.h"
      20             : #include "nodes/params.h"
      21             : #include "nodes/parsenodes.h"
      22             : #include "nodes/plannodes.h"
      23             : #include "tcop/cmdtag.h"
      24             : #include "utils/queryenvironment.h"
      25             : #include "utils/resowner.h"
      26             : 
      27             : 
      28             : /* Forward declaration, to avoid including parsenodes.h here */
      29             : struct RawStmt;
      30             : 
      31             : /* possible values for plan_cache_mode */
      32             : typedef enum
      33             : {
      34             :     PLAN_CACHE_MODE_AUTO,
      35             :     PLAN_CACHE_MODE_FORCE_GENERIC_PLAN,
      36             :     PLAN_CACHE_MODE_FORCE_CUSTOM_PLAN,
      37             : }           PlanCacheMode;
      38             : 
      39             : /* GUC parameter */
      40             : extern PGDLLIMPORT int plan_cache_mode;
      41             : 
      42             : #define CACHEDPLANSOURCE_MAGIC      195726186
      43             : #define CACHEDPLAN_MAGIC            953717834
      44             : #define CACHEDEXPR_MAGIC            838275847
      45             : 
      46             : /*
      47             :  * CachedPlanSource (which might better have been called CachedQuery)
      48             :  * represents a SQL query that we expect to use multiple times.  It stores
      49             :  * the query source text, the raw parse tree, and the analyzed-and-rewritten
      50             :  * query tree, as well as adjunct data.  Cache invalidation can happen as a
      51             :  * result of DDL affecting objects used by the query.  In that case we discard
      52             :  * the analyzed-and-rewritten query tree, and rebuild it when next needed.
      53             :  *
      54             :  * An actual execution plan, represented by CachedPlan, is derived from the
      55             :  * CachedPlanSource when we need to execute the query.  The plan could be
      56             :  * either generic (usable with any set of plan parameters) or custom (for a
      57             :  * specific set of parameters).  plancache.c contains the logic that decides
      58             :  * which way to do it for any particular execution.  If we are using a generic
      59             :  * cached plan then it is meant to be re-used across multiple executions, so
      60             :  * callers must always treat CachedPlans as read-only.
      61             :  *
      62             :  * Once successfully built and "saved", CachedPlanSources typically live
      63             :  * for the life of the backend, although they can be dropped explicitly.
      64             :  * CachedPlans are reference-counted and go away automatically when the last
      65             :  * reference is dropped.  A CachedPlan can outlive the CachedPlanSource it
      66             :  * was created from.
      67             :  *
      68             :  * An "unsaved" CachedPlanSource can be used for generating plans, but it
      69             :  * lives in transient storage and will not be updated in response to sinval
      70             :  * events.
      71             :  *
      72             :  * CachedPlans made from saved CachedPlanSources are likewise in permanent
      73             :  * storage, so to avoid memory leaks, the reference-counted references to them
      74             :  * must be held in permanent data structures or ResourceOwners.  CachedPlans
      75             :  * made from unsaved CachedPlanSources are in children of the caller's
      76             :  * memory context, so references to them should not be longer-lived than
      77             :  * that context.  (Reference counting is somewhat pro forma in that case,
      78             :  * though it may be useful if the CachedPlan can be discarded early.)
      79             :  *
      80             :  * A CachedPlanSource has two associated memory contexts: one that holds the
      81             :  * struct itself, the query source text and the raw parse tree, and another
      82             :  * context that holds the rewritten query tree and associated data.  This
      83             :  * allows the query tree to be discarded easily when it is invalidated.
      84             :  *
      85             :  * Some callers wish to use the CachedPlan API even with one-shot queries
      86             :  * that have no reason to be saved at all.  We therefore support a "oneshot"
      87             :  * variant that does no data copying or invalidation checking.  In this case
      88             :  * there are no separate memory contexts: the CachedPlanSource struct and
      89             :  * all subsidiary data live in the caller's CurrentMemoryContext, and there
      90             :  * is no way to free memory short of clearing that entire context.  A oneshot
      91             :  * plan is always treated as unsaved.
      92             :  */
      93             : typedef struct CachedPlanSource
      94             : {
      95             :     int         magic;          /* should equal CACHEDPLANSOURCE_MAGIC */
      96             :     struct RawStmt *raw_parse_tree; /* output of raw_parser(), or NULL */
      97             :     const char *query_string;   /* source text of query */
      98             :     CommandTag  commandTag;     /* command tag for query */
      99             :     Oid        *param_types;    /* array of parameter type OIDs, or NULL */
     100             :     int         num_params;     /* length of param_types array */
     101             :     ParserSetupHook parserSetup;    /* alternative parameter spec method */
     102             :     void       *parserSetupArg;
     103             :     int         cursor_options; /* cursor options used for planning */
     104             :     bool        fixed_result;   /* disallow change in result tupdesc? */
     105             :     TupleDesc   resultDesc;     /* result type; NULL = doesn't return tuples */
     106             :     MemoryContext context;      /* memory context holding all above */
     107             :     /* These fields describe the current analyzed-and-rewritten query tree: */
     108             :     List       *query_list;     /* list of Query nodes, or NIL if not valid */
     109             :     List       *relationOids;   /* OIDs of relations the queries depend on */
     110             :     List       *invalItems;     /* other dependencies, as PlanInvalItems */
     111             :     struct SearchPathMatcher *search_path;  /* search_path used for parsing
     112             :                                              * and planning */
     113             :     MemoryContext query_context;    /* context holding the above, or NULL */
     114             :     Oid         rewriteRoleId;  /* Role ID we did rewriting for */
     115             :     bool        rewriteRowSecurity; /* row_security used during rewrite */
     116             :     bool        dependsOnRLS;   /* is rewritten query specific to the above? */
     117             :     /* If we have a generic plan, this is a reference-counted link to it: */
     118             :     struct CachedPlan *gplan;   /* generic plan, or NULL if not valid */
     119             :     /* Some state flags: */
     120             :     bool        is_oneshot;     /* is it a "oneshot" plan? */
     121             :     bool        is_complete;    /* has CompleteCachedPlan been done? */
     122             :     bool        is_saved;       /* has CachedPlanSource been "saved"? */
     123             :     bool        is_valid;       /* is the query_list currently valid? */
     124             :     int         generation;     /* increments each time we create a plan */
     125             :     /* If CachedPlanSource has been saved, it is a member of a global list */
     126             :     dlist_node  node;           /* list link, if is_saved */
     127             :     /* State kept to help decide whether to use custom or generic plans: */
     128             :     double      generic_cost;   /* cost of generic plan, or -1 if not known */
     129             :     double      total_custom_cost;  /* total cost of custom plans so far */
     130             :     int64       num_custom_plans;   /* # of custom plans included in total */
     131             :     int64       num_generic_plans;  /* # of generic plans */
     132             : } CachedPlanSource;
     133             : 
     134             : /*
     135             :  * CachedPlan represents an execution plan derived from a CachedPlanSource.
     136             :  * The reference count includes both the link from the parent CachedPlanSource
     137             :  * (if any), and any active plan executions, so the plan can be discarded
     138             :  * exactly when refcount goes to zero.  Both the struct itself and the
     139             :  * subsidiary data, except the PlannedStmts in stmt_list live in the context
     140             :  * denoted by the context field; the PlannedStmts live in the context denoted
     141             :  * by stmt_context.  Separate contexts makes it easy to free a no-longer-needed
     142             :  * cached plan. (However, if is_oneshot is true, the context does not belong
     143             :  * solely to the CachedPlan so no freeing is possible.)
     144             :  */
     145             : typedef struct CachedPlan
     146             : {
     147             :     int         magic;          /* should equal CACHEDPLAN_MAGIC */
     148             :     List       *stmt_list;      /* list of PlannedStmts */
     149             :     bool        is_oneshot;     /* is it a "oneshot" plan? */
     150             :     bool        is_saved;       /* is CachedPlan in a long-lived context? */
     151             :     bool        is_reused;      /* is it a reused generic plan? */
     152             :     bool        is_valid;       /* is the stmt_list currently valid? */
     153             :     Oid         planRoleId;     /* Role ID the plan was created for */
     154             :     bool        dependsOnRole;  /* is plan specific to that role? */
     155             :     TransactionId saved_xmin;   /* if valid, replan when TransactionXmin
     156             :                                  * changes from this value */
     157             :     int         generation;     /* parent's generation number for this plan */
     158             :     int         refcount;       /* count of live references to this struct */
     159             :     MemoryContext context;      /* context containing this CachedPlan */
     160             :     MemoryContext stmt_context; /* context containing the PlannedStmts in
     161             :                                  * stmt_list, but not the List itself which is
     162             :                                  * in the above context; NULL if is_oneshot is
     163             :                                  * true. */
     164             : } CachedPlan;
     165             : 
     166             : /*
     167             :  * CachedExpression is a low-overhead mechanism for caching the planned form
     168             :  * of standalone scalar expressions.  While such expressions are not usually
     169             :  * subject to cache invalidation events, that can happen, for example because
     170             :  * of replacement of a SQL function that was inlined into the expression.
     171             :  * The plancache takes care of storing the expression tree and marking it
     172             :  * invalid if a cache invalidation occurs, but the caller must notice the
     173             :  * !is_valid status and discard the obsolete expression without reusing it.
     174             :  * We do not store the original parse tree, only the planned expression;
     175             :  * this is an optimization based on the assumption that we usually will not
     176             :  * need to replan for the life of the session.
     177             :  */
     178             : typedef struct CachedExpression
     179             : {
     180             :     int         magic;          /* should equal CACHEDEXPR_MAGIC */
     181             :     Node       *expr;           /* planned form of expression */
     182             :     bool        is_valid;       /* is the expression still valid? */
     183             :     /* remaining fields should be treated as private to plancache.c: */
     184             :     List       *relationOids;   /* OIDs of relations the expr depends on */
     185             :     List       *invalItems;     /* other dependencies, as PlanInvalItems */
     186             :     MemoryContext context;      /* context containing this CachedExpression */
     187             :     dlist_node  node;           /* link in global list of CachedExpressions */
     188             : } CachedExpression;
     189             : 
     190             : 
     191             : extern void InitPlanCache(void);
     192             : extern void ResetPlanCache(void);
     193             : 
     194             : extern void ReleaseAllPlanCacheRefsInOwner(ResourceOwner owner);
     195             : 
     196             : extern CachedPlanSource *CreateCachedPlan(struct RawStmt *raw_parse_tree,
     197             :                                           const char *query_string,
     198             :                                           CommandTag commandTag);
     199             : extern CachedPlanSource *CreateOneShotCachedPlan(struct RawStmt *raw_parse_tree,
     200             :                                                  const char *query_string,
     201             :                                                  CommandTag commandTag);
     202             : extern void CompleteCachedPlan(CachedPlanSource *plansource,
     203             :                                List *querytree_list,
     204             :                                MemoryContext querytree_context,
     205             :                                Oid *param_types,
     206             :                                int num_params,
     207             :                                ParserSetupHook parserSetup,
     208             :                                void *parserSetupArg,
     209             :                                int cursor_options,
     210             :                                bool fixed_result);
     211             : 
     212             : extern void SaveCachedPlan(CachedPlanSource *plansource);
     213             : extern void DropCachedPlan(CachedPlanSource *plansource);
     214             : 
     215             : extern void CachedPlanSetParentContext(CachedPlanSource *plansource,
     216             :                                        MemoryContext newcontext);
     217             : 
     218             : extern CachedPlanSource *CopyCachedPlan(CachedPlanSource *plansource);
     219             : 
     220             : extern bool CachedPlanIsValid(CachedPlanSource *plansource);
     221             : 
     222             : extern List *CachedPlanGetTargetList(CachedPlanSource *plansource,
     223             :                                      QueryEnvironment *queryEnv);
     224             : 
     225             : extern CachedPlan *GetCachedPlan(CachedPlanSource *plansource,
     226             :                                  ParamListInfo boundParams,
     227             :                                  ResourceOwner owner,
     228             :                                  QueryEnvironment *queryEnv);
     229             : extern PlannedStmt *UpdateCachedPlan(CachedPlanSource *plansource,
     230             :                                      int query_index,
     231             :                                      QueryEnvironment *queryEnv);
     232             : 
     233             : extern void ReleaseCachedPlan(CachedPlan *plan, ResourceOwner owner);
     234             : 
     235             : extern bool CachedPlanAllowsSimpleValidityCheck(CachedPlanSource *plansource,
     236             :                                                 CachedPlan *plan,
     237             :                                                 ResourceOwner owner);
     238             : extern bool CachedPlanIsSimplyValid(CachedPlanSource *plansource,
     239             :                                     CachedPlan *plan,
     240             :                                     ResourceOwner owner);
     241             : 
     242             : extern CachedExpression *GetCachedExpression(Node *expr);
     243             : extern void FreeCachedExpression(CachedExpression *cexpr);
     244             : 
     245             : /*
     246             :  * CachedPlanRequiresLocking: should the executor acquire additional locks?
     247             :  *
     248             :  * If the plan is a saved generic plan, the executor must acquire locks for
     249             :  * relations that are not covered by AcquireExecutorLocks(), such as partitions
     250             :  * that are subject to initial runtime pruning.
     251             :  */
     252             : static inline bool
     253       40054 : CachedPlanRequiresLocking(CachedPlan *cplan)
     254             : {
     255       40054 :     return !cplan->is_oneshot && cplan->is_reused;
     256             : }
     257             : 
     258             : /*
     259             :  * CachedPlanValid
     260             :  *      Returns whether a cached generic plan is still valid.
     261             :  *
     262             :  * Invoked by the executor to check if the plan has not been invalidated after
     263             :  * taking locks during the initialization of the plan.
     264             :  */
     265             : static inline bool
     266      400758 : CachedPlanValid(CachedPlan *cplan)
     267             : {
     268      400758 :     return cplan->is_valid;
     269             : }
     270             : 
     271             : #endif                          /* PLANCACHE_H */

Generated by: LCOV version 1.14