Florian Pflug <f...@phlo.org> writes:
> More formally, let there be two arbitrary ranges
>   a,b,i_a,i_b
>   c,d,i_c,i_d
> where the first two parameters are the lower respectively upper bound, and
> the last two are booleans saying whether the lower respectively upper bound
> is inclusive (true) or exclusive (false).

> These ranges are then adjacent exactly if the range
>   b,c,!i_b,!i_c
> is empty.

I tried to implement this, and I think it has a small bug.  It works as
stated if we have b < c.  However, if we have b == c, then we want to
consider the ranges adjacent if i_b != i_c (ie, only one of them claims
the common boundary point).  But a singleton range is empty unless it's
inclusive on both sides.  So we have to have a special case when the
bounds are equal.

(If b > c, then of course we have to consider the two ranges in the
opposite order.)

Attached is a draft patch for this.  It passes regression tests but I've
not tried to exercise it with a canonical function that actually does
something different.  It's going to be a bit slower than Jeff's
original, because it does not only range_cmp_bound_values but also a
make_range cycle (in most cases).  So I guess the question is how much
we care about supporting canonical functions with non-default policies.
Thoughts?

                        regards, tom lane

diff --git a/src/backend/utils/adt/rangetypes.c b/src/backend/utils/adt/rangetypes.c
index 3326cb17c895273fd01c4eda5eb0d65a521d0168..890b6850cb6f5611e9afa922b85b0c64125f31bb 100644
*** a/src/backend/utils/adt/rangetypes.c
--- b/src/backend/utils/adt/rangetypes.c
*************** range_adjacent(PG_FUNCTION_ARGS)
*** 699,704 ****
--- 699,706 ----
  				upper2;
  	bool		empty1,
  				empty2;
+ 	RangeType  *r3;
+ 	int			cmp;
  
  	/* Different types should be prevented by ANYRANGE matching rules */
  	if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
*************** range_adjacent(PG_FUNCTION_ARGS)
*** 714,736 ****
  		PG_RETURN_BOOL(false);
  
  	/*
! 	 * For two ranges to be adjacent, the lower boundary of one range has to
! 	 * match the upper boundary of the other. However, the inclusivity of
! 	 * those two boundaries must also be different.
! 	 *
! 	 * The semantics for range_cmp_bounds aren't quite what we need here, so
! 	 * we do the comparison more directly.
  	 */
! 	if (lower1.inclusive != upper2.inclusive)
  	{
! 		if (range_cmp_bound_values(typcache, &lower1, &upper2) == 0)
! 			PG_RETURN_BOOL(true);
  	}
! 
! 	if (upper1.inclusive != lower2.inclusive)
  	{
! 		if (range_cmp_bound_values(typcache, &upper1, &lower2) == 0)
! 			PG_RETURN_BOOL(true);
  	}
  
  	PG_RETURN_BOOL(false);
--- 716,758 ----
  		PG_RETURN_BOOL(false);
  
  	/*
! 	 * Given two ranges A..B and C..D, where B < C, the ranges are adjacent
! 	 * if and only if the range B..C is empty, where inclusivity of these two
! 	 * bounds is inverted compared to the original bounds.  For discrete
! 	 * ranges, we have to rely on the canonicalization function to normalize
! 	 * B..C to empty if it contains no elements of the subtype.  If B == C,
! 	 * the ranges are adjacent only if these bounds have different inclusive
! 	 * flags (i.e., exactly one of the ranges includes the common boundary).
! 	 * And if B > C then the ranges cannot be adjacent in this order, but we
! 	 * must consider the other order (i.e., check D <= A).
  	 */
! 	cmp = range_cmp_bound_values(typcache, &upper1, &lower2);
! 	if (cmp < 0)
  	{
! 		upper1.inclusive = !upper1.inclusive;
! 		upper1.lower = true;
! 		lower2.inclusive = !lower2.inclusive;
! 		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);
! 	if (cmp < 0)
! 	{
! 		upper2.inclusive = !upper2.inclusive;
! 		upper2.lower = true;
! 		lower1.inclusive = !lower1.inclusive;
! 		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);
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to