summaryrefslogtreecommitdiff
path: root/src/include/utils/plancache.h
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2018-12-13 13:24:43 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2018-12-13 13:24:43 -0500
commit04fe805a1734eccd8dcdd34c8cc0ddcb62c7240c (patch)
tree5e7731081fd4fd783141753c079e772fb452a999 /src/include/utils/plancache.h
parent52ac6cd2d0cd70e01291e0ac4ee6d068b69bc478 (diff)
Drop no-op CoerceToDomain nodes from expressions at planning time.
If a domain has no constraints, then CoerceToDomain doesn't really do anything and can be simplified to a RelabelType. This not only eliminates cycles at execution, but allows the planner to optimize better (for instance, match the coerced expression to an index on the underlying column). However, we do have to support invalidating the plan later if a constraint gets added to the domain. That's comparable to the case of a change to a SQL function that had been inlined into a plan, so all the necessary logic already exists for plans depending on functions. We need only duplicate or share that logic for domains. ALTER DOMAIN ADD/DROP CONSTRAINT need to be taught to send out sinval messages for the domain's pg_type entry, since those operations don't update that row. (ALTER DOMAIN SET/DROP NOT NULL do update that row, so no code change is needed for them.) Testing this revealed what's really a pre-existing bug in plpgsql: it caches the SQL-expression-tree expansion of type coercions and had no provision for invalidating entries in that cache. Up to now that was only a problem if such an expression had inlined a SQL function that got changed, which is unlikely though not impossible. But failing to track changes of domain constraints breaks an existing regression test case and would likely cause practical problems too. We could fix that locally in plpgsql, but what seems like a better idea is to build some generic infrastructure in plancache.c to store standalone expressions and track invalidation events for them. (It's tempting to wonder whether plpgsql's "simple expression" stuff could use this code with lower overhead than its current use of the heavyweight plancache APIs. But I've left that idea for later.) Other stuff fixed in passing: * Allow estimate_expression_value() to drop CoerceToDomain unconditionally, effectively assuming that the coercion will succeed. This will improve planner selectivity estimates for cases involving estimatable expressions that are coerced to domains. We could have done this independently of everything else here, but there wasn't previously any need for eval_const_expressions_mutator to know about CoerceToDomain at all. * Use a dlist for plancache.c's list of cached plans, rather than a manually threaded singly-linked list. That eliminates a potential performance problem in DropCachedPlan. * Fix a couple of inconsistencies in typecmds.c about whether operations on domains drop RowExclusiveLock on pg_type. Our common practice is that DDL operations do drop catalog locks, so standardize on that choice. Discussion: https://postgr.es/m/19958.1544122124@sss.pgh.pa.us
Diffstat (limited to 'src/include/utils/plancache.h')
-rw-r--r--src/include/utils/plancache.h51
1 files changed, 40 insertions, 11 deletions
diff --git a/src/include/utils/plancache.h b/src/include/utils/plancache.h
index 5fc7903a068..7fd7ea6c168 100644
--- a/src/include/utils/plancache.h
+++ b/src/include/utils/plancache.h
@@ -16,14 +16,27 @@
#define PLANCACHE_H
#include "access/tupdesc.h"
+#include "lib/ilist.h"
#include "nodes/params.h"
#include "utils/queryenvironment.h"
/* Forward declaration, to avoid including parsenodes.h here */
struct RawStmt;
+/* possible values for plan_cache_mode */
+typedef enum
+{
+ PLAN_CACHE_MODE_AUTO,
+ PLAN_CACHE_MODE_FORCE_GENERIC_PLAN,
+ PLAN_CACHE_MODE_FORCE_CUSTOM_PLAN
+} PlanCacheMode;
+
+/* GUC parameter */
+extern int plan_cache_mode;
+
#define CACHEDPLANSOURCE_MAGIC 195726186
#define CACHEDPLAN_MAGIC 953717834
+#define CACHEDEXPR_MAGIC 838275847
/*
* CachedPlanSource (which might better have been called CachedQuery)
@@ -110,7 +123,7 @@ typedef struct CachedPlanSource
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 */
+ dlist_node node; /* list link, if is_saved */
/* 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 */
@@ -143,6 +156,30 @@ typedef struct CachedPlan
MemoryContext context; /* context containing this CachedPlan */
} CachedPlan;
+/*
+ * CachedExpression is a low-overhead mechanism for caching the planned form
+ * of standalone scalar expressions. While such expressions are not usually
+ * subject to cache invalidation events, that can happen, for example because
+ * of replacement of a SQL function that was inlined into the expression.
+ * The plancache takes care of storing the expression tree and marking it
+ * invalid if a cache invalidation occurs, but the caller must notice the
+ * !is_valid status and discard the obsolete expression without reusing it.
+ * We do not store the original parse tree, only the planned expression;
+ * this is an optimization based on the assumption that we usually will not
+ * need to replan for the life of the session.
+ */
+typedef struct CachedExpression
+{
+ int magic; /* should equal CACHEDEXPR_MAGIC */
+ Node *expr; /* planned form of expression */
+ bool is_valid; /* is the expression still valid? */
+ /* remaining fields should be treated as private to plancache.c: */
+ List *relationOids; /* OIDs of relations the expr depends on */
+ List *invalItems; /* other dependencies, as PlanInvalItems */
+ MemoryContext context; /* context containing this CachedExpression */
+ dlist_node node; /* link in global list of CachedExpressions */
+} CachedExpression;
+
extern void InitPlanCache(void);
extern void ResetPlanCache(void);
@@ -182,15 +219,7 @@ extern CachedPlan *GetCachedPlan(CachedPlanSource *plansource,
QueryEnvironment *queryEnv);
extern void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner);
-/* possible values for plan_cache_mode */
-typedef enum
-{
- PLAN_CACHE_MODE_AUTO,
- PLAN_CACHE_MODE_FORCE_GENERIC_PLAN,
- PLAN_CACHE_MODE_FORCE_CUSTOM_PLAN
-} PlanCacheMode;
-
-/* GUC parameter */
-extern int plan_cache_mode;
+extern CachedExpression *GetCachedExpression(Node *expr);
+extern void FreeCachedExpression(CachedExpression *cexpr);
#endif /* PLANCACHE_H */