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