Commit 37ee4b75 authored by Tom Lane's avatar Tom Lane

Restructure function-internal caching in the range type code.

Move the responsibility for caching specialized information about range
types into the type cache, so that the catalog lookups only have to occur
once per session.  Rearrange APIs a bit so that fn_extra caching is
actually effective in the GiST support code.  (Use of OidFunctionCallN is
bad enough for performance in itself, but it also prevents the function
from exploiting fn_extra caching.)

The range I/O functions are still not very bright about caching repeated
lookups, but that seems like material for a separate patch.

Also, avoid unnecessary use of memcpy to fetch/store the range type OID and
flags, and don't use the full range_deserialize machinery when all we need
to see is the flags value.

Also fix API error in range_gist_penalty --- it was failing to set *penalty
for any case involving an empty range.
parent ad50934e
This diff is collapsed.
This diff is collapsed.
...@@ -51,6 +51,7 @@ ...@@ -51,6 +51,7 @@
#include "catalog/indexing.h" #include "catalog/indexing.h"
#include "catalog/pg_enum.h" #include "catalog/pg_enum.h"
#include "catalog/pg_operator.h" #include "catalog/pg_operator.h"
#include "catalog/pg_range.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "commands/defrem.h" #include "commands/defrem.h"
#include "utils/builtins.h" #include "utils/builtins.h"
...@@ -120,6 +121,7 @@ static int32 RecordCacheArrayLen = 0; /* allocated length of array */ ...@@ -120,6 +121,7 @@ static int32 RecordCacheArrayLen = 0; /* allocated length of array */
static int32 NextRecordTypmod = 0; /* number of entries used */ static int32 NextRecordTypmod = 0; /* number of entries used */
static void load_typcache_tupdesc(TypeCacheEntry *typentry); static void load_typcache_tupdesc(TypeCacheEntry *typentry);
static void load_rangetype_info(TypeCacheEntry *typentry);
static bool array_element_has_equality(TypeCacheEntry *typentry); static bool array_element_has_equality(TypeCacheEntry *typentry);
static bool array_element_has_compare(TypeCacheEntry *typentry); static bool array_element_has_compare(TypeCacheEntry *typentry);
static bool array_element_has_hashing(TypeCacheEntry *typentry); static bool array_element_has_hashing(TypeCacheEntry *typentry);
...@@ -205,6 +207,7 @@ lookup_type_cache(Oid type_id, int flags) ...@@ -205,6 +207,7 @@ lookup_type_cache(Oid type_id, int flags)
typentry->typlen = typtup->typlen; typentry->typlen = typtup->typlen;
typentry->typbyval = typtup->typbyval; typentry->typbyval = typtup->typbyval;
typentry->typalign = typtup->typalign; typentry->typalign = typtup->typalign;
typentry->typstorage = typtup->typstorage;
typentry->typtype = typtup->typtype; typentry->typtype = typtup->typtype;
typentry->typrelid = typtup->typrelid; typentry->typrelid = typtup->typrelid;
...@@ -448,6 +451,16 @@ lookup_type_cache(Oid type_id, int flags) ...@@ -448,6 +451,16 @@ lookup_type_cache(Oid type_id, int flags)
load_typcache_tupdesc(typentry); load_typcache_tupdesc(typentry);
} }
/*
* If requested, get information about a range type
*/
if ((flags & TYPECACHE_RANGE_INFO) &&
typentry->rngelemtype == NULL &&
typentry->typtype == TYPTYPE_RANGE)
{
load_rangetype_info(typentry);
}
return typentry; return typentry;
} }
...@@ -479,6 +492,62 @@ load_typcache_tupdesc(TypeCacheEntry *typentry) ...@@ -479,6 +492,62 @@ load_typcache_tupdesc(TypeCacheEntry *typentry)
relation_close(rel, AccessShareLock); relation_close(rel, AccessShareLock);
} }
/*
* load_rangetype_info --- helper routine to set up range type information
*/
static void
load_rangetype_info(TypeCacheEntry *typentry)
{
Form_pg_range pg_range;
HeapTuple tup;
Oid subtypeOid;
Oid opclassOid;
Oid canonicalOid;
Oid subdiffOid;
Oid opfamilyOid;
Oid opcintype;
Oid cmpFnOid;
/* get information from pg_range */
tup = SearchSysCache1(RANGETYPE, ObjectIdGetDatum(typentry->type_id));
/* should not fail, since we already checked typtype ... */
if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for range type %u",
typentry->type_id);
pg_range = (Form_pg_range) GETSTRUCT(tup);
subtypeOid = pg_range->rngsubtype;
typentry->rng_collation = pg_range->rngcollation;
opclassOid = pg_range->rngsubopc;
canonicalOid = pg_range->rngcanonical;
subdiffOid = pg_range->rngsubdiff;
ReleaseSysCache(tup);
/* get opclass properties and look up the comparison function */
opfamilyOid = get_opclass_family(opclassOid);
opcintype = get_opclass_input_type(opclassOid);
cmpFnOid = get_opfamily_proc(opfamilyOid, opcintype, opcintype,
BTORDER_PROC);
if (!RegProcedureIsValid(cmpFnOid))
elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
BTORDER_PROC, opcintype, opcintype, opfamilyOid);
/* set up cached fmgrinfo structs */
fmgr_info_cxt(cmpFnOid, &typentry->rng_cmp_proc_finfo,
CacheMemoryContext);
if (OidIsValid(canonicalOid))
fmgr_info_cxt(canonicalOid, &typentry->rng_canonical_finfo,
CacheMemoryContext);
if (OidIsValid(subdiffOid))
fmgr_info_cxt(subdiffOid, &typentry->rng_subdiff_finfo,
CacheMemoryContext);
/* Lastly, set up link to the element type --- this marks data valid */
typentry->rngelemtype = lookup_type_cache(subtypeOid, 0);
}
/* /*
* array_element_has_equality and friends are helper routines to check * array_element_has_equality and friends are helper routines to check
......
...@@ -14,37 +14,51 @@ ...@@ -14,37 +14,51 @@
#ifndef RANGETYPES_H #ifndef RANGETYPES_H
#define RANGETYPES_H #define RANGETYPES_H
#include "fmgr.h" #include "utils/typcache.h"
/* All ranges are represented as varlena objects */ /*
typedef struct varlena RangeType; * Ranges are varlena objects, so must meet the varlena convention that
* the first int32 of the object contains the total object size in bytes.
* Be sure to use VARSIZE() and SET_VARSIZE() to access it, though!
*/
typedef struct
{
int32 vl_len_; /* varlena header (do not touch directly!) */
Oid rangetypid; /* range type's own OID */
/* Following the OID are zero to two bound values, then a flags byte */
} RangeType;
/* Use this macro in preference to fetching rangetypid field directly */
#define RangeTypeGetOid(r) ((r)->rangetypid)
/* A range's flags byte contains these bits: */
#define RANGE_EMPTY 0x01 /* range is empty */
#define RANGE_LB_INC 0x02 /* lower bound is inclusive (vs exclusive) */
#define RANGE_LB_NULL 0x04 /* lower bound is null (NOT CURRENTLY USED) */
#define RANGE_LB_INF 0x08 /* lower bound is +/- infinity */
#define RANGE_UB_INC 0x10 /* upper bound is inclusive (vs exclusive) */
#define RANGE_UB_NULL 0x20 /* upper bound is null (NOT CURRENTLY USED) */
#define RANGE_UB_INF 0x40 /* upper bound is +/- infinity */
#define RANGE_HAS_LBOUND(flags) (!((flags) & (RANGE_EMPTY | \
RANGE_LB_NULL | \
RANGE_LB_INF)))
#define RANGE_HAS_UBOUND(flags) (!((flags) & (RANGE_EMPTY | \
RANGE_UB_NULL | \
RANGE_UB_INF)))
/* Internal representation of either bound of a range (not what's on disk) */ /* Internal representation of either bound of a range (not what's on disk) */
typedef struct typedef struct
{ {
Datum val; /* the bound value, if any */ Datum val; /* the bound value, if any */
Oid rngtypid; /* OID of the range type itself */
bool infinite; /* bound is +/- infinity */ bool infinite; /* bound is +/- infinity */
bool lower; /* this is the lower (vs upper) bound */
bool inclusive; /* bound is inclusive (vs exclusive) */ bool inclusive; /* bound is inclusive (vs exclusive) */
bool lower; /* this is the lower (vs upper) bound */
} RangeBound; } RangeBound;
/* Standard runtime-cached data for a range type */
typedef struct
{
FmgrInfo canonicalFn; /* canonicalization function, if any */
FmgrInfo cmpFn; /* element type's btree comparison function */
FmgrInfo subdiffFn; /* element type difference function, if any */
Oid rngtypid; /* OID of the range type itself */
Oid subtype; /* OID of the element type */
Oid collation; /* collation for comparisons, if any */
int16 subtyplen; /* typlen of element type */
char subtypalign; /* typalign of element type */
char subtypstorage; /* typstorage of element type */
bool subtypbyval; /* typbyval of element type */
} RangeTypeInfo;
/* /*
* fmgr macros for range type objects * fmgr macros for range type objects
*/ */
...@@ -129,18 +143,19 @@ extern Datum tsrange_subdiff(PG_FUNCTION_ARGS); ...@@ -129,18 +143,19 @@ extern Datum tsrange_subdiff(PG_FUNCTION_ARGS);
extern Datum tstzrange_subdiff(PG_FUNCTION_ARGS); extern Datum tstzrange_subdiff(PG_FUNCTION_ARGS);
/* assorted support functions */ /* assorted support functions */
extern Datum range_serialize(FunctionCallInfo fcinfo, RangeBound *lower, extern TypeCacheEntry *range_get_typcache(FunctionCallInfo fcinfo,
Oid rngtypid);
extern RangeType *range_serialize(TypeCacheEntry *typcache, RangeBound *lower,
RangeBound *upper, bool empty); RangeBound *upper, bool empty);
extern void range_deserialize(FunctionCallInfo fcinfo, RangeType *range, extern void range_deserialize(TypeCacheEntry *typcache, RangeType *range,
RangeBound *lower, RangeBound *upper, RangeBound *lower, RangeBound *upper,
bool *empty); bool *empty);
extern Datum make_range(FunctionCallInfo fcinfo, RangeBound *lower, extern char range_get_flags(RangeType *range);
extern RangeType *make_range(TypeCacheEntry *typcache, RangeBound *lower,
RangeBound *upper, bool empty); RangeBound *upper, bool empty);
extern int range_cmp_bounds(FunctionCallInfo fcinfo, RangeBound *b1, extern int range_cmp_bounds(TypeCacheEntry *typcache, RangeBound *b1,
RangeBound *b2); RangeBound *b2);
extern RangeType *make_empty_range(FunctionCallInfo fcinfo, Oid rngtypid); extern RangeType *make_empty_range(TypeCacheEntry *typcache);
extern void range_gettypinfo(FunctionCallInfo fcinfo, Oid rngtypid,
RangeTypeInfo *rngtypinfo);
/* GiST support (in rangetypes_gist.c) */ /* GiST support (in rangetypes_gist.c) */
extern Datum range_gist_consistent(PG_FUNCTION_ARGS); extern Datum range_gist_consistent(PG_FUNCTION_ARGS);
......
...@@ -32,6 +32,7 @@ typedef struct TypeCacheEntry ...@@ -32,6 +32,7 @@ typedef struct TypeCacheEntry
int16 typlen; int16 typlen;
bool typbyval; bool typbyval;
char typalign; char typalign;
char typstorage;
char typtype; char typtype;
Oid typrelid; Oid typrelid;
...@@ -71,6 +72,18 @@ typedef struct TypeCacheEntry ...@@ -71,6 +72,18 @@ typedef struct TypeCacheEntry
*/ */
TupleDesc tupDesc; TupleDesc tupDesc;
/*
* Fields computed when TYPECACHE_RANGE_INFO is requested. Zeroes if
* not a range type or information hasn't yet been requested. Note that
* rng_cmp_proc_finfo could be different from the element type's default
* btree comparison function.
*/
struct TypeCacheEntry *rngelemtype; /* range's element type */
Oid rng_collation; /* collation for comparisons, if any */
FmgrInfo rng_cmp_proc_finfo; /* comparison function */
FmgrInfo rng_canonical_finfo; /* canonicalization function, if any */
FmgrInfo rng_subdiff_finfo; /* difference function, if any */
/* Private data, for internal use of typcache.c only */ /* Private data, for internal use of typcache.c only */
int flags; /* flags about what we've computed */ int flags; /* flags about what we've computed */
...@@ -93,6 +106,7 @@ typedef struct TypeCacheEntry ...@@ -93,6 +106,7 @@ typedef struct TypeCacheEntry
#define TYPECACHE_TUPDESC 0x0100 #define TYPECACHE_TUPDESC 0x0100
#define TYPECACHE_BTREE_OPFAMILY 0x0200 #define TYPECACHE_BTREE_OPFAMILY 0x0200
#define TYPECACHE_HASH_OPFAMILY 0x0400 #define TYPECACHE_HASH_OPFAMILY 0x0400
#define TYPECACHE_RANGE_INFO 0x0800
extern TypeCacheEntry *lookup_type_cache(Oid type_id, int flags); extern TypeCacheEntry *lookup_type_cache(Oid type_id, int flags);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment