2011-11-22 22:05:49 +01:00
|
|
|
-- Tests for range data types.
|
2011-11-03 12:16:28 +01:00
|
|
|
--
|
2011-11-22 22:05:49 +01:00
|
|
|
-- test input parser
|
2022-02-08 21:30:38 +01:00
|
|
|
-- (type textrange was already made in test_setup.sql)
|
2011-11-03 12:16:28 +01:00
|
|
|
--
|
|
|
|
-- negative tests; should fail
|
|
|
|
select ''::textrange;
|
|
|
|
ERROR: malformed range literal: ""
|
|
|
|
LINE 1: select ''::textrange;
|
|
|
|
^
|
|
|
|
DETAIL: Missing left parenthesis or bracket.
|
|
|
|
select '-[a,z)'::textrange;
|
|
|
|
ERROR: malformed range literal: "-[a,z)"
|
|
|
|
LINE 1: select '-[a,z)'::textrange;
|
|
|
|
^
|
|
|
|
DETAIL: Missing left parenthesis or bracket.
|
|
|
|
select '[a,z) - '::textrange;
|
|
|
|
ERROR: malformed range literal: "[a,z) - "
|
|
|
|
LINE 1: select '[a,z) - '::textrange;
|
|
|
|
^
|
|
|
|
DETAIL: Junk after right parenthesis or bracket.
|
|
|
|
select '(",a)'::textrange;
|
|
|
|
ERROR: malformed range literal: "(",a)"
|
|
|
|
LINE 1: select '(",a)'::textrange;
|
|
|
|
^
|
|
|
|
DETAIL: Unexpected end of input.
|
|
|
|
select '(,,a)'::textrange;
|
|
|
|
ERROR: malformed range literal: "(,,a)"
|
|
|
|
LINE 1: select '(,,a)'::textrange;
|
|
|
|
^
|
2011-11-22 22:05:49 +01:00
|
|
|
DETAIL: Too many commas.
|
2011-11-03 12:16:28 +01:00
|
|
|
select '(),a)'::textrange;
|
|
|
|
ERROR: malformed range literal: "(),a)"
|
|
|
|
LINE 1: select '(),a)'::textrange;
|
|
|
|
^
|
2011-11-22 22:05:49 +01:00
|
|
|
DETAIL: Missing comma after lower bound.
|
2011-11-03 12:16:28 +01:00
|
|
|
select '(a,))'::textrange;
|
|
|
|
ERROR: malformed range literal: "(a,))"
|
|
|
|
LINE 1: select '(a,))'::textrange;
|
|
|
|
^
|
|
|
|
DETAIL: Junk after right parenthesis or bracket.
|
|
|
|
select '(],a)'::textrange;
|
|
|
|
ERROR: malformed range literal: "(],a)"
|
|
|
|
LINE 1: select '(],a)'::textrange;
|
|
|
|
^
|
2011-11-22 22:05:49 +01:00
|
|
|
DETAIL: Missing comma after lower bound.
|
2011-11-03 12:16:28 +01:00
|
|
|
select '(a,])'::textrange;
|
|
|
|
ERROR: malformed range literal: "(a,])"
|
|
|
|
LINE 1: select '(a,])'::textrange;
|
|
|
|
^
|
|
|
|
DETAIL: Junk after right parenthesis or bracket.
|
2011-11-22 22:05:49 +01:00
|
|
|
select '[z,a]'::textrange;
|
2011-11-17 22:50:32 +01:00
|
|
|
ERROR: range lower bound must be less than or equal to range upper bound
|
2011-11-22 22:05:49 +01:00
|
|
|
LINE 1: select '[z,a]'::textrange;
|
2011-11-17 22:50:32 +01:00
|
|
|
^
|
2011-11-03 12:16:28 +01:00
|
|
|
-- should succeed
|
|
|
|
select ' empty '::textrange;
|
|
|
|
textrange
|
|
|
|
-----------
|
|
|
|
empty
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select ' ( empty, empty ) '::textrange;
|
|
|
|
textrange
|
|
|
|
----------------------
|
|
|
|
(" empty"," empty ")
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select ' ( " a " " a ", " z " " z " ) '::textrange;
|
|
|
|
textrange
|
|
|
|
--------------------------
|
|
|
|
(" a a "," z z ")
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select '(a,)'::textrange;
|
|
|
|
textrange
|
|
|
|
-----------
|
|
|
|
(a,)
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select '[,z]'::textrange;
|
|
|
|
textrange
|
|
|
|
-----------
|
|
|
|
(,z]
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select '[a,]'::textrange;
|
|
|
|
textrange
|
|
|
|
-----------
|
|
|
|
[a,)
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-17 22:50:32 +01:00
|
|
|
select '(,)'::textrange;
|
2011-11-03 12:16:28 +01:00
|
|
|
textrange
|
|
|
|
-----------
|
2011-11-17 22:50:32 +01:00
|
|
|
(,)
|
2011-11-03 12:16:28 +01:00
|
|
|
(1 row)
|
|
|
|
|
2011-11-22 22:05:49 +01:00
|
|
|
select '[ , ]'::textrange;
|
|
|
|
textrange
|
|
|
|
-----------
|
|
|
|
[" "," "]
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-17 22:50:32 +01:00
|
|
|
select '["",""]'::textrange;
|
2011-11-03 12:16:28 +01:00
|
|
|
textrange
|
|
|
|
-----------
|
2011-11-17 22:50:32 +01:00
|
|
|
["",""]
|
2011-11-03 12:16:28 +01:00
|
|
|
(1 row)
|
|
|
|
|
2011-11-17 22:50:32 +01:00
|
|
|
select '[",",","]'::textrange;
|
2011-11-03 12:16:28 +01:00
|
|
|
textrange
|
|
|
|
-----------
|
2011-11-17 22:50:32 +01:00
|
|
|
[",",","]
|
2011-11-03 12:16:28 +01:00
|
|
|
(1 row)
|
|
|
|
|
2011-11-17 22:50:32 +01:00
|
|
|
select '["\\","\\"]'::textrange;
|
|
|
|
textrange
|
|
|
|
-------------
|
|
|
|
["\\","\\"]
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select '(\\,a)'::textrange;
|
2011-11-03 12:16:28 +01:00
|
|
|
textrange
|
|
|
|
-----------
|
2011-11-17 22:50:32 +01:00
|
|
|
("\\",a)
|
2011-11-03 12:16:28 +01:00
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select '((,z)'::textrange;
|
|
|
|
textrange
|
|
|
|
-----------
|
|
|
|
("(",z)
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select '([,z)'::textrange;
|
|
|
|
textrange
|
|
|
|
-----------
|
|
|
|
("[",z)
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select '(!,()'::textrange;
|
|
|
|
textrange
|
|
|
|
-----------
|
|
|
|
(!,"(")
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select '(!,[)'::textrange;
|
|
|
|
textrange
|
|
|
|
-----------
|
|
|
|
(!,"[")
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-22 22:05:49 +01:00
|
|
|
select '[a,a]'::textrange;
|
|
|
|
textrange
|
|
|
|
-----------
|
|
|
|
[a,a]
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
-- these are allowed but normalize to empty:
|
|
|
|
select '[a,a)'::textrange;
|
|
|
|
textrange
|
|
|
|
-----------
|
|
|
|
empty
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select '(a,a]'::textrange;
|
|
|
|
textrange
|
|
|
|
-----------
|
|
|
|
empty
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select '(a,a)'::textrange;
|
|
|
|
textrange
|
|
|
|
-----------
|
|
|
|
empty
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-03 12:16:28 +01:00
|
|
|
--
|
|
|
|
-- create some test data and test the operators
|
|
|
|
--
|
|
|
|
CREATE TABLE numrange_test (nr NUMRANGE);
|
|
|
|
create index numrange_test_btree on numrange_test(nr);
|
|
|
|
INSERT INTO numrange_test VALUES('[,)');
|
|
|
|
INSERT INTO numrange_test VALUES('[3,]');
|
|
|
|
INSERT INTO numrange_test VALUES('[, 5)');
|
|
|
|
INSERT INTO numrange_test VALUES(numrange(1.1, 2.2));
|
|
|
|
INSERT INTO numrange_test VALUES('empty');
|
2011-11-23 02:45:05 +01:00
|
|
|
INSERT INTO numrange_test VALUES(numrange(1.7, 1.7, '[]'));
|
2011-11-22 22:05:49 +01:00
|
|
|
SELECT nr, isempty(nr), lower(nr), upper(nr) FROM numrange_test;
|
|
|
|
nr | isempty | lower | upper
|
|
|
|
-----------+---------+-------+-------
|
|
|
|
(,) | f | |
|
|
|
|
[3,) | f | 3 |
|
|
|
|
(,5) | f | | 5
|
|
|
|
[1.1,2.2) | f | 1.1 | 2.2
|
|
|
|
empty | t | |
|
|
|
|
[1.7,1.7] | f | 1.7 | 1.7
|
2011-11-03 12:16:28 +01:00
|
|
|
(6 rows)
|
|
|
|
|
2011-11-22 22:05:49 +01:00
|
|
|
SELECT nr, lower_inc(nr), lower_inf(nr), upper_inc(nr), upper_inf(nr) FROM numrange_test;
|
|
|
|
nr | lower_inc | lower_inf | upper_inc | upper_inf
|
|
|
|
-----------+-----------+-----------+-----------+-----------
|
|
|
|
(,) | f | t | f | t
|
|
|
|
[3,) | t | f | f | t
|
|
|
|
(,5) | f | t | f | f
|
|
|
|
[1.1,2.2) | t | f | f | f
|
|
|
|
empty | f | f | f | f
|
|
|
|
[1.7,1.7] | t | f | t | f
|
|
|
|
(6 rows)
|
2011-11-03 12:16:28 +01:00
|
|
|
|
2011-11-17 00:21:34 +01:00
|
|
|
SELECT * FROM numrange_test WHERE range_contains(nr, numrange(1.9,1.91));
|
2011-11-03 12:16:28 +01:00
|
|
|
nr
|
|
|
|
-----------
|
|
|
|
(,)
|
|
|
|
(,5)
|
|
|
|
[1.1,2.2)
|
|
|
|
(3 rows)
|
|
|
|
|
|
|
|
SELECT * FROM numrange_test WHERE nr @> numrange(1.0,10000.1);
|
|
|
|
nr
|
|
|
|
-----
|
|
|
|
(,)
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-17 00:21:34 +01:00
|
|
|
SELECT * FROM numrange_test WHERE range_contained_by(numrange(-1e7,-10000.1), nr);
|
2011-11-03 12:16:28 +01:00
|
|
|
nr
|
|
|
|
------
|
|
|
|
(,)
|
|
|
|
(,5)
|
|
|
|
(2 rows)
|
|
|
|
|
|
|
|
SELECT * FROM numrange_test WHERE 1.9 <@ nr;
|
|
|
|
nr
|
|
|
|
-----------
|
|
|
|
(,)
|
|
|
|
(,5)
|
|
|
|
[1.1,2.2)
|
|
|
|
(3 rows)
|
|
|
|
|
2011-11-22 22:05:49 +01:00
|
|
|
select * from numrange_test where nr = 'empty';
|
2011-11-03 12:16:28 +01:00
|
|
|
nr
|
|
|
|
-------
|
|
|
|
empty
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-22 22:05:49 +01:00
|
|
|
select * from numrange_test where nr = '(1.1, 2.2)';
|
2011-11-03 12:16:28 +01:00
|
|
|
nr
|
|
|
|
----
|
|
|
|
(0 rows)
|
|
|
|
|
2011-11-22 22:05:49 +01:00
|
|
|
select * from numrange_test where nr = '[1.1, 2.2)';
|
2011-11-03 12:16:28 +01:00
|
|
|
nr
|
|
|
|
-----------
|
|
|
|
[1.1,2.2)
|
|
|
|
(1 row)
|
|
|
|
|
2015-01-30 18:30:38 +01:00
|
|
|
select * from numrange_test where nr < 'empty';
|
|
|
|
nr
|
|
|
|
----
|
|
|
|
(0 rows)
|
|
|
|
|
2011-11-22 22:05:49 +01:00
|
|
|
select * from numrange_test where nr < numrange(-1000.0, -1000.0,'[]');
|
|
|
|
nr
|
|
|
|
-------
|
|
|
|
(,)
|
|
|
|
(,5)
|
|
|
|
empty
|
|
|
|
(3 rows)
|
|
|
|
|
|
|
|
select * from numrange_test where nr < numrange(0.0, 1.0,'[]');
|
|
|
|
nr
|
|
|
|
-------
|
|
|
|
(,)
|
|
|
|
(,5)
|
|
|
|
empty
|
|
|
|
(3 rows)
|
|
|
|
|
|
|
|
select * from numrange_test where nr < numrange(1000.0, 1001.0,'[]');
|
|
|
|
nr
|
|
|
|
-----------
|
|
|
|
(,)
|
|
|
|
[3,)
|
|
|
|
(,5)
|
|
|
|
[1.1,2.2)
|
|
|
|
empty
|
|
|
|
[1.7,1.7]
|
|
|
|
(6 rows)
|
|
|
|
|
2015-01-30 18:30:38 +01:00
|
|
|
select * from numrange_test where nr <= 'empty';
|
|
|
|
nr
|
|
|
|
-------
|
|
|
|
empty
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select * from numrange_test where nr >= 'empty';
|
|
|
|
nr
|
|
|
|
-----------
|
|
|
|
(,)
|
|
|
|
[3,)
|
|
|
|
(,5)
|
|
|
|
[1.1,2.2)
|
|
|
|
empty
|
|
|
|
[1.7,1.7]
|
|
|
|
(6 rows)
|
|
|
|
|
|
|
|
select * from numrange_test where nr > 'empty';
|
|
|
|
nr
|
|
|
|
-----------
|
|
|
|
(,)
|
|
|
|
[3,)
|
|
|
|
(,5)
|
|
|
|
[1.1,2.2)
|
|
|
|
[1.7,1.7]
|
|
|
|
(5 rows)
|
|
|
|
|
2011-11-22 22:05:49 +01:00
|
|
|
select * from numrange_test where nr > numrange(-1001.0, -1000.0,'[]');
|
|
|
|
nr
|
|
|
|
-----------
|
|
|
|
[3,)
|
|
|
|
[1.1,2.2)
|
|
|
|
[1.7,1.7]
|
|
|
|
(3 rows)
|
|
|
|
|
|
|
|
select * from numrange_test where nr > numrange(0.0, 1.0,'[]');
|
|
|
|
nr
|
|
|
|
-----------
|
|
|
|
[3,)
|
|
|
|
[1.1,2.2)
|
|
|
|
[1.7,1.7]
|
|
|
|
(3 rows)
|
|
|
|
|
|
|
|
select * from numrange_test where nr > numrange(1000.0, 1000.0,'[]');
|
|
|
|
nr
|
|
|
|
----
|
|
|
|
(0 rows)
|
|
|
|
|
2011-11-03 12:16:28 +01:00
|
|
|
select numrange(2.0, 1.0);
|
|
|
|
ERROR: range lower bound must be less than or equal to range upper bound
|
|
|
|
select numrange(2.0, 3.0) -|- numrange(3.0, 4.0);
|
|
|
|
?column?
|
|
|
|
----------
|
|
|
|
t
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-17 00:21:34 +01:00
|
|
|
select range_adjacent(numrange(2.0, 3.0), numrange(3.1, 4.0));
|
|
|
|
range_adjacent
|
|
|
|
----------------
|
2011-11-03 12:16:28 +01:00
|
|
|
f
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-22 22:05:49 +01:00
|
|
|
select range_adjacent(numrange(2.0, 3.0), numrange(3.1, null));
|
|
|
|
range_adjacent
|
|
|
|
----------------
|
|
|
|
f
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-03 12:16:28 +01:00
|
|
|
select numrange(2.0, 3.0, '[]') -|- numrange(3.0, 4.0, '()');
|
|
|
|
?column?
|
|
|
|
----------
|
|
|
|
t
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select numrange(1.0, 2.0) -|- numrange(2.0, 3.0,'[]');
|
|
|
|
?column?
|
|
|
|
----------
|
|
|
|
t
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-17 00:21:34 +01:00
|
|
|
select range_adjacent(numrange(2.0, 3.0, '(]'), numrange(1.0, 2.0, '(]'));
|
|
|
|
range_adjacent
|
|
|
|
----------------
|
2011-11-03 12:16:28 +01:00
|
|
|
t
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select numrange(1.1, 3.3) <@ numrange(0.1,10.1);
|
|
|
|
?column?
|
|
|
|
----------
|
|
|
|
t
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select numrange(0.1, 10.1) <@ numrange(1.1,3.3);
|
|
|
|
?column?
|
|
|
|
----------
|
|
|
|
f
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select numrange(1.1, 2.2) - numrange(2.0, 3.0);
|
|
|
|
?column?
|
|
|
|
-----------
|
|
|
|
[1.1,2.0)
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select numrange(1.1, 2.2) - numrange(2.2, 3.0);
|
|
|
|
?column?
|
|
|
|
-----------
|
|
|
|
[1.1,2.2)
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select numrange(1.1, 2.2,'[]') - numrange(2.0, 3.0);
|
|
|
|
?column?
|
|
|
|
-----------
|
|
|
|
[1.1,2.0)
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-17 00:21:34 +01:00
|
|
|
select range_minus(numrange(10.1,12.2,'[]'), numrange(110.0,120.2,'(]'));
|
|
|
|
range_minus
|
2011-11-03 12:16:28 +01:00
|
|
|
-------------
|
|
|
|
[10.1,12.2]
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-17 00:21:34 +01:00
|
|
|
select range_minus(numrange(10.1,12.2,'[]'), numrange(0.0,120.2,'(]'));
|
|
|
|
range_minus
|
|
|
|
-------------
|
2011-11-03 12:16:28 +01:00
|
|
|
empty
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select numrange(4.5, 5.5, '[]') && numrange(5.5, 6.5);
|
|
|
|
?column?
|
|
|
|
----------
|
|
|
|
t
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select numrange(1.0, 2.0) << numrange(3.0, 4.0);
|
|
|
|
?column?
|
|
|
|
----------
|
|
|
|
t
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-17 22:50:32 +01:00
|
|
|
select numrange(1.0, 3.0,'[]') << numrange(3.0, 4.0,'[]');
|
|
|
|
?column?
|
|
|
|
----------
|
|
|
|
f
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select numrange(1.0, 3.0,'()') << numrange(3.0, 4.0,'()');
|
|
|
|
?column?
|
|
|
|
----------
|
|
|
|
t
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-03 12:16:28 +01:00
|
|
|
select numrange(1.0, 2.0) >> numrange(3.0, 4.0);
|
|
|
|
?column?
|
|
|
|
----------
|
|
|
|
f
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select numrange(3.0, 70.0) &< numrange(6.6, 100.0);
|
|
|
|
?column?
|
|
|
|
----------
|
|
|
|
t
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select numrange(1.1, 2.2) < numrange(1.0, 200.2);
|
|
|
|
?column?
|
|
|
|
----------
|
|
|
|
f
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select numrange(1.1, 2.2) < numrange(1.1, 1.2);
|
|
|
|
?column?
|
|
|
|
----------
|
|
|
|
f
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select numrange(1.0, 2.0) + numrange(2.0, 3.0);
|
|
|
|
?column?
|
|
|
|
-----------
|
|
|
|
[1.0,3.0)
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select numrange(1.0, 2.0) + numrange(1.5, 3.0);
|
|
|
|
?column?
|
|
|
|
-----------
|
|
|
|
[1.0,3.0)
|
|
|
|
(1 row)
|
|
|
|
|
2015-05-05 20:22:24 +02:00
|
|
|
select numrange(1.0, 2.0) + numrange(2.5, 3.0); -- should fail
|
2011-11-14 19:59:34 +01:00
|
|
|
ERROR: result of range union would not be contiguous
|
2015-05-05 20:22:24 +02:00
|
|
|
select range_merge(numrange(1.0, 2.0), numrange(2.0, 3.0));
|
|
|
|
range_merge
|
|
|
|
-------------
|
|
|
|
[1.0,3.0)
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select range_merge(numrange(1.0, 2.0), numrange(1.5, 3.0));
|
|
|
|
range_merge
|
|
|
|
-------------
|
|
|
|
[1.0,3.0)
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select range_merge(numrange(1.0, 2.0), numrange(2.5, 3.0)); -- shouldn't fail
|
|
|
|
range_merge
|
|
|
|
-------------
|
|
|
|
[1.0,3.0)
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-03 12:16:28 +01:00
|
|
|
select numrange(1.0, 2.0) * numrange(2.0, 3.0);
|
|
|
|
?column?
|
|
|
|
----------
|
|
|
|
empty
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select numrange(1.0, 2.0) * numrange(1.5, 3.0);
|
|
|
|
?column?
|
|
|
|
-----------
|
|
|
|
[1.5,2.0)
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select numrange(1.0, 2.0) * numrange(2.5, 3.0);
|
|
|
|
?column?
|
|
|
|
----------
|
|
|
|
empty
|
|
|
|
(1 row)
|
|
|
|
|
Multirange datatypes
Multiranges are basically sorted arrays of non-overlapping ranges with
set-theoretic operations defined over them.
Since v14, each range type automatically gets a corresponding multirange
datatype. There are both manual and automatic mechanisms for naming multirange
types. Once can specify multirange type name using multirange_type_name
attribute in CREATE TYPE. Otherwise, a multirange type name is generated
automatically. If the range type name contains "range" then we change that to
"multirange". Otherwise, we add "_multirange" to the end.
Implementation of multiranges comes with a space-efficient internal
representation format, which evades extra paddings and duplicated storage of
oids. Altogether this format allows fetching a particular range by its index
in O(n).
Statistic gathering and selectivity estimation are implemented for multiranges.
For this purpose, stored multirange is approximated as union range without gaps.
This field will likely need improvements in the future.
Catversion is bumped.
Discussion: https://postgr.es/m/CALNJ-vSUpQ_Y%3DjXvTxt1VYFztaBSsWVXeF1y6gTYQ4bOiWDLgQ%40mail.gmail.com
Discussion: https://postgr.es/m/a0b8026459d1e6167933be2104a6174e7d40d0ab.camel%40j-davis.com#fe7218c83b08068bfffb0c5293eceda0
Author: Paul Jungwirth, revised by me
Reviewed-by: David Fetter, Corey Huinker, Jeff Davis, Pavel Stehule
Reviewed-by: Alvaro Herrera, Tom Lane, Isaac Morland, David G. Johnston
Reviewed-by: Zhihong Yu, Alexander Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
select range_intersect_agg(nr) from numrange_test;
|
|
|
|
range_intersect_agg
|
|
|
|
---------------------
|
|
|
|
empty
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select range_intersect_agg(nr) from numrange_test where false;
|
|
|
|
range_intersect_agg
|
|
|
|
---------------------
|
|
|
|
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select range_intersect_agg(nr) from numrange_test where nr @> 4.0;
|
|
|
|
range_intersect_agg
|
|
|
|
---------------------
|
|
|
|
[3,5)
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
analyze numrange_test;
|
2011-11-03 12:16:28 +01:00
|
|
|
create table numrange_test2(nr numrange);
|
2019-09-18 05:44:26 +02:00
|
|
|
create index numrange_test2_hash_idx on numrange_test2 using hash (nr);
|
2011-11-03 12:16:28 +01:00
|
|
|
INSERT INTO numrange_test2 VALUES('[, 5)');
|
|
|
|
INSERT INTO numrange_test2 VALUES(numrange(1.1, 2.2));
|
|
|
|
INSERT INTO numrange_test2 VALUES(numrange(1.1, 2.2));
|
|
|
|
INSERT INTO numrange_test2 VALUES(numrange(1.1, 2.2,'()'));
|
|
|
|
INSERT INTO numrange_test2 VALUES('empty');
|
|
|
|
select * from numrange_test2 where nr = 'empty'::numrange;
|
|
|
|
nr
|
|
|
|
-------
|
|
|
|
empty
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select * from numrange_test2 where nr = numrange(1.1, 2.2);
|
|
|
|
nr
|
|
|
|
-----------
|
|
|
|
[1.1,2.2)
|
|
|
|
[1.1,2.2)
|
|
|
|
(2 rows)
|
|
|
|
|
|
|
|
select * from numrange_test2 where nr = numrange(1.1, 2.3);
|
|
|
|
nr
|
|
|
|
----
|
|
|
|
(0 rows)
|
|
|
|
|
|
|
|
set enable_nestloop=t;
|
|
|
|
set enable_hashjoin=f;
|
|
|
|
set enable_mergejoin=f;
|
|
|
|
select * from numrange_test natural join numrange_test2 order by nr;
|
|
|
|
nr
|
|
|
|
-----------
|
|
|
|
empty
|
|
|
|
(,5)
|
|
|
|
[1.1,2.2)
|
|
|
|
[1.1,2.2)
|
|
|
|
(4 rows)
|
|
|
|
|
|
|
|
set enable_nestloop=f;
|
|
|
|
set enable_hashjoin=t;
|
|
|
|
set enable_mergejoin=f;
|
|
|
|
select * from numrange_test natural join numrange_test2 order by nr;
|
|
|
|
nr
|
|
|
|
-----------
|
|
|
|
empty
|
|
|
|
(,5)
|
|
|
|
[1.1,2.2)
|
|
|
|
[1.1,2.2)
|
|
|
|
(4 rows)
|
|
|
|
|
|
|
|
set enable_nestloop=f;
|
|
|
|
set enable_hashjoin=f;
|
|
|
|
set enable_mergejoin=t;
|
|
|
|
select * from numrange_test natural join numrange_test2 order by nr;
|
|
|
|
nr
|
|
|
|
-----------
|
|
|
|
empty
|
|
|
|
(,5)
|
|
|
|
[1.1,2.2)
|
|
|
|
[1.1,2.2)
|
|
|
|
(4 rows)
|
|
|
|
|
|
|
|
set enable_nestloop to default;
|
|
|
|
set enable_hashjoin to default;
|
|
|
|
set enable_mergejoin to default;
|
2020-01-31 23:03:55 +01:00
|
|
|
-- keep numrange_test around to help exercise dump/reload
|
2011-11-03 12:16:28 +01:00
|
|
|
DROP TABLE numrange_test2;
|
2020-01-31 23:03:55 +01:00
|
|
|
--
|
|
|
|
-- Apply a subset of the above tests on a collatable type, too
|
|
|
|
--
|
|
|
|
CREATE TABLE textrange_test (tr textrange);
|
|
|
|
create index textrange_test_btree on textrange_test(tr);
|
|
|
|
INSERT INTO textrange_test VALUES('[,)');
|
|
|
|
INSERT INTO textrange_test VALUES('["a",]');
|
|
|
|
INSERT INTO textrange_test VALUES('[,"q")');
|
|
|
|
INSERT INTO textrange_test VALUES(textrange('b', 'g'));
|
|
|
|
INSERT INTO textrange_test VALUES('empty');
|
|
|
|
INSERT INTO textrange_test VALUES(textrange('d', 'd', '[]'));
|
|
|
|
SELECT tr, isempty(tr), lower(tr), upper(tr) FROM textrange_test;
|
|
|
|
tr | isempty | lower | upper
|
|
|
|
-------+---------+-------+-------
|
|
|
|
(,) | f | |
|
|
|
|
[a,) | f | a |
|
|
|
|
(,q) | f | | q
|
|
|
|
[b,g) | f | b | g
|
|
|
|
empty | t | |
|
|
|
|
[d,d] | f | d | d
|
|
|
|
(6 rows)
|
|
|
|
|
|
|
|
SELECT tr, lower_inc(tr), lower_inf(tr), upper_inc(tr), upper_inf(tr) FROM textrange_test;
|
|
|
|
tr | lower_inc | lower_inf | upper_inc | upper_inf
|
|
|
|
-------+-----------+-----------+-----------+-----------
|
|
|
|
(,) | f | t | f | t
|
|
|
|
[a,) | t | f | f | t
|
|
|
|
(,q) | f | t | f | f
|
|
|
|
[b,g) | t | f | f | f
|
|
|
|
empty | f | f | f | f
|
|
|
|
[d,d] | t | f | t | f
|
|
|
|
(6 rows)
|
|
|
|
|
|
|
|
SELECT * FROM textrange_test WHERE range_contains(tr, textrange('f', 'fx'));
|
|
|
|
tr
|
|
|
|
-------
|
|
|
|
(,)
|
|
|
|
[a,)
|
|
|
|
(,q)
|
|
|
|
[b,g)
|
|
|
|
(4 rows)
|
|
|
|
|
|
|
|
SELECT * FROM textrange_test WHERE tr @> textrange('a', 'z');
|
|
|
|
tr
|
|
|
|
------
|
|
|
|
(,)
|
|
|
|
[a,)
|
|
|
|
(2 rows)
|
|
|
|
|
|
|
|
SELECT * FROM textrange_test WHERE range_contained_by(textrange('0','9'), tr);
|
|
|
|
tr
|
|
|
|
------
|
|
|
|
(,)
|
|
|
|
(,q)
|
|
|
|
(2 rows)
|
|
|
|
|
|
|
|
SELECT * FROM textrange_test WHERE 'e'::text <@ tr;
|
|
|
|
tr
|
|
|
|
-------
|
|
|
|
(,)
|
|
|
|
[a,)
|
|
|
|
(,q)
|
|
|
|
[b,g)
|
|
|
|
(4 rows)
|
|
|
|
|
|
|
|
select * from textrange_test where tr = 'empty';
|
|
|
|
tr
|
|
|
|
-------
|
|
|
|
empty
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select * from textrange_test where tr = '("b","g")';
|
|
|
|
tr
|
|
|
|
----
|
|
|
|
(0 rows)
|
|
|
|
|
|
|
|
select * from textrange_test where tr = '["b","g")';
|
|
|
|
tr
|
|
|
|
-------
|
|
|
|
[b,g)
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select * from textrange_test where tr < 'empty';
|
|
|
|
tr
|
|
|
|
----
|
|
|
|
(0 rows)
|
|
|
|
|
2011-11-03 12:16:28 +01:00
|
|
|
-- test canonical form for int4range
|
2011-11-22 22:05:49 +01:00
|
|
|
select int4range(1, 10, '[]');
|
2011-11-03 12:16:28 +01:00
|
|
|
int4range
|
|
|
|
-----------
|
|
|
|
[1,11)
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-22 22:05:49 +01:00
|
|
|
select int4range(1, 10, '[)');
|
2011-11-03 12:16:28 +01:00
|
|
|
int4range
|
|
|
|
-----------
|
|
|
|
[1,10)
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-22 22:05:49 +01:00
|
|
|
select int4range(1, 10, '(]');
|
2011-11-03 12:16:28 +01:00
|
|
|
int4range
|
|
|
|
-----------
|
|
|
|
[2,11)
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-22 22:05:49 +01:00
|
|
|
select int4range(1, 10, '()');
|
2011-11-03 12:16:28 +01:00
|
|
|
int4range
|
|
|
|
-----------
|
2011-11-22 22:05:49 +01:00
|
|
|
[2,10)
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select int4range(1, 2, '()');
|
|
|
|
int4range
|
|
|
|
-----------
|
|
|
|
empty
|
2011-11-03 12:16:28 +01:00
|
|
|
(1 row)
|
|
|
|
|
|
|
|
-- test canonical form for daterange
|
2011-11-22 22:05:49 +01:00
|
|
|
select daterange('2000-01-10'::date, '2000-01-20'::date, '[]');
|
2011-11-03 12:16:28 +01:00
|
|
|
daterange
|
|
|
|
-------------------------
|
|
|
|
[01-10-2000,01-21-2000)
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-22 22:05:49 +01:00
|
|
|
select daterange('2000-01-10'::date, '2000-01-20'::date, '[)');
|
2011-11-03 12:16:28 +01:00
|
|
|
daterange
|
|
|
|
-------------------------
|
|
|
|
[01-10-2000,01-20-2000)
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-22 22:05:49 +01:00
|
|
|
select daterange('2000-01-10'::date, '2000-01-20'::date, '(]');
|
2011-11-03 12:16:28 +01:00
|
|
|
daterange
|
|
|
|
-------------------------
|
|
|
|
[01-11-2000,01-21-2000)
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-22 22:05:49 +01:00
|
|
|
select daterange('2000-01-10'::date, '2000-01-20'::date, '()');
|
2011-11-03 12:16:28 +01:00
|
|
|
daterange
|
|
|
|
-------------------------
|
2011-11-22 22:05:49 +01:00
|
|
|
[01-11-2000,01-20-2000)
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select daterange('2000-01-10'::date, '2000-01-11'::date, '()');
|
|
|
|
daterange
|
|
|
|
-----------
|
|
|
|
empty
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select daterange('2000-01-10'::date, '2000-01-11'::date, '(]');
|
|
|
|
daterange
|
|
|
|
-------------------------
|
|
|
|
[01-11-2000,01-12-2000)
|
2011-11-03 12:16:28 +01:00
|
|
|
(1 row)
|
|
|
|
|
2019-07-18 21:42:39 +02:00
|
|
|
select daterange('-infinity'::date, '2000-01-01'::date, '()');
|
|
|
|
daterange
|
|
|
|
------------------------
|
|
|
|
(-infinity,01-01-2000)
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select daterange('-infinity'::date, '2000-01-01'::date, '[)');
|
|
|
|
daterange
|
|
|
|
------------------------
|
|
|
|
[-infinity,01-01-2000)
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select daterange('2000-01-01'::date, 'infinity'::date, '[)');
|
|
|
|
daterange
|
|
|
|
-----------------------
|
|
|
|
[01-01-2000,infinity)
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select daterange('2000-01-01'::date, 'infinity'::date, '[]');
|
|
|
|
daterange
|
|
|
|
-----------------------
|
|
|
|
[01-01-2000,infinity]
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-14 21:15:53 +01:00
|
|
|
-- test GiST index that's been built incrementally
|
2011-11-03 12:16:28 +01:00
|
|
|
create table test_range_gist(ir int4range);
|
|
|
|
create index test_range_gist_idx on test_range_gist using gist (ir);
|
|
|
|
insert into test_range_gist select int4range(g, g+10) from generate_series(1,2000) g;
|
|
|
|
insert into test_range_gist select 'empty'::int4range from generate_series(1,500) g;
|
|
|
|
insert into test_range_gist select int4range(g, g+10000) from generate_series(1,1000) g;
|
|
|
|
insert into test_range_gist select 'empty'::int4range from generate_series(1,500) g;
|
|
|
|
insert into test_range_gist select int4range(NULL,g*10,'(]') from generate_series(1,100) g;
|
|
|
|
insert into test_range_gist select int4range(g*10,NULL,'(]') from generate_series(1,100) g;
|
|
|
|
insert into test_range_gist select int4range(g, g+10) from generate_series(1,2000) g;
|
2020-12-30 18:19:15 +01:00
|
|
|
-- test statistics and selectivity estimation as well
|
|
|
|
--
|
|
|
|
-- We don't check the accuracy of selectivity estimation, but at least check
|
|
|
|
-- it doesn't fall.
|
|
|
|
analyze test_range_gist;
|
2011-11-14 21:15:53 +01:00
|
|
|
-- first, verify non-indexed results
|
|
|
|
SET enable_seqscan = t;
|
|
|
|
SET enable_indexscan = f;
|
|
|
|
SET enable_bitmapscan = f;
|
2011-11-03 12:16:28 +01:00
|
|
|
select count(*) from test_range_gist where ir @> 'empty'::int4range;
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
6200
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir = int4range(10,20);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
2
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir @> 10;
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
130
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir @> int4range(10,20);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
111
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir && int4range(10,20);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
158
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir <@ int4range(10,50);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
1062
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-14 21:15:53 +01:00
|
|
|
select count(*) from test_range_gist where ir << int4range(100,500);
|
2011-11-03 12:16:28 +01:00
|
|
|
count
|
|
|
|
-------
|
|
|
|
189
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-14 21:15:53 +01:00
|
|
|
select count(*) from test_range_gist where ir >> int4range(100,500);
|
2011-11-03 12:16:28 +01:00
|
|
|
count
|
|
|
|
-------
|
|
|
|
3554
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-14 21:15:53 +01:00
|
|
|
select count(*) from test_range_gist where ir &< int4range(100,500);
|
2011-11-03 12:16:28 +01:00
|
|
|
count
|
|
|
|
-------
|
|
|
|
1029
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-14 21:15:53 +01:00
|
|
|
select count(*) from test_range_gist where ir &> int4range(100,500);
|
2011-11-03 12:16:28 +01:00
|
|
|
count
|
|
|
|
-------
|
|
|
|
4794
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-14 21:15:53 +01:00
|
|
|
select count(*) from test_range_gist where ir -|- int4range(100,500);
|
2011-11-03 12:16:28 +01:00
|
|
|
count
|
|
|
|
-------
|
|
|
|
5
|
|
|
|
(1 row)
|
|
|
|
|
2020-12-29 21:36:43 +01:00
|
|
|
select count(*) from test_range_gist where ir @> '{}'::int4multirange;
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
6200
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir @> int4multirange(int4range(10,20), int4range(30,40));
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
107
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir && '{(10,20),(30,40),(50,60)}'::int4multirange;
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
271
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir <@ '{(10,30),(40,60),(70,90)}'::int4multirange;
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
1060
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir << int4multirange(int4range(100,200), int4range(400,500));
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
189
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir >> int4multirange(int4range(100,200), int4range(400,500));
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
3554
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir &< int4multirange(int4range(100,200), int4range(400,500));
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
1029
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir &> int4multirange(int4range(100,200), int4range(400,500));
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
4794
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir -|- int4multirange(int4range(100,200), int4range(400,500));
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
5
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-14 21:15:53 +01:00
|
|
|
-- now check same queries using index
|
|
|
|
SET enable_seqscan = f;
|
|
|
|
SET enable_indexscan = t;
|
|
|
|
SET enable_bitmapscan = f;
|
2011-11-03 12:16:28 +01:00
|
|
|
select count(*) from test_range_gist where ir @> 'empty'::int4range;
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
6200
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir = int4range(10,20);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
2
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir @> 10;
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
130
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir @> int4range(10,20);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
111
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir && int4range(10,20);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
158
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir <@ int4range(10,50);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
1062
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir << int4range(100,500);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
189
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir >> int4range(100,500);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
3554
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir &< int4range(100,500);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
1029
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir &> int4range(100,500);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
4794
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir -|- int4range(100,500);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
5
|
|
|
|
(1 row)
|
|
|
|
|
2020-12-29 21:36:43 +01:00
|
|
|
select count(*) from test_range_gist where ir @> '{}'::int4multirange;
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
6200
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir @> int4multirange(int4range(10,20), int4range(30,40));
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
107
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir && '{(10,20),(30,40),(50,60)}'::int4multirange;
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
271
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir <@ '{(10,30),(40,60),(70,90)}'::int4multirange;
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
1060
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir << int4multirange(int4range(100,200), int4range(400,500));
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
189
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir >> int4multirange(int4range(100,200), int4range(400,500));
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
3554
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir &< int4multirange(int4range(100,200), int4range(400,500));
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
1029
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir &> int4multirange(int4range(100,200), int4range(400,500));
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
4794
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir -|- int4multirange(int4range(100,200), int4range(400,500));
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
5
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-14 21:15:53 +01:00
|
|
|
-- now check same queries using a bulk-loaded index
|
2011-11-03 12:16:28 +01:00
|
|
|
drop index test_range_gist_idx;
|
|
|
|
create index test_range_gist_idx on test_range_gist using gist (ir);
|
|
|
|
select count(*) from test_range_gist where ir @> 'empty'::int4range;
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
6200
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir = int4range(10,20);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
2
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir @> 10;
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
130
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir @> int4range(10,20);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
111
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir && int4range(10,20);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
158
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir <@ int4range(10,50);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
1062
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir << int4range(100,500);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
189
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir >> int4range(100,500);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
3554
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir &< int4range(100,500);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
1029
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir &> int4range(100,500);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
4794
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir -|- int4range(100,500);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
5
|
|
|
|
(1 row)
|
|
|
|
|
2020-12-29 21:36:43 +01:00
|
|
|
select count(*) from test_range_gist where ir @> '{}'::int4multirange;
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
6200
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir @> int4multirange(int4range(10,20), int4range(30,40));
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
107
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir && '{(10,20),(30,40),(50,60)}'::int4multirange;
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
271
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir <@ '{(10,30),(40,60),(70,90)}'::int4multirange;
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
1060
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir << int4multirange(int4range(100,200), int4range(400,500));
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
189
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir >> int4multirange(int4range(100,200), int4range(400,500));
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
3554
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir &< int4multirange(int4range(100,200), int4range(400,500));
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
1029
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir &> int4multirange(int4range(100,200), int4range(400,500));
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
4794
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_gist where ir -|- int4multirange(int4range(100,200), int4range(400,500));
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
5
|
|
|
|
(1 row)
|
|
|
|
|
2012-08-16 11:55:37 +02:00
|
|
|
-- test SP-GiST index that's been built incrementally
|
|
|
|
create table test_range_spgist(ir int4range);
|
|
|
|
create index test_range_spgist_idx on test_range_spgist using spgist (ir);
|
|
|
|
insert into test_range_spgist select int4range(g, g+10) from generate_series(1,2000) g;
|
|
|
|
insert into test_range_spgist select 'empty'::int4range from generate_series(1,500) g;
|
|
|
|
insert into test_range_spgist select int4range(g, g+10000) from generate_series(1,1000) g;
|
|
|
|
insert into test_range_spgist select 'empty'::int4range from generate_series(1,500) g;
|
|
|
|
insert into test_range_spgist select int4range(NULL,g*10,'(]') from generate_series(1,100) g;
|
|
|
|
insert into test_range_spgist select int4range(g*10,NULL,'(]') from generate_series(1,100) g;
|
|
|
|
insert into test_range_spgist select int4range(g, g+10) from generate_series(1,2000) g;
|
|
|
|
-- first, verify non-indexed results
|
|
|
|
SET enable_seqscan = t;
|
|
|
|
SET enable_indexscan = f;
|
|
|
|
SET enable_bitmapscan = f;
|
|
|
|
select count(*) from test_range_spgist where ir @> 'empty'::int4range;
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
6200
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_spgist where ir = int4range(10,20);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
2
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_spgist where ir @> 10;
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
130
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_spgist where ir @> int4range(10,20);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
111
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_spgist where ir && int4range(10,20);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
158
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_spgist where ir <@ int4range(10,50);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
1062
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_spgist where ir << int4range(100,500);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
189
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_spgist where ir >> int4range(100,500);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
3554
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_spgist where ir &< int4range(100,500);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
1029
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_spgist where ir &> int4range(100,500);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
4794
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_spgist where ir -|- int4range(100,500);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
5
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
-- now check same queries using index
|
|
|
|
SET enable_seqscan = f;
|
|
|
|
SET enable_indexscan = t;
|
|
|
|
SET enable_bitmapscan = f;
|
|
|
|
select count(*) from test_range_spgist where ir @> 'empty'::int4range;
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
6200
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_spgist where ir = int4range(10,20);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
2
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_spgist where ir @> 10;
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
130
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_spgist where ir @> int4range(10,20);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
111
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_spgist where ir && int4range(10,20);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
158
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_spgist where ir <@ int4range(10,50);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
1062
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_spgist where ir << int4range(100,500);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
189
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_spgist where ir >> int4range(100,500);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
3554
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_spgist where ir &< int4range(100,500);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
1029
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_spgist where ir &> int4range(100,500);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
4794
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_spgist where ir -|- int4range(100,500);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
5
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
-- now check same queries using a bulk-loaded index
|
|
|
|
drop index test_range_spgist_idx;
|
|
|
|
create index test_range_spgist_idx on test_range_spgist using spgist (ir);
|
|
|
|
select count(*) from test_range_spgist where ir @> 'empty'::int4range;
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
6200
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_spgist where ir = int4range(10,20);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
2
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_spgist where ir @> 10;
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
130
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_spgist where ir @> int4range(10,20);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
111
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_spgist where ir && int4range(10,20);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
158
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_spgist where ir <@ int4range(10,50);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
1062
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_spgist where ir << int4range(100,500);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
189
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_spgist where ir >> int4range(100,500);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
3554
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_spgist where ir &< int4range(100,500);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
1029
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_spgist where ir &> int4range(100,500);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
4794
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select count(*) from test_range_spgist where ir -|- int4range(100,500);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
5
|
|
|
|
(1 row)
|
|
|
|
|
2015-03-30 12:21:43 +02:00
|
|
|
-- test index-only scans
|
|
|
|
explain (costs off)
|
|
|
|
select ir from test_range_spgist where ir -|- int4range(10,20) order by ir;
|
|
|
|
QUERY PLAN
|
|
|
|
------------------------------------------------------------------------
|
|
|
|
Sort
|
|
|
|
Sort Key: ir
|
|
|
|
-> Index Only Scan using test_range_spgist_idx on test_range_spgist
|
|
|
|
Index Cond: (ir -|- '[10,20)'::int4range)
|
|
|
|
(4 rows)
|
|
|
|
|
|
|
|
select ir from test_range_spgist where ir -|- int4range(10,20) order by ir;
|
|
|
|
ir
|
|
|
|
------------
|
|
|
|
[20,30)
|
|
|
|
[20,30)
|
|
|
|
[20,10020)
|
|
|
|
(3 rows)
|
|
|
|
|
2011-11-14 21:15:53 +01:00
|
|
|
RESET enable_seqscan;
|
|
|
|
RESET enable_indexscan;
|
|
|
|
RESET enable_bitmapscan;
|
2013-03-21 10:15:45 +01:00
|
|
|
-- test elem <@ range operator
|
|
|
|
create table test_range_elem(i int4);
|
|
|
|
create index test_range_elem_idx on test_range_elem (i);
|
|
|
|
insert into test_range_elem select i from generate_series(1,100) i;
|
Fix confusion in SP-GiST between attribute type and leaf storage type.
According to the documentation, the attType passed to the opclass
config function (and also relied on by the core code) is the type
of the heap column or expression being indexed. But what was
actually being passed was the type stored for the index column.
This made no difference for user-defined SP-GiST opclasses,
because we weren't allowing the STORAGE clause of CREATE OPCLASS
to be used, so the two types would be the same. But it's silly
not to allow that, seeing that the built-in poly_ops opclass
has a different value for opckeytype than opcintype, and that if you
want to do lossy storage then the types must really be different.
(Thus, user-defined opclasses doing lossy storage had to lie about
what type is in the index.) Hence, remove the restriction, and make
sure that we use the input column type not opckeytype where relevant.
For reasons of backwards compatibility with existing user-defined
opclasses, we can't quite insist that the specified leafType match
the STORAGE clause; instead just add an amvalidate() warning if
they don't match.
Also fix some bugs that would only manifest when trying to return
index entries when attType is different from attLeafType. It's not
too surprising that these have not been reported, because the only
usual reason for such a difference is to store the leaf value
lossily, rendering index-only scans impossible.
Add a src/test/modules module to exercise cases where attType is
different from attLeafType and yet index-only scan is supported.
Discussion: https://postgr.es/m/3728741.1617381471@sss.pgh.pa.us
2021-04-04 20:28:35 +02:00
|
|
|
SET enable_seqscan = f;
|
2013-03-21 10:15:45 +01:00
|
|
|
select count(*) from test_range_elem where i <@ int4range(10,50);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
40
|
|
|
|
(1 row)
|
|
|
|
|
Fix confusion in SP-GiST between attribute type and leaf storage type.
According to the documentation, the attType passed to the opclass
config function (and also relied on by the core code) is the type
of the heap column or expression being indexed. But what was
actually being passed was the type stored for the index column.
This made no difference for user-defined SP-GiST opclasses,
because we weren't allowing the STORAGE clause of CREATE OPCLASS
to be used, so the two types would be the same. But it's silly
not to allow that, seeing that the built-in poly_ops opclass
has a different value for opckeytype than opcintype, and that if you
want to do lossy storage then the types must really be different.
(Thus, user-defined opclasses doing lossy storage had to lie about
what type is in the index.) Hence, remove the restriction, and make
sure that we use the input column type not opckeytype where relevant.
For reasons of backwards compatibility with existing user-defined
opclasses, we can't quite insist that the specified leafType match
the STORAGE clause; instead just add an amvalidate() warning if
they don't match.
Also fix some bugs that would only manifest when trying to return
index entries when attType is different from attLeafType. It's not
too surprising that these have not been reported, because the only
usual reason for such a difference is to store the leaf value
lossily, rendering index-only scans impossible.
Add a src/test/modules module to exercise cases where attType is
different from attLeafType and yet index-only scan is supported.
Discussion: https://postgr.es/m/3728741.1617381471@sss.pgh.pa.us
2021-04-04 20:28:35 +02:00
|
|
|
-- also test spgist index on anyrange expression
|
|
|
|
create index on test_range_elem using spgist(int4range(i,i+10));
|
|
|
|
explain (costs off)
|
|
|
|
select count(*) from test_range_elem where int4range(i,i+10) <@ int4range(10,30);
|
|
|
|
QUERY PLAN
|
|
|
|
-------------------------------------------------------------------------
|
|
|
|
Aggregate
|
|
|
|
-> Index Scan using test_range_elem_int4range_idx on test_range_elem
|
|
|
|
Index Cond: (int4range(i, (i + 10)) <@ '[10,30)'::int4range)
|
|
|
|
(3 rows)
|
|
|
|
|
|
|
|
select count(*) from test_range_elem where int4range(i,i+10) <@ int4range(10,30);
|
|
|
|
count
|
|
|
|
-------
|
|
|
|
11
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
RESET enable_seqscan;
|
2013-03-21 10:15:45 +01:00
|
|
|
drop table test_range_elem;
|
2011-11-03 12:16:28 +01:00
|
|
|
--
|
|
|
|
-- Btree_gist is not included by default, so to test exclusion
|
|
|
|
-- constraints with range types, use singleton int ranges for the "="
|
|
|
|
-- portion of the constraint.
|
|
|
|
--
|
|
|
|
create table test_range_excl(
|
|
|
|
room int4range,
|
|
|
|
speaker int4range,
|
|
|
|
during tsrange,
|
|
|
|
exclude using gist (room with =, during with &&),
|
|
|
|
exclude using gist (speaker with =, during with &&)
|
|
|
|
);
|
|
|
|
insert into test_range_excl
|
2011-11-23 02:45:05 +01:00
|
|
|
values(int4range(123, 123, '[]'), int4range(1, 1, '[]'), '[2010-01-02 10:00, 2010-01-02 11:00)');
|
2011-11-03 12:16:28 +01:00
|
|
|
insert into test_range_excl
|
2011-11-23 02:45:05 +01:00
|
|
|
values(int4range(123, 123, '[]'), int4range(2, 2, '[]'), '[2010-01-02 11:00, 2010-01-02 12:00)');
|
2011-11-03 12:16:28 +01:00
|
|
|
insert into test_range_excl
|
2011-11-23 02:45:05 +01:00
|
|
|
values(int4range(123, 123, '[]'), int4range(3, 3, '[]'), '[2010-01-02 10:10, 2010-01-02 11:00)');
|
2011-11-03 12:16:28 +01:00
|
|
|
ERROR: conflicting key value violates exclusion constraint "test_range_excl_room_during_excl"
|
2011-11-22 22:05:49 +01:00
|
|
|
DETAIL: Key (room, during)=([123,124), ["Sat Jan 02 10:10:00 2010","Sat Jan 02 11:00:00 2010")) conflicts with existing key (room, during)=([123,124), ["Sat Jan 02 10:00:00 2010","Sat Jan 02 11:00:00 2010")).
|
2011-11-03 12:16:28 +01:00
|
|
|
insert into test_range_excl
|
2011-11-23 02:45:05 +01:00
|
|
|
values(int4range(124, 124, '[]'), int4range(3, 3, '[]'), '[2010-01-02 10:10, 2010-01-02 11:10)');
|
2011-11-03 12:16:28 +01:00
|
|
|
insert into test_range_excl
|
2011-11-23 02:45:05 +01:00
|
|
|
values(int4range(125, 125, '[]'), int4range(1, 1, '[]'), '[2010-01-02 10:10, 2010-01-02 11:00)');
|
2011-11-03 12:16:28 +01:00
|
|
|
ERROR: conflicting key value violates exclusion constraint "test_range_excl_speaker_during_excl"
|
2011-11-22 22:05:49 +01:00
|
|
|
DETAIL: Key (speaker, during)=([1,2), ["Sat Jan 02 10:10:00 2010","Sat Jan 02 11:00:00 2010")) conflicts with existing key (speaker, during)=([1,2), ["Sat Jan 02 10:00:00 2010","Sat Jan 02 11:00:00 2010")).
|
2011-11-03 12:16:28 +01:00
|
|
|
-- test bigint ranges
|
|
|
|
select int8range(10000000000::int8, 20000000000::int8,'(]');
|
|
|
|
int8range
|
|
|
|
---------------------------
|
|
|
|
[10000000001,20000000001)
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
-- test tstz ranges
|
|
|
|
set timezone to '-08';
|
|
|
|
select '[2010-01-01 01:00:00 -05, 2010-01-01 02:00:00 -08)'::tstzrange;
|
|
|
|
tstzrange
|
|
|
|
-----------------------------------------------------------------
|
|
|
|
["Thu Dec 31 22:00:00 2009 -08","Fri Jan 01 02:00:00 2010 -08")
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
-- should fail
|
|
|
|
select '[2010-01-01 01:00:00 -08, 2010-01-01 02:00:00 -05)'::tstzrange;
|
|
|
|
ERROR: range lower bound must be less than or equal to range upper bound
|
|
|
|
LINE 1: select '[2010-01-01 01:00:00 -08, 2010-01-01 02:00:00 -05)':...
|
|
|
|
^
|
|
|
|
set timezone to default;
|
|
|
|
--
|
|
|
|
-- Test user-defined range of floats
|
2022-02-08 21:30:38 +01:00
|
|
|
-- (type float8range was already made in test_setup.sql)
|
2011-11-03 12:16:28 +01:00
|
|
|
--
|
|
|
|
--should fail
|
2022-02-08 21:30:38 +01:00
|
|
|
create type bogus_float8range as range (subtype=float8, subtype_diff=float4mi);
|
2011-11-03 12:16:28 +01:00
|
|
|
ERROR: function float4mi(double precision, double precision) does not exist
|
|
|
|
select '[123.001, 5.e9)'::float8range @> 888.882::float8;
|
|
|
|
?column?
|
|
|
|
----------
|
|
|
|
t
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
create table float8range_test(f8r float8range, i int);
|
2011-11-22 22:05:49 +01:00
|
|
|
insert into float8range_test values(float8range(-100.00007, '1.111113e9'), 42);
|
2011-11-03 12:16:28 +01:00
|
|
|
select * from float8range_test;
|
2011-11-22 22:05:49 +01:00
|
|
|
f8r | i
|
|
|
|
-------------------------+----
|
|
|
|
[-100.00007,1111113000) | 42
|
2011-11-03 12:16:28 +01:00
|
|
|
(1 row)
|
|
|
|
|
|
|
|
drop table float8range_test;
|
|
|
|
--
|
|
|
|
-- Test range types over domains
|
|
|
|
--
|
|
|
|
create domain mydomain as int4;
|
|
|
|
create type mydomainrange as range(subtype=mydomain);
|
|
|
|
select '[4,50)'::mydomainrange @> 7::mydomain;
|
|
|
|
?column?
|
|
|
|
----------
|
|
|
|
t
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-22 22:05:49 +01:00
|
|
|
drop domain mydomain; -- fail
|
|
|
|
ERROR: cannot drop type mydomain because other objects depend on it
|
|
|
|
DETAIL: type mydomainrange depends on type mydomain
|
|
|
|
HINT: Use DROP ... CASCADE to drop the dependent objects too.
|
|
|
|
drop domain mydomain cascade;
|
|
|
|
NOTICE: drop cascades to type mydomainrange
|
2011-11-03 12:16:28 +01:00
|
|
|
--
|
|
|
|
-- Test domains over range types
|
|
|
|
--
|
2011-11-22 22:05:49 +01:00
|
|
|
create domain restrictedrange as int4range check (upper(value) < 10);
|
2011-11-03 12:16:28 +01:00
|
|
|
select '[4,5)'::restrictedrange @> 7;
|
|
|
|
?column?
|
|
|
|
----------
|
|
|
|
f
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select '[4,50)'::restrictedrange @> 7; -- should fail
|
|
|
|
ERROR: value for domain restrictedrange violates check constraint "restrictedrange_check"
|
|
|
|
drop domain restrictedrange;
|
|
|
|
--
|
|
|
|
-- Test multiple range types over the same subtype
|
|
|
|
--
|
|
|
|
create type textrange1 as range(subtype=text, collation="C");
|
|
|
|
create type textrange2 as range(subtype=text, collation="C");
|
|
|
|
select textrange1('a','Z') @> 'b'::text;
|
|
|
|
ERROR: range lower bound must be less than or equal to range upper bound
|
|
|
|
select textrange2('a','z') @> 'b'::text;
|
|
|
|
?column?
|
|
|
|
----------
|
|
|
|
t
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
drop type textrange1;
|
|
|
|
drop type textrange2;
|
|
|
|
--
|
2011-11-22 22:05:49 +01:00
|
|
|
-- Test polymorphic type system
|
2011-11-03 12:16:28 +01:00
|
|
|
--
|
|
|
|
create function anyarray_anyrange_func(a anyarray, r anyrange)
|
|
|
|
returns anyelement as 'select $1[1] + lower($2);' language sql;
|
|
|
|
select anyarray_anyrange_func(ARRAY[1,2], int4range(10,20));
|
|
|
|
anyarray_anyrange_func
|
|
|
|
------------------------
|
|
|
|
11
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
-- should fail
|
|
|
|
select anyarray_anyrange_func(ARRAY[1,2], numrange(10,20));
|
|
|
|
ERROR: function anyarray_anyrange_func(integer[], numrange) does not exist
|
|
|
|
LINE 1: select anyarray_anyrange_func(ARRAY[1,2], numrange(10,20));
|
|
|
|
^
|
|
|
|
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
|
|
|
|
drop function anyarray_anyrange_func(anyarray, anyrange);
|
|
|
|
-- should fail
|
|
|
|
create function bogus_func(anyelement)
|
|
|
|
returns anyrange as 'select int4range(1,10)' language sql;
|
|
|
|
ERROR: cannot determine result data type
|
Multirange datatypes
Multiranges are basically sorted arrays of non-overlapping ranges with
set-theoretic operations defined over them.
Since v14, each range type automatically gets a corresponding multirange
datatype. There are both manual and automatic mechanisms for naming multirange
types. Once can specify multirange type name using multirange_type_name
attribute in CREATE TYPE. Otherwise, a multirange type name is generated
automatically. If the range type name contains "range" then we change that to
"multirange". Otherwise, we add "_multirange" to the end.
Implementation of multiranges comes with a space-efficient internal
representation format, which evades extra paddings and duplicated storage of
oids. Altogether this format allows fetching a particular range by its index
in O(n).
Statistic gathering and selectivity estimation are implemented for multiranges.
For this purpose, stored multirange is approximated as union range without gaps.
This field will likely need improvements in the future.
Catversion is bumped.
Discussion: https://postgr.es/m/CALNJ-vSUpQ_Y%3DjXvTxt1VYFztaBSsWVXeF1y6gTYQ4bOiWDLgQ%40mail.gmail.com
Discussion: https://postgr.es/m/a0b8026459d1e6167933be2104a6174e7d40d0ab.camel%40j-davis.com#fe7218c83b08068bfffb0c5293eceda0
Author: Paul Jungwirth, revised by me
Reviewed-by: David Fetter, Corey Huinker, Jeff Davis, Pavel Stehule
Reviewed-by: Alvaro Herrera, Tom Lane, Isaac Morland, David G. Johnston
Reviewed-by: Zhihong Yu, Alexander Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
DETAIL: A result of type anyrange requires at least one input of type anyrange or anymultirange.
|
2011-11-03 12:16:28 +01:00
|
|
|
-- should fail
|
|
|
|
create function bogus_func(int)
|
|
|
|
returns anyrange as 'select int4range(1,10)' language sql;
|
|
|
|
ERROR: cannot determine result data type
|
Multirange datatypes
Multiranges are basically sorted arrays of non-overlapping ranges with
set-theoretic operations defined over them.
Since v14, each range type automatically gets a corresponding multirange
datatype. There are both manual and automatic mechanisms for naming multirange
types. Once can specify multirange type name using multirange_type_name
attribute in CREATE TYPE. Otherwise, a multirange type name is generated
automatically. If the range type name contains "range" then we change that to
"multirange". Otherwise, we add "_multirange" to the end.
Implementation of multiranges comes with a space-efficient internal
representation format, which evades extra paddings and duplicated storage of
oids. Altogether this format allows fetching a particular range by its index
in O(n).
Statistic gathering and selectivity estimation are implemented for multiranges.
For this purpose, stored multirange is approximated as union range without gaps.
This field will likely need improvements in the future.
Catversion is bumped.
Discussion: https://postgr.es/m/CALNJ-vSUpQ_Y%3DjXvTxt1VYFztaBSsWVXeF1y6gTYQ4bOiWDLgQ%40mail.gmail.com
Discussion: https://postgr.es/m/a0b8026459d1e6167933be2104a6174e7d40d0ab.camel%40j-davis.com#fe7218c83b08068bfffb0c5293eceda0
Author: Paul Jungwirth, revised by me
Reviewed-by: David Fetter, Corey Huinker, Jeff Davis, Pavel Stehule
Reviewed-by: Alvaro Herrera, Tom Lane, Isaac Morland, David G. Johnston
Reviewed-by: Zhihong Yu, Alexander Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
DETAIL: A result of type anyrange requires at least one input of type anyrange or anymultirange.
|
2011-11-03 12:16:28 +01:00
|
|
|
create function range_add_bounds(anyrange)
|
|
|
|
returns anyelement as 'select lower($1) + upper($1)' language sql;
|
2011-11-22 22:05:49 +01:00
|
|
|
select range_add_bounds(int4range(1, 17));
|
|
|
|
range_add_bounds
|
|
|
|
------------------
|
|
|
|
18
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-03 12:16:28 +01:00
|
|
|
select range_add_bounds(numrange(1.0001, 123.123));
|
|
|
|
range_add_bounds
|
|
|
|
------------------
|
|
|
|
124.1231
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-21 22:19:53 +01:00
|
|
|
create function rangetypes_sql(q anyrange, b anyarray, out c anyelement)
|
|
|
|
as $$ select upper($1) + $2[1] $$
|
|
|
|
language sql;
|
|
|
|
select rangetypes_sql(int4range(1,10), ARRAY[2,20]);
|
|
|
|
rangetypes_sql
|
|
|
|
----------------
|
|
|
|
12
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select rangetypes_sql(numrange(1,10), ARRAY[2,20]); -- match failure
|
|
|
|
ERROR: function rangetypes_sql(numrange, integer[]) does not exist
|
|
|
|
LINE 1: select rangetypes_sql(numrange(1,10), ARRAY[2,20]);
|
|
|
|
^
|
|
|
|
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
|
Introduce "anycompatible" family of polymorphic types.
This patch adds the pseudo-types anycompatible, anycompatiblearray,
anycompatiblenonarray, and anycompatiblerange. They work much like
anyelement, anyarray, anynonarray, and anyrange respectively, except
that the actual input values need not match precisely in type.
Instead, if we can find a common supertype (using the same rules
as for UNION/CASE type resolution), then the parser automatically
promotes the input values to that type. For example,
"myfunc(anycompatible, anycompatible)" can match a call with one
integer and one bigint argument, with the integer automatically
promoted to bigint. With anyelement in the definition, the user
would have had to cast the integer explicitly.
The new types also provide a second, independent set of type variables
for function matching; thus with "myfunc(anyelement, anyelement,
anycompatible) returns anycompatible" the first two arguments are
constrained to be the same type, but the third can be some other
type, and the result has the type of the third argument. The need
for more than one set of type variables was foreseen back when we
first invented the polymorphic types, but we never did anything
about it.
Pavel Stehule, revised a bit by me
Discussion: https://postgr.es/m/CAFj8pRDna7VqNi8gR+Tt2Ktmz0cq5G93guc3Sbn_NVPLdXAkqA@mail.gmail.com
2020-03-19 16:43:11 +01:00
|
|
|
create function anycompatiblearray_anycompatiblerange_func(a anycompatiblearray, r anycompatiblerange)
|
|
|
|
returns anycompatible as 'select $1[1] + lower($2);' language sql;
|
|
|
|
select anycompatiblearray_anycompatiblerange_func(ARRAY[1,2], int4range(10,20));
|
|
|
|
anycompatiblearray_anycompatiblerange_func
|
|
|
|
--------------------------------------------
|
|
|
|
11
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select anycompatiblearray_anycompatiblerange_func(ARRAY[1,2], numrange(10,20));
|
|
|
|
anycompatiblearray_anycompatiblerange_func
|
|
|
|
--------------------------------------------
|
|
|
|
11
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
-- should fail
|
|
|
|
select anycompatiblearray_anycompatiblerange_func(ARRAY[1.1,2], int4range(10,20));
|
|
|
|
ERROR: function anycompatiblearray_anycompatiblerange_func(numeric[], int4range) does not exist
|
|
|
|
LINE 1: select anycompatiblearray_anycompatiblerange_func(ARRAY[1.1,...
|
|
|
|
^
|
|
|
|
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
|
|
|
|
drop function anycompatiblearray_anycompatiblerange_func(anycompatiblearray, anycompatiblerange);
|
|
|
|
-- should fail
|
|
|
|
create function bogus_func(anycompatible)
|
|
|
|
returns anycompatiblerange as 'select int4range(1,10)' language sql;
|
|
|
|
ERROR: cannot determine result data type
|
Multirange datatypes
Multiranges are basically sorted arrays of non-overlapping ranges with
set-theoretic operations defined over them.
Since v14, each range type automatically gets a corresponding multirange
datatype. There are both manual and automatic mechanisms for naming multirange
types. Once can specify multirange type name using multirange_type_name
attribute in CREATE TYPE. Otherwise, a multirange type name is generated
automatically. If the range type name contains "range" then we change that to
"multirange". Otherwise, we add "_multirange" to the end.
Implementation of multiranges comes with a space-efficient internal
representation format, which evades extra paddings and duplicated storage of
oids. Altogether this format allows fetching a particular range by its index
in O(n).
Statistic gathering and selectivity estimation are implemented for multiranges.
For this purpose, stored multirange is approximated as union range without gaps.
This field will likely need improvements in the future.
Catversion is bumped.
Discussion: https://postgr.es/m/CALNJ-vSUpQ_Y%3DjXvTxt1VYFztaBSsWVXeF1y6gTYQ4bOiWDLgQ%40mail.gmail.com
Discussion: https://postgr.es/m/a0b8026459d1e6167933be2104a6174e7d40d0ab.camel%40j-davis.com#fe7218c83b08068bfffb0c5293eceda0
Author: Paul Jungwirth, revised by me
Reviewed-by: David Fetter, Corey Huinker, Jeff Davis, Pavel Stehule
Reviewed-by: Alvaro Herrera, Tom Lane, Isaac Morland, David G. Johnston
Reviewed-by: Zhihong Yu, Alexander Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
DETAIL: A result of type anycompatiblerange requires at least one input of type anycompatiblerange or anycompatiblemultirange.
|
2011-11-03 12:16:28 +01:00
|
|
|
--
|
|
|
|
-- Arrays of ranges
|
|
|
|
--
|
2011-11-23 02:45:05 +01:00
|
|
|
select ARRAY[numrange(1.1, 1.2), numrange(12.3, 155.5)];
|
2011-11-03 12:16:28 +01:00
|
|
|
array
|
|
|
|
------------------------------
|
2011-11-23 02:45:05 +01:00
|
|
|
{"[1.1,1.2)","[12.3,155.5)"}
|
2011-11-03 12:16:28 +01:00
|
|
|
(1 row)
|
|
|
|
|
2011-11-15 03:42:04 +01:00
|
|
|
create table i8r_array (f1 int, f2 int8range[]);
|
|
|
|
insert into i8r_array values (42, array[int8range(1,10), int8range(2,20)]);
|
|
|
|
select * from i8r_array;
|
|
|
|
f1 | f2
|
|
|
|
----+---------------------
|
|
|
|
42 | {"[1,10)","[2,20)"}
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
drop table i8r_array;
|
2011-11-03 12:16:28 +01:00
|
|
|
--
|
|
|
|
-- Ranges of arrays
|
|
|
|
--
|
|
|
|
create type arrayrange as range (subtype=int4[]);
|
|
|
|
select arrayrange(ARRAY[1,2], ARRAY[2,1]);
|
|
|
|
arrayrange
|
|
|
|
-------------------
|
|
|
|
["{1,2}","{2,1}")
|
|
|
|
(1 row)
|
|
|
|
|
2011-11-22 22:05:49 +01:00
|
|
|
select arrayrange(ARRAY[2,1], ARRAY[1,2]); -- fail
|
|
|
|
ERROR: range lower bound must be less than or equal to range upper bound
|
2011-11-18 00:56:33 +01:00
|
|
|
select array[1,1] <@ arrayrange(array[1,2], array[2,1]);
|
|
|
|
?column?
|
|
|
|
----------
|
|
|
|
f
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select array[1,3] <@ arrayrange(array[1,2], array[2,1]);
|
|
|
|
?column?
|
|
|
|
----------
|
|
|
|
t
|
|
|
|
(1 row)
|
|
|
|
|
2016-07-29 20:13:19 +02:00
|
|
|
--
|
|
|
|
-- Ranges of composites
|
|
|
|
--
|
|
|
|
create type two_ints as (a int, b int);
|
|
|
|
create type two_ints_range as range (subtype = two_ints);
|
|
|
|
-- with force_parallel_mode on, this exercises tqueue.c's range remapping
|
|
|
|
select *, row_to_json(upper(t)) as u from
|
|
|
|
(values (two_ints_range(row(1,2), row(3,4))),
|
|
|
|
(two_ints_range(row(5,6), row(7,8)))) v(t);
|
|
|
|
t | u
|
|
|
|
-------------------+---------------
|
|
|
|
["(1,2)","(3,4)") | {"a":3,"b":4}
|
|
|
|
["(5,6)","(7,8)") | {"a":7,"b":8}
|
|
|
|
(2 rows)
|
|
|
|
|
2019-12-23 18:08:23 +01:00
|
|
|
-- this must be rejected to avoid self-inclusion issues:
|
|
|
|
alter type two_ints add attribute c two_ints_range;
|
|
|
|
ERROR: composite type two_ints cannot be made a member of itself
|
2016-07-29 20:13:19 +02:00
|
|
|
drop type two_ints cascade;
|
|
|
|
NOTICE: drop cascades to type two_ints_range
|
2011-11-03 12:16:28 +01:00
|
|
|
--
|
2017-10-20 23:12:27 +02:00
|
|
|
-- Check behavior when subtype lacks a hash function
|
|
|
|
--
|
|
|
|
create type cashrange as range (subtype = money);
|
|
|
|
set enable_sort = off; -- try to make it pick a hash setop implementation
|
|
|
|
select '(2,5)'::cashrange except select '(5,6)'::cashrange;
|
|
|
|
cashrange
|
|
|
|
---------------
|
|
|
|
($2.00,$5.00)
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
reset enable_sort;
|
|
|
|
--
|
2011-11-03 12:16:28 +01:00
|
|
|
-- OUT/INOUT/TABLE functions
|
|
|
|
--
|
Multirange datatypes
Multiranges are basically sorted arrays of non-overlapping ranges with
set-theoretic operations defined over them.
Since v14, each range type automatically gets a corresponding multirange
datatype. There are both manual and automatic mechanisms for naming multirange
types. Once can specify multirange type name using multirange_type_name
attribute in CREATE TYPE. Otherwise, a multirange type name is generated
automatically. If the range type name contains "range" then we change that to
"multirange". Otherwise, we add "_multirange" to the end.
Implementation of multiranges comes with a space-efficient internal
representation format, which evades extra paddings and duplicated storage of
oids. Altogether this format allows fetching a particular range by its index
in O(n).
Statistic gathering and selectivity estimation are implemented for multiranges.
For this purpose, stored multirange is approximated as union range without gaps.
This field will likely need improvements in the future.
Catversion is bumped.
Discussion: https://postgr.es/m/CALNJ-vSUpQ_Y%3DjXvTxt1VYFztaBSsWVXeF1y6gTYQ4bOiWDLgQ%40mail.gmail.com
Discussion: https://postgr.es/m/a0b8026459d1e6167933be2104a6174e7d40d0ab.camel%40j-davis.com#fe7218c83b08068bfffb0c5293eceda0
Author: Paul Jungwirth, revised by me
Reviewed-by: David Fetter, Corey Huinker, Jeff Davis, Pavel Stehule
Reviewed-by: Alvaro Herrera, Tom Lane, Isaac Morland, David G. Johnston
Reviewed-by: Zhihong Yu, Alexander Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
-- infer anyrange from anyrange
|
2011-11-03 12:16:28 +01:00
|
|
|
create function outparam_succeed(i anyrange, out r anyrange, out t text)
|
2011-11-22 22:05:49 +01:00
|
|
|
as $$ select $1, 'foo'::text $$ language sql;
|
|
|
|
select * from outparam_succeed(int4range(1,2));
|
|
|
|
r | t
|
|
|
|
-------+-----
|
|
|
|
[1,2) | foo
|
|
|
|
(1 row)
|
|
|
|
|
Restructure polymorphic-type resolution in funcapi.c.
resolve_polymorphic_tupdesc() and resolve_polymorphic_argtypes() failed to
cover the case of having to resolve anyarray given only an anyrange input.
The bug was masked if anyelement was also used (as either input or
output), which probably helps account for our not having noticed.
While looking at this I noticed that resolve_generic_type() would produce
the wrong answer if asked to make that same resolution. ISTM that
resolve_generic_type() is confusingly defined and overly complex, so
rather than fix it, let's just make funcapi.c do the specific lookups
it requires for itself.
With this change, resolve_generic_type() is not used anywhere, so remove
it in HEAD. In the back branches, leave it alone (complete with bug)
just in case any external code is using it.
While we're here, make some other refactoring adjustments in funcapi.c
with an eye to upcoming future expansion of the set of polymorphic types:
* Simplify quick-exit tests by adding an overall have_polymorphic_result
flag. This is about a wash now but will be a win when there are more
flags.
* Reduce duplication of code between resolve_polymorphic_tupdesc() and
resolve_polymorphic_argtypes().
* Don't bother to validate correct matching of anynonarray or anyenum;
the parser should have done that, and even if it didn't, just doing
"return false" here would lead to a very confusing, off-point error
message. (Really, "return false" in these two functions should only
occur if the call_expr isn't supplied or we can't obtain data type
info from it.)
* For the same reason, throw an elog rather than "return false" if
we fail to resolve a polymorphic type.
The bug's been there since we added anyrange, so back-patch to
all supported branches.
Discussion: https://postgr.es/m/6093.1584202130@sss.pgh.pa.us
2020-03-14 19:42:22 +01:00
|
|
|
create function outparam2_succeed(r anyrange, out lu anyarray, out ul anyarray)
|
|
|
|
as $$ select array[lower($1), upper($1)], array[upper($1), lower($1)] $$
|
|
|
|
language sql;
|
|
|
|
select * from outparam2_succeed(int4range(1,11));
|
|
|
|
lu | ul
|
|
|
|
--------+--------
|
|
|
|
{1,11} | {11,1}
|
|
|
|
(1 row)
|
|
|
|
|
Multirange datatypes
Multiranges are basically sorted arrays of non-overlapping ranges with
set-theoretic operations defined over them.
Since v14, each range type automatically gets a corresponding multirange
datatype. There are both manual and automatic mechanisms for naming multirange
types. Once can specify multirange type name using multirange_type_name
attribute in CREATE TYPE. Otherwise, a multirange type name is generated
automatically. If the range type name contains "range" then we change that to
"multirange". Otherwise, we add "_multirange" to the end.
Implementation of multiranges comes with a space-efficient internal
representation format, which evades extra paddings and duplicated storage of
oids. Altogether this format allows fetching a particular range by its index
in O(n).
Statistic gathering and selectivity estimation are implemented for multiranges.
For this purpose, stored multirange is approximated as union range without gaps.
This field will likely need improvements in the future.
Catversion is bumped.
Discussion: https://postgr.es/m/CALNJ-vSUpQ_Y%3DjXvTxt1VYFztaBSsWVXeF1y6gTYQ4bOiWDLgQ%40mail.gmail.com
Discussion: https://postgr.es/m/a0b8026459d1e6167933be2104a6174e7d40d0ab.camel%40j-davis.com#fe7218c83b08068bfffb0c5293eceda0
Author: Paul Jungwirth, revised by me
Reviewed-by: David Fetter, Corey Huinker, Jeff Davis, Pavel Stehule
Reviewed-by: Alvaro Herrera, Tom Lane, Isaac Morland, David G. Johnston
Reviewed-by: Zhihong Yu, Alexander Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
-- infer anyarray from anyrange
|
|
|
|
create function outparam_succeed2(i anyrange, out r anyarray, out t text)
|
|
|
|
as $$ select ARRAY[upper($1)], 'foo'::text $$ language sql;
|
|
|
|
select * from outparam_succeed2(int4range(int4range(1,2)));
|
|
|
|
r | t
|
|
|
|
-----+-----
|
|
|
|
{2} | foo
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
-- infer anyelement from anyrange
|
2011-11-03 12:16:28 +01:00
|
|
|
create function inoutparam_succeed(out i anyelement, inout r anyrange)
|
2011-11-22 22:05:49 +01:00
|
|
|
as $$ select upper($1), $1 $$ language sql;
|
|
|
|
select * from inoutparam_succeed(int4range(1,2));
|
|
|
|
i | r
|
|
|
|
---+-------
|
|
|
|
2 | [1,2)
|
|
|
|
(1 row)
|
|
|
|
|
Restructure polymorphic-type resolution in funcapi.c.
resolve_polymorphic_tupdesc() and resolve_polymorphic_argtypes() failed to
cover the case of having to resolve anyarray given only an anyrange input.
The bug was masked if anyelement was also used (as either input or
output), which probably helps account for our not having noticed.
While looking at this I noticed that resolve_generic_type() would produce
the wrong answer if asked to make that same resolution. ISTM that
resolve_generic_type() is confusingly defined and overly complex, so
rather than fix it, let's just make funcapi.c do the specific lookups
it requires for itself.
With this change, resolve_generic_type() is not used anywhere, so remove
it in HEAD. In the back branches, leave it alone (complete with bug)
just in case any external code is using it.
While we're here, make some other refactoring adjustments in funcapi.c
with an eye to upcoming future expansion of the set of polymorphic types:
* Simplify quick-exit tests by adding an overall have_polymorphic_result
flag. This is about a wash now but will be a win when there are more
flags.
* Reduce duplication of code between resolve_polymorphic_tupdesc() and
resolve_polymorphic_argtypes().
* Don't bother to validate correct matching of anynonarray or anyenum;
the parser should have done that, and even if it didn't, just doing
"return false" here would lead to a very confusing, off-point error
message. (Really, "return false" in these two functions should only
occur if the call_expr isn't supplied or we can't obtain data type
info from it.)
* For the same reason, throw an elog rather than "return false" if
we fail to resolve a polymorphic type.
The bug's been there since we added anyrange, so back-patch to
all supported branches.
Discussion: https://postgr.es/m/6093.1584202130@sss.pgh.pa.us
2020-03-14 19:42:22 +01:00
|
|
|
create function table_succeed(r anyrange)
|
|
|
|
returns table(l anyelement, u anyelement)
|
|
|
|
as $$ select lower($1), upper($1) $$
|
|
|
|
language sql;
|
|
|
|
select * from table_succeed(int4range(1,11));
|
|
|
|
l | u
|
|
|
|
---+----
|
|
|
|
1 | 11
|
2011-11-22 22:05:49 +01:00
|
|
|
(1 row)
|
|
|
|
|
2011-11-03 12:16:28 +01:00
|
|
|
-- should fail
|
|
|
|
create function outparam_fail(i anyelement, out r anyrange, out t text)
|
|
|
|
as $$ select '[1,10]', 'foo' $$ language sql;
|
|
|
|
ERROR: cannot determine result data type
|
Multirange datatypes
Multiranges are basically sorted arrays of non-overlapping ranges with
set-theoretic operations defined over them.
Since v14, each range type automatically gets a corresponding multirange
datatype. There are both manual and automatic mechanisms for naming multirange
types. Once can specify multirange type name using multirange_type_name
attribute in CREATE TYPE. Otherwise, a multirange type name is generated
automatically. If the range type name contains "range" then we change that to
"multirange". Otherwise, we add "_multirange" to the end.
Implementation of multiranges comes with a space-efficient internal
representation format, which evades extra paddings and duplicated storage of
oids. Altogether this format allows fetching a particular range by its index
in O(n).
Statistic gathering and selectivity estimation are implemented for multiranges.
For this purpose, stored multirange is approximated as union range without gaps.
This field will likely need improvements in the future.
Catversion is bumped.
Discussion: https://postgr.es/m/CALNJ-vSUpQ_Y%3DjXvTxt1VYFztaBSsWVXeF1y6gTYQ4bOiWDLgQ%40mail.gmail.com
Discussion: https://postgr.es/m/a0b8026459d1e6167933be2104a6174e7d40d0ab.camel%40j-davis.com#fe7218c83b08068bfffb0c5293eceda0
Author: Paul Jungwirth, revised by me
Reviewed-by: David Fetter, Corey Huinker, Jeff Davis, Pavel Stehule
Reviewed-by: Alvaro Herrera, Tom Lane, Isaac Morland, David G. Johnston
Reviewed-by: Zhihong Yu, Alexander Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
DETAIL: A result of type anyrange requires at least one input of type anyrange or anymultirange.
|
2011-11-03 12:16:28 +01:00
|
|
|
--should fail
|
|
|
|
create function inoutparam_fail(inout i anyelement, out r anyrange)
|
|
|
|
as $$ select $1, '[1,10]' $$ language sql;
|
|
|
|
ERROR: cannot determine result data type
|
Multirange datatypes
Multiranges are basically sorted arrays of non-overlapping ranges with
set-theoretic operations defined over them.
Since v14, each range type automatically gets a corresponding multirange
datatype. There are both manual and automatic mechanisms for naming multirange
types. Once can specify multirange type name using multirange_type_name
attribute in CREATE TYPE. Otherwise, a multirange type name is generated
automatically. If the range type name contains "range" then we change that to
"multirange". Otherwise, we add "_multirange" to the end.
Implementation of multiranges comes with a space-efficient internal
representation format, which evades extra paddings and duplicated storage of
oids. Altogether this format allows fetching a particular range by its index
in O(n).
Statistic gathering and selectivity estimation are implemented for multiranges.
For this purpose, stored multirange is approximated as union range without gaps.
This field will likely need improvements in the future.
Catversion is bumped.
Discussion: https://postgr.es/m/CALNJ-vSUpQ_Y%3DjXvTxt1VYFztaBSsWVXeF1y6gTYQ4bOiWDLgQ%40mail.gmail.com
Discussion: https://postgr.es/m/a0b8026459d1e6167933be2104a6174e7d40d0ab.camel%40j-davis.com#fe7218c83b08068bfffb0c5293eceda0
Author: Paul Jungwirth, revised by me
Reviewed-by: David Fetter, Corey Huinker, Jeff Davis, Pavel Stehule
Reviewed-by: Alvaro Herrera, Tom Lane, Isaac Morland, David G. Johnston
Reviewed-by: Zhihong Yu, Alexander Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
DETAIL: A result of type anyrange requires at least one input of type anyrange or anymultirange.
|
2011-11-03 12:16:28 +01:00
|
|
|
--should fail
|
2011-11-22 22:05:49 +01:00
|
|
|
create function table_fail(i anyelement) returns table(i anyelement, r anyrange)
|
2011-11-03 12:16:28 +01:00
|
|
|
as $$ select $1, '[1,10]' $$ language sql;
|
|
|
|
ERROR: cannot determine result data type
|
Multirange datatypes
Multiranges are basically sorted arrays of non-overlapping ranges with
set-theoretic operations defined over them.
Since v14, each range type automatically gets a corresponding multirange
datatype. There are both manual and automatic mechanisms for naming multirange
types. Once can specify multirange type name using multirange_type_name
attribute in CREATE TYPE. Otherwise, a multirange type name is generated
automatically. If the range type name contains "range" then we change that to
"multirange". Otherwise, we add "_multirange" to the end.
Implementation of multiranges comes with a space-efficient internal
representation format, which evades extra paddings and duplicated storage of
oids. Altogether this format allows fetching a particular range by its index
in O(n).
Statistic gathering and selectivity estimation are implemented for multiranges.
For this purpose, stored multirange is approximated as union range without gaps.
This field will likely need improvements in the future.
Catversion is bumped.
Discussion: https://postgr.es/m/CALNJ-vSUpQ_Y%3DjXvTxt1VYFztaBSsWVXeF1y6gTYQ4bOiWDLgQ%40mail.gmail.com
Discussion: https://postgr.es/m/a0b8026459d1e6167933be2104a6174e7d40d0ab.camel%40j-davis.com#fe7218c83b08068bfffb0c5293eceda0
Author: Paul Jungwirth, revised by me
Reviewed-by: David Fetter, Corey Huinker, Jeff Davis, Pavel Stehule
Reviewed-by: Alvaro Herrera, Tom Lane, Isaac Morland, David G. Johnston
Reviewed-by: Zhihong Yu, Alexander Korotkov
2020-12-20 05:20:33 +01:00
|
|
|
DETAIL: A result of type anyrange requires at least one input of type anyrange or anymultirange.
|