Skip to content

Commit b7056b8

Browse files
committed
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.
1 parent a912a27 commit b7056b8

File tree

1 file changed

+49
-11
lines changed

1 file changed

+49
-11
lines changed

src/backend/utils/adt/rangetypes.c

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,8 @@ range_adjacent(PG_FUNCTION_ARGS)
699699
upper2;
700700
bool empty1,
701701
empty2;
702+
RangeType *r3;
703+
int cmp;
702704

703705
/* Different types should be prevented by ANYRANGE matching rules */
704706
if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
@@ -714,23 +716,59 @@ range_adjacent(PG_FUNCTION_ARGS)
714716
PG_RETURN_BOOL(false);
715717

716718
/*
717-
* For two ranges to be adjacent, the lower boundary of one range has to
718-
* match the upper boundary of the other. However, the inclusivity of
719-
* those two boundaries must also be different.
719+
* Given two ranges A..B and C..D, where B < C, the ranges are adjacent
720+
* if and only if the range B..C is empty, where inclusivity of these two
721+
* bounds is inverted compared to the original bounds. For discrete
722+
* ranges, we have to rely on the canonicalization function to normalize
723+
* B..C to empty if it contains no elements of the subtype. (If there is
724+
* no canonicalization function, it's impossible for such a range to
725+
* normalize to empty, so we needn't bother to try.)
726+
*
727+
* If B == C, the ranges are adjacent only if these bounds have different
728+
* inclusive flags (i.e., exactly one of the ranges includes the common
729+
* boundary point).
720730
*
721-
* The semantics for range_cmp_bounds aren't quite what we need here, so
722-
* we do the comparison more directly.
731+
* And if B > C then the ranges cannot be adjacent in this order, but we
732+
* must consider the other order (i.e., check D <= A).
723733
*/
724-
if (lower1.inclusive != upper2.inclusive)
734+
cmp = range_cmp_bound_values(typcache, &upper1, &lower2);
735+
if (cmp < 0)
736+
{
737+
/* in a continuous subtype, there are assumed to be points between */
738+
if (!OidIsValid(typcache->rng_canonical_finfo.fn_oid))
739+
PG_RETURN_BOOL(false);
740+
/* flip the inclusion flags */
741+
upper1.inclusive = !upper1.inclusive;
742+
lower2.inclusive = !lower2.inclusive;
743+
/* change upper/lower labels to avoid Assert failures */
744+
upper1.lower = true;
745+
lower2.lower = false;
746+
r3 = make_range(typcache, &upper1, &lower2, false);
747+
PG_RETURN_BOOL(RangeIsEmpty(r3));
748+
}
749+
if (cmp == 0)
725750
{
726-
if (range_cmp_bound_values(typcache, &lower1, &upper2) == 0)
727-
PG_RETURN_BOOL(true);
751+
PG_RETURN_BOOL(upper1.inclusive != lower2.inclusive);
728752
}
729753

730-
if (upper1.inclusive != lower2.inclusive)
754+
cmp = range_cmp_bound_values(typcache, &upper2, &lower1);
755+
if (cmp < 0)
756+
{
757+
/* in a continuous subtype, there are assumed to be points between */
758+
if (!OidIsValid(typcache->rng_canonical_finfo.fn_oid))
759+
PG_RETURN_BOOL(false);
760+
/* flip the inclusion flags */
761+
upper2.inclusive = !upper2.inclusive;
762+
lower1.inclusive = !lower1.inclusive;
763+
/* change upper/lower labels to avoid Assert failures */
764+
upper2.lower = true;
765+
lower1.lower = false;
766+
r3 = make_range(typcache, &upper2, &lower1, false);
767+
PG_RETURN_BOOL(RangeIsEmpty(r3));
768+
}
769+
if (cmp == 0)
731770
{
732-
if (range_cmp_bound_values(typcache, &upper1, &lower2) == 0)
733-
PG_RETURN_BOOL(true);
771+
PG_RETURN_BOOL(upper2.inclusive != lower1.inclusive);
734772
}
735773

736774
PG_RETURN_BOOL(false);

0 commit comments

Comments
 (0)