1
0
mirror of https://github.com/postgres/postgres.git synced 2025-12-19 17:02:53 +03:00

Add range_minus_multi and multirange_minus_multi functions

The existing range_minus function raises an exception when the range is
"split", because then the result can't be represented by a single range.
For example '[0,10)'::int4range - '[4,5)' would be '[0,4)' and '[5,10)'.

This commit adds new set-returning functions so that callers can get
results even in the case of splits. There is no risk of an exception for
multiranges, but a set-returning function lets us handle them the same
way we handle ranges.

Both functions return zero results if the subtraction would give an
empty range/multirange.

The main use-case for these functions is to implement UPDATE/DELETE FOR
PORTION OF, which must compute the application-time of "temporal
leftovers": the part of history in an updated/deleted row that was not
changed. To preserve the untouched history, we will implicitly insert
one record for each result returned by range/multirange_minus_multi.
Using a set-returning function will also let us support user-defined
types for application-time update/delete in the future.

Author: Paul A. Jungwirth <pj@illuminatedcomputing.com>
Reviewed-by: Peter Eisentraut <peter@eisentraut.org>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Discussion: https://www.postgresql.org/message-id/flat/ec498c3d-5f2b-48ec-b989-5561c8aa2024%40illuminatedcomputing.com
This commit is contained in:
Peter Eisentraut
2025-11-22 09:40:00 +01:00
parent 0dceba21d7
commit 5eed8ce50c
10 changed files with 493 additions and 1 deletions

View File

@@ -2200,6 +2200,122 @@ SELECT nummultirange(numrange(1,2), numrange(4,5)) - nummultirange(numrange(-2,0
{[1,2),[4,5)}
(1 row)
-- multirange_minus_multi
SELECT multirange_minus_multi(nummultirange(), nummultirange());
multirange_minus_multi
------------------------
(0 rows)
SELECT multirange_minus_multi(nummultirange(), nummultirange(numrange(1,2)));
multirange_minus_multi
------------------------
(0 rows)
SELECT multirange_minus_multi(nummultirange(numrange(1,2)), nummultirange());
multirange_minus_multi
------------------------
{[1,2)}
(1 row)
SELECT multirange_minus_multi(nummultirange(numrange(1,2), numrange(3,4)), nummultirange());
multirange_minus_multi
------------------------
{[1,2),[3,4)}
(1 row)
SELECT multirange_minus_multi(nummultirange(numrange(1,2)), nummultirange(numrange(1,2)));
multirange_minus_multi
------------------------
(0 rows)
SELECT multirange_minus_multi(nummultirange(numrange(1,2)), nummultirange(numrange(2,4)));
multirange_minus_multi
------------------------
{[1,2)}
(1 row)
SELECT multirange_minus_multi(nummultirange(numrange(1,2)), nummultirange(numrange(3,4)));
multirange_minus_multi
------------------------
{[1,2)}
(1 row)
SELECT multirange_minus_multi(nummultirange(numrange(1,4)), nummultirange(numrange(1,2)));
multirange_minus_multi
------------------------
{[2,4)}
(1 row)
SELECT multirange_minus_multi(nummultirange(numrange(1,4)), nummultirange(numrange(2,3)));
multirange_minus_multi
------------------------
{[1,2),[3,4)}
(1 row)
SELECT multirange_minus_multi(nummultirange(numrange(1,4)), nummultirange(numrange(0,8)));
multirange_minus_multi
------------------------
(0 rows)
SELECT multirange_minus_multi(nummultirange(numrange(1,4)), nummultirange(numrange(0,2)));
multirange_minus_multi
------------------------
{[2,4)}
(1 row)
SELECT multirange_minus_multi(nummultirange(numrange(1,8)), nummultirange(numrange(0,2), numrange(3,4)));
multirange_minus_multi
------------------------
{[2,3),[4,8)}
(1 row)
SELECT multirange_minus_multi(nummultirange(numrange(1,8)), nummultirange(numrange(2,3), numrange(5,null)));
multirange_minus_multi
------------------------
{[1,2),[3,5)}
(1 row)
SELECT multirange_minus_multi(nummultirange(numrange(1,2), numrange(4,5)), nummultirange(numrange(-2,0)));
multirange_minus_multi
------------------------
{[1,2),[4,5)}
(1 row)
SELECT multirange_minus_multi(nummultirange(numrange(1,2), numrange(4,5)), nummultirange(numrange(2,4)));
multirange_minus_multi
------------------------
{[1,2),[4,5)}
(1 row)
SELECT multirange_minus_multi(nummultirange(numrange(1,2), numrange(4,5)), nummultirange(numrange(3,5)));
multirange_minus_multi
------------------------
{[1,2)}
(1 row)
SELECT multirange_minus_multi(nummultirange(numrange(1,2), numrange(4,5)), nummultirange(numrange(0,9)));
multirange_minus_multi
------------------------
(0 rows)
SELECT multirange_minus_multi(nummultirange(numrange(1,3), numrange(4,5)), nummultirange(numrange(2,9)));
multirange_minus_multi
------------------------
{[1,2)}
(1 row)
SELECT multirange_minus_multi(nummultirange(numrange(1,2), numrange(4,5)), nummultirange(numrange(8,9)));
multirange_minus_multi
------------------------
{[1,2),[4,5)}
(1 row)
SELECT multirange_minus_multi(nummultirange(numrange(1,2), numrange(4,5)), nummultirange(numrange(-2,0), numrange(8,9)));
multirange_minus_multi
------------------------
{[1,2),[4,5)}
(1 row)
-- intersection
SELECT nummultirange() * nummultirange();
?column?

View File

@@ -481,6 +481,60 @@ select range_minus(numrange(10.1,12.2,'[]'), numrange(0.0,120.2,'(]'));
empty
(1 row)
select range_minus_multi('empty'::numrange, numrange(2.0, 3.0));
range_minus_multi
-------------------
(0 rows)
select range_minus_multi(numrange(1.1, 2.2), 'empty'::numrange);
range_minus_multi
-------------------
[1.1,2.2)
(1 row)
select range_minus_multi(numrange(1.1, 2.2), numrange(2.0, 3.0));
range_minus_multi
-------------------
[1.1,2.0)
(1 row)
select range_minus_multi(numrange(1.1, 2.2), numrange(2.2, 3.0));
range_minus_multi
-------------------
[1.1,2.2)
(1 row)
select range_minus_multi(numrange(1.1, 2.2,'[]'), numrange(2.0, 3.0));
range_minus_multi
-------------------
[1.1,2.0)
(1 row)
select range_minus_multi(numrange(1.0, 3.0), numrange(1.5, 2.0));
range_minus_multi
-------------------
[1.0,1.5)
[2.0,3.0)
(2 rows)
select range_minus_multi(numrange(10.1,12.2,'[]'), numrange(110.0,120.2,'(]'));
range_minus_multi
-------------------
[10.1,12.2]
(1 row)
select range_minus_multi(numrange(10.1,12.2,'[]'), numrange(0.0,120.2,'(]'));
range_minus_multi
-------------------
(0 rows)
select range_minus_multi(numrange(1.0,3.0,'[]'), numrange(1.5,2.0,'(]'));
range_minus_multi
-------------------
[1.0,1.5]
(2.0,3.0]
(2 rows)
select numrange(4.5, 5.5, '[]') && numrange(5.5, 6.5);
?column?
----------

View File

@@ -414,6 +414,28 @@ SELECT nummultirange(numrange(1,3), numrange(4,5)) - nummultirange(numrange(2,9)
SELECT nummultirange(numrange(1,2), numrange(4,5)) - nummultirange(numrange(8,9));
SELECT nummultirange(numrange(1,2), numrange(4,5)) - nummultirange(numrange(-2,0), numrange(8,9));
-- multirange_minus_multi
SELECT multirange_minus_multi(nummultirange(), nummultirange());
SELECT multirange_minus_multi(nummultirange(), nummultirange(numrange(1,2)));
SELECT multirange_minus_multi(nummultirange(numrange(1,2)), nummultirange());
SELECT multirange_minus_multi(nummultirange(numrange(1,2), numrange(3,4)), nummultirange());
SELECT multirange_minus_multi(nummultirange(numrange(1,2)), nummultirange(numrange(1,2)));
SELECT multirange_minus_multi(nummultirange(numrange(1,2)), nummultirange(numrange(2,4)));
SELECT multirange_minus_multi(nummultirange(numrange(1,2)), nummultirange(numrange(3,4)));
SELECT multirange_minus_multi(nummultirange(numrange(1,4)), nummultirange(numrange(1,2)));
SELECT multirange_minus_multi(nummultirange(numrange(1,4)), nummultirange(numrange(2,3)));
SELECT multirange_minus_multi(nummultirange(numrange(1,4)), nummultirange(numrange(0,8)));
SELECT multirange_minus_multi(nummultirange(numrange(1,4)), nummultirange(numrange(0,2)));
SELECT multirange_minus_multi(nummultirange(numrange(1,8)), nummultirange(numrange(0,2), numrange(3,4)));
SELECT multirange_minus_multi(nummultirange(numrange(1,8)), nummultirange(numrange(2,3), numrange(5,null)));
SELECT multirange_minus_multi(nummultirange(numrange(1,2), numrange(4,5)), nummultirange(numrange(-2,0)));
SELECT multirange_minus_multi(nummultirange(numrange(1,2), numrange(4,5)), nummultirange(numrange(2,4)));
SELECT multirange_minus_multi(nummultirange(numrange(1,2), numrange(4,5)), nummultirange(numrange(3,5)));
SELECT multirange_minus_multi(nummultirange(numrange(1,2), numrange(4,5)), nummultirange(numrange(0,9)));
SELECT multirange_minus_multi(nummultirange(numrange(1,3), numrange(4,5)), nummultirange(numrange(2,9)));
SELECT multirange_minus_multi(nummultirange(numrange(1,2), numrange(4,5)), nummultirange(numrange(8,9)));
SELECT multirange_minus_multi(nummultirange(numrange(1,2), numrange(4,5)), nummultirange(numrange(-2,0), numrange(8,9)));
-- intersection
SELECT nummultirange() * nummultirange();
SELECT nummultirange() * nummultirange(numrange(1,2));

View File

@@ -107,6 +107,16 @@ select numrange(1.1, 2.2,'[]') - numrange(2.0, 3.0);
select range_minus(numrange(10.1,12.2,'[]'), numrange(110.0,120.2,'(]'));
select range_minus(numrange(10.1,12.2,'[]'), numrange(0.0,120.2,'(]'));
select range_minus_multi('empty'::numrange, numrange(2.0, 3.0));
select range_minus_multi(numrange(1.1, 2.2), 'empty'::numrange);
select range_minus_multi(numrange(1.1, 2.2), numrange(2.0, 3.0));
select range_minus_multi(numrange(1.1, 2.2), numrange(2.2, 3.0));
select range_minus_multi(numrange(1.1, 2.2,'[]'), numrange(2.0, 3.0));
select range_minus_multi(numrange(1.0, 3.0), numrange(1.5, 2.0));
select range_minus_multi(numrange(10.1,12.2,'[]'), numrange(110.0,120.2,'(]'));
select range_minus_multi(numrange(10.1,12.2,'[]'), numrange(0.0,120.2,'(]'));
select range_minus_multi(numrange(1.0,3.0,'[]'), numrange(1.5,2.0,'(]'));
select numrange(4.5, 5.5, '[]') && numrange(5.5, 6.5);
select numrange(1.0, 2.0) << numrange(3.0, 4.0);
select numrange(1.0, 3.0,'[]') << numrange(3.0, 4.0,'[]');