*** a/src/backend/utils/adt/rangetypes.c --- b/src/backend/utils/adt/rangetypes.c *************** *** 63,72 **** static const char *range_parse_bound(const char *string, const char *ptr, static char *range_deparse(char flags, const char *lbound_str, const char *ubound_str); 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, char typalign, int16 typlen, char typstorage); static Pointer datum_write(Pointer ptr, Datum datum, bool typbyval, --- 63,68 ---- *************** *** 546,558 **** elem_contained_by_range(PG_FUNCTION_ARGS) /* range, range -> bool functions */ ! /* equality */ ! Datum ! range_eq(PG_FUNCTION_ARGS) { - RangeType *r1 = PG_GETARG_RANGE(0); - RangeType *r2 = PG_GETARG_RANGE(1); - TypeCacheEntry *typcache; RangeBound lower1, lower2; RangeBound upper1, --- 542,551 ---- /* range, range -> bool functions */ ! /* equality (internal version) */ ! bool ! range_eq_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2) { RangeBound lower1, lower2; RangeBound upper1, *************** *** 564,595 **** range_eq(PG_FUNCTION_ARGS) 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(typcache, &lower1, &lower2) != 0) ! PG_RETURN_BOOL(false); if (range_cmp_bounds(typcache, &upper1, &upper2) != 0) ! PG_RETURN_BOOL(false); ! PG_RETURN_BOOL(true); } /* inequality */ Datum range_ne(PG_FUNCTION_ARGS) { ! bool eq = DatumGetBool(range_eq(fcinfo)); ! PG_RETURN_BOOL(!eq); } /* contains? */ --- 557,610 ---- if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2)) elog(ERROR, "range types do not match"); range_deserialize(typcache, r1, &lower1, &upper1, &empty1); range_deserialize(typcache, r2, &lower2, &upper2, &empty2); if (empty1 && empty2) ! return true; if (empty1 != empty2) ! return false; if (range_cmp_bounds(typcache, &lower1, &lower2) != 0) ! return false; if (range_cmp_bounds(typcache, &upper1, &upper2) != 0) ! return false; ! ! return 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 */ Datum range_ne(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_ne_internal(typcache, r1, r2)); } /* contains? */ *************** *** 600,609 **** range_contains(PG_FUNCTION_ARGS) 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(typcache, r1, r2)); --- 615,620 ---- *************** *** 617,638 **** range_contained_by(PG_FUNCTION_ARGS) 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(typcache, r2, r1)); } ! /* strictly left of? */ ! Datum ! range_before(PG_FUNCTION_ARGS) { - RangeType *r1 = PG_GETARG_RANGE(0); - RangeType *r2 = PG_GETARG_RANGE(1); - TypeCacheEntry *typcache; RangeBound lower1, lower2; RangeBound upper1, --- 628,642 ---- RangeType *r2 = PG_GETARG_RANGE(1); TypeCacheEntry *typcache; typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1)); ! PG_RETURN_BOOL(range_contained_by_internal(typcache, r1, r2)); } ! /* strictly left of? (internal version) */ ! bool ! range_before_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2) { RangeBound lower1, lower2; RangeBound upper1, *************** *** 644,668 **** range_before(PG_FUNCTION_ARGS) 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(typcache, &upper1, &lower2) < 0); } ! /* strictly right of? */ Datum ! range_after(PG_FUNCTION_ARGS) { RangeType *r1 = PG_GETARG_RANGE(0); RangeType *r2 = PG_GETARG_RANGE(1); TypeCacheEntry *typcache; RangeBound lower1, lower2; RangeBound upper1, --- 648,680 ---- if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2)) elog(ERROR, "range types do not match"); 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) ! return false; ! return (range_cmp_bounds(typcache, &upper1, &lower2) < 0); } ! /* strictly left of? */ Datum ! range_before(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_before_internal(typcache, r1, r2)); + } + + /* strictly right of? (internal version) */ + bool + range_after_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2) + { RangeBound lower1, lower2; RangeBound upper1, *************** *** 674,698 **** range_after(PG_FUNCTION_ARGS) 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(typcache, &lower1, &upper2) > 0); } ! /* adjacent to (but not overlapping)? */ Datum ! range_adjacent(PG_FUNCTION_ARGS) { RangeType *r1 = PG_GETARG_RANGE(0); RangeType *r2 = PG_GETARG_RANGE(1); TypeCacheEntry *typcache; RangeBound lower1, lower2; RangeBound upper1, --- 686,718 ---- if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2)) elog(ERROR, "range types do not match"); 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) ! return false; ! return (range_cmp_bounds(typcache, &lower1, &upper2) > 0); } ! /* strictly right of? */ Datum ! range_after(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_after_internal(typcache, r1, r2)); + } + + /* adjacent to (but not overlapping)? (internal version) */ + bool + range_adjacent_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2) + { RangeBound lower1, lower2; RangeBound upper1, *************** *** 706,719 **** range_adjacent(PG_FUNCTION_ARGS) 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); /* * Given two ranges A..B and C..D, where B < C, the ranges are adjacent if --- 726,737 ---- if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2)) elog(ERROR, "range types do not match"); 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) ! return false; /* * Given two ranges A..B and C..D, where B < C, the ranges are adjacent if *************** *** 736,742 **** range_adjacent(PG_FUNCTION_ARGS) { /* in a continuous subtype, there are assumed to be points between */ if (!OidIsValid(typcache->rng_canonical_finfo.fn_oid)) ! PG_RETURN_BOOL(false); /* flip the inclusion flags */ upper1.inclusive = !upper1.inclusive; lower2.inclusive = !lower2.inclusive; --- 754,760 ---- { /* in a continuous subtype, there are assumed to be points between */ if (!OidIsValid(typcache->rng_canonical_finfo.fn_oid)) ! return (false); /* flip the inclusion flags */ upper1.inclusive = !upper1.inclusive; lower2.inclusive = !lower2.inclusive; *************** *** 744,754 **** range_adjacent(PG_FUNCTION_ARGS) upper1.lower = true; lower2.lower = false; r3 = make_range(typcache, &upper1, &lower2, false); ! PG_RETURN_BOOL(RangeIsEmpty(r3)); } if (cmp == 0) { ! PG_RETURN_BOOL(upper1.inclusive != lower2.inclusive); } cmp = range_cmp_bound_values(typcache, &upper2, &lower1); --- 762,772 ---- upper1.lower = true; lower2.lower = false; r3 = make_range(typcache, &upper1, &lower2, false); ! return RangeIsEmpty(r3); } if (cmp == 0) { ! return (upper1.inclusive != lower2.inclusive); } cmp = range_cmp_bound_values(typcache, &upper2, &lower1); *************** *** 756,762 **** range_adjacent(PG_FUNCTION_ARGS) { /* in a continuous subtype, there are assumed to be points between */ if (!OidIsValid(typcache->rng_canonical_finfo.fn_oid)) ! PG_RETURN_BOOL(false); /* flip the inclusion flags */ upper2.inclusive = !upper2.inclusive; lower1.inclusive = !lower1.inclusive; --- 774,780 ---- { /* in a continuous subtype, there are assumed to be points between */ if (!OidIsValid(typcache->rng_canonical_finfo.fn_oid)) ! return (false); /* flip the inclusion flags */ upper2.inclusive = !upper2.inclusive; lower1.inclusive = !lower1.inclusive; *************** *** 764,786 **** range_adjacent(PG_FUNCTION_ARGS) upper2.lower = true; lower1.lower = false; r3 = make_range(typcache, &upper2, &lower1, false); ! PG_RETURN_BOOL(RangeIsEmpty(r3)); } if (cmp == 0) { ! PG_RETURN_BOOL(upper2.inclusive != lower1.inclusive); } ! PG_RETURN_BOOL(false); } ! /* overlaps? */ Datum ! range_overlaps(PG_FUNCTION_ARGS) { RangeType *r1 = PG_GETARG_RANGE(0); RangeType *r2 = PG_GETARG_RANGE(1); TypeCacheEntry *typcache; RangeBound lower1, lower2; RangeBound upper1, --- 782,814 ---- upper2.lower = true; lower1.lower = false; r3 = make_range(typcache, &upper2, &lower1, false); ! return RangeIsEmpty(r3); } if (cmp == 0) { ! return (upper2.inclusive != lower1.inclusive); } ! return false; } ! /* adjacent to (but not overlapping)? */ Datum ! range_adjacent(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_adjacent_internal(typcache, r1, r2)); + } + + /* overlaps? (internal version) */ + bool + range_overlaps_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2) + { RangeBound lower1, lower2; RangeBound upper1, *************** *** 792,824 **** range_overlaps(PG_FUNCTION_ARGS) 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(typcache, &lower1, &lower2) >= 0 && range_cmp_bounds(typcache, &lower1, &upper2) <= 0) ! PG_RETURN_BOOL(true); if (range_cmp_bounds(typcache, &lower2, &lower1) >= 0 && range_cmp_bounds(typcache, &lower2, &upper1) <= 0) ! PG_RETURN_BOOL(true); ! PG_RETURN_BOOL(false); } ! /* does not extend to right of? */ Datum ! range_overleft(PG_FUNCTION_ARGS) { RangeType *r1 = PG_GETARG_RANGE(0); RangeType *r2 = PG_GETARG_RANGE(1); TypeCacheEntry *typcache; RangeBound lower1, lower2; RangeBound upper1, --- 820,860 ---- if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2)) elog(ERROR, "range types do not match"); 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) ! return false; if (range_cmp_bounds(typcache, &lower1, &lower2) >= 0 && range_cmp_bounds(typcache, &lower1, &upper2) <= 0) ! return true; if (range_cmp_bounds(typcache, &lower2, &lower1) >= 0 && range_cmp_bounds(typcache, &lower2, &upper1) <= 0) ! return true; ! return false; } ! /* overlaps? */ Datum ! range_overlaps(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_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, lower2; RangeBound upper1, *************** *** 830,857 **** range_overleft(PG_FUNCTION_ARGS) 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(typcache, &upper1, &upper2) <= 0) ! PG_RETURN_BOOL(true); ! 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; RangeBound lower1, lower2; RangeBound upper1, --- 866,901 ---- if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2)) elog(ERROR, "range types do not match"); 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) ! return false; if (range_cmp_bounds(typcache, &upper1, &upper2) <= 0) ! return true; ! return false; } ! /* does not extend to right of? */ Datum ! range_overleft(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_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, lower2; RangeBound upper1, *************** *** 863,870 **** range_overright(PG_FUNCTION_ARGS) 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); --- 907,912 ---- *************** *** 878,883 **** range_overright(PG_FUNCTION_ARGS) --- 920,938 ---- 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 */ *************** *** 2152,2158 **** range_bound_escape(const char *value) * Caller has already checked that they are the same range type, and looked up * the necessary typcache entry. */ ! static bool range_contains_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2) { RangeBound lower1; --- 2207,2213 ---- * Caller has already checked that they are the same range type, and looked up * the necessary typcache entry. */ ! bool range_contains_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2) { RangeBound lower1; *************** *** 2162,2167 **** range_contains_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2) --- 2217,2226 ---- RangeBound upper2; 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, r2, &lower2, &upper2, &empty2); *************** *** 2180,2189 **** range_contains_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2) return true; } /* * Test whether range r contains a specific element value. */ ! static bool range_contains_elem_internal(TypeCacheEntry *typcache, RangeType *r, Datum val) { RangeBound lower; --- 2239,2254 ---- 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. */ ! bool range_contains_elem_internal(TypeCacheEntry *typcache, RangeType *r, Datum val) { RangeBound lower; *** a/src/backend/utils/adt/rangetypes_gist.c --- b/src/backend/utils/adt/rangetypes_gist.c *************** *** 148,157 **** typedef struct static RangeType *range_super_union(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2); ! static bool range_gist_consistent_int(FmgrInfo *flinfo, StrategyNumber strategy, RangeType *key, Datum query); ! static bool range_gist_consistent_leaf(FmgrInfo *flinfo, StrategyNumber strategy, RangeType *key, Datum query); static void range_gist_fallback_split(TypeCacheEntry *typcache, --- 148,157 ---- static RangeType *range_super_union(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2); ! static bool range_gist_consistent_int(TypeCacheEntry *typcache, StrategyNumber strategy, RangeType *key, Datum query); ! static bool range_gist_consistent_leaf(TypeCacheEntry *typcache, StrategyNumber strategy, RangeType *key, Datum query); static void range_gist_fallback_split(TypeCacheEntry *typcache, *************** *** 191,205 **** range_gist_consistent(PG_FUNCTION_ARGS) /* Oid subtype = PG_GETARG_OID(3); */ bool *recheck = (bool *) PG_GETARG_POINTER(4); RangeType *key = DatumGetRangeType(entry->key); /* All operators served by this function are exact */ *recheck = false; if (GIST_LEAF(entry)) ! PG_RETURN_BOOL(range_gist_consistent_leaf(fcinfo->flinfo, strategy, key, query)); else ! PG_RETURN_BOOL(range_gist_consistent_int(fcinfo->flinfo, strategy, key, query)); } --- 191,208 ---- /* Oid subtype = PG_GETARG_OID(3); */ bool *recheck = (bool *) PG_GETARG_POINTER(4); RangeType *key = DatumGetRangeType(entry->key); + TypeCacheEntry *typcache; /* All operators served by this function are exact */ *recheck = false; + typcache = range_get_typcache(fcinfo, RangeTypeGetOid(key)); + if (GIST_LEAF(entry)) ! PG_RETURN_BOOL(range_gist_consistent_leaf(typcache, strategy, key, query)); else ! PG_RETURN_BOOL(range_gist_consistent_int(typcache, strategy, key, query)); } *************** *** 781,870 **** range_super_union(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2) } /* - * 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(FmgrInfo *flinfo, StrategyNumber strategy, RangeType *key, Datum query) { - PGFunction proc; - bool negate = false; - bool retval; - switch (strategy) { case RANGESTRAT_BEFORE: if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeType(query))) return false; ! proc = range_overright; ! negate = true; ! break; case RANGESTRAT_OVERLEFT: if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeType(query))) return false; ! proc = range_after; ! negate = true; ! break; case RANGESTRAT_OVERLAPS: ! proc = range_overlaps; ! break; case RANGESTRAT_OVERRIGHT: if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeType(query))) return false; ! proc = range_before; ! negate = true; ! break; case RANGESTRAT_AFTER: if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeType(query))) return false; ! proc = range_overleft; ! negate = true; ! break; case RANGESTRAT_ADJACENT: if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeType(query))) return false; ! if (DatumGetBool(TrickFunctionCall2(range_adjacent, flinfo, ! RangeTypeGetDatum(key), ! query))) return true; ! proc = range_overlaps; ! break; case RANGESTRAT_CONTAINS: ! proc = range_contains; ! break; case RANGESTRAT_CONTAINED_BY: /* --- 784,831 ---- } /* * GiST consistent test on an index internal page */ static bool ! range_gist_consistent_int(TypeCacheEntry *typcache, StrategyNumber strategy, RangeType *key, Datum query) { switch (strategy) { case RANGESTRAT_BEFORE: if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeType(query))) return false; ! return (!range_overright_internal(typcache, key, ! DatumGetRangeType(query))); case RANGESTRAT_OVERLEFT: if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeType(query))) return false; ! return (!range_after_internal(typcache, key, ! DatumGetRangeType(query))); case RANGESTRAT_OVERLAPS: ! return range_overlaps_internal(typcache, key, ! DatumGetRangeType(query)); case RANGESTRAT_OVERRIGHT: if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeType(query))) return false; ! return (!range_before_internal(typcache, key, ! DatumGetRangeType(query))); case RANGESTRAT_AFTER: if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeType(query))) return false; ! return (!range_overleft_internal(typcache, key, ! DatumGetRangeType(query))); case RANGESTRAT_ADJACENT: if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeType(query))) return false; ! if (range_adjacent_internal(typcache, key, ! DatumGetRangeType(query))) return true; ! return range_overlaps_internal(typcache, key, ! DatumGetRangeType(query)); case RANGESTRAT_CONTAINS: ! return range_contains_internal(typcache, key, ! DatumGetRangeType(query)); case RANGESTRAT_CONTAINED_BY: /* *************** *** 874,884 **** range_gist_consistent_int(FmgrInfo *flinfo, StrategyNumber strategy, */ if (RangeIsOrContainsEmpty(key)) return true; ! proc = range_overlaps; ! break; case RANGESTRAT_CONTAINS_ELEM: ! proc = range_contains_elem; ! break; case RANGESTRAT_EQ: /* --- 835,844 ---- */ if (RangeIsOrContainsEmpty(key)) return true; ! return range_overlaps_internal(typcache, key, ! DatumGetRangeType(query)); case RANGESTRAT_CONTAINS_ELEM: ! return range_contains_elem_internal(typcache, key, query); case RANGESTRAT_EQ: /* *************** *** 887,959 **** range_gist_consistent_int(FmgrInfo *flinfo, StrategyNumber strategy, */ if (RangeIsEmpty(DatumGetRangeType(query))) return RangeIsOrContainsEmpty(key); ! proc = range_contains; ! break; default: elog(ERROR, "unrecognized range strategy: %d", strategy); - proc = NULL; /* 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 */ static bool ! range_gist_consistent_leaf(FmgrInfo *flinfo, StrategyNumber strategy, RangeType *key, Datum query) { - PGFunction proc; - switch (strategy) { case RANGESTRAT_BEFORE: ! proc = range_before; ! break; case RANGESTRAT_OVERLEFT: ! proc = range_overleft; ! break; case RANGESTRAT_OVERLAPS: ! proc = range_overlaps; ! break; case RANGESTRAT_OVERRIGHT: ! proc = range_overright; ! break; case RANGESTRAT_AFTER: ! proc = range_after; ! break; case RANGESTRAT_ADJACENT: ! proc = range_adjacent; ! break; case RANGESTRAT_CONTAINS: ! proc = range_contains; ! break; case RANGESTRAT_CONTAINED_BY: ! proc = range_contained_by; ! break; case RANGESTRAT_CONTAINS_ELEM: ! proc = range_contains_elem; ! break; case RANGESTRAT_EQ: ! proc = range_eq; ! break; default: elog(ERROR, "unrecognized range strategy: %d", strategy); - proc = NULL; /* keep compiler quiet */ break; } ! return DatumGetBool(TrickFunctionCall2(proc, flinfo, ! RangeTypeGetDatum(key), ! query)); } /* --- 847,907 ---- */ if (RangeIsEmpty(DatumGetRangeType(query))) return RangeIsOrContainsEmpty(key); ! return range_contains_internal(typcache, key, ! DatumGetRangeType(query)); default: elog(ERROR, "unrecognized range strategy: %d", strategy); break; } ! /* Keep compiler quite */ ! return false; } /* * GiST consistent test on an index leaf page */ static bool ! range_gist_consistent_leaf(TypeCacheEntry *typcache, StrategyNumber strategy, RangeType *key, Datum query) { switch (strategy) { case RANGESTRAT_BEFORE: ! return range_before_internal(typcache, key, ! DatumGetRangeType(query)); case RANGESTRAT_OVERLEFT: ! return range_overleft_internal(typcache, key, ! DatumGetRangeType(query)); case RANGESTRAT_OVERLAPS: ! return range_overlaps_internal(typcache, key, ! DatumGetRangeType(query)); case RANGESTRAT_OVERRIGHT: ! return range_overright_internal(typcache, key, ! DatumGetRangeType(query)); case RANGESTRAT_AFTER: ! return range_after_internal(typcache, key, ! DatumGetRangeType(query)); case RANGESTRAT_ADJACENT: ! return range_adjacent_internal(typcache, key, ! DatumGetRangeType(query)); case RANGESTRAT_CONTAINS: ! return range_contains_internal(typcache, key, ! DatumGetRangeType(query)); case RANGESTRAT_CONTAINED_BY: ! return range_contained_by_internal(typcache, key, ! DatumGetRangeType(query)); case RANGESTRAT_CONTAINS_ELEM: ! return range_contains_elem_internal(typcache, key, query); case RANGESTRAT_EQ: ! return range_eq_internal(typcache, key, DatumGetRangeType(query)); default: elog(ERROR, "unrecognized range strategy: %d", strategy); break; } ! /* Keep compiler quite */ ! return false; } /* *** a/src/include/utils/rangetypes.h --- b/src/include/utils/rangetypes.h *************** *** 104,109 **** extern Datum range_upper_inf(PG_FUNCTION_ARGS); --- 104,111 ---- extern Datum range_contains_elem(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 */ extern Datum range_eq(PG_FUNCTION_ARGS); extern Datum range_ne(PG_FUNCTION_ARGS); *************** *** 116,121 **** extern Datum range_overlaps(PG_FUNCTION_ARGS); --- 118,135 ---- extern Datum range_overleft(PG_FUNCTION_ARGS); extern Datum range_overright(PG_FUNCTION_ARGS); + /* internal versions */ + 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 */ extern Datum range_minus(PG_FUNCTION_ARGS); extern Datum range_union(PG_FUNCTION_ARGS);