Commit a7a4add6 authored by Heikki Linnakangas's avatar Heikki Linnakangas

Refactor the way code is shared between some range type functions.

Functions like range_eq, range_before etc. are exposed at the SQL-level, but
they're also used internally by the GiST consistent support function. The
code sharing was done by a hack, TrickFunctionCall2, which relied on the
knowledge that all the functions used fn_extra the same way. This commit
splits the functions into internal versions that take a TypeCacheEntry as
argument, and thin wrappers to expose the functions at the SQL-level. The
internal versions can then be called directly and in a less hacky way from
the GiST consistent function.

This is just cosmetic, but backpatch to 9.2 anyway, to avoid having a
different version of this code in the 9.2 branch. That would make
backpatching fixes in this area more difficult.

Alexander Korotkov
parent 80e373c3
...@@ -63,10 +63,6 @@ static const char *range_parse_bound(const char *string, const char *ptr, ...@@ -63,10 +63,6 @@ static const char *range_parse_bound(const char *string, const char *ptr,
static char *range_deparse(char flags, const char *lbound_str, static char *range_deparse(char flags, const char *lbound_str,
const char *ubound_str); const char *ubound_str);
static char *range_bound_escape(const char *value); static char *range_bound_escape(const char *value);
static bool range_contains_internal(TypeCacheEntry *typcache,
RangeType *r1, RangeType *r2);
static bool range_contains_elem_internal(TypeCacheEntry *typcache,
RangeType *r, Datum val);
static Size datum_compute_size(Size sz, Datum datum, bool typbyval, static Size datum_compute_size(Size sz, Datum datum, bool typbyval,
char typalign, int16 typlen, char typstorage); char typalign, int16 typlen, char typstorage);
static Pointer datum_write(Pointer ptr, Datum datum, bool typbyval, static Pointer datum_write(Pointer ptr, Datum datum, bool typbyval,
...@@ -546,13 +542,10 @@ elem_contained_by_range(PG_FUNCTION_ARGS) ...@@ -546,13 +542,10 @@ elem_contained_by_range(PG_FUNCTION_ARGS)
/* range, range -> bool functions */ /* range, range -> bool functions */
/* equality */ /* equality (internal version) */
Datum bool
range_eq(PG_FUNCTION_ARGS) range_eq_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
{ {
RangeType *r1 = PG_GETARG_RANGE(0);
RangeType *r2 = PG_GETARG_RANGE(1);
TypeCacheEntry *typcache;
RangeBound lower1, RangeBound lower1,
lower2; lower2;
RangeBound upper1, RangeBound upper1,
...@@ -564,32 +557,54 @@ range_eq(PG_FUNCTION_ARGS) ...@@ -564,32 +557,54 @@ range_eq(PG_FUNCTION_ARGS)
if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2)) if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
elog(ERROR, "range types do not match"); elog(ERROR, "range types do not match");
typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
range_deserialize(typcache, r1, &lower1, &upper1, &empty1); range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
range_deserialize(typcache, r2, &lower2, &upper2, &empty2); range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
if (empty1 && empty2) if (empty1 && empty2)
PG_RETURN_BOOL(true); return true;
if (empty1 != empty2) if (empty1 != empty2)
PG_RETURN_BOOL(false); return false;
if (range_cmp_bounds(typcache, &lower1, &lower2) != 0) if (range_cmp_bounds(typcache, &lower1, &lower2) != 0)
PG_RETURN_BOOL(false); return false;
if (range_cmp_bounds(typcache, &upper1, &upper2) != 0) if (range_cmp_bounds(typcache, &upper1, &upper2) != 0)
PG_RETURN_BOOL(false); return false;
return true;
}
PG_RETURN_BOOL(true); /* equality */
Datum
range_eq(PG_FUNCTION_ARGS)
{
RangeType *r1 = PG_GETARG_RANGE(0);
RangeType *r2 = PG_GETARG_RANGE(1);
TypeCacheEntry *typcache;
typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
PG_RETURN_BOOL(range_eq_internal(typcache, r1, r2));
}
/* inequality (internal version) */
bool
range_ne_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
{
return (!range_eq_internal(typcache, r1, r2));
} }
/* inequality */ /* inequality */
Datum Datum
range_ne(PG_FUNCTION_ARGS) range_ne(PG_FUNCTION_ARGS)
{ {
bool eq = DatumGetBool(range_eq(fcinfo)); RangeType *r1 = PG_GETARG_RANGE(0);
RangeType *r2 = PG_GETARG_RANGE(1);
TypeCacheEntry *typcache;
typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
PG_RETURN_BOOL(!eq); PG_RETURN_BOOL(range_ne_internal(typcache, r1, r2));
} }
/* contains? */ /* contains? */
...@@ -600,10 +615,6 @@ range_contains(PG_FUNCTION_ARGS) ...@@ -600,10 +615,6 @@ range_contains(PG_FUNCTION_ARGS)
RangeType *r2 = PG_GETARG_RANGE(1); RangeType *r2 = PG_GETARG_RANGE(1);
TypeCacheEntry *typcache; 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)); typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
PG_RETURN_BOOL(range_contains_internal(typcache, r1, r2)); PG_RETURN_BOOL(range_contains_internal(typcache, r1, r2));
...@@ -617,22 +628,15 @@ range_contained_by(PG_FUNCTION_ARGS) ...@@ -617,22 +628,15 @@ range_contained_by(PG_FUNCTION_ARGS)
RangeType *r2 = PG_GETARG_RANGE(1); RangeType *r2 = PG_GETARG_RANGE(1);
TypeCacheEntry *typcache; 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)); typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
PG_RETURN_BOOL(range_contains_internal(typcache, r2, r1)); PG_RETURN_BOOL(range_contained_by_internal(typcache, r1, r2));
} }
/* strictly left of? */ /* strictly left of? (internal version) */
Datum bool
range_before(PG_FUNCTION_ARGS) range_before_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
{ {
RangeType *r1 = PG_GETARG_RANGE(0);
RangeType *r2 = PG_GETARG_RANGE(1);
TypeCacheEntry *typcache;
RangeBound lower1, RangeBound lower1,
lower2; lower2;
RangeBound upper1, RangeBound upper1,
...@@ -644,25 +648,33 @@ range_before(PG_FUNCTION_ARGS) ...@@ -644,25 +648,33 @@ range_before(PG_FUNCTION_ARGS)
if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2)) if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
elog(ERROR, "range types do not match"); elog(ERROR, "range types do not match");
typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
range_deserialize(typcache, r1, &lower1, &upper1, &empty1); range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
range_deserialize(typcache, r2, &lower2, &upper2, &empty2); range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
/* An empty range is neither before nor after any other range */ /* An empty range is neither before nor after any other range */
if (empty1 || empty2) if (empty1 || empty2)
PG_RETURN_BOOL(false); return false;
PG_RETURN_BOOL(range_cmp_bounds(typcache, &upper1, &lower2) < 0); return (range_cmp_bounds(typcache, &upper1, &lower2) < 0);
} }
/* strictly right of? */ /* strictly left of? */
Datum Datum
range_after(PG_FUNCTION_ARGS) range_before(PG_FUNCTION_ARGS)
{ {
RangeType *r1 = PG_GETARG_RANGE(0); RangeType *r1 = PG_GETARG_RANGE(0);
RangeType *r2 = PG_GETARG_RANGE(1); RangeType *r2 = PG_GETARG_RANGE(1);
TypeCacheEntry *typcache; TypeCacheEntry *typcache;
typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
PG_RETURN_BOOL(range_before_internal(typcache, r1, r2));
}
/* strictly right of? (internal version) */
bool
range_after_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
{
RangeBound lower1, RangeBound lower1,
lower2; lower2;
RangeBound upper1, RangeBound upper1,
...@@ -674,25 +686,33 @@ range_after(PG_FUNCTION_ARGS) ...@@ -674,25 +686,33 @@ range_after(PG_FUNCTION_ARGS)
if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2)) if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
elog(ERROR, "range types do not match"); elog(ERROR, "range types do not match");
typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
range_deserialize(typcache, r1, &lower1, &upper1, &empty1); range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
range_deserialize(typcache, r2, &lower2, &upper2, &empty2); range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
/* An empty range is neither before nor after any other range */ /* An empty range is neither before nor after any other range */
if (empty1 || empty2) if (empty1 || empty2)
PG_RETURN_BOOL(false); return false;
PG_RETURN_BOOL(range_cmp_bounds(typcache, &lower1, &upper2) > 0); return (range_cmp_bounds(typcache, &lower1, &upper2) > 0);
} }
/* adjacent to (but not overlapping)? */ /* strictly right of? */
Datum Datum
range_adjacent(PG_FUNCTION_ARGS) range_after(PG_FUNCTION_ARGS)
{ {
RangeType *r1 = PG_GETARG_RANGE(0); RangeType *r1 = PG_GETARG_RANGE(0);
RangeType *r2 = PG_GETARG_RANGE(1); RangeType *r2 = PG_GETARG_RANGE(1);
TypeCacheEntry *typcache; TypeCacheEntry *typcache;
typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
PG_RETURN_BOOL(range_after_internal(typcache, r1, r2));
}
/* adjacent to (but not overlapping)? (internal version) */
bool
range_adjacent_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
{
RangeBound lower1, RangeBound lower1,
lower2; lower2;
RangeBound upper1, RangeBound upper1,
...@@ -706,14 +726,12 @@ range_adjacent(PG_FUNCTION_ARGS) ...@@ -706,14 +726,12 @@ range_adjacent(PG_FUNCTION_ARGS)
if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2)) if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
elog(ERROR, "range types do not match"); elog(ERROR, "range types do not match");
typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
range_deserialize(typcache, r1, &lower1, &upper1, &empty1); range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
range_deserialize(typcache, r2, &lower2, &upper2, &empty2); range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
/* An empty range is not adjacent to any other range */ /* An empty range is not adjacent to any other range */
if (empty1 || empty2) if (empty1 || empty2)
PG_RETURN_BOOL(false); return false;
/* /*
* Given two ranges A..B and C..D, where B < C, the ranges are adjacent if * Given two ranges A..B and C..D, where B < C, the ranges are adjacent if
...@@ -736,7 +754,7 @@ range_adjacent(PG_FUNCTION_ARGS) ...@@ -736,7 +754,7 @@ range_adjacent(PG_FUNCTION_ARGS)
{ {
/* in a continuous subtype, there are assumed to be points between */ /* in a continuous subtype, there are assumed to be points between */
if (!OidIsValid(typcache->rng_canonical_finfo.fn_oid)) if (!OidIsValid(typcache->rng_canonical_finfo.fn_oid))
PG_RETURN_BOOL(false); return (false);
/* flip the inclusion flags */ /* flip the inclusion flags */
upper1.inclusive = !upper1.inclusive; upper1.inclusive = !upper1.inclusive;
lower2.inclusive = !lower2.inclusive; lower2.inclusive = !lower2.inclusive;
...@@ -744,11 +762,11 @@ range_adjacent(PG_FUNCTION_ARGS) ...@@ -744,11 +762,11 @@ range_adjacent(PG_FUNCTION_ARGS)
upper1.lower = true; upper1.lower = true;
lower2.lower = false; lower2.lower = false;
r3 = make_range(typcache, &upper1, &lower2, false); r3 = make_range(typcache, &upper1, &lower2, false);
PG_RETURN_BOOL(RangeIsEmpty(r3)); return RangeIsEmpty(r3);
} }
if (cmp == 0) if (cmp == 0)
{ {
PG_RETURN_BOOL(upper1.inclusive != lower2.inclusive); return (upper1.inclusive != lower2.inclusive);
} }
cmp = range_cmp_bound_values(typcache, &upper2, &lower1); cmp = range_cmp_bound_values(typcache, &upper2, &lower1);
...@@ -756,7 +774,7 @@ range_adjacent(PG_FUNCTION_ARGS) ...@@ -756,7 +774,7 @@ range_adjacent(PG_FUNCTION_ARGS)
{ {
/* in a continuous subtype, there are assumed to be points between */ /* in a continuous subtype, there are assumed to be points between */
if (!OidIsValid(typcache->rng_canonical_finfo.fn_oid)) if (!OidIsValid(typcache->rng_canonical_finfo.fn_oid))
PG_RETURN_BOOL(false); return (false);
/* flip the inclusion flags */ /* flip the inclusion flags */
upper2.inclusive = !upper2.inclusive; upper2.inclusive = !upper2.inclusive;
lower1.inclusive = !lower1.inclusive; lower1.inclusive = !lower1.inclusive;
...@@ -764,23 +782,33 @@ range_adjacent(PG_FUNCTION_ARGS) ...@@ -764,23 +782,33 @@ range_adjacent(PG_FUNCTION_ARGS)
upper2.lower = true; upper2.lower = true;
lower1.lower = false; lower1.lower = false;
r3 = make_range(typcache, &upper2, &lower1, false); r3 = make_range(typcache, &upper2, &lower1, false);
PG_RETURN_BOOL(RangeIsEmpty(r3)); return RangeIsEmpty(r3);
} }
if (cmp == 0) if (cmp == 0)
{ {
PG_RETURN_BOOL(upper2.inclusive != lower1.inclusive); return (upper2.inclusive != lower1.inclusive);
} }
PG_RETURN_BOOL(false); return false;
} }
/* overlaps? */ /* adjacent to (but not overlapping)? */
Datum Datum
range_overlaps(PG_FUNCTION_ARGS) range_adjacent(PG_FUNCTION_ARGS)
{ {
RangeType *r1 = PG_GETARG_RANGE(0); RangeType *r1 = PG_GETARG_RANGE(0);
RangeType *r2 = PG_GETARG_RANGE(1); RangeType *r2 = PG_GETARG_RANGE(1);
TypeCacheEntry *typcache; TypeCacheEntry *typcache;
typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
PG_RETURN_BOOL(range_adjacent_internal(typcache, r1, r2));
}
/* overlaps? (internal version) */
bool
range_overlaps_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
{
RangeBound lower1, RangeBound lower1,
lower2; lower2;
RangeBound upper1, RangeBound upper1,
...@@ -792,33 +820,41 @@ range_overlaps(PG_FUNCTION_ARGS) ...@@ -792,33 +820,41 @@ range_overlaps(PG_FUNCTION_ARGS)
if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2)) if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
elog(ERROR, "range types do not match"); elog(ERROR, "range types do not match");
typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
range_deserialize(typcache, r1, &lower1, &upper1, &empty1); range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
range_deserialize(typcache, r2, &lower2, &upper2, &empty2); range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
/* An empty range does not overlap any other range */ /* An empty range does not overlap any other range */
if (empty1 || empty2) if (empty1 || empty2)
PG_RETURN_BOOL(false); return false;
if (range_cmp_bounds(typcache, &lower1, &lower2) >= 0 && if (range_cmp_bounds(typcache, &lower1, &lower2) >= 0 &&
range_cmp_bounds(typcache, &lower1, &upper2) <= 0) range_cmp_bounds(typcache, &lower1, &upper2) <= 0)
PG_RETURN_BOOL(true); return true;
if (range_cmp_bounds(typcache, &lower2, &lower1) >= 0 && if (range_cmp_bounds(typcache, &lower2, &lower1) >= 0 &&
range_cmp_bounds(typcache, &lower2, &upper1) <= 0) range_cmp_bounds(typcache, &lower2, &upper1) <= 0)
PG_RETURN_BOOL(true); return true;
PG_RETURN_BOOL(false); return false;
} }
/* does not extend to right of? */ /* overlaps? */
Datum Datum
range_overleft(PG_FUNCTION_ARGS) range_overlaps(PG_FUNCTION_ARGS)
{ {
RangeType *r1 = PG_GETARG_RANGE(0); RangeType *r1 = PG_GETARG_RANGE(0);
RangeType *r2 = PG_GETARG_RANGE(1); RangeType *r2 = PG_GETARG_RANGE(1);
TypeCacheEntry *typcache; TypeCacheEntry *typcache;
typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
PG_RETURN_BOOL(range_overlaps_internal(typcache, r1, r2));
}
/* does not extend to right of? (internal version) */
bool
range_overleft_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
{
RangeBound lower1, RangeBound lower1,
lower2; lower2;
RangeBound upper1, RangeBound upper1,
...@@ -830,28 +866,36 @@ range_overleft(PG_FUNCTION_ARGS) ...@@ -830,28 +866,36 @@ range_overleft(PG_FUNCTION_ARGS)
if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2)) if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
elog(ERROR, "range types do not match"); elog(ERROR, "range types do not match");
typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
range_deserialize(typcache, r1, &lower1, &upper1, &empty1); range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
range_deserialize(typcache, r2, &lower2, &upper2, &empty2); range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
/* An empty range is neither before nor after any other range */ /* An empty range is neither before nor after any other range */
if (empty1 || empty2) if (empty1 || empty2)
PG_RETURN_BOOL(false); return false;
if (range_cmp_bounds(typcache, &upper1, &upper2) <= 0) if (range_cmp_bounds(typcache, &upper1, &upper2) <= 0)
PG_RETURN_BOOL(true); return true;
PG_RETURN_BOOL(false); return false;
} }
/* does not extend to left of? */ /* does not extend to right of? */
Datum Datum
range_overright(PG_FUNCTION_ARGS) range_overleft(PG_FUNCTION_ARGS)
{ {
RangeType *r1 = PG_GETARG_RANGE(0); RangeType *r1 = PG_GETARG_RANGE(0);
RangeType *r2 = PG_GETARG_RANGE(1); RangeType *r2 = PG_GETARG_RANGE(1);
TypeCacheEntry *typcache; TypeCacheEntry *typcache;
typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
PG_RETURN_BOOL(range_overleft_internal(typcache, r1, r2));
}
/* does not extend to left of? (internal version) */
bool
range_overright_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
{
RangeBound lower1, RangeBound lower1,
lower2; lower2;
RangeBound upper1, RangeBound upper1,
...@@ -863,8 +907,6 @@ range_overright(PG_FUNCTION_ARGS) ...@@ -863,8 +907,6 @@ range_overright(PG_FUNCTION_ARGS)
if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2)) if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
elog(ERROR, "range types do not match"); elog(ERROR, "range types do not match");
typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
range_deserialize(typcache, r1, &lower1, &upper1, &empty1); range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
range_deserialize(typcache, r2, &lower2, &upper2, &empty2); range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
...@@ -878,6 +920,19 @@ range_overright(PG_FUNCTION_ARGS) ...@@ -878,6 +920,19 @@ range_overright(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(false); PG_RETURN_BOOL(false);
} }
/* does not extend to left of? */
Datum
range_overright(PG_FUNCTION_ARGS)
{
RangeType *r1 = PG_GETARG_RANGE(0);
RangeType *r2 = PG_GETARG_RANGE(1);
TypeCacheEntry *typcache;
typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
PG_RETURN_BOOL(range_overright_internal(typcache, r1, r2));
}
/* range, range -> range functions */ /* range, range -> range functions */
...@@ -2152,7 +2207,7 @@ range_bound_escape(const char *value) ...@@ -2152,7 +2207,7 @@ range_bound_escape(const char *value)
* Caller has already checked that they are the same range type, and looked up * Caller has already checked that they are the same range type, and looked up
* the necessary typcache entry. * the necessary typcache entry.
*/ */
static bool bool
range_contains_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2) range_contains_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
{ {
RangeBound lower1; RangeBound lower1;
...@@ -2162,6 +2217,10 @@ range_contains_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2) ...@@ -2162,6 +2217,10 @@ range_contains_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
RangeBound upper2; RangeBound upper2;
bool empty2; bool empty2;
/* Different types should be prevented by ANYRANGE matching rules */
if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
elog(ERROR, "range types do not match");
range_deserialize(typcache, r1, &lower1, &upper1, &empty1); range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
range_deserialize(typcache, r2, &lower2, &upper2, &empty2); range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
...@@ -2180,10 +2239,16 @@ range_contains_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2) ...@@ -2180,10 +2239,16 @@ range_contains_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
return true; return true;
} }
bool
range_contained_by_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
{
return range_contains_internal(typcache, r2, r1);
}
/* /*
* Test whether range r contains a specific element value. * Test whether range r contains a specific element value.
*/ */
static bool bool
range_contains_elem_internal(TypeCacheEntry *typcache, RangeType *r, Datum val) range_contains_elem_internal(TypeCacheEntry *typcache, RangeType *r, Datum val)
{ {
RangeBound lower; RangeBound lower;
......
...@@ -148,10 +148,10 @@ typedef struct ...@@ -148,10 +148,10 @@ typedef struct
static RangeType *range_super_union(TypeCacheEntry *typcache, RangeType *r1, static RangeType *range_super_union(TypeCacheEntry *typcache, RangeType *r1,
RangeType *r2); RangeType *r2);
static bool range_gist_consistent_int(FmgrInfo *flinfo, static bool range_gist_consistent_int(TypeCacheEntry *typcache,
StrategyNumber strategy, RangeType *key, StrategyNumber strategy, RangeType *key,
Datum query); Datum query);
static bool range_gist_consistent_leaf(FmgrInfo *flinfo, static bool range_gist_consistent_leaf(TypeCacheEntry *typcache,
StrategyNumber strategy, RangeType *key, StrategyNumber strategy, RangeType *key,
Datum query); Datum query);
static void range_gist_fallback_split(TypeCacheEntry *typcache, static void range_gist_fallback_split(TypeCacheEntry *typcache,
...@@ -191,15 +191,18 @@ range_gist_consistent(PG_FUNCTION_ARGS) ...@@ -191,15 +191,18 @@ range_gist_consistent(PG_FUNCTION_ARGS)
/* Oid subtype = PG_GETARG_OID(3); */ /* Oid subtype = PG_GETARG_OID(3); */
bool *recheck = (bool *) PG_GETARG_POINTER(4); bool *recheck = (bool *) PG_GETARG_POINTER(4);
RangeType *key = DatumGetRangeType(entry->key); RangeType *key = DatumGetRangeType(entry->key);
TypeCacheEntry *typcache;
/* All operators served by this function are exact */ /* All operators served by this function are exact */
*recheck = false; *recheck = false;
typcache = range_get_typcache(fcinfo, RangeTypeGetOid(key));
if (GIST_LEAF(entry)) if (GIST_LEAF(entry))
PG_RETURN_BOOL(range_gist_consistent_leaf(fcinfo->flinfo, strategy, PG_RETURN_BOOL(range_gist_consistent_leaf(typcache, strategy,
key, query)); key, query));
else else
PG_RETURN_BOOL(range_gist_consistent_int(fcinfo->flinfo, strategy, PG_RETURN_BOOL(range_gist_consistent_int(typcache, strategy,
key, query)); key, query));
} }
...@@ -686,12 +689,10 @@ range_gist_same(PG_FUNCTION_ARGS) ...@@ -686,12 +689,10 @@ range_gist_same(PG_FUNCTION_ARGS)
*result = false; *result = false;
else else
{ {
/* TypeCacheEntry *typcache;
* We can safely call range_eq using our fcinfo directly; it won't typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
* notice the third argument. This allows it to use fn_extra for
* caching. *result = range_eq_internal(typcache, r1, r2);
*/
*result = DatumGetBool(range_eq(fcinfo));
} }
PG_RETURN_POINTER(result); PG_RETURN_POINTER(result);
...@@ -780,91 +781,49 @@ range_super_union(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2) ...@@ -780,91 +781,49 @@ range_super_union(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
return result; return result;
} }
/*
* 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 * GiST consistent test on an index internal page
*/ */
static bool static bool
range_gist_consistent_int(FmgrInfo *flinfo, StrategyNumber strategy, range_gist_consistent_int(TypeCacheEntry *typcache, StrategyNumber strategy,
RangeType *key, Datum query) RangeType *key, Datum query)
{ {
PGFunction proc;
bool negate = false;
bool retval;
switch (strategy) switch (strategy)
{ {
case RANGESTRAT_BEFORE: case RANGESTRAT_BEFORE:
if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeType(query))) if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeType(query)))
return false; return false;
proc = range_overright; return (!range_overright_internal(typcache, key,
negate = true; DatumGetRangeType(query)));
break;
case RANGESTRAT_OVERLEFT: case RANGESTRAT_OVERLEFT:
if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeType(query))) if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeType(query)))
return false; return false;
proc = range_after; return (!range_after_internal(typcache, key,
negate = true; DatumGetRangeType(query)));
break;
case RANGESTRAT_OVERLAPS: case RANGESTRAT_OVERLAPS:
proc = range_overlaps; return range_overlaps_internal(typcache, key,
break; DatumGetRangeType(query));
case RANGESTRAT_OVERRIGHT: case RANGESTRAT_OVERRIGHT:
if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeType(query))) if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeType(query)))
return false; return false;
proc = range_before; return (!range_before_internal(typcache, key,
negate = true; DatumGetRangeType(query)));
break;
case RANGESTRAT_AFTER: case RANGESTRAT_AFTER:
if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeType(query))) if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeType(query)))
return false; return false;
proc = range_overleft; return (!range_overleft_internal(typcache, key,
negate = true; DatumGetRangeType(query)));
break;
case RANGESTRAT_ADJACENT: case RANGESTRAT_ADJACENT:
if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeType(query))) if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeType(query)))
return false; return false;
if (DatumGetBool(TrickFunctionCall2(range_adjacent, flinfo, if (range_adjacent_internal(typcache, key,
RangeTypeGetDatum(key), DatumGetRangeType(query)))
query)))
return true; return true;
proc = range_overlaps; return range_overlaps_internal(typcache, key,
break; DatumGetRangeType(query));
case RANGESTRAT_CONTAINS: case RANGESTRAT_CONTAINS:
proc = range_contains; return range_contains_internal(typcache, key,
break; DatumGetRangeType(query));
case RANGESTRAT_CONTAINED_BY: case RANGESTRAT_CONTAINED_BY:
/* /*
...@@ -874,11 +833,10 @@ range_gist_consistent_int(FmgrInfo *flinfo, StrategyNumber strategy, ...@@ -874,11 +833,10 @@ range_gist_consistent_int(FmgrInfo *flinfo, StrategyNumber strategy,
*/ */
if (RangeIsOrContainsEmpty(key)) if (RangeIsOrContainsEmpty(key))
return true; return true;
proc = range_overlaps; return range_overlaps_internal(typcache, key,
break; DatumGetRangeType(query));
case RANGESTRAT_CONTAINS_ELEM: case RANGESTRAT_CONTAINS_ELEM:
proc = range_contains_elem; return range_contains_elem_internal(typcache, key, query);
break;
case RANGESTRAT_EQ: case RANGESTRAT_EQ:
/* /*
...@@ -887,73 +845,55 @@ range_gist_consistent_int(FmgrInfo *flinfo, StrategyNumber strategy, ...@@ -887,73 +845,55 @@ range_gist_consistent_int(FmgrInfo *flinfo, StrategyNumber strategy,
*/ */
if (RangeIsEmpty(DatumGetRangeType(query))) if (RangeIsEmpty(DatumGetRangeType(query)))
return RangeIsOrContainsEmpty(key); return RangeIsOrContainsEmpty(key);
proc = range_contains; return range_contains_internal(typcache, key,
break; DatumGetRangeType(query));
default: default:
elog(ERROR, "unrecognized range strategy: %d", strategy); elog(ERROR, "unrecognized range strategy: %d", strategy);
proc = NULL; /* keep compiler quiet */ return false; /* keep compiler quiet */
break;
} }
retval = DatumGetBool(TrickFunctionCall2(proc, flinfo,
RangeTypeGetDatum(key),
query));
if (negate)
retval = !retval;
return retval;
} }
/* /*
* GiST consistent test on an index leaf page * GiST consistent test on an index leaf page
*/ */
static bool static bool
range_gist_consistent_leaf(FmgrInfo *flinfo, StrategyNumber strategy, range_gist_consistent_leaf(TypeCacheEntry *typcache, StrategyNumber strategy,
RangeType *key, Datum query) RangeType *key, Datum query)
{ {
PGFunction proc;
switch (strategy) switch (strategy)
{ {
case RANGESTRAT_BEFORE: case RANGESTRAT_BEFORE:
proc = range_before; return range_before_internal(typcache, key,
break; DatumGetRangeType(query));
case RANGESTRAT_OVERLEFT: case RANGESTRAT_OVERLEFT:
proc = range_overleft; return range_overleft_internal(typcache, key,
break; DatumGetRangeType(query));
case RANGESTRAT_OVERLAPS: case RANGESTRAT_OVERLAPS:
proc = range_overlaps; return range_overlaps_internal(typcache, key,
break; DatumGetRangeType(query));
case RANGESTRAT_OVERRIGHT: case RANGESTRAT_OVERRIGHT:
proc = range_overright; return range_overright_internal(typcache, key,
break; DatumGetRangeType(query));
case RANGESTRAT_AFTER: case RANGESTRAT_AFTER:
proc = range_after; return range_after_internal(typcache, key,
break; DatumGetRangeType(query));
case RANGESTRAT_ADJACENT: case RANGESTRAT_ADJACENT:
proc = range_adjacent; return range_adjacent_internal(typcache, key,
break; DatumGetRangeType(query));
case RANGESTRAT_CONTAINS: case RANGESTRAT_CONTAINS:
proc = range_contains; return range_contains_internal(typcache, key,
break; DatumGetRangeType(query));
case RANGESTRAT_CONTAINED_BY: case RANGESTRAT_CONTAINED_BY:
proc = range_contained_by; return range_contained_by_internal(typcache, key,
break; DatumGetRangeType(query));
case RANGESTRAT_CONTAINS_ELEM: case RANGESTRAT_CONTAINS_ELEM:
proc = range_contains_elem; return range_contains_elem_internal(typcache, key, query);
break;
case RANGESTRAT_EQ: case RANGESTRAT_EQ:
proc = range_eq; return range_eq_internal(typcache, key, DatumGetRangeType(query));
break;
default: default:
elog(ERROR, "unrecognized range strategy: %d", strategy); elog(ERROR, "unrecognized range strategy: %d", strategy);
proc = NULL; /* keep compiler quiet */ return false; /* keep compiler quiet */
break;
} }
return DatumGetBool(TrickFunctionCall2(proc, flinfo,
RangeTypeGetDatum(key),
query));
} }
/* /*
......
...@@ -104,6 +104,8 @@ extern Datum range_upper_inf(PG_FUNCTION_ARGS); ...@@ -104,6 +104,8 @@ extern Datum range_upper_inf(PG_FUNCTION_ARGS);
extern Datum range_contains_elem(PG_FUNCTION_ARGS); extern Datum range_contains_elem(PG_FUNCTION_ARGS);
extern Datum elem_contained_by_range(PG_FUNCTION_ARGS); extern Datum elem_contained_by_range(PG_FUNCTION_ARGS);
extern bool range_contains_elem_internal(TypeCacheEntry *typcache, RangeType *r, Datum val);
/* range, range -> bool */ /* range, range -> bool */
extern Datum range_eq(PG_FUNCTION_ARGS); extern Datum range_eq(PG_FUNCTION_ARGS);
extern Datum range_ne(PG_FUNCTION_ARGS); extern Datum range_ne(PG_FUNCTION_ARGS);
...@@ -116,6 +118,28 @@ extern Datum range_overlaps(PG_FUNCTION_ARGS); ...@@ -116,6 +118,28 @@ extern Datum range_overlaps(PG_FUNCTION_ARGS);
extern Datum range_overleft(PG_FUNCTION_ARGS); extern Datum range_overleft(PG_FUNCTION_ARGS);
extern Datum range_overright(PG_FUNCTION_ARGS); extern Datum range_overright(PG_FUNCTION_ARGS);
/* internal versions of the above */
extern bool range_eq_internal(TypeCacheEntry *typcache, RangeType *r1,
RangeType *r2);
extern bool range_ne_internal(TypeCacheEntry *typcache, RangeType *r1,
RangeType *r2);
extern bool range_contains_internal(TypeCacheEntry *typcache, RangeType *r1,
RangeType *r2);
extern bool range_contained_by_internal(TypeCacheEntry *typcache, RangeType *r1,
RangeType *r2);
extern bool range_before_internal(TypeCacheEntry *typcache, RangeType *r1,
RangeType *r2);
extern bool range_after_internal(TypeCacheEntry *typcache, RangeType *r1,
RangeType *r2);
extern bool range_adjacent_internal(TypeCacheEntry *typcache, RangeType *r1,
RangeType *r2);
extern bool range_overlaps_internal(TypeCacheEntry *typcache, RangeType *r1,
RangeType *r2);
extern bool range_overleft_internal(TypeCacheEntry *typcache, RangeType *r1,
RangeType *r2);
extern bool range_overright_internal(TypeCacheEntry *typcache, RangeType *r1,
RangeType *r2);
/* range, range -> range */ /* range, range -> range */
extern Datum range_minus(PG_FUNCTION_ARGS); extern Datum range_minus(PG_FUNCTION_ARGS);
extern Datum range_union(PG_FUNCTION_ARGS); extern Datum range_union(PG_FUNCTION_ARGS);
......
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