postgresqlrangeinfinity

Why does `upper_inf` return false when the range uses `infinity` as an explicit upper boundary?


PostgreSQL range docs suggest that the magic timestamp infinity should work the same as omitting the bounding value:

Element types that have the notion of “infinity” can use them as explicit bound values. For example, with timestamp ranges, [today,infinity) excludes the special timestamp value infinity, while [today,infinity] include it, as does [today,) and [today,].

The functions lower_inf and upper_inf test for infinite lower and upper bounds of a range, respectively.

Yet when using upper_inf to test whether the range (or multirange) includes infinity, the result is always false with the infinity in place:

SELECT * FROM (
    SELECT 1 AS test, upper_inf('{(,)}'::tstzmultirange)
    UNION SELECT 2, upper_inf('{(,infinity)}'::tstzmultirange)
    UNION SELECT 3, upper_inf('{(,]}'::tstzmultirange)
    UNION SELECT 4, upper_inf('{(,infinity]}'::tstzmultirange)
    UNION SELECT 5, upper_inf('(,)'::tstzrange)
    UNION SELECT 6, upper_inf('(,infinity)'::tstzrange)
    UNION SELECT 7, upper_inf('(,]'::tstzrange)
    UNION SELECT 8, upper_inf('(,infinity]'::tstzrange)
) AS cases ORDER BY test;

Produces:

1   true
2   false
3   true
4   false
5   true
6   false
7   true
8   false

Why?


Solution

  • Adrian Klaver correctly pointed out another section of the docs that I have missed:

    upper_inf ( anyrange ) → boolean
    Does the range have no upper bound? (An upper bound of Infinity returns false.)
    upper_inf('(,)'::daterange) → t
    

    So, upper_inf tests whether the upper bound is explicitly set, rather than what it is.

    Infinity means "unlimited", so the "end value of the range" effectively doesn't exist (any value above the lower end will be within the range). Still, the range itself defines infinity as its upper end, so technically speaking, the upper bound is set.

    It kind of makes sense. But it's also rather confusing.