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

Generated by: LCOV version 1.14