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