diff options
| author | Tom Lane | 2013-09-03 21:08:38 +0000 |
|---|---|---|
| committer | Tom Lane | 2013-09-03 21:08:46 +0000 |
| commit | 0d3f4406dfa00d848711fdb4af53be663ffc7d0f (patch) | |
| tree | 1241750b2425a43f2cdc09cb9f0c8641dc1c4904 /src/test | |
| parent | 8b290f3115db5bbe85176160c7cabe0d927dcc37 (diff) | |
Allow aggregate functions to be VARIADIC.
There's no inherent reason why an aggregate function can't be variadic
(even VARIADIC ANY) if its transition function can handle the case.
Indeed, this patch to add the feature touches none of the planner or
executor, and little of the parser; the main missing stuff was DDL and
pg_dump support.
It is true that variadic aggregates can create the same sort of ambiguity
about parameters versus ORDER BY keys that was complained of when we
(briefly) had both one- and two-argument forms of string_agg(). However,
the policy formed in response to that discussion only said that we'd not
create any built-in aggregates with varying numbers of arguments, not that
we shouldn't allow users to do it. So the logical extension of that is
we can allow users to make variadic aggregates as long as we're wary about
shipping any such in core.
In passing, this patch allows aggregate function arguments to be named, to
the extent of remembering the names in pg_proc and dumping them in pg_dump.
You can't yet call an aggregate using named-parameter notation. That seems
like a likely future extension, but it'll take some work, and it's not what
this patch is really about. Likewise, there's still some work needed to
make window functions handle VARIADIC fully, but I left that for another
day.
initdb forced because of new aggvariadic field in Aggref parse nodes.
Diffstat (limited to 'src/test')
| -rw-r--r-- | src/test/regress/expected/aggregates.out | 13 | ||||
| -rw-r--r-- | src/test/regress/expected/create_aggregate.out | 7 | ||||
| -rw-r--r-- | src/test/regress/expected/opr_sanity.out | 12 | ||||
| -rw-r--r-- | src/test/regress/sql/aggregates.sql | 4 | ||||
| -rw-r--r-- | src/test/regress/sql/create_aggregate.sql | 9 | ||||
| -rw-r--r-- | src/test/regress/sql/opr_sanity.sql | 10 |
6 files changed, 53 insertions, 2 deletions
diff --git a/src/test/regress/expected/aggregates.out b/src/test/regress/expected/aggregates.out index 7fa900578c..1af79e57e9 100644 --- a/src/test/regress/expected/aggregates.out +++ b/src/test/regress/expected/aggregates.out @@ -1249,3 +1249,16 @@ select aggfns(distinct a,b,c order by a,c using ~<~,b) filter (where a > 1) {"(2,2,bar)","(3,1,baz)"} (1 row) +-- variadic aggregates +select least_agg(q1,q2) from int8_tbl; + least_agg +------------------- + -4567890123456789 +(1 row) + +select least_agg(variadic array[q1,q2]) from int8_tbl; + least_agg +------------------- + -4567890123456789 +(1 row) + diff --git a/src/test/regress/expected/create_aggregate.out b/src/test/regress/expected/create_aggregate.out index ad1459419f..6c7566f172 100644 --- a/src/test/regress/expected/create_aggregate.out +++ b/src/test/regress/expected/create_aggregate.out @@ -59,3 +59,10 @@ create aggregate aggfns(integer,integer,text) ( sfunc = aggfns_trans, stype = aggtype[], initcond = '{}' ); +-- variadic aggregate +create function least_accum(anyelement, variadic anyarray) +returns anyelement language sql as + 'select least($1, min($2[i])) from generate_subscripts($2,1) g(i)'; +create aggregate least_agg(variadic items anyarray) ( + stype = anyelement, sfunc = least_accum +); diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out index 256b7196d0..515cd9daaa 100644 --- a/src/test/regress/expected/opr_sanity.out +++ b/src/test/regress/expected/opr_sanity.out @@ -843,6 +843,8 @@ ORDER BY 1, 2; -- to avoid this because it opens the door for confusion in connection with -- ORDER BY: novices frequently put the ORDER BY in the wrong place. -- See the fate of the single-argument form of string_agg() for history. +-- (Note: we don't forbid users from creating such aggregates; the policy is +-- just to think twice before creating built-in aggregates like this.) -- The only aggregates that should show up here are count(x) and count(*). SELECT p1.oid::regprocedure, p2.oid::regprocedure FROM pg_proc AS p1, pg_proc AS p2 @@ -855,7 +857,15 @@ ORDER BY 1; count("any") | count() (1 row) --- For the same reason, aggregates with default arguments are no good. +-- For the same reason, we avoid creating built-in variadic aggregates. +SELECT oid, proname +FROM pg_proc AS p +WHERE proisagg AND provariadic != 0; + oid | proname +-----+--------- +(0 rows) + +-- For the same reason, built-in aggregates with default arguments are no good. SELECT oid, proname FROM pg_proc AS p WHERE proisagg AND proargdefaults IS NOT NULL; diff --git a/src/test/regress/sql/aggregates.sql b/src/test/regress/sql/aggregates.sql index 5c0196f5cf..397edffd3a 100644 --- a/src/test/regress/sql/aggregates.sql +++ b/src/test/regress/sql/aggregates.sql @@ -480,3 +480,7 @@ select sum(unique1) FILTER (WHERE select aggfns(distinct a,b,c order by a,c using ~<~,b) filter (where a > 1) from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c), generate_series(1,2) i; + +-- variadic aggregates +select least_agg(q1,q2) from int8_tbl; +select least_agg(variadic array[q1,q2]) from int8_tbl; diff --git a/src/test/regress/sql/create_aggregate.sql b/src/test/regress/sql/create_aggregate.sql index 84f9a4f1e0..3c7d330960 100644 --- a/src/test/regress/sql/create_aggregate.sql +++ b/src/test/regress/sql/create_aggregate.sql @@ -71,3 +71,12 @@ create aggregate aggfns(integer,integer,text) ( sfunc = aggfns_trans, stype = aggtype[], initcond = '{}' ); + +-- variadic aggregate +create function least_accum(anyelement, variadic anyarray) +returns anyelement language sql as + 'select least($1, min($2[i])) from generate_subscripts($2,1) g(i)'; + +create aggregate least_agg(variadic items anyarray) ( + stype = anyelement, sfunc = least_accum +); diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql index a3be0c1114..efcd70f03b 100644 --- a/src/test/regress/sql/opr_sanity.sql +++ b/src/test/regress/sql/opr_sanity.sql @@ -674,6 +674,8 @@ ORDER BY 1, 2; -- to avoid this because it opens the door for confusion in connection with -- ORDER BY: novices frequently put the ORDER BY in the wrong place. -- See the fate of the single-argument form of string_agg() for history. +-- (Note: we don't forbid users from creating such aggregates; the policy is +-- just to think twice before creating built-in aggregates like this.) -- The only aggregates that should show up here are count(x) and count(*). SELECT p1.oid::regprocedure, p2.oid::regprocedure @@ -683,7 +685,13 @@ WHERE p1.oid < p2.oid AND p1.proname = p2.proname AND array_dims(p1.proargtypes) != array_dims(p2.proargtypes) ORDER BY 1; --- For the same reason, aggregates with default arguments are no good. +-- For the same reason, we avoid creating built-in variadic aggregates. + +SELECT oid, proname +FROM pg_proc AS p +WHERE proisagg AND provariadic != 0; + +-- For the same reason, built-in aggregates with default arguments are no good. SELECT oid, proname FROM pg_proc AS p |
