Re: range_adjacent and discrete ranges

Поиск
Список
Период
Сортировка
От Tom Lane
Тема Re: range_adjacent and discrete ranges
Дата
Msg-id 11024.1322016048@sss.pgh.pa.us
обсуждение исходный текст
Ответ на Re: range_adjacent and discrete ranges  (Florian Pflug <fgp@phlo.org>)
Ответы Re: range_adjacent and discrete ranges  (Tom Lane <tgl@sss.pgh.pa.us>)
Список pgsql-hackers
Florian Pflug <fgp@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);

В списке pgsql-hackers по дате отправления:

Предыдущее
От: Peter Geoghegan
Дата:
Сообщение: Re: Inlining comparators as a performance optimisation
Следующее
От: Tom Lane
Дата:
Сообщение: Re: Permissions checks for range-type support functions