notrickfunctioncall-0.1.patch

application/octet-stream

Filename: notrickfunctioncall-0.1.patch
Type: application/octet-stream
Part: 0
Message: Re: SP-GiST for ranges based on 2d-mapping and quad-tree

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: context
File+
src/backend/utils/adt/rangetypes.c 142 0
src/backend/utils/adt/rangetypes_gist.c 52 0
src/include/utils/rangetypes.h 14 0
*** 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);