mirror of
https://github.com/postgres/postgres.git
synced 2025-04-25 21:42:33 +03:00
Add range_agg with multirange inputs
range_agg for normal ranges already existed. A lot of code can be shared. Author: Paul Jungwirth <pj@illuminatedcomputing.com> Reviewed-by: Chapman Flack <chap@anastigmatix.net> Discussion: https://www.postgresql.org/message-id/flat/007ef255-35ef-fd26-679c-f97e7a7f30c2@illuminatedcomputing.com
This commit is contained in:
parent
ff50baec65
commit
7ae1619bc5
@ -20007,6 +20007,11 @@ SELECT NULLIF(value, '(none)') ...
|
||||
<type>anyrange</type> )
|
||||
<returnvalue>anymultirange</returnvalue>
|
||||
</para>
|
||||
<para role="func_signature">
|
||||
<function>range_agg</function> ( <parameter>value</parameter>
|
||||
<type>anymultirange</type> )
|
||||
<returnvalue>anymultirange</returnvalue>
|
||||
</para>
|
||||
<para>
|
||||
Computes the union of the non-null input values.
|
||||
</para></entry>
|
||||
|
@ -1361,6 +1361,9 @@ range_agg_transfn(PG_FUNCTION_ARGS)
|
||||
|
||||
/*
|
||||
* range_agg_finalfn: use our internal array to merge touching ranges.
|
||||
*
|
||||
* Shared by range_agg_finalfn(anyrange) and
|
||||
* multirange_agg_finalfn(anymultirange).
|
||||
*/
|
||||
Datum
|
||||
range_agg_finalfn(PG_FUNCTION_ARGS)
|
||||
@ -1396,6 +1399,64 @@ range_agg_finalfn(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_MULTIRANGE_P(make_multirange(mltrngtypoid, typcache->rngtype, range_count, ranges));
|
||||
}
|
||||
|
||||
/*
|
||||
* multirange_agg_transfn: combine adjacent/overlapping multiranges.
|
||||
*
|
||||
* All we do here is gather the input multiranges' ranges into an array so
|
||||
* that the finalfn can sort and combine them.
|
||||
*/
|
||||
Datum
|
||||
multirange_agg_transfn(PG_FUNCTION_ARGS)
|
||||
{
|
||||
MemoryContext aggContext;
|
||||
Oid mltrngtypoid;
|
||||
TypeCacheEntry *typcache;
|
||||
TypeCacheEntry *rngtypcache;
|
||||
ArrayBuildState *state;
|
||||
|
||||
if (!AggCheckCallContext(fcinfo, &aggContext))
|
||||
elog(ERROR, "multirange_agg_transfn called in non-aggregate context");
|
||||
|
||||
mltrngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
|
||||
if (!type_is_multirange(mltrngtypoid))
|
||||
elog(ERROR, "range_agg must be called with a multirange");
|
||||
|
||||
typcache = multirange_get_typcache(fcinfo, mltrngtypoid);
|
||||
rngtypcache = typcache->rngtype;
|
||||
|
||||
if (PG_ARGISNULL(0))
|
||||
state = initArrayResult(rngtypcache->type_id, aggContext, false);
|
||||
else
|
||||
state = (ArrayBuildState *) PG_GETARG_POINTER(0);
|
||||
|
||||
/* skip NULLs */
|
||||
if (!PG_ARGISNULL(1))
|
||||
{
|
||||
MultirangeType *current;
|
||||
int32 range_count;
|
||||
RangeType **ranges;
|
||||
|
||||
current = PG_GETARG_MULTIRANGE_P(1);
|
||||
multirange_deserialize(rngtypcache, current, &range_count, &ranges);
|
||||
if (range_count == 0)
|
||||
{
|
||||
/*
|
||||
* Add an empty range so we get an empty result (not a null result).
|
||||
*/
|
||||
accumArrayResult(state,
|
||||
RangeTypePGetDatum(make_empty_range(rngtypcache)),
|
||||
false, rngtypcache->type_id, aggContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int32 i = 0; i < range_count; i++)
|
||||
accumArrayResult(state, RangeTypePGetDatum(ranges[i]), false, rngtypcache->type_id, aggContext);
|
||||
}
|
||||
}
|
||||
|
||||
PG_RETURN_POINTER(state);
|
||||
}
|
||||
|
||||
Datum
|
||||
multirange_intersect_agg_transfn(PG_FUNCTION_ARGS)
|
||||
{
|
||||
|
@ -53,6 +53,6 @@
|
||||
*/
|
||||
|
||||
/* yyyymmddN */
|
||||
#define CATALOG_VERSION_NO 202203291
|
||||
#define CATALOG_VERSION_NO 202203301
|
||||
|
||||
#endif
|
||||
|
@ -563,6 +563,9 @@
|
||||
{ aggfnoid => 'range_agg(anyrange)', aggtransfn => 'range_agg_transfn',
|
||||
aggfinalfn => 'range_agg_finalfn', aggfinalextra => 't',
|
||||
aggtranstype => 'internal' },
|
||||
{ aggfnoid => 'range_agg(anymultirange)', aggtransfn => 'multirange_agg_transfn',
|
||||
aggfinalfn => 'multirange_agg_finalfn', aggfinalextra => 't',
|
||||
aggtranstype => 'internal' },
|
||||
|
||||
# json
|
||||
{ aggfnoid => 'json_agg', aggtransfn => 'json_agg_transfn',
|
||||
|
@ -10688,6 +10688,17 @@
|
||||
proname => 'range_agg', prokind => 'a', proisstrict => 'f',
|
||||
prorettype => 'anymultirange', proargtypes => 'anyrange',
|
||||
prosrc => 'aggregate_dummy' },
|
||||
{ oid => '8205', descr => 'aggregate transition function',
|
||||
proname => 'multirange_agg_transfn', proisstrict => 'f', prorettype => 'internal',
|
||||
proargtypes => 'internal anymultirange', prosrc => 'multirange_agg_transfn' },
|
||||
{ oid => '8206', descr => 'aggregate final function',
|
||||
proname => 'multirange_agg_finalfn', proisstrict => 'f',
|
||||
prorettype => 'anymultirange', proargtypes => 'internal anymultirange',
|
||||
prosrc => 'range_agg_finalfn' },
|
||||
{ oid => '8207', descr => 'combine aggregate input into a multirange',
|
||||
proname => 'range_agg', prokind => 'a', proisstrict => 'f',
|
||||
prorettype => 'anymultirange', proargtypes => 'anymultirange',
|
||||
prosrc => 'aggregate_dummy' },
|
||||
{ oid => '4388', descr => 'range aggregate by intersecting',
|
||||
proname => 'multirange_intersect_agg_transfn', prorettype => 'anymultirange',
|
||||
proargtypes => 'anymultirange anymultirange',
|
||||
|
@ -2784,6 +2784,67 @@ FROM (VALUES
|
||||
{[a,f],[g,j)}
|
||||
(1 row)
|
||||
|
||||
-- range_agg with multirange inputs
|
||||
select range_agg(nmr) from nummultirange_test;
|
||||
range_agg
|
||||
-----------
|
||||
{(,)}
|
||||
(1 row)
|
||||
|
||||
select range_agg(nmr) from nummultirange_test where false;
|
||||
range_agg
|
||||
-----------
|
||||
|
||||
(1 row)
|
||||
|
||||
select range_agg(null::nummultirange) from nummultirange_test;
|
||||
range_agg
|
||||
-----------
|
||||
|
||||
(1 row)
|
||||
|
||||
select range_agg(nmr) from (values ('{}'::nummultirange)) t(nmr);
|
||||
range_agg
|
||||
-----------
|
||||
{}
|
||||
(1 row)
|
||||
|
||||
select range_agg(nmr) from (values ('{}'::nummultirange), ('{}'::nummultirange)) t(nmr);
|
||||
range_agg
|
||||
-----------
|
||||
{}
|
||||
(1 row)
|
||||
|
||||
select range_agg(nmr) from (values ('{[1,2]}'::nummultirange)) t(nmr);
|
||||
range_agg
|
||||
-----------
|
||||
{[1,2]}
|
||||
(1 row)
|
||||
|
||||
select range_agg(nmr) from (values ('{[1,2], [5,6]}'::nummultirange)) t(nmr);
|
||||
range_agg
|
||||
---------------
|
||||
{[1,2],[5,6]}
|
||||
(1 row)
|
||||
|
||||
select range_agg(nmr) from (values ('{[1,2], [2,3]}'::nummultirange)) t(nmr);
|
||||
range_agg
|
||||
-----------
|
||||
{[1,3]}
|
||||
(1 row)
|
||||
|
||||
select range_agg(nmr) from (values ('{[1,2]}'::nummultirange), ('{[5,6]}'::nummultirange)) t(nmr);
|
||||
range_agg
|
||||
---------------
|
||||
{[1,2],[5,6]}
|
||||
(1 row)
|
||||
|
||||
select range_agg(nmr) from (values ('{[1,2]}'::nummultirange), ('{[2,3]}'::nummultirange)) t(nmr);
|
||||
range_agg
|
||||
-----------
|
||||
{[1,3]}
|
||||
(1 row)
|
||||
|
||||
--
|
||||
-- range_intersect_agg function
|
||||
--
|
||||
|
@ -201,7 +201,8 @@ ORDER BY 1, 2;
|
||||
timestamp without time zone | timestamp with time zone
|
||||
bit | bit varying
|
||||
txid_snapshot | pg_snapshot
|
||||
(4 rows)
|
||||
anyrange | anymultirange
|
||||
(5 rows)
|
||||
|
||||
SELECT DISTINCT p1.proargtypes[2]::regtype, p2.proargtypes[2]::regtype
|
||||
FROM pg_proc AS p1, pg_proc AS p2
|
||||
|
@ -572,6 +572,18 @@ FROM (VALUES
|
||||
('[h,j)'::textrange)
|
||||
) t(r);
|
||||
|
||||
-- range_agg with multirange inputs
|
||||
select range_agg(nmr) from nummultirange_test;
|
||||
select range_agg(nmr) from nummultirange_test where false;
|
||||
select range_agg(null::nummultirange) from nummultirange_test;
|
||||
select range_agg(nmr) from (values ('{}'::nummultirange)) t(nmr);
|
||||
select range_agg(nmr) from (values ('{}'::nummultirange), ('{}'::nummultirange)) t(nmr);
|
||||
select range_agg(nmr) from (values ('{[1,2]}'::nummultirange)) t(nmr);
|
||||
select range_agg(nmr) from (values ('{[1,2], [5,6]}'::nummultirange)) t(nmr);
|
||||
select range_agg(nmr) from (values ('{[1,2], [2,3]}'::nummultirange)) t(nmr);
|
||||
select range_agg(nmr) from (values ('{[1,2]}'::nummultirange), ('{[5,6]}'::nummultirange)) t(nmr);
|
||||
select range_agg(nmr) from (values ('{[1,2]}'::nummultirange), ('{[2,3]}'::nummultirange)) t(nmr);
|
||||
|
||||
--
|
||||
-- range_intersect_agg function
|
||||
--
|
||||
|
Loading…
x
Reference in New Issue
Block a user