#include "utils/typcache.h"
-/* flags */
-#define RANGE_EMPTY 0x01
-#define RANGE_LB_INC 0x02
-#define RANGE_LB_NULL 0x04 /* NOT CURRENTLY USED */
-#define RANGE_LB_INF 0x08
-#define RANGE_UB_INC 0x10
-#define RANGE_UB_NULL 0x20 /* NOT CURRENTLY USED */
-#define RANGE_UB_INF 0x40
-
-#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)))
-
#define RANGE_EMPTY_LITERAL "empty"
#define RANGE_DEFAULT_FLAGS "[)"
bool *infinite);
static char *range_deparse(char flags, char *lbound_str, char *ubound_str);
static char *range_bound_escape(char *in_str);
-static bool range_contains_internal(FunctionCallInfo fcinfo, RangeType *r1,
- RangeType *r2);
+static bool range_contains_internal(TypeCacheEntry *typcache,
+ RangeType *r1, RangeType *r2);
static Size datum_compute_size(Size sz, Datum datum, bool typbyval,
char typalign, int16 typlen, char typstorage);
static Pointer datum_write(Pointer ptr, Datum datum, bool typbyval,
char *input_str = PG_GETARG_CSTRING(0);
Oid rngtypoid = PG_GETARG_OID(1);
Oid typmod = PG_GETARG_INT32(2);
- Datum range;
+ RangeType *range;
+ TypeCacheEntry *typcache;
char flags;
char *lbound_str;
char *ubound_str;
regproc subInput;
FmgrInfo subInputFn;
Oid ioParam;
- RangeTypeInfo rngtypinfo;
RangeBound lower;
RangeBound upper;
- if (rngtypoid == ANYRANGEOID)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("cannot accept a value of type anyrange")));
-
- range_gettypinfo(fcinfo, rngtypoid, &rngtypinfo);
+ typcache = range_get_typcache(fcinfo, rngtypoid);
/* parse */
range_parse(input_str, &flags, &lbound_str, &ubound_str);
/* input */
- getTypeInputInfo(rngtypinfo.subtype, &subInput, &ioParam);
+ getTypeInputInfo(typcache->rngelemtype->type_id, &subInput, &ioParam);
fmgr_info(subInput, &subInputFn);
- lower.rngtypid = rngtypoid;
- lower.infinite = (flags & RANGE_LB_INF) != 0;
- lower.inclusive = (flags & RANGE_LB_INC) != 0;
- lower.lower = true;
- upper.rngtypid = rngtypoid;
- upper.infinite = (flags & RANGE_UB_INF) != 0;
- upper.inclusive = (flags & RANGE_UB_INC) != 0;
- upper.lower = false;
-
if (RANGE_HAS_LBOUND(flags))
lower.val = InputFunctionCall(&subInputFn, lbound_str,
ioParam, typmod);
upper.val = InputFunctionCall(&subInputFn, ubound_str,
ioParam, typmod);
+ lower.infinite = (flags & RANGE_LB_INF) != 0;
+ lower.inclusive = (flags & RANGE_LB_INC) != 0;
+ lower.lower = true;
+ upper.infinite = (flags & RANGE_UB_INF) != 0;
+ upper.inclusive = (flags & RANGE_UB_INC) != 0;
+ upper.lower = false;
+
/* serialize and canonicalize */
- range = make_range(fcinfo, &lower, &upper, flags & RANGE_EMPTY);
+ range = make_range(typcache, &lower, &upper, flags & RANGE_EMPTY);
PG_RETURN_RANGE(range);
}
range_out(PG_FUNCTION_ARGS)
{
RangeType *range = PG_GETARG_RANGE(0);
+ TypeCacheEntry *typcache;
char *output_str;
regproc subOutput;
FmgrInfo subOutputFn;
char *lbound_str = NULL;
char *ubound_str = NULL;
bool empty;
- RangeTypeInfo rngtypinfo;
RangeBound lower;
RangeBound upper;
- /* deserialize */
- range_deserialize(fcinfo, range, &lower, &upper, &empty);
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(range));
- range_gettypinfo(fcinfo, lower.rngtypid, &rngtypinfo);
+ /* deserialize */
+ range_deserialize(typcache, range, &lower, &upper, &empty);
if (empty)
flags |= RANGE_EMPTY;
flags |= upper.infinite ? RANGE_UB_INF : 0;
/* output */
- getTypeOutputInfo(rngtypinfo.subtype, &subOutput, &isVarlena);
+ getTypeOutputInfo(typcache->rngelemtype->type_id, &subOutput, &isVarlena);
fmgr_info(subOutput, &subOutputFn);
if (RANGE_HAS_LBOUND(flags))
range_recv(PG_FUNCTION_ARGS)
{
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
- Oid rngtypid = PG_GETARG_OID(1);
+ Oid rngtypoid = PG_GETARG_OID(1);
int32 typmod = PG_GETARG_INT32(2);
- Datum range;
+ RangeType *range;
+ TypeCacheEntry *typcache;
Oid subrecv;
Oid ioparam;
char flags;
RangeBound lower;
RangeBound upper;
- RangeTypeInfo rngtypinfo;
- flags = (unsigned char) pq_getmsgbyte(buf);
+ typcache = range_get_typcache(fcinfo, rngtypoid);
- range_gettypinfo(fcinfo, rngtypid, &rngtypinfo);
+ flags = (unsigned char) pq_getmsgbyte(buf);
- getTypeBinaryInputInfo(rngtypinfo.subtype, &subrecv, &ioparam);
+ getTypeBinaryInputInfo(typcache->rngelemtype->type_id, &subrecv, &ioparam);
if (RANGE_HAS_LBOUND(flags))
{
pq_getmsgend(buf);
- lower.rngtypid = rngtypid;
lower.infinite = (flags & RANGE_LB_INF) != 0;
lower.inclusive = (flags & RANGE_LB_INC) != 0;
lower.lower = true;
- upper.rngtypid = rngtypid;
upper.infinite = (flags & RANGE_UB_INF) != 0;
upper.inclusive = (flags & RANGE_UB_INC) != 0;
upper.lower = false;
/* serialize and canonicalize */
- range = make_range(fcinfo, &lower, &upper, flags & RANGE_EMPTY);
+ range = make_range(typcache, &lower, &upper, flags & RANGE_EMPTY);
PG_RETURN_RANGE(range);
}
{
RangeType *range = PG_GETARG_RANGE(0);
StringInfo buf = makeStringInfo();
+ TypeCacheEntry *typcache;
char flags = 0;
RangeBound lower;
RangeBound upper;
bool empty;
Oid subsend;
bool typIsVarlena;
- RangeTypeInfo rngtypinfo;
+
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(range));
+
+ getTypeBinaryOutputInfo(typcache->rngelemtype->type_id,
+ &subsend, &typIsVarlena);
pq_begintypsend(buf);
- range_deserialize(fcinfo, range, &lower, &upper, &empty);
+ range_deserialize(typcache, range, &lower, &upper, &empty);
if (empty)
flags |= RANGE_EMPTY;
flags |= upper.inclusive ? RANGE_UB_INC : 0;
flags |= upper.infinite ? RANGE_UB_INF : 0;
- range_gettypinfo(fcinfo, lower.rngtypid, &rngtypinfo);
-
- getTypeBinaryOutputInfo(rngtypinfo.subtype,
- &subsend, &typIsVarlena);
-
pq_sendbyte(buf, flags);
if (RANGE_HAS_LBOUND(flags))
{
Oid rngtypid = get_fn_expr_rettype(fcinfo->flinfo);
RangeType *range;
+ TypeCacheEntry *typcache;
RangeBound lower;
RangeBound upper;
- lower.rngtypid = rngtypid;
+ typcache = range_get_typcache(fcinfo, rngtypid);
+
lower.val = (Datum) 0;
- lower.inclusive = false;
lower.infinite = false;
+ lower.inclusive = false;
lower.lower = true;
- upper.rngtypid = rngtypid;
upper.val = (Datum) 0;
- upper.inclusive = false;
upper.infinite = false;
+ upper.inclusive = false;
upper.lower = false;
- range = DatumGetRangeType(make_range(fcinfo, &lower, &upper, true));
+ range = make_range(typcache, &lower, &upper, true);
PG_RETURN_RANGE(range);
}
Datum arg1 = PG_GETARG_DATUM(0);
Oid rngtypid = get_fn_expr_rettype(fcinfo->flinfo);
RangeType *range;
+ TypeCacheEntry *typcache;
RangeBound lower;
RangeBound upper;
+ typcache = range_get_typcache(fcinfo, rngtypid);
+
if (PG_ARGISNULL(0))
ereport(ERROR,
(errcode(ERRCODE_DATA_EXCEPTION),
- errmsg("argument must not be NULL")));
+ errmsg("range constructor argument must not be NULL")));
- lower.rngtypid = rngtypid;
lower.val = arg1;
- lower.inclusive = true;
lower.infinite = false;
+ lower.inclusive = true;
lower.lower = true;
- upper.rngtypid = rngtypid;
upper.val = arg1;
- upper.inclusive = true;
upper.infinite = false;
+ upper.inclusive = true;
upper.lower = false;
- range = DatumGetRangeType(make_range(fcinfo, &lower, &upper, false));
+ range = make_range(typcache, &lower, &upper, false);
PG_RETURN_RANGE(range);
}
Datum arg2 = PG_GETARG_DATUM(1);
Oid rngtypid = get_fn_expr_rettype(fcinfo->flinfo);
RangeType *range;
+ TypeCacheEntry *typcache;
RangeBound lower;
RangeBound upper;
char flags;
+ typcache = range_get_typcache(fcinfo, rngtypid);
+
flags = range_parse_flags(RANGE_DEFAULT_FLAGS);
- lower.rngtypid = rngtypid;
lower.val = PG_ARGISNULL(0) ? (Datum) 0 : arg1;
- lower.inclusive = (flags & RANGE_LB_INC) != 0;
lower.infinite = PG_ARGISNULL(0);
+ lower.inclusive = (flags & RANGE_LB_INC) != 0;
lower.lower = true;
- upper.rngtypid = rngtypid;
upper.val = PG_ARGISNULL(1) ? (Datum) 0 : arg2;
- upper.inclusive = (flags & RANGE_UB_INC) != 0;
upper.infinite = PG_ARGISNULL(1);
+ upper.inclusive = (flags & RANGE_UB_INC) != 0;
upper.lower = false;
- range = DatumGetRangeType(make_range(fcinfo, &lower, &upper, false));
+ range = make_range(typcache, &lower, &upper, false);
PG_RETURN_RANGE(range);
}
Datum arg2 = PG_GETARG_DATUM(1);
Oid rngtypid = get_fn_expr_rettype(fcinfo->flinfo);
RangeType *range;
+ TypeCacheEntry *typcache;
RangeBound lower;
RangeBound upper;
char flags;
+ typcache = range_get_typcache(fcinfo, rngtypid);
+
if (PG_ARGISNULL(2))
ereport(ERROR,
(errcode(ERRCODE_DATA_EXCEPTION),
- errmsg("flags argument must not be NULL")));
+ errmsg("range constructor flags argument must not be NULL")));
flags = range_parse_flags(text_to_cstring(PG_GETARG_TEXT_P(2)));
- lower.rngtypid = rngtypid;
lower.val = PG_ARGISNULL(0) ? (Datum) 0 : arg1;
- lower.inclusive = (flags & RANGE_LB_INC) != 0;
lower.infinite = PG_ARGISNULL(0);
+ lower.inclusive = (flags & RANGE_LB_INC) != 0;
lower.lower = true;
- upper.rngtypid = rngtypid;
upper.val = PG_ARGISNULL(1) ? (Datum) 0 : arg2;
- upper.inclusive = (flags & RANGE_UB_INC) != 0;
upper.infinite = PG_ARGISNULL(1);
+ upper.inclusive = (flags & RANGE_UB_INC) != 0;
upper.lower = false;
- range = DatumGetRangeType(make_range(fcinfo, &lower, &upper, false));
+ range = make_range(typcache, &lower, &upper, false);
PG_RETURN_RANGE(range);
}
range_lower(PG_FUNCTION_ARGS)
{
RangeType *r1 = PG_GETARG_RANGE(0);
+ TypeCacheEntry *typcache;
RangeBound lower;
RangeBound upper;
bool empty;
- range_deserialize(fcinfo, r1, &lower, &upper, &empty);
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
+
+ range_deserialize(typcache, r1, &lower, &upper, &empty);
/* Return NULL if there's no finite lower bound */
if (empty || lower.infinite)
range_upper(PG_FUNCTION_ARGS)
{
RangeType *r1 = PG_GETARG_RANGE(0);
+ TypeCacheEntry *typcache;
RangeBound lower;
RangeBound upper;
bool empty;
- range_deserialize(fcinfo, r1, &lower, &upper, &empty);
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
+
+ range_deserialize(typcache, r1, &lower, &upper, &empty);
/* Return NULL if there's no finite upper bound */
if (empty || upper.infinite)
range_empty(PG_FUNCTION_ARGS)
{
RangeType *r1 = PG_GETARG_RANGE(0);
- RangeBound lower;
- RangeBound upper;
- bool empty;
+ char flags = range_get_flags(r1);
- range_deserialize(fcinfo, r1, &lower, &upper, &empty);
-
- PG_RETURN_BOOL(empty);
+ PG_RETURN_BOOL(flags & RANGE_EMPTY);
}
Datum
range_lower_inc(PG_FUNCTION_ARGS)
{
RangeType *r1 = PG_GETARG_RANGE(0);
- RangeBound lower;
- RangeBound upper;
- bool empty;
-
- range_deserialize(fcinfo, r1, &lower, &upper, &empty);
+ char flags = range_get_flags(r1);
- PG_RETURN_BOOL(lower.inclusive);
+ PG_RETURN_BOOL(flags & RANGE_LB_INC);
}
Datum
range_upper_inc(PG_FUNCTION_ARGS)
{
RangeType *r1 = PG_GETARG_RANGE(0);
- RangeBound lower;
- RangeBound upper;
- bool empty;
-
- range_deserialize(fcinfo, r1, &lower, &upper, &empty);
+ char flags = range_get_flags(r1);
- PG_RETURN_BOOL(upper.inclusive);
+ PG_RETURN_BOOL(flags & RANGE_UB_INC);
}
Datum
range_lower_inf(PG_FUNCTION_ARGS)
{
RangeType *r1 = PG_GETARG_RANGE(0);
- RangeBound lower;
- RangeBound upper;
- bool empty;
-
- range_deserialize(fcinfo, r1, &lower, &upper, &empty);
+ char flags = range_get_flags(r1);
- PG_RETURN_BOOL(lower.infinite);
+ PG_RETURN_BOOL(flags & RANGE_LB_INF);
}
Datum
range_upper_inf(PG_FUNCTION_ARGS)
{
RangeType *r1 = PG_GETARG_RANGE(0);
- RangeBound lower;
- RangeBound upper;
- bool empty;
-
- range_deserialize(fcinfo, r1, &lower, &upper, &empty);
+ char flags = range_get_flags(r1);
- PG_RETURN_BOOL(upper.infinite);
+ PG_RETURN_BOOL(flags & RANGE_UB_INF);
}
{
RangeType *r1 = PG_GETARG_RANGE(0);
RangeType *r2 = PG_GETARG_RANGE(1);
+ TypeCacheEntry *typcache;
RangeBound lower1,
lower2;
RangeBound upper1,
bool empty1,
empty2;
- range_deserialize(fcinfo, r1, &lower1, &upper1, &empty1);
- range_deserialize(fcinfo, r2, &lower2, &upper2, &empty2);
-
- if (lower1.rngtypid != lower2.rngtypid)
+ /* Different types should be prevented by ANYRANGE matching rules */
+ if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
elog(ERROR, "range types do not match");
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
+
+ range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
+ range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
+
if (empty1 && empty2)
PG_RETURN_BOOL(true);
if (empty1 != empty2)
PG_RETURN_BOOL(false);
- if (range_cmp_bounds(fcinfo, &lower1, &lower2) != 0)
+ if (range_cmp_bounds(typcache, &lower1, &lower2) != 0)
PG_RETURN_BOOL(false);
- if (range_cmp_bounds(fcinfo, &upper1, &upper2) != 0)
+ if (range_cmp_bounds(typcache, &upper1, &upper2) != 0)
PG_RETURN_BOOL(false);
PG_RETURN_BOOL(true);
{
RangeType *r1 = PG_GETARG_RANGE(0);
Datum val = PG_GETARG_DATUM(1);
+ TypeCacheEntry *typcache;
+ RangeBound lower2;
+ RangeBound upper2;
RangeType *r2;
- RangeBound lower1,
- lower2;
- RangeBound upper1,
- upper2;
- bool empty1;
- range_deserialize(fcinfo, r1, &lower1, &upper1, &empty1);
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
- lower2.rngtypid = lower1.rngtypid;
- lower2.inclusive = true;
+ /* Construct a singleton range representing just "val" */
+ lower2.val = val;
lower2.infinite = false;
+ lower2.inclusive = true;
lower2.lower = true;
- lower2.val = val;
- upper2.rngtypid = lower1.rngtypid;
- upper2.inclusive = true;
+ upper2.val = val;
upper2.infinite = false;
+ upper2.inclusive = true;
upper2.lower = false;
- upper2.val = val;
- r2 = DatumGetRangeType(make_range(fcinfo, &lower2, &upper2, false));
+ r2 = make_range(typcache, &lower2, &upper2, false);
- PG_RETURN_BOOL(range_contains_internal(fcinfo, r1, r2));
+ /* And use range_contains */
+ PG_RETURN_BOOL(range_contains_internal(typcache, r1, r2));
}
Datum
{
RangeType *r1 = PG_GETARG_RANGE(0);
RangeType *r2 = PG_GETARG_RANGE(1);
+ TypeCacheEntry *typcache;
+
+ /* Different types should be prevented by ANYRANGE matching rules */
+ if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
+ elog(ERROR, "range types do not match");
+
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
- PG_RETURN_BOOL(range_contains_internal(fcinfo, r1, r2));
+ PG_RETURN_BOOL(range_contains_internal(typcache, r1, r2));
}
Datum
elem_contained_by_range(PG_FUNCTION_ARGS)
{
- RangeType *r1 = PG_GETARG_RANGE(1);
Datum val = PG_GETARG_DATUM(0);
+ RangeType *r1 = PG_GETARG_RANGE(1);
+ TypeCacheEntry *typcache;
+ RangeBound lower2;
+ RangeBound upper2;
RangeType *r2;
- RangeBound lower1,
- lower2;
- RangeBound upper1,
- upper2;
- bool empty1;
- range_deserialize(fcinfo, r1, &lower1, &upper1, &empty1);
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
- lower2.rngtypid = lower1.rngtypid;
- lower2.inclusive = true;
+ /* Construct a singleton range representing just "val" */
+ lower2.val = val;
lower2.infinite = false;
+ lower2.inclusive = true;
lower2.lower = true;
- lower2.val = val;
- upper2.rngtypid = lower1.rngtypid;
- upper2.inclusive = true;
+ upper2.val = val;
upper2.infinite = false;
+ upper2.inclusive = true;
upper2.lower = false;
- upper2.val = val;
- r2 = DatumGetRangeType(make_range(fcinfo, &lower2, &upper2, false));
+ r2 = make_range(typcache, &lower2, &upper2, false);
- PG_RETURN_BOOL(range_contains_internal(fcinfo, r1, r2));
+ /* And use range_contains */
+ PG_RETURN_BOOL(range_contains_internal(typcache, r1, r2));
}
Datum
{
RangeType *r1 = PG_GETARG_RANGE(0);
RangeType *r2 = PG_GETARG_RANGE(1);
+ TypeCacheEntry *typcache;
+
+ /* Different types should be prevented by ANYRANGE matching rules */
+ if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
+ elog(ERROR, "range types do not match");
+
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
- PG_RETURN_BOOL(range_contains_internal(fcinfo, r2, r1));
+ PG_RETURN_BOOL(range_contains_internal(typcache, r2, r1));
}
Datum
{
RangeType *r1 = PG_GETARG_RANGE(0);
RangeType *r2 = PG_GETARG_RANGE(1);
+ TypeCacheEntry *typcache;
RangeBound lower1,
lower2;
RangeBound upper1,
bool empty1,
empty2;
- range_deserialize(fcinfo, r1, &lower1, &upper1, &empty1);
- range_deserialize(fcinfo, r2, &lower2, &upper2, &empty2);
-
- if (lower1.rngtypid != lower2.rngtypid)
+ /* Different types should be prevented by ANYRANGE matching rules */
+ if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
elog(ERROR, "range types do not match");
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
+
+ range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
+ range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
+
/* An empty range is neither before nor after any other range */
if (empty1 || empty2)
PG_RETURN_BOOL(false);
- PG_RETURN_BOOL(range_cmp_bounds(fcinfo, &upper1, &lower2) < 0);
+ PG_RETURN_BOOL(range_cmp_bounds(typcache, &upper1, &lower2) < 0);
}
Datum
{
RangeType *r1 = PG_GETARG_RANGE(0);
RangeType *r2 = PG_GETARG_RANGE(1);
+ TypeCacheEntry *typcache;
RangeBound lower1,
lower2;
RangeBound upper1,
bool empty1,
empty2;
- range_deserialize(fcinfo, r1, &lower1, &upper1, &empty1);
- range_deserialize(fcinfo, r2, &lower2, &upper2, &empty2);
-
- if (lower1.rngtypid != lower2.rngtypid)
+ /* Different types should be prevented by ANYRANGE matching rules */
+ if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
elog(ERROR, "range types do not match");
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
+
+ range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
+ range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
+
/* An empty range is neither before nor after any other range */
if (empty1 || empty2)
PG_RETURN_BOOL(false);
- PG_RETURN_BOOL(range_cmp_bounds(fcinfo, &lower1, &upper2) > 0);
+ PG_RETURN_BOOL(range_cmp_bounds(typcache, &lower1, &upper2) > 0);
}
Datum
{
RangeType *r1 = PG_GETARG_RANGE(0);
RangeType *r2 = PG_GETARG_RANGE(1);
- RangeTypeInfo rngtypinfo;
+ TypeCacheEntry *typcache;
RangeBound lower1,
lower2;
RangeBound upper1,
bool empty1,
empty2;
- range_deserialize(fcinfo, r1, &lower1, &upper1, &empty1);
- range_deserialize(fcinfo, r2, &lower2, &upper2, &empty2);
-
- if (lower1.rngtypid != lower2.rngtypid)
+ /* Different types should be prevented by ANYRANGE matching rules */
+ if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
elog(ERROR, "range types do not match");
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
+
+ range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
+ range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
+
/* An empty range is not adjacent to any other range */
if (empty1 || empty2)
PG_RETURN_BOOL(false);
* The semantics for range_cmp_bounds aren't quite what we need here, so
* we do the comparison more directly.
*/
-
- range_gettypinfo(fcinfo, lower1.rngtypid, &rngtypinfo);
-
if (lower1.inclusive != upper2.inclusive)
{
- if (DatumGetInt32(FunctionCall2Coll(&rngtypinfo.cmpFn,
- rngtypinfo.collation,
+ if (DatumGetInt32(FunctionCall2Coll(&typcache->rng_cmp_proc_finfo,
+ typcache->rng_collation,
lower1.val, upper2.val)) == 0)
PG_RETURN_BOOL(true);
}
if (upper1.inclusive != lower2.inclusive)
{
- if (DatumGetInt32(FunctionCall2Coll(&rngtypinfo.cmpFn,
- rngtypinfo.collation,
+ if (DatumGetInt32(FunctionCall2Coll(&typcache->rng_cmp_proc_finfo,
+ typcache->rng_collation,
upper1.val, lower2.val)) == 0)
PG_RETURN_BOOL(true);
}
{
RangeType *r1 = PG_GETARG_RANGE(0);
RangeType *r2 = PG_GETARG_RANGE(1);
+ TypeCacheEntry *typcache;
RangeBound lower1,
lower2;
RangeBound upper1,
bool empty1,
empty2;
- range_deserialize(fcinfo, r1, &lower1, &upper1, &empty1);
- range_deserialize(fcinfo, r2, &lower2, &upper2, &empty2);
-
- if (lower1.rngtypid != lower2.rngtypid)
+ /* Different types should be prevented by ANYRANGE matching rules */
+ if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
elog(ERROR, "range types do not match");
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
+
+ range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
+ range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
+
/* An empty range does not overlap any other range */
if (empty1 || empty2)
PG_RETURN_BOOL(false);
- if (range_cmp_bounds(fcinfo, &lower1, &lower2) >= 0 &&
- range_cmp_bounds(fcinfo, &lower1, &upper2) <= 0)
+ if (range_cmp_bounds(typcache, &lower1, &lower2) >= 0 &&
+ range_cmp_bounds(typcache, &lower1, &upper2) <= 0)
PG_RETURN_BOOL(true);
- if (range_cmp_bounds(fcinfo, &lower2, &lower1) >= 0 &&
- range_cmp_bounds(fcinfo, &lower2, &upper1) <= 0)
+ if (range_cmp_bounds(typcache, &lower2, &lower1) >= 0 &&
+ range_cmp_bounds(typcache, &lower2, &upper1) <= 0)
PG_RETURN_BOOL(true);
PG_RETURN_BOOL(false);
{
RangeType *r1 = PG_GETARG_RANGE(0);
RangeType *r2 = PG_GETARG_RANGE(1);
+ TypeCacheEntry *typcache;
RangeBound lower1,
lower2;
RangeBound upper1,
bool empty1,
empty2;
- range_deserialize(fcinfo, r1, &lower1, &upper1, &empty1);
- range_deserialize(fcinfo, r2, &lower2, &upper2, &empty2);
-
- if (lower1.rngtypid != lower2.rngtypid)
+ /* Different types should be prevented by ANYRANGE matching rules */
+ if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
elog(ERROR, "range types do not match");
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
+
+ range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
+ range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
+
/* An empty range is neither before nor after any other range */
if (empty1 || empty2)
PG_RETURN_BOOL(false);
- if (range_cmp_bounds(fcinfo, &upper1, &upper2) <= 0)
+ if (range_cmp_bounds(typcache, &upper1, &upper2) <= 0)
PG_RETURN_BOOL(true);
PG_RETURN_BOOL(false);
{
RangeType *r1 = PG_GETARG_RANGE(0);
RangeType *r2 = PG_GETARG_RANGE(1);
+ TypeCacheEntry *typcache;
RangeBound lower1,
lower2;
RangeBound upper1,
bool empty1,
empty2;
- range_deserialize(fcinfo, r1, &lower1, &upper1, &empty1);
- range_deserialize(fcinfo, r2, &lower2, &upper2, &empty2);
-
- if (lower1.rngtypid != lower2.rngtypid)
+ /* Different types should be prevented by ANYRANGE matching rules */
+ if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
elog(ERROR, "range types do not match");
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
+
+ range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
+ range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
+
/* An empty range is neither before nor after any other range */
if (empty1 || empty2)
PG_RETURN_BOOL(false);
- if (range_cmp_bounds(fcinfo, &lower1, &lower2) >= 0)
+ if (range_cmp_bounds(typcache, &lower1, &lower2) >= 0)
PG_RETURN_BOOL(true);
PG_RETURN_BOOL(false);
{
RangeType *r1 = PG_GETARG_RANGE(0);
RangeType *r2 = PG_GETARG_RANGE(1);
+ TypeCacheEntry *typcache;
RangeBound lower1,
lower2;
RangeBound upper1,
cmp_u1l2,
cmp_u1u2;
- range_deserialize(fcinfo, r1, &lower1, &upper1, &empty1);
- range_deserialize(fcinfo, r2, &lower2, &upper2, &empty2);
-
- if (lower1.rngtypid != lower2.rngtypid)
+ /* Different types should be prevented by ANYRANGE matching rules */
+ if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
elog(ERROR, "range types do not match");
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
+
+ range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
+ range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
+
/* if either is empty, r1 is the correct answer */
if (empty1 || empty2)
PG_RETURN_RANGE(r1);
- cmp_l1l2 = range_cmp_bounds(fcinfo, &lower1, &lower2);
- cmp_l1u2 = range_cmp_bounds(fcinfo, &lower1, &upper2);
- cmp_u1l2 = range_cmp_bounds(fcinfo, &upper1, &lower2);
- cmp_u1u2 = range_cmp_bounds(fcinfo, &upper1, &upper2);
+ cmp_l1l2 = range_cmp_bounds(typcache, &lower1, &lower2);
+ cmp_l1u2 = range_cmp_bounds(typcache, &lower1, &upper2);
+ cmp_u1l2 = range_cmp_bounds(typcache, &upper1, &lower2);
+ cmp_u1u2 = range_cmp_bounds(typcache, &upper1, &upper2);
if (cmp_l1l2 < 0 && cmp_u1u2 > 0)
ereport(ERROR,
PG_RETURN_RANGE(r1);
if (cmp_l1l2 >= 0 && cmp_u1u2 <= 0)
- PG_RETURN_RANGE(make_empty_range(fcinfo, lower1.rngtypid));
+ PG_RETURN_RANGE(make_empty_range(typcache));
if (cmp_l1l2 <= 0 && cmp_u1l2 >= 0 && cmp_u1u2 <= 0)
{
lower2.inclusive = !lower2.inclusive;
lower2.lower = false; /* it will become the upper bound */
- PG_RETURN_RANGE(make_range(fcinfo, &lower1, &lower2, false));
+ PG_RETURN_RANGE(make_range(typcache, &lower1, &lower2, false));
}
if (cmp_l1l2 >= 0 && cmp_u1u2 >= 0 && cmp_l1u2 <= 0)
{
upper2.inclusive = !upper2.inclusive;
upper2.lower = true; /* it will become the lower bound */
- PG_RETURN_RANGE(make_range(fcinfo, &upper2, &upper1, false));
+ PG_RETURN_RANGE(make_range(typcache, &upper2, &upper1, false));
}
elog(ERROR, "unexpected case in range_minus");
{
RangeType *r1 = PG_GETARG_RANGE(0);
RangeType *r2 = PG_GETARG_RANGE(1);
+ TypeCacheEntry *typcache;
RangeBound lower1,
lower2;
RangeBound upper1,
RangeBound *result_lower;
RangeBound *result_upper;
- range_deserialize(fcinfo, r1, &lower1, &upper1, &empty1);
- range_deserialize(fcinfo, r2, &lower2, &upper2, &empty2);
-
- if (lower1.rngtypid != lower2.rngtypid)
+ /* Different types should be prevented by ANYRANGE matching rules */
+ if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
elog(ERROR, "range types do not match");
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
+
+ range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
+ range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
+
/* if either is empty, the other is the correct answer */
if (empty1)
PG_RETURN_RANGE(r2);
(errcode(ERRCODE_DATA_EXCEPTION),
errmsg("result of range union would not be contiguous")));
- if (range_cmp_bounds(fcinfo, &lower1, &lower2) < 0)
+ if (range_cmp_bounds(typcache, &lower1, &lower2) < 0)
result_lower = &lower1;
else
result_lower = &lower2;
- if (range_cmp_bounds(fcinfo, &upper1, &upper2) > 0)
+ if (range_cmp_bounds(typcache, &upper1, &upper2) > 0)
result_upper = &upper1;
else
result_upper = &upper2;
- PG_RETURN_RANGE(make_range(fcinfo, result_lower, result_upper, false));
+ PG_RETURN_RANGE(make_range(typcache, result_lower, result_upper, false));
}
Datum
{
RangeType *r1 = PG_GETARG_RANGE(0);
RangeType *r2 = PG_GETARG_RANGE(1);
+ TypeCacheEntry *typcache;
RangeBound lower1,
lower2;
RangeBound upper1,
RangeBound *result_lower;
RangeBound *result_upper;
- range_deserialize(fcinfo, r1, &lower1, &upper1, &empty1);
- range_deserialize(fcinfo, r2, &lower2, &upper2, &empty2);
-
- if (lower1.rngtypid != lower2.rngtypid)
+ /* Different types should be prevented by ANYRANGE matching rules */
+ if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
elog(ERROR, "range types do not match");
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
+
+ range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
+ range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
+
if (empty1 || empty2 || !DatumGetBool(range_overlaps(fcinfo)))
- PG_RETURN_RANGE(make_empty_range(fcinfo, lower1.rngtypid));
+ PG_RETURN_RANGE(make_empty_range(typcache));
- if (range_cmp_bounds(fcinfo, &lower1, &lower2) >= 0)
+ if (range_cmp_bounds(typcache, &lower1, &lower2) >= 0)
result_lower = &lower1;
else
result_lower = &lower2;
- if (range_cmp_bounds(fcinfo, &upper1, &upper2) <= 0)
+ if (range_cmp_bounds(typcache, &upper1, &upper2) <= 0)
result_upper = &upper1;
else
result_upper = &upper2;
- PG_RETURN_RANGE(make_range(fcinfo, result_lower, result_upper, false));
+ PG_RETURN_RANGE(make_range(typcache, result_lower, result_upper, false));
}
/* Btree support */
{
RangeType *r1 = PG_GETARG_RANGE(0);
RangeType *r2 = PG_GETARG_RANGE(1);
+ TypeCacheEntry *typcache;
RangeBound lower1,
lower2;
RangeBound upper1,
empty2;
int cmp;
- range_deserialize(fcinfo, r1, &lower1, &upper1, &empty1);
- range_deserialize(fcinfo, r2, &lower2, &upper2, &empty2);
-
- if (lower1.rngtypid != lower2.rngtypid)
+ /* Different types should be prevented by ANYRANGE matching rules */
+ if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
elog(ERROR, "range types do not match");
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
+
+ range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
+ range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
+
/* For b-tree use, empty ranges sort before all else */
if (empty1 && empty2)
PG_RETURN_INT32(0);
else if (empty2)
PG_RETURN_INT32(1);
- if ((cmp = range_cmp_bounds(fcinfo, &lower1, &lower2)) != 0)
+ if ((cmp = range_cmp_bounds(typcache, &lower1, &lower2)) != 0)
PG_RETURN_INT32(cmp);
- PG_RETURN_INT32(range_cmp_bounds(fcinfo, &upper1, &upper2));
+ PG_RETURN_INT32(range_cmp_bounds(typcache, &upper1, &upper2));
}
Datum
hash_range(PG_FUNCTION_ARGS)
{
RangeType *r = PG_GETARG_RANGE(0);
+ TypeCacheEntry *typcache;
RangeBound lower;
RangeBound upper;
bool empty;
uint32 lower_hash = 0;
uint32 upper_hash = 0;
uint32 result = 0;
- RangeTypeInfo rngtypinfo;
- TypeCacheEntry *typentry;
- Oid subtype;
+ TypeCacheEntry *subtypcache;
FunctionCallInfoData locfcinfo;
- range_deserialize(fcinfo, r, &lower, &upper, &empty);
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));
+
+ range_deserialize(typcache, r, &lower, &upper, &empty);
if (empty)
flags |= RANGE_EMPTY;
flags |= upper.inclusive ? RANGE_UB_INC : 0;
flags |= upper.infinite ? RANGE_UB_INF : 0;
- range_gettypinfo(fcinfo, lower.rngtypid, &rngtypinfo);
- subtype = rngtypinfo.subtype;
-
/*
- * We arrange to look up the hash function only once per series of calls,
- * assuming the subtype doesn't change underneath us. The typcache is
- * used so that we have no memory leakage when being used as an index
- * support function.
+ * Look up the element type's hash function, if not done already.
*/
- typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
- if (typentry == NULL || typentry->type_id != subtype)
+ subtypcache = typcache->rngelemtype;
+ if (!OidIsValid(subtypcache->hash_proc_finfo.fn_oid))
{
- typentry = lookup_type_cache(subtype, TYPECACHE_HASH_PROC_FINFO);
- if (!OidIsValid(typentry->hash_proc_finfo.fn_oid))
+ subtypcache = lookup_type_cache(subtypcache->type_id,
+ TYPECACHE_HASH_PROC_FINFO);
+ if (!OidIsValid(subtypcache->hash_proc_finfo.fn_oid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("could not identify a hash function for type %s",
- format_type_be(subtype))));
- fcinfo->flinfo->fn_extra = (void *) typentry;
+ format_type_be(subtypcache->type_id))));
}
/*
* Apply the hash function to each bound (the hash function shouldn't care
* about the collation).
*/
- InitFunctionCallInfoData(locfcinfo, &typentry->hash_proc_finfo, 1,
+ InitFunctionCallInfoData(locfcinfo, &subtypcache->hash_proc_finfo, 1,
InvalidOid, NULL, NULL);
if (RANGE_HAS_LBOUND(flags))
int4range_canonical(PG_FUNCTION_ARGS)
{
RangeType *r = PG_GETARG_RANGE(0);
+ TypeCacheEntry *typcache;
RangeBound lower;
RangeBound upper;
bool empty;
- range_deserialize(fcinfo, r, &lower, &upper, &empty);
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));
+
+ range_deserialize(typcache, r, &lower, &upper, &empty);
if (empty)
PG_RETURN_RANGE(r);
upper.inclusive = false;
}
- PG_RETURN_RANGE(range_serialize(fcinfo, &lower, &upper, false));
+ PG_RETURN_RANGE(range_serialize(typcache, &lower, &upper, false));
}
Datum
int8range_canonical(PG_FUNCTION_ARGS)
{
RangeType *r = PG_GETARG_RANGE(0);
+ TypeCacheEntry *typcache;
RangeBound lower;
RangeBound upper;
bool empty;
- range_deserialize(fcinfo, r, &lower, &upper, &empty);
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));
+
+ range_deserialize(typcache, r, &lower, &upper, &empty);
if (empty)
PG_RETURN_RANGE(r);
upper.inclusive = false;
}
- PG_RETURN_RANGE(range_serialize(fcinfo, &lower, &upper, false));
+ PG_RETURN_RANGE(range_serialize(typcache, &lower, &upper, false));
}
Datum
daterange_canonical(PG_FUNCTION_ARGS)
{
RangeType *r = PG_GETARG_RANGE(0);
+ TypeCacheEntry *typcache;
RangeBound lower;
RangeBound upper;
bool empty;
- range_deserialize(fcinfo, r, &lower, &upper, &empty);
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));
+
+ range_deserialize(typcache, r, &lower, &upper, &empty);
if (empty)
PG_RETURN_RANGE(r);
upper.inclusive = false;
}
- PG_RETURN_RANGE(range_serialize(fcinfo, &lower, &upper, false));
+ PG_RETURN_RANGE(range_serialize(typcache, &lower, &upper, false));
}
/*
*----------------------------------------------------------
*/
+/*
+ * range_get_typcache: get cached information about a range type
+ *
+ * This is for use by range-related functions that follow the convention
+ * of using the fn_extra field as a pointer to the type cache entry for
+ * the range type. Functions that need to cache more information than
+ * that must fend for themselves.
+ */
+TypeCacheEntry *
+range_get_typcache(FunctionCallInfo fcinfo, Oid rngtypid)
+{
+ TypeCacheEntry *typcache = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
+
+ if (typcache == NULL ||
+ typcache->type_id != rngtypid)
+ {
+ typcache = lookup_type_cache(rngtypid, TYPECACHE_RANGE_INFO);
+ if (typcache->rngelemtype == NULL)
+ elog(ERROR, "type %u is not a range type", rngtypid);
+ fcinfo->flinfo->fn_extra = (void *) typcache;
+ }
+
+ return typcache;
+}
+
+
/*
* Serialized format is:
*
* This does not force canonicalization of the range value. In most cases,
* external callers should only be canonicalization functions.
*/
-Datum
-range_serialize(FunctionCallInfo fcinfo, RangeBound *lower, RangeBound *upper,
+RangeType *
+range_serialize(TypeCacheEntry *typcache, RangeBound *lower, RangeBound *upper,
bool empty)
{
- Datum range;
- size_t msize;
+ RangeType *range;
+ Size msize;
Pointer ptr;
int16 typlen;
- char typalign;
bool typbyval;
+ char typalign;
char typstorage;
char flags = 0;
- RangeTypeInfo rngtypinfo;
-
- if (lower->rngtypid != upper->rngtypid)
- elog(ERROR, "range types do not match");
-
- range_gettypinfo(fcinfo, lower->rngtypid, &rngtypinfo);
- typlen = rngtypinfo.subtyplen;
- typalign = rngtypinfo.subtypalign;
- typbyval = rngtypinfo.subtypbyval;
- typstorage = rngtypinfo.subtypstorage;
+ /* fetch information about range's element type */
+ typlen = typcache->rngelemtype->typlen;
+ typbyval = typcache->rngelemtype->typbyval;
+ typalign = typcache->rngelemtype->typalign;
+ typstorage = typcache->rngelemtype->typstorage;
+ /* construct flags value */
if (empty)
flags |= RANGE_EMPTY;
- else if (range_cmp_bounds(fcinfo, lower, upper) > 0)
+ else if (range_cmp_bounds(typcache, lower, upper) > 0)
ereport(ERROR,
(errcode(ERRCODE_DATA_EXCEPTION),
errmsg("range lower bound must be less than or equal to range upper bound")));
flags |= upper->inclusive ? RANGE_UB_INC : 0;
flags |= upper->infinite ? RANGE_UB_INF : 0;
- msize = VARHDRSZ;
- msize += sizeof(Oid);
+ /* Count space for varlena header and range type's OID */
+ msize = sizeof(RangeType);
+ Assert(msize == MAXALIGN(msize));
+ /* Count space for bounds */
if (RANGE_HAS_LBOUND(flags))
{
/*
typlen, typstorage);
}
+ /* Add space for flag byte */
msize += sizeof(char);
/* Note: zero-fill is required here, just as in heap tuples */
- ptr = palloc0(msize);
- range = (Datum) ptr;
+ range = (RangeType *) palloc0(msize);
+ SET_VARSIZE(range, msize);
- ptr += VARHDRSZ;
+ /* Now fill in the datum */
+ range->rangetypid = typcache->type_id;
- memcpy(ptr, &lower->rngtypid, sizeof(Oid));
- ptr += sizeof(Oid);
+ ptr = (char *) (range + 1);
if (RANGE_HAS_LBOUND(flags))
{
typstorage);
}
- memcpy(ptr, &flags, sizeof(char));
- ptr += sizeof(char);
+ *((char *) ptr) = flags;
- SET_VARSIZE(range, msize);
- PG_RETURN_RANGE(range);
+ return range;
}
/*
* RangeBound structs will be pointers into the given range object.
*/
void
-range_deserialize(FunctionCallInfo fcinfo, RangeType *range, RangeBound *lower,
- RangeBound *upper, bool *empty)
+range_deserialize(TypeCacheEntry *typcache, RangeType *range,
+ RangeBound *lower, RangeBound *upper, bool *empty)
{
- Pointer ptr = VARDATA(range);
- char typalign;
- int16 typlen;
- int16 typbyval;
char flags;
- Oid rngtypid;
+ int16 typlen;
+ bool typbyval;
+ char typalign;
+ Pointer ptr;
Datum lbound;
Datum ubound;
- RangeTypeInfo rngtypinfo;
+
+ /* assert caller passed the right typcache entry */
+ Assert(RangeTypeGetOid(range) == typcache->type_id);
/* fetch the flag byte from datum's last byte */
- flags = *((char *) (ptr + VARSIZE(range) - VARHDRSZ - 1));
+ flags = *((char *) range + VARSIZE(range) - 1);
- /* fetch and advance over the range type OID */
- rngtypid = *((Oid *) ptr);
- ptr += sizeof(Oid);
+ /* fetch information about range's element type */
+ typlen = typcache->rngelemtype->typlen;
+ typbyval = typcache->rngelemtype->typbyval;
+ typalign = typcache->rngelemtype->typalign;
- /* fetch information about range type */
- range_gettypinfo(fcinfo, rngtypid, &rngtypinfo);
- typalign = rngtypinfo.subtypalign;
- typlen = rngtypinfo.subtyplen;
- typbyval = rngtypinfo.subtypbyval;
+ /* initialize data pointer just after the range OID */
+ ptr = (Pointer) (range + 1);
/* fetch lower bound, if any */
if (RANGE_HAS_LBOUND(flags))
/* emit results */
- *empty = flags & RANGE_EMPTY;
+ *empty = (flags & RANGE_EMPTY) != 0;
- lower->rngtypid = rngtypid;
lower->val = lbound;
- lower->inclusive = (flags & RANGE_LB_INC) != 0;
lower->infinite = (flags & RANGE_LB_INF) != 0;
+ lower->inclusive = (flags & RANGE_LB_INC) != 0;
lower->lower = true;
- upper->rngtypid = rngtypid;
upper->val = ubound;
- upper->inclusive = (flags & RANGE_UB_INC) != 0;
upper->infinite = (flags & RANGE_UB_INF) != 0;
+ upper->inclusive = (flags & RANGE_UB_INC) != 0;
upper->lower = false;
}
+/*
+ * range_get_flags: just get the flags from a RangeType value.
+ *
+ * This is frequently useful in places that only need the flags and not
+ * the full results of range_deserialize.
+ */
+char
+range_get_flags(RangeType *range)
+{
+ /* fetch the flag byte from datum's last byte */
+ return *((char *) range + VARSIZE(range) - 1);
+}
+
/*
* This both serializes and canonicalizes (if applicable) the range.
* This should be used by most callers.
*/
-Datum
-make_range(FunctionCallInfo fcinfo, RangeBound *lower, RangeBound *upper,
+RangeType *
+make_range(TypeCacheEntry *typcache, RangeBound *lower, RangeBound *upper,
bool empty)
{
- Datum range;
- RangeTypeInfo rngtypinfo;
-
- range_gettypinfo(fcinfo, lower->rngtypid, &rngtypinfo);
+ RangeType *range;
- range = range_serialize(fcinfo, lower, upper, empty);
+ range = range_serialize(typcache, lower, upper, empty);
- if (rngtypinfo.canonicalFn.fn_addr != NULL)
- range = FunctionCall1(&rngtypinfo.canonicalFn, range);
+ if (OidIsValid(typcache->rng_canonical_finfo.fn_oid))
+ range = DatumGetRangeType(FunctionCall1(&typcache->rng_canonical_finfo,
+ RangeTypeGetDatum(range)));
- PG_RETURN_RANGE(range);
+ return range;
}
int
-range_cmp_bounds(FunctionCallInfo fcinfo, RangeBound *b1, RangeBound *b2)
+range_cmp_bounds(TypeCacheEntry *typcache, RangeBound *b1, RangeBound *b2)
{
- int result;
- RangeTypeInfo rngtypinfo;
+ int32 result;
if (b1->infinite && b2->infinite)
{
else if (!b1->infinite && b2->infinite)
return (b2->lower) ? 1 : -1;
- range_gettypinfo(fcinfo, b1->rngtypid, &rngtypinfo);
-
- result = DatumGetInt32(FunctionCall2Coll(&rngtypinfo.cmpFn,
- rngtypinfo.collation,
+ result = DatumGetInt32(FunctionCall2Coll(&typcache->rng_cmp_proc_finfo,
+ typcache->rng_collation,
b1->val, b2->val));
if (result == 0)
}
RangeType *
-make_empty_range(FunctionCallInfo fcinfo, Oid rngtypid)
+make_empty_range(TypeCacheEntry *typcache)
{
RangeBound lower;
RangeBound upper;
- memset(&lower, 0, sizeof(RangeBound));
- memset(&upper, 0, sizeof(RangeBound));
-
- lower.rngtypid = rngtypid;
+ lower.val = (Datum) 0;
+ lower.infinite = false;
+ lower.inclusive = false;
lower.lower = true;
- upper.rngtypid = rngtypid;
+
+ upper.val = (Datum) 0;
+ upper.infinite = false;
+ upper.inclusive = false;
upper.lower = false;
- return DatumGetRangeType(make_range(fcinfo, &lower, &upper, true));
+ return make_range(typcache, &lower, &upper, true);
}
-/*
- * Fills in rngtypinfo, from a cached copy if available.
- */
-void
-range_gettypinfo(FunctionCallInfo fcinfo, Oid rngtypid,
- RangeTypeInfo *rngtypinfo)
-{
- RangeTypeInfo *cached = (RangeTypeInfo *) fcinfo->flinfo->fn_extra;
-
- if (cached == NULL)
- {
- fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
- sizeof(RangeTypeInfo));
- cached = (RangeTypeInfo *) fcinfo->flinfo->fn_extra;
- cached->rngtypid = ~rngtypid;
- }
-
- if (cached->rngtypid != rngtypid)
- {
- Form_pg_range pg_range;
- Form_pg_opclass pg_opclass;
- Form_pg_type pg_type;
- HeapTuple tup;
- Oid subtypeOid;
- Oid collationOid;
- Oid canonicalOid;
- Oid subdiffOid;
- Oid opclassOid;
- Oid cmpFnOid;
- Oid opfamilyOid;
- Oid opcintype;
- int16 subtyplen;
- char subtypalign;
- char subtypstorage;
- bool subtypbyval;
-
- /* get information from pg_range */
- tup = SearchSysCache1(RANGETYPE, ObjectIdGetDatum(rngtypid));
- if (!HeapTupleIsValid(tup))
- elog(ERROR, "cache lookup failed for range type %u", rngtypid);
-
- pg_range = (Form_pg_range) GETSTRUCT(tup);
-
- subtypeOid = pg_range->rngsubtype;
- collationOid = pg_range->rngcollation;
- canonicalOid = pg_range->rngcanonical;
- opclassOid = pg_range->rngsubopc;
- subdiffOid = pg_range->rngsubdiff;
-
- ReleaseSysCache(tup);
-
- /* get information from pg_opclass */
- tup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassOid));
- if (!HeapTupleIsValid(tup))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("operator class with OID %u does not exist",
- opclassOid)));
-
- pg_opclass = (Form_pg_opclass) GETSTRUCT(tup);
-
- opfamilyOid = pg_opclass->opcfamily;
- opcintype = pg_opclass->opcintype;
-
- ReleaseSysCache(tup);
-
- 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);
-
- /* get information from pg_type */
- tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(subtypeOid));
- if (!HeapTupleIsValid(tup))
- elog(ERROR, "cache lookup failed for type %u", subtypeOid);
-
- pg_type = (Form_pg_type) GETSTRUCT(tup);
-
- subtyplen = pg_type->typlen;
- subtypalign = pg_type->typalign;
- subtypstorage = pg_type->typstorage;
- subtypbyval = pg_type->typbyval;
-
- ReleaseSysCache(tup);
-
- /* set up the cache */
-
- if (OidIsValid(canonicalOid))
- fmgr_info(canonicalOid, &cached->canonicalFn);
- else
- cached->canonicalFn.fn_addr = NULL;
-
- if (OidIsValid(subdiffOid))
- fmgr_info(subdiffOid, &cached->subdiffFn);
- else
- cached->subdiffFn.fn_addr = NULL;
-
- fmgr_info(cmpFnOid, &cached->cmpFn);
- cached->subtype = subtypeOid;
- cached->collation = collationOid;
- cached->subtyplen = subtyplen;
- cached->subtypalign = subtypalign;
- cached->subtypstorage = subtypstorage;
- cached->subtypbyval = subtypbyval;
- cached->rngtypid = rngtypid;
- }
-
- memcpy(rngtypinfo, cached, sizeof(RangeTypeInfo));
-}
/*
*----------------------------------------------------------
}
static bool
-range_contains_internal(FunctionCallInfo fcinfo, RangeType *r1, RangeType *r2)
+range_contains_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
{
RangeBound lower1;
RangeBound upper1;
RangeBound upper2;
bool empty2;
- range_deserialize(fcinfo, r1, &lower1, &upper1, &empty1);
- range_deserialize(fcinfo, r2, &lower2, &upper2, &empty2);
-
- if (lower1.rngtypid != lower2.rngtypid)
- elog(ERROR, "range types do not match");
+ range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
+ range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
if (empty2)
return true;
else if (empty1)
return false;
- if (range_cmp_bounds(fcinfo, &lower1, &lower2) > 0)
+ if (range_cmp_bounds(typcache, &lower1, &lower2) > 0)
return false;
- if (range_cmp_bounds(fcinfo, &upper1, &upper2) < 0)
+ if (range_cmp_bounds(typcache, &upper1, &upper2) < 0)
return false;
return true;
#include "access/gist.h"
#include "access/skey.h"
#include "utils/builtins.h"
-#include "utils/fmgroids.h"
-#include "utils/lsyscache.h"
#include "utils/rangetypes.h"
#define RANGESTRAT_OVERRIGHT 11
#define RANGESTRAT_ADJACENT 12
+#define RangeIsEmpty(r) (range_get_flags(r) & RANGE_EMPTY)
+
/*
* Auxiliary structure for picksplit method.
*/
typedef struct
{
- int index;
- RangeType *data;
- FunctionCallInfo fcinfo;
+ int index; /* original index in entryvec->vector[] */
+ RangeType *data; /* range value to sort */
+ TypeCacheEntry *typcache; /* range type's info */
} PickSplitSortItem;
-static RangeType *range_super_union(FunctionCallInfo fcinfo, RangeType * r1,
+static RangeType *range_super_union(TypeCacheEntry *typcache, RangeType * r1,
RangeType * r2);
-static bool range_gist_consistent_int(FunctionCallInfo fcinfo,
+static bool range_gist_consistent_int(FmgrInfo *flinfo,
StrategyNumber strategy, RangeType * key,
RangeType * query);
-static bool range_gist_consistent_leaf(FunctionCallInfo fcinfo,
+static bool range_gist_consistent_leaf(FmgrInfo *flinfo,
StrategyNumber strategy, RangeType * key,
RangeType * query);
static int sort_item_cmp(const void *a, const void *b);
/* Oid subtype = PG_GETARG_OID(3); */
bool *recheck = (bool *) PG_GETARG_POINTER(4);
RangeType *key = DatumGetRangeType(entry->key);
+ TypeCacheEntry *typcache;
RangeType *query;
RangeBound lower;
RangeBound upper;
- bool empty;
- Oid rngtypid;
+ /* All operators served by this function are exact */
*recheck = false;
- range_deserialize(fcinfo, key, &lower, &upper, &empty);
- rngtypid = lower.rngtypid;
switch (strategy)
{
*/
case RANGESTRAT_CONTAINS_ELEM:
case RANGESTRAT_ELEM_CONTAINED_BY:
- lower.rngtypid = rngtypid;
- lower.inclusive = true;
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(key));
+
lower.val = dquery;
- lower.lower = true;
lower.infinite = false;
- upper.rngtypid = rngtypid;
- upper.inclusive = true;
+ lower.inclusive = true;
+ lower.lower = true;
+
upper.val = dquery;
- upper.lower = false;
upper.infinite = false;
- query = DatumGetRangeType(make_range(fcinfo,
- &lower, &upper, false));
+ upper.inclusive = true;
+ upper.lower = false;
+
+ query = make_range(typcache, &lower, &upper, false);
break;
default:
}
if (GIST_LEAF(entry))
- PG_RETURN_BOOL(range_gist_consistent_leaf(fcinfo, strategy,
+ PG_RETURN_BOOL(range_gist_consistent_leaf(fcinfo->flinfo, strategy,
key, query));
else
- PG_RETURN_BOOL(range_gist_consistent_int(fcinfo, strategy,
+ PG_RETURN_BOOL(range_gist_consistent_int(fcinfo->flinfo, strategy,
key, query));
}
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
GISTENTRY *ent = entryvec->vector;
RangeType *result_range;
+ TypeCacheEntry *typcache;
int i;
result_range = DatumGetRangeType(ent[0].key);
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(result_range));
+
for (i = 1; i < entryvec->n; i++)
{
- result_range = range_super_union(fcinfo, result_range,
+ result_range = range_super_union(typcache, result_range,
DatumGetRangeType(ent[i].key));
}
float *penalty = (float *) PG_GETARG_POINTER(2);
RangeType *orig = DatumGetRangeType(origentry->key);
RangeType *new = DatumGetRangeType(newentry->key);
+ TypeCacheEntry *typcache;
RangeType *s_union;
FmgrInfo *subtype_diff;
RangeBound lower1,
upper2;
bool empty1,
empty2;
- float lower_diff,
+ float8 lower_diff,
upper_diff;
- RangeTypeInfo rngtypinfo;
- s_union = range_super_union(fcinfo, orig, new);
+ if (RangeTypeGetOid(orig) != RangeTypeGetOid(new))
+ elog(ERROR, "range types do not match");
+
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(orig));
- range_deserialize(fcinfo, orig, &lower1, &upper1, &empty1);
- range_deserialize(fcinfo, s_union, &lower2, &upper2, &empty2);
+ subtype_diff = &typcache->rng_subdiff_finfo;
- range_gettypinfo(fcinfo, lower1.rngtypid, &rngtypinfo);
- subtype_diff = &rngtypinfo.subdiffFn;
+ s_union = range_super_union(typcache, orig, new);
+ range_deserialize(typcache, orig, &lower1, &upper1, &empty1);
+ range_deserialize(typcache, s_union, &lower2, &upper2, &empty2);
+
+ /* if orig isn't empty, s_union can't be either */
Assert(empty1 || !empty2);
if (empty1 && empty2)
- return 0;
+ {
+ *penalty = 0;
+ PG_RETURN_POINTER(penalty);
+ }
else if (empty1 && !empty2)
{
if (lower2.infinite || upper2.infinite)
+ {
/* from empty to infinite */
- return get_float8_infinity();
- else if (subtype_diff->fn_addr != NULL)
+ *penalty = get_float4_infinity();
+ PG_RETURN_POINTER(penalty);
+ }
+ else if (OidIsValid(subtype_diff->fn_oid))
+ {
/* from empty to upper2-lower2 */
- return DatumGetFloat8(FunctionCall2(subtype_diff,
- upper2.val, lower2.val));
+ *penalty = DatumGetFloat8(FunctionCall2Coll(subtype_diff,
+ typcache->rng_collation,
+ upper2.val,
+ lower2.val));
+ if (*penalty < 0)
+ *penalty = 0; /* subtype_diff is broken */
+ PG_RETURN_POINTER(penalty);
+ }
else
+ {
/* wild guess */
- return 1.0;
+ *penalty = 1.0;
+ PG_RETURN_POINTER(penalty);
+ }
}
Assert(lower2.infinite || !lower1.infinite);
lower_diff = get_float8_infinity();
else if (lower2.infinite && lower1.infinite)
lower_diff = 0;
- else if (subtype_diff->fn_addr != NULL)
+ else if (OidIsValid(subtype_diff->fn_oid))
{
- lower_diff = DatumGetFloat8(FunctionCall2(subtype_diff,
- lower1.val, lower2.val));
+ lower_diff = DatumGetFloat8(FunctionCall2Coll(subtype_diff,
+ typcache->rng_collation,
+ lower1.val,
+ lower2.val));
if (lower_diff < 0)
lower_diff = 0; /* subtype_diff is broken */
}
- else /* only know whether there is a difference or not */
- lower_diff = (float) range_cmp_bounds(fcinfo, &lower1, &lower2);
+ else
+ {
+ /* only know whether there is a difference or not */
+ lower_diff = (float) range_cmp_bounds(typcache, &lower1, &lower2);
+ }
Assert(upper2.infinite || !upper1.infinite);
upper_diff = get_float8_infinity();
else if (upper2.infinite && upper1.infinite)
upper_diff = 0;
- else if (subtype_diff->fn_addr != NULL)
+ else if (OidIsValid(subtype_diff->fn_oid))
{
- upper_diff = DatumGetFloat8(FunctionCall2(subtype_diff,
- upper2.val, upper1.val));
+ upper_diff = DatumGetFloat8(FunctionCall2Coll(subtype_diff,
+ typcache->rng_collation,
+ upper2.val,
+ upper1.val));
if (upper_diff < 0)
upper_diff = 0; /* subtype_diff is broken */
}
- else /* only know whether there is a difference or not */
- upper_diff = (float) range_cmp_bounds(fcinfo, &upper2, &upper1);
+ else
+ {
+ /* only know whether there is a difference or not */
+ upper_diff = (float) range_cmp_bounds(typcache, &upper2, &upper1);
+ }
Assert(lower_diff >= 0 && upper_diff >= 0);
{
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
+ TypeCacheEntry *typcache;
OffsetNumber i;
RangeType *pred_left;
RangeType *pred_right;
OffsetNumber *right;
OffsetNumber maxoff;
+ /* use first item to look up range type's info */
+ pred_left = DatumGetRangeType(entryvec->vector[FirstOffsetNumber].key);
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(pred_left));
+
+ /* allocate result and work arrays */
maxoff = entryvec->n - 1;
nbytes = (maxoff + 1) * sizeof(OffsetNumber);
- sortItems = (PickSplitSortItem *) palloc(
- maxoff * sizeof(PickSplitSortItem));
v->spl_left = (OffsetNumber *) palloc(nbytes);
v->spl_right = (OffsetNumber *) palloc(nbytes);
+ sortItems = (PickSplitSortItem *) palloc(maxoff * sizeof(PickSplitSortItem));
/*
- * Preparing auxiliary array and sorting.
+ * Prepare auxiliary array and sort the values.
*/
for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
{
sortItems[i - 1].index = i;
sortItems[i - 1].data = DatumGetRangeType(entryvec->vector[i].key);
- sortItems[i - 1].fcinfo = fcinfo;
+ sortItems[i - 1].typcache = typcache;
}
qsort(sortItems, maxoff, sizeof(PickSplitSortItem), sort_item_cmp);
+
split_idx = maxoff / 2;
left = v->spl_left;
v->spl_nright = 0;
/*
- * First half of segs goes to the left datum.
+ * First half of items goes to the left datum.
*/
- pred_left = DatumGetRangeType(sortItems[0].data);
+ pred_left = sortItems[0].data;
*left++ = sortItems[0].index;
v->spl_nleft++;
for (i = 1; i < split_idx; i++)
{
- pred_left = range_super_union(fcinfo, pred_left,
- DatumGetRangeType(sortItems[i].data));
+ pred_left = range_super_union(typcache, pred_left, sortItems[i].data);
*left++ = sortItems[i].index;
v->spl_nleft++;
}
/*
- * Second half of segs goes to the right datum.
+ * Second half of items goes to the right datum.
*/
- pred_right = DatumGetRangeType(sortItems[split_idx].data);
+ pred_right = sortItems[split_idx].data;
*right++ = sortItems[split_idx].index;
v->spl_nright++;
for (i = split_idx + 1; i < maxoff; i++)
{
- pred_right = range_super_union(fcinfo, pred_right,
- DatumGetRangeType(sortItems[i].data));
+ pred_right = range_super_union(typcache, pred_right, sortItems[i].data);
*right++ = sortItems[i].index;
v->spl_nright++;
}
Datum
range_gist_same(PG_FUNCTION_ARGS)
{
- Datum r1 = PG_GETARG_DATUM(0);
- Datum r2 = PG_GETARG_DATUM(1);
+ /* Datum r1 = PG_GETARG_DATUM(0); */
+ /* Datum r2 = PG_GETARG_DATUM(1); */
bool *result = (bool *) PG_GETARG_POINTER(2);
- *result = DatumGetBool(OidFunctionCall2(F_RANGE_EQ, r1, r2));
+ /*
+ * We can safely call range_eq using our fcinfo directly; it won't notice
+ * the third argument. This allows it to use fn_extra for caching.
+ */
+ *result = DatumGetBool(range_eq(fcinfo));
+
PG_RETURN_POINTER(result);
}
*----------------------------------------------------------
*/
-/* return the smallest range that contains r1 and r2 */
+/*
+ * Return the smallest range that contains r1 and r2
+ */
static RangeType *
-range_super_union(FunctionCallInfo fcinfo, RangeType * r1, RangeType * r2)
+range_super_union(TypeCacheEntry *typcache, RangeType * r1, RangeType * r2)
{
RangeBound lower1,
lower2;
RangeBound *result_lower;
RangeBound *result_upper;
- range_deserialize(fcinfo, r1, &lower1, &upper1, &empty1);
- range_deserialize(fcinfo, r2, &lower2, &upper2, &empty2);
+ range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
+ range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
if (empty1)
return r2;
if (empty2)
return r1;
- if (range_cmp_bounds(fcinfo, &lower1, &lower2) <= 0)
+ if (range_cmp_bounds(typcache, &lower1, &lower2) <= 0)
result_lower = &lower1;
else
result_lower = &lower2;
- if (range_cmp_bounds(fcinfo, &upper1, &upper2) >= 0)
+ if (range_cmp_bounds(typcache, &upper1, &upper2) >= 0)
result_upper = &upper1;
else
result_upper = &upper2;
if (result_lower == &lower2 && result_upper == &upper2)
return r2;
- return DatumGetRangeType(make_range(fcinfo, result_lower, result_upper,
- false));
+ return make_range(typcache, result_lower, result_upper, false);
+}
+
+/*
+ * trick function call: call the given function with given FmgrInfo
+ *
+ * To allow the various functions called here to cache lookups of range
+ * datatype information, we use a trick: we pass them the FmgrInfo struct
+ * for the GiST consistent function. This relies on the knowledge that
+ * none of them consult FmgrInfo for anything but fn_extra, and that they
+ * all use fn_extra the same way, i.e. as a pointer to the typcache entry
+ * for the range data type. Since the FmgrInfo is long-lived (it's actually
+ * part of the relcache entry for the index, typically) this essentially
+ * eliminates lookup overhead during operations on a GiST range index.
+ */
+static Datum
+TrickFunctionCall2(PGFunction proc, FmgrInfo *flinfo, Datum arg1, Datum arg2)
+{
+ FunctionCallInfoData fcinfo;
+ Datum result;
+
+ InitFunctionCallInfoData(fcinfo, flinfo, 2, InvalidOid, NULL, NULL);
+
+ fcinfo.arg[0] = arg1;
+ fcinfo.arg[1] = arg2;
+ fcinfo.argnull[0] = false;
+ fcinfo.argnull[1] = false;
+
+ result = (*proc) (&fcinfo);
+
+ if (fcinfo.isnull)
+ elog(ERROR, "function %p returned NULL", proc);
+
+ return result;
}
+/*
+ * GiST consistent test on an index internal page
+ */
static bool
-range_gist_consistent_int(FunctionCallInfo fcinfo, StrategyNumber strategy,
+range_gist_consistent_int(FmgrInfo *flinfo, StrategyNumber strategy,
RangeType * key, RangeType * query)
{
- Oid proc;
- RangeBound lower1,
- lower2;
- RangeBound upper1,
- upper2;
- bool empty1,
- empty2;
- bool retval;
+ PGFunction proc;
bool negate = false;
-
- range_deserialize(fcinfo, key, &lower1, &upper1, &empty1);
- range_deserialize(fcinfo, query, &lower2, &upper2, &empty2);
+ bool retval;
switch (strategy)
{
case RANGESTRAT_EQ:
- proc = F_RANGE_CONTAINS;
+ proc = range_contains;
break;
case RANGESTRAT_NE:
return true;
break;
case RANGESTRAT_OVERLAPS:
- proc = F_RANGE_OVERLAPS;
+ proc = range_overlaps;
break;
case RANGESTRAT_CONTAINS_ELEM:
case RANGESTRAT_CONTAINS:
- proc = F_RANGE_CONTAINS;
+ proc = range_contains;
break;
case RANGESTRAT_ELEM_CONTAINED_BY:
case RANGESTRAT_CONTAINED_BY:
return true;
break;
case RANGESTRAT_BEFORE:
- if (empty1)
+ if (RangeIsEmpty(key))
return false;
- proc = F_RANGE_OVERRIGHT;
+ proc = range_overright;
negate = true;
break;
case RANGESTRAT_AFTER:
- if (empty1)
+ if (RangeIsEmpty(key))
return false;
- proc = F_RANGE_OVERLEFT;
+ proc = range_overleft;
negate = true;
break;
case RANGESTRAT_OVERLEFT:
- if (empty1)
+ if (RangeIsEmpty(key))
return false;
- proc = F_RANGE_AFTER;
+ proc = range_after;
negate = true;
break;
case RANGESTRAT_OVERRIGHT:
- if (empty1)
+ if (RangeIsEmpty(key))
return false;
- proc = F_RANGE_BEFORE;
+ proc = range_before;
negate = true;
break;
case RANGESTRAT_ADJACENT:
- if (empty1 || empty2)
+ if (RangeIsEmpty(key) || RangeIsEmpty(query))
return false;
- if (DatumGetBool(OidFunctionCall2(F_RANGE_ADJACENT,
- RangeTypeGetDatum(key),
- RangeTypeGetDatum(query))))
+ if (DatumGetBool(TrickFunctionCall2(range_adjacent, flinfo,
+ RangeTypeGetDatum(key),
+ RangeTypeGetDatum(query))))
return true;
- proc = F_RANGE_OVERLAPS;
+ proc = range_overlaps;
break;
default:
elog(ERROR, "unrecognized range strategy: %d", strategy);
- proc = InvalidOid;
+ proc = NULL; /* keep compiler quiet */
break;
}
- retval = DatumGetBool(OidFunctionCall2(proc, RangeTypeGetDatum(key),
- RangeTypeGetDatum(query)));
-
+ retval = DatumGetBool(TrickFunctionCall2(proc, flinfo,
+ RangeTypeGetDatum(key),
+ RangeTypeGetDatum(query)));
if (negate)
retval = !retval;
- PG_RETURN_BOOL(retval);
+ return retval;
}
+/*
+ * GiST consistent test on an index leaf page
+ */
static bool
-range_gist_consistent_leaf(FunctionCallInfo fcinfo, StrategyNumber strategy,
+range_gist_consistent_leaf(FmgrInfo *flinfo, StrategyNumber strategy,
RangeType * key, RangeType * query)
{
- Oid proc;
- RangeBound lower1,
- lower2;
- RangeBound upper1,
- upper2;
- bool empty1,
- empty2;
-
- range_deserialize(fcinfo, key, &lower1, &upper1, &empty1);
- range_deserialize(fcinfo, query, &lower2, &upper2, &empty2);
+ PGFunction proc;
switch (strategy)
{
case RANGESTRAT_EQ:
- proc = F_RANGE_EQ;
+ proc = range_eq;
break;
case RANGESTRAT_NE:
- proc = F_RANGE_NE;
+ proc = range_ne;
break;
case RANGESTRAT_OVERLAPS:
- proc = F_RANGE_OVERLAPS;
+ proc = range_overlaps;
break;
case RANGESTRAT_CONTAINS_ELEM:
case RANGESTRAT_CONTAINS:
- proc = F_RANGE_CONTAINS;
+ proc = range_contains;
break;
case RANGESTRAT_ELEM_CONTAINED_BY:
case RANGESTRAT_CONTAINED_BY:
- proc = F_RANGE_CONTAINED_BY;
+ proc = range_contained_by;
break;
case RANGESTRAT_BEFORE:
- if (empty1 || empty2)
+ if (RangeIsEmpty(key) || RangeIsEmpty(query))
return false;
- proc = F_RANGE_BEFORE;
+ proc = range_before;
break;
case RANGESTRAT_AFTER:
- if (empty1 || empty2)
+ if (RangeIsEmpty(key) || RangeIsEmpty(query))
return false;
- proc = F_RANGE_AFTER;
+ proc = range_after;
break;
case RANGESTRAT_OVERLEFT:
- if (empty1 || empty2)
+ if (RangeIsEmpty(key) || RangeIsEmpty(query))
return false;
- proc = F_RANGE_OVERLEFT;
+ proc = range_overleft;
break;
case RANGESTRAT_OVERRIGHT:
- if (empty1 || empty2)
+ if (RangeIsEmpty(key) || RangeIsEmpty(query))
return false;
- proc = F_RANGE_OVERRIGHT;
+ proc = range_overright;
break;
case RANGESTRAT_ADJACENT:
- if (empty1 || empty2)
+ if (RangeIsEmpty(key) || RangeIsEmpty(query))
return false;
- proc = F_RANGE_ADJACENT;
+ proc = range_adjacent;
break;
default:
elog(ERROR, "unrecognized range strategy: %d", strategy);
- proc = InvalidOid;
+ proc = NULL; /* keep compiler quiet */
break;
}
- return DatumGetBool(OidFunctionCall2(proc, RangeTypeGetDatum(key),
- RangeTypeGetDatum(query)));
+ return DatumGetBool(TrickFunctionCall2(proc, flinfo,
+ RangeTypeGetDatum(key),
+ RangeTypeGetDatum(query)));
}
/*
PickSplitSortItem *i2 = (PickSplitSortItem *) b;
RangeType *r1 = i1->data;
RangeType *r2 = i2->data;
+ TypeCacheEntry *typcache = i1->typcache;
RangeBound lower1,
lower2;
RangeBound upper1,
upper2;
bool empty1,
empty2;
- FunctionCallInfo fcinfo = i1->fcinfo;
int cmp;
- range_deserialize(fcinfo, r1, &lower1, &upper1, &empty1);
- range_deserialize(fcinfo, r2, &lower2, &upper2, &empty2);
+ range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
+ range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
if (empty1 || empty2)
{
lower2.infinite || upper2.infinite)
{
if (lower1.infinite && lower2.infinite)
- return range_cmp_bounds(fcinfo, &upper1, &upper2);
+ return range_cmp_bounds(typcache, &upper1, &upper2);
else if (lower1.infinite)
return -1;
else if (lower2.infinite)
return 1;
else if (upper1.infinite && upper2.infinite)
- return -1 * range_cmp_bounds(fcinfo, &lower1, &lower2);
+ return -1 * range_cmp_bounds(typcache, &lower1, &lower2);
else if (upper1.infinite)
return 1;
else if (upper2.infinite)
Assert(false);
}
- if ((cmp = range_cmp_bounds(fcinfo, &lower1, &lower2)) != 0)
+ if ((cmp = range_cmp_bounds(typcache, &lower1, &lower2)) != 0)
return cmp;
- return range_cmp_bounds(fcinfo, &upper1, &upper2);
+ return range_cmp_bounds(typcache, &upper1, &upper2);
}