Skip to content

Commit bf4f96b

Browse files
committed
Fix range_cmp_bounds for the case of equal-valued exclusive bounds.
Also improve its comments and related regression tests. Jeff Davis, with some further adjustments by Tom
1 parent ef27c81 commit bf4f96b

File tree

3 files changed

+126
-26
lines changed

3 files changed

+126
-26
lines changed

src/backend/utils/adt/rangetypes.c

Lines changed: 65 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1622,33 +1622,89 @@ make_range(TypeCacheEntry *typcache, RangeBound *lower, RangeBound *upper,
16221622
return range;
16231623
}
16241624

1625+
/*
1626+
* Compare two range boundary points, returning <0, 0, or >0 according to
1627+
* whether b1 is less than, equal to, or greater than b2.
1628+
*
1629+
* The boundaries can be any combination of upper and lower; so it's useful
1630+
* for a variety of operators.
1631+
*
1632+
* The simple case is when b1 and b2 are both finite and inclusive, in which
1633+
* case the result is just a comparison of the values held in b1 and b2.
1634+
*
1635+
* If a bound is exclusive, then we need to know whether it's a lower bound,
1636+
* in which case we treat the boundary point as "just greater than" the held
1637+
* value; or an upper bound, in which case we treat the boundary point as
1638+
* "just less than" the held value.
1639+
*
1640+
* If a bound is infinite, it represents minus infinity (less than every other
1641+
* point) if it's a lower bound; or plus infinity (greater than every other
1642+
* point) if it's an upper bound.
1643+
*
1644+
* There is only one case where two boundaries compare equal but are not
1645+
* identical: when both bounds are inclusive and hold the same finite value,
1646+
* but one is an upper bound and the other a lower bound.
1647+
*/
16251648
int
16261649
range_cmp_bounds(TypeCacheEntry *typcache, RangeBound *b1, RangeBound *b2)
16271650
{
16281651
int32 result;
16291652

1653+
/*
1654+
* First, handle cases involving infinity, which don't require invoking
1655+
* the comparison proc.
1656+
*/
16301657
if (b1->infinite && b2->infinite)
16311658
{
1659+
/*
1660+
* Both are infinity, so they are equal unless one is lower and the
1661+
* other not.
1662+
*/
16321663
if (b1->lower == b2->lower)
16331664
return 0;
16341665
else
1635-
return (b1->lower) ? -1 : 1;
1666+
return b1->lower ? -1 : 1;
16361667
}
1637-
else if (b1->infinite && !b2->infinite)
1638-
return (b1->lower) ? -1 : 1;
1639-
else if (!b1->infinite && b2->infinite)
1640-
return (b2->lower) ? 1 : -1;
1668+
else if (b1->infinite)
1669+
return b1->lower ? -1 : 1;
1670+
else if (b2->infinite)
1671+
return b2->lower ? 1 : -1;
16411672

1673+
/*
1674+
* Both boundaries are finite, so compare the held values.
1675+
*/
16421676
result = DatumGetInt32(FunctionCall2Coll(&typcache->rng_cmp_proc_finfo,
16431677
typcache->rng_collation,
16441678
b1->val, b2->val));
16451679

1680+
/*
1681+
* If the comparison is anything other than equal, we're done. If they
1682+
* compare equal though, we still have to consider whether the boundaries
1683+
* are inclusive or exclusive.
1684+
*/
16461685
if (result == 0)
16471686
{
1648-
if (b1->inclusive && !b2->inclusive)
1649-
return (b2->lower) ? -1 : 1;
1650-
else if (!b1->inclusive && b2->inclusive)
1651-
return (b1->lower) ? 1 : -1;
1687+
if (!b1->inclusive && !b2->inclusive)
1688+
{
1689+
/* both are exclusive */
1690+
if (b1->lower == b2->lower)
1691+
return 0;
1692+
else
1693+
return b1->lower ? 1 : -1;
1694+
}
1695+
else if (!b1->inclusive)
1696+
return b1->lower ? 1 : -1;
1697+
else if (!b2->inclusive)
1698+
return b2->lower ? -1 : 1;
1699+
else
1700+
{
1701+
/*
1702+
* Both are inclusive and the values held are equal, so they are
1703+
* equal regardless of whether they are upper or lower boundaries,
1704+
* or a mix.
1705+
*/
1706+
return 0;
1707+
}
16521708
}
16531709

16541710
return result;

src/test/regress/expected/rangetypes.out

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,30 @@ ERROR: malformed range literal: "(a,])"
4848
LINE 1: select '(a,])'::textrange;
4949
^
5050
DETAIL: Junk after right parenthesis or bracket.
51+
select '( , )'::textrange;
52+
ERROR: range lower bound must be less than or equal to range upper bound
53+
LINE 1: select '( , )'::textrange;
54+
^
55+
select '("","")'::textrange;
56+
ERROR: range lower bound must be less than or equal to range upper bound
57+
LINE 1: select '("","")'::textrange;
58+
^
59+
select '(",",",")'::textrange;
60+
ERROR: range lower bound must be less than or equal to range upper bound
61+
LINE 1: select '(",",",")'::textrange;
62+
^
63+
select '("\\","\\")'::textrange;
64+
ERROR: range lower bound must be less than or equal to range upper bound
65+
LINE 1: select '("\\","\\")'::textrange;
66+
^
67+
select '[a,a)'::textrange;
68+
ERROR: range lower bound must be less than or equal to range upper bound
69+
LINE 1: select '[a,a)'::textrange;
70+
^
71+
select '(a,a]'::textrange;
72+
ERROR: range lower bound must be less than or equal to range upper bound
73+
LINE 1: select '(a,a]'::textrange;
74+
^
5175
-- should succeed
5276
select ' empty '::textrange;
5377
textrange
@@ -91,35 +115,36 @@ select '[a,]'::textrange;
91115
[a,)
92116
(1 row)
93117

94-
select '( , )'::textrange;
118+
select '(,)'::textrange;
95119
textrange
96120
-----------
97-
(" "," ")
121+
(,)
98122
(1 row)
99123

100-
select '("","")'::textrange;
124+
select '["",""]'::textrange;
101125
textrange
102126
-----------
103-
("","")
127+
["",""]
104128
(1 row)
105129

106-
select '["",""]'::textrange;
130+
select '[",",","]'::textrange;
107131
textrange
108132
-----------
109-
["",""]
133+
[",",","]
110134
(1 row)
111135

112-
select '(",",",")'::textrange;
136+
select '["\\","\\"]'::textrange;
137+
textrange
138+
-------------
139+
["\\","\\"]
140+
(1 row)
141+
142+
select '(\\,a)'::textrange;
113143
textrange
114144
-----------
115-
(",",",")
145+
("\\",a)
116146
(1 row)
117147

118-
select '("\\","\\")'::textrange
119-
select '(\\,a)'::textrange;
120-
ERROR: syntax error at or near "select"
121-
LINE 2: select '(\\,a)'::textrange;
122-
^
123148
select '((,z)'::textrange;
124149
textrange
125150
-----------
@@ -307,6 +332,18 @@ select numrange(1.0, 2.0) << numrange(3.0, 4.0);
307332
t
308333
(1 row)
309334

335+
select numrange(1.0, 3.0,'[]') << numrange(3.0, 4.0,'[]');
336+
?column?
337+
----------
338+
f
339+
(1 row)
340+
341+
select numrange(1.0, 3.0,'()') << numrange(3.0, 4.0,'()');
342+
?column?
343+
----------
344+
t
345+
(1 row)
346+
310347
select numrange(1.0, 2.0) >> numrange(3.0, 4.0);
311348
?column?
312349
----------

src/test/regress/sql/rangetypes.sql

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ select '(),a)'::textrange;
1515
select '(a,))'::textrange;
1616
select '(],a)'::textrange;
1717
select '(a,])'::textrange;
18+
select '( , )'::textrange;
19+
select '("","")'::textrange;
20+
select '(",",",")'::textrange;
21+
select '("\\","\\")'::textrange;
22+
select '[a,a)'::textrange;
23+
select '(a,a]'::textrange;
1824

1925
-- should succeed
2026
select ' empty '::textrange;
@@ -24,11 +30,10 @@ select '(,z)'::textrange;
2430
select '(a,)'::textrange;
2531
select '[,z]'::textrange;
2632
select '[a,]'::textrange;
27-
select '( , )'::textrange;
28-
select '("","")'::textrange;
33+
select '(,)'::textrange;
2934
select '["",""]'::textrange;
30-
select '(",",",")'::textrange;
31-
select '("\\","\\")'::textrange
35+
select '[",",","]'::textrange;
36+
select '["\\","\\"]'::textrange;
3237
select '(\\,a)'::textrange;
3338
select '((,z)'::textrange;
3439
select '([,z)'::textrange;
@@ -81,6 +86,8 @@ select range_minus(numrange(10.1,12.2,'[]'), numrange(0.0,120.2,'(]'));
8186

8287
select numrange(4.5, 5.5, '[]') && numrange(5.5, 6.5);
8388
select numrange(1.0, 2.0) << numrange(3.0, 4.0);
89+
select numrange(1.0, 3.0,'[]') << numrange(3.0, 4.0,'[]');
90+
select numrange(1.0, 3.0,'()') << numrange(3.0, 4.0,'()');
8491
select numrange(1.0, 2.0) >> numrange(3.0, 4.0);
8592
select numrange(3.0, 70.0) &< numrange(6.6, 100.0);
8693

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy