aboutsummaryrefslogtreecommitdiff
path: root/src/include/utils/plancache.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/include/utils/plancache.h')
-rw-r--r--src/include/utils/plancache.h156
1 files changed, 96 insertions, 60 deletions
diff --git a/src/include/utils/plancache.h b/src/include/utils/plancache.h
index b8639a59a0e..c8c27bbb207 100644
--- a/src/include/utils/plancache.h
+++ b/src/include/utils/plancache.h
@@ -18,26 +18,47 @@
#include "access/tupdesc.h"
#include "nodes/params.h"
+#define CACHEDPLANSOURCE_MAGIC 195726186
+#define CACHEDPLAN_MAGIC 953717834
+
/*
- * CachedPlanSource represents the portion of a cached plan that persists
- * across invalidation/replan cycles. It stores a raw parse tree (required),
- * the original source text (also required, as of 8.4), and adjunct data.
+ * CachedPlanSource (which might better have been called CachedQuery)
+ * represents a SQL query that we expect to use multiple times. It stores
+ * the query source text, the raw parse tree, and the analyzed-and-rewritten
+ * query tree, as well as adjunct data. Cache invalidation can happen as a
+ * result of DDL affecting objects used by the query. In that case we discard
+ * the analyzed-and-rewritten query tree, and rebuild it when next needed.
+ *
+ * An actual execution plan, represented by CachedPlan, is derived from the
+ * CachedPlanSource when we need to execute the query. The plan could be
+ * either generic (usable with any set of plan parameters) or custom (for a
+ * specific set of parameters). plancache.c contains the logic that decides
+ * which way to do it for any particular execution. If we are using a generic
+ * cached plan then it is meant to be re-used across multiple executions, so
+ * callers must always treat CachedPlans as read-only.
+ *
+ * Once successfully built and "saved", CachedPlanSources typically live
+ * for the life of the backend, although they can be dropped explicitly.
+ * CachedPlans are reference-counted and go away automatically when the last
+ * reference is dropped. A CachedPlan can outlive the CachedPlanSource it
+ * was created from.
*
- * Normally, both the struct itself and the subsidiary data live in the
- * context denoted by the context field, while the linked-to CachedPlan, if
- * any, has its own context. Thus an invalidated CachedPlan can be dropped
- * when no longer needed, and conversely a CachedPlanSource can be dropped
- * without worrying whether any portals depend on particular instances of
- * its plan.
+ * An "unsaved" CachedPlanSource can be used for generating plans, but it
+ * lives in transient storage and will not be updated in response to sinval
+ * events.
*
- * But for entries created by FastCreateCachedPlan, the CachedPlanSource
- * and the initial version of the CachedPlan share the same memory context.
- * In this case, we treat the memory context as belonging to the CachedPlan.
- * The CachedPlanSource has an extra reference-counted link (orig_plan)
- * to the CachedPlan, and the memory context goes away when the CachedPlan's
- * reference count goes to zero. This arrangement saves overhead for plans
- * that aren't expected to live long enough to need replanning, while not
- * losing any flexibility if a replan turns out to be necessary.
+ * CachedPlans made from saved CachedPlanSources are likewise in permanent
+ * storage, so to avoid memory leaks, the reference-counted references to them
+ * must be held in permanent data structures or ResourceOwners. CachedPlans
+ * made from unsaved CachedPlanSources are in children of the caller's
+ * memory context, so references to them should not be longer-lived than
+ * that context. (Reference counting is somewhat pro forma in that case,
+ * though it may be useful if the CachedPlan can be discarded early.)
+ *
+ * A CachedPlanSource has two associated memory contexts: one that holds the
+ * struct itself, the query source text and the raw parse tree, and another
+ * context that holds the rewritten query tree and associated data. This
+ * allows the query tree to be discarded easily when it is invalidated.
*
* Note: the string referenced by commandTag is not subsidiary storage;
* it is assumed to be a compile-time-constant string. As with portals,
@@ -46,78 +67,93 @@
*/
typedef struct CachedPlanSource
{
+ int magic; /* should equal CACHEDPLANSOURCE_MAGIC */
Node *raw_parse_tree; /* output of raw_parser() */
- char *query_string; /* text of query (as of 8.4, never NULL) */
+ char *query_string; /* source text of query */
const char *commandTag; /* command tag (a constant!), or NULL */
Oid *param_types; /* array of parameter type OIDs, or NULL */
int num_params; /* length of param_types array */
ParserSetupHook parserSetup; /* alternative parameter spec method */
void *parserSetupArg;
int cursor_options; /* cursor options used for planning */
- bool fully_planned; /* do we cache planner or rewriter output? */
bool fixed_result; /* disallow change in result tupdesc? */
- struct OverrideSearchPath *search_path; /* saved search_path */
- int generation; /* counter, starting at 1, for replans */
TupleDesc resultDesc; /* result type; NULL = doesn't return tuples */
- struct CachedPlan *plan; /* link to plan, or NULL if not valid */
- MemoryContext context; /* context containing this CachedPlanSource */
- struct CachedPlan *orig_plan; /* link to plan owning my context */
+ struct OverrideSearchPath *search_path; /* saved search_path */
+ MemoryContext context; /* memory context holding all above */
+ /* These fields describe the current analyzed-and-rewritten query tree: */
+ List *query_list; /* list of Query nodes, or NIL if not valid */
+ List *relationOids; /* OIDs of relations the queries depend on */
+ List *invalItems; /* other dependencies, as PlanInvalItems */
+ MemoryContext query_context; /* context holding the above, or NULL */
+ /* If we have a generic plan, this is a reference-counted link to it: */
+ struct CachedPlan *gplan; /* generic plan, or NULL if not valid */
+ /* Some state flags: */
+ bool is_complete; /* has CompleteCachedPlan been done? */
+ bool is_saved; /* has CachedPlanSource been "saved"? */
+ bool is_valid; /* is the query_list currently valid? */
+ int generation; /* increments each time we create a plan */
+ /* If CachedPlanSource has been saved, it is a member of a global list */
+ struct CachedPlanSource *next_saved; /* list link, if so */
+ /* State kept to help decide whether to use custom or generic plans: */
+ double generic_cost; /* cost of generic plan, or -1 if not known */
+ double total_custom_cost; /* total cost of custom plans so far */
+ int num_custom_plans; /* number of plans included in total */
} CachedPlanSource;
/*
- * CachedPlan represents the portion of a cached plan that is discarded when
- * invalidation occurs. The reference count includes both the link(s) from the
- * parent CachedPlanSource, and any active plan executions, so the plan can be
- * discarded exactly when refcount goes to zero. Both the struct itself and
- * the subsidiary data live in the context denoted by the context field.
+ * CachedPlan represents an execution plan derived from a CachedPlanSource.
+ * The reference count includes both the link from the parent CachedPlanSource
+ * (if any), and any active plan executions, so the plan can be discarded
+ * exactly when refcount goes to zero. Both the struct itself and the
+ * subsidiary data live in the context denoted by the context field.
* This makes it easy to free a no-longer-needed cached plan.
*/
typedef struct CachedPlan
{
- List *stmt_list; /* list of statement or Query nodes */
- bool fully_planned; /* do we cache planner or rewriter output? */
- bool dead; /* if true, do not use */
+ int magic; /* should equal CACHEDPLAN_MAGIC */
+ List *stmt_list; /* list of statement nodes (PlannedStmts
+ * and bare utility statements) */
+ bool is_saved; /* is CachedPlan in a long-lived context? */
+ bool is_valid; /* is the stmt_list currently valid? */
TransactionId saved_xmin; /* if valid, replan when TransactionXmin
* changes from this value */
+ int generation; /* parent's generation number for this plan */
int refcount; /* count of live references to this struct */
- int generation; /* counter, starting at 1, for replans */
MemoryContext context; /* context containing this CachedPlan */
- /* These fields are used only in the not-fully-planned case: */
- List *relationOids; /* OIDs of relations the stmts depend on */
- List *invalItems; /* other dependencies, as PlanInvalItems */
} CachedPlan;
extern void InitPlanCache(void);
+extern void ResetPlanCache(void);
+
extern CachedPlanSource *CreateCachedPlan(Node *raw_parse_tree,
const char *query_string,
- const char *commandTag,
- Oid *param_types,
- int num_params,
- int cursor_options,
- List *stmt_list,
- bool fully_planned,
- bool fixed_result);
-extern CachedPlanSource *FastCreateCachedPlan(Node *raw_parse_tree,
- char *query_string,
- const char *commandTag,
- Oid *param_types,
- int num_params,
- int cursor_options,
- List *stmt_list,
- bool fully_planned,
- bool fixed_result,
- MemoryContext context);
-extern void CachedPlanSetParserHook(CachedPlanSource *plansource,
+ const char *commandTag);
+extern void CompleteCachedPlan(CachedPlanSource *plansource,
+ List *querytree_list,
+ MemoryContext querytree_context,
+ Oid *param_types,
+ int num_params,
ParserSetupHook parserSetup,
- void *parserSetupArg);
+ void *parserSetupArg,
+ int cursor_options,
+ bool fixed_result);
+
+extern void SaveCachedPlan(CachedPlanSource *plansource);
extern void DropCachedPlan(CachedPlanSource *plansource);
-extern CachedPlan *RevalidateCachedPlan(CachedPlanSource *plansource,
- bool useResOwner);
-extern void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner);
+
+extern void CachedPlanSetParentContext(CachedPlanSource *plansource,
+ MemoryContext newcontext);
+
+extern CachedPlanSource *CopyCachedPlan(CachedPlanSource *plansource);
+
extern bool CachedPlanIsValid(CachedPlanSource *plansource);
-extern TupleDesc PlanCacheComputeResultDesc(List *stmt_list);
-extern void ResetPlanCache(void);
+extern List *CachedPlanGetTargetList(CachedPlanSource *plansource);
+
+extern CachedPlan *GetCachedPlan(CachedPlanSource *plansource,
+ ParamListInfo boundParams,
+ bool useResOwner);
+extern void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner);
#endif /* PLANCACHE_H */