1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-30 11:03:19 +03:00

Adjust range_adjacent to support different canonicalization rules.

The original coding would not work for discrete ranges in which the
canonicalization rule is to produce symmetric boundaries (either [] or ()
style), as noted by Jeff Davis.  Florian Pflug pointed out that we could
fix that by invoking the canonicalization function to see if the range
"between" the two given ranges normalizes to empty.  This implementation
of Florian's idea is a tad slower than the original code, but only in the
case where there actually is a canonicalization function --- if not, it's
essentially the same logic as before.
This commit is contained in:
Tom Lane
2011-11-23 17:13:02 -05:00
parent a912a2784b
commit b7056b8324

View File

@ -699,6 +699,8 @@ range_adjacent(PG_FUNCTION_ARGS)
upper2; upper2;
bool empty1, bool empty1,
empty2; empty2;
RangeType *r3;
int cmp;
/* Different types should be prevented by ANYRANGE matching rules */ /* Different types should be prevented by ANYRANGE matching rules */
if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2)) if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
@ -714,23 +716,59 @@ range_adjacent(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(false); PG_RETURN_BOOL(false);
/* /*
* For two ranges to be adjacent, the lower boundary of one range has to * Given two ranges A..B and C..D, where B < C, the ranges are adjacent
* match the upper boundary of the other. However, the inclusivity of * if and only if the range B..C is empty, where inclusivity of these two
* those two boundaries must also be different. * 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 there is
* no canonicalization function, it's impossible for such a range to
* normalize to empty, so we needn't bother to try.)
* *
* The semantics for range_cmp_bounds aren't quite what we need here, so * If B == C, the ranges are adjacent only if these bounds have different
* we do the comparison more directly. * inclusive flags (i.e., exactly one of the ranges includes the common
* boundary point).
*
* 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).
*/ */
if (lower1.inclusive != upper2.inclusive) cmp = range_cmp_bound_values(typcache, &upper1, &lower2);
if (cmp < 0)
{ {
if (range_cmp_bound_values(typcache, &lower1, &upper2) == 0) /* in a continuous subtype, there are assumed to be points between */
PG_RETURN_BOOL(true); if (!OidIsValid(typcache->rng_canonical_finfo.fn_oid))
PG_RETURN_BOOL(false);
/* flip the inclusion flags */
upper1.inclusive = !upper1.inclusive;
lower2.inclusive = !lower2.inclusive;
/* change upper/lower labels to avoid Assert failures */
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);
} }
if (upper1.inclusive != lower2.inclusive) cmp = range_cmp_bound_values(typcache, &upper2, &lower1);
if (cmp < 0)
{ {
if (range_cmp_bound_values(typcache, &upper1, &lower2) == 0) /* in a continuous subtype, there are assumed to be points between */
PG_RETURN_BOOL(true); if (!OidIsValid(typcache->rng_canonical_finfo.fn_oid))
PG_RETURN_BOOL(false);
/* flip the inclusion flags */
upper2.inclusive = !upper2.inclusive;
lower1.inclusive = !lower1.inclusive;
/* change upper/lower labels to avoid Assert failures */
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); PG_RETURN_BOOL(false);