summaryrefslogtreecommitdiff
path: root/src/include/utils
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2015-03-01 14:06:50 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2015-03-01 14:06:55 -0500
commit8abb3cda0ddc00a0ab98977a1633a95b97068d4e (patch)
tree9ce473ff40b28839e2fb9c2656babae23ce35bb8 /src/include/utils
parentb8a18ad4850ea5ad7884aa6ab731fd392e73b4ad (diff)
downloadpostgresql-8abb3cda0ddc00a0ab98977a1633a95b97068d4e.tar.gz
Use the typcache to cache constraints for domain types.
Previously, we cached domain constraints for the life of a query, or really for the life of the FmgrInfo struct that was used to invoke domain_in() or domain_check(). But plpgsql (and probably other places) are set up to cache such FmgrInfos for the whole lifespan of a session, which meant they could be enforcing really stale sets of constraints. On the other hand, searching pg_constraint once per query gets kind of expensive too: testing says that as much as half the runtime of a trivial query such as "SELECT 0::domaintype" went into that. To fix this, delegate the responsibility for tracking a domain's constraints to the typcache, which has the infrastructure needed to detect syscache invalidation events that signal possible changes. This not only removes unnecessary repeat reads of pg_constraint, but ensures that we never apply stale constraint data: whatever we use is the current data according to syscache rules. Unfortunately, the current configuration of the system catalogs means we have to flush cached domain-constraint data whenever either pg_type or pg_constraint changes, which happens rather a lot (eg, creation or deletion of a temp table will do it). It might be worth rearranging things to split pg_constraint into two catalogs, of which the domain constraint one would probably be very low-traffic. That's a job for another patch though, and in any case this patch should improve matters materially even with that handicap. This patch makes use of the recently-added memory context reset callback feature to manage the lifespan of domain constraint caches, so that we don't risk deleting a cache that might be in the midst of evaluation. Although this is a bug fix as well as a performance improvement, no back-patch. There haven't been many if any field complaints about stale domain constraint checks, so it doesn't seem worth taking the risk of modifying data structures as basic as MemoryContexts in back branches.
Diffstat (limited to 'src/include/utils')
-rw-r--r--src/include/utils/typcache.h37
1 files changed, 37 insertions, 0 deletions
diff --git a/src/include/utils/typcache.h b/src/include/utils/typcache.h
index b544180b46..1a9befb9d7 100644
--- a/src/include/utils/typcache.h
+++ b/src/include/utils/typcache.h
@@ -20,6 +20,9 @@
#include "fmgr.h"
+/* DomainConstraintCache is an opaque struct known only within typcache.c */
+typedef struct DomainConstraintCache DomainConstraintCache;
+
/* TypeCacheEnumData is an opaque struct known only within typcache.c */
struct TypeCacheEnumData;
@@ -84,6 +87,12 @@ typedef struct TypeCacheEntry
FmgrInfo rng_canonical_finfo; /* canonicalization function, if any */
FmgrInfo rng_subdiff_finfo; /* difference function, if any */
+ /*
+ * Domain constraint data if it's a domain type. NULL if not domain, or
+ * if domain has no constraints, or if information hasn't been requested.
+ */
+ DomainConstraintCache *domainData;
+
/* Private data, for internal use of typcache.c only */
int flags; /* flags about what we've computed */
@@ -92,6 +101,9 @@ typedef struct TypeCacheEntry
* information hasn't been requested.
*/
struct TypeCacheEnumData *enumData;
+
+ /* We also maintain a list of all known domain-type cache entries */
+ struct TypeCacheEntry *nextDomain;
} TypeCacheEntry;
/* Bit flags to indicate which fields a given caller needs to have set */
@@ -107,9 +119,34 @@ typedef struct TypeCacheEntry
#define TYPECACHE_BTREE_OPFAMILY 0x0200
#define TYPECACHE_HASH_OPFAMILY 0x0400
#define TYPECACHE_RANGE_INFO 0x0800
+#define TYPECACHE_DOMAIN_INFO 0x1000
+
+/*
+ * Callers wishing to maintain a long-lived reference to a domain's constraint
+ * set must store it in one of these. Use InitDomainConstraintRef() and
+ * UpdateDomainConstraintRef() to manage it. Note: DomainConstraintState is
+ * considered an executable expression type, so it's defined in execnodes.h.
+ */
+typedef struct DomainConstraintRef
+{
+ List *constraints; /* list of DomainConstraintState nodes */
+
+ /* Management data --- treat these fields as private to typcache.c */
+ TypeCacheEntry *tcache; /* owning typcache entry */
+ DomainConstraintCache *dcc; /* current constraints, or NULL if none */
+ MemoryContextCallback callback; /* used to release refcount when done */
+} DomainConstraintRef;
+
extern TypeCacheEntry *lookup_type_cache(Oid type_id, int flags);
+extern void InitDomainConstraintRef(Oid type_id, DomainConstraintRef *ref,
+ MemoryContext refctx);
+
+extern void UpdateDomainConstraintRef(DomainConstraintRef *ref);
+
+extern bool DomainHasConstraints(Oid type_id);
+
extern TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod);
extern TupleDesc lookup_rowtype_tupdesc_noerror(Oid type_id, int32 typmod,