diff options
| author | Tom Lane <tgl@sss.pgh.pa.us> | 2014-04-23 19:17:31 -0400 |
|---|---|---|
| committer | Tom Lane <tgl@sss.pgh.pa.us> | 2014-04-23 19:17:41 -0400 |
| commit | f0fedfe82c8adea78354652d67c027a1a8fbce88 (patch) | |
| tree | 5fdcf952d50c1f7a49e9e13ddc8a24de2778fb7a /src/test | |
| parent | 125ba2945aacde7713f3767b012c429c384f3b62 (diff) | |
Allow polymorphic aggregates to have non-polymorphic state data types.
Before 9.4, such an aggregate couldn't be declared, because its final
function would have to have polymorphic result type but no polymorphic
argument, which CREATE FUNCTION would quite properly reject. The
ordered-set-aggregate patch found a workaround: allow the final function
to be declared as accepting additional dummy arguments that have types
matching the aggregate's regular input arguments. However, we failed
to notice that this problem applies just as much to regular aggregates,
despite the fact that we had a built-in regular aggregate array_agg()
that was known to be undeclarable in SQL because its final function
had an illegal signature. So what we should have done, and what this
patch does, is to decouple the extra-dummy-arguments behavior from
ordered-set aggregates and make it generally available for all aggregate
declarations. We have to put this into 9.4 rather than waiting till
later because it slightly alters the rules for declaring ordered-set
aggregates.
The patch turned out a bit bigger than I'd hoped because it proved
necessary to record the extra-arguments option in a new pg_aggregate
column. I'd thought we could just look at the final function's pronargs
at runtime, but that didn't work well for variadic final functions.
It's probably just as well though, because it simplifies life for pg_dump
to record the option explicitly.
While at it, fix array_agg() to have a valid final-function signature,
and add an opr_sanity test to notice future deviations from polymorphic
consistency. I also marked the percentile_cont() aggregates as not
needing extra arguments, since they don't.
Diffstat (limited to 'src/test')
| -rw-r--r-- | src/test/regress/expected/create_aggregate.out | 4 | ||||
| -rw-r--r-- | src/test/regress/expected/opr_sanity.out | 60 | ||||
| -rw-r--r-- | src/test/regress/sql/create_aggregate.sql | 4 | ||||
| -rw-r--r-- | src/test/regress/sql/opr_sanity.sql | 46 |
4 files changed, 84 insertions, 30 deletions
diff --git a/src/test/regress/expected/create_aggregate.out b/src/test/regress/expected/create_aggregate.out index a547ca535fb..82a34fbcd47 100644 --- a/src/test/regress/expected/create_aggregate.out +++ b/src/test/regress/expected/create_aggregate.out @@ -70,12 +70,14 @@ create aggregate least_agg(variadic items anyarray) ( create aggregate my_percentile_disc(float8 ORDER BY anyelement) ( stype = internal, sfunc = ordered_set_transition, - finalfunc = percentile_disc_final + finalfunc = percentile_disc_final, + finalfunc_extra = true ); create aggregate my_rank(VARIADIC "any" ORDER BY VARIADIC "any") ( stype = internal, sfunc = ordered_set_transition_multi, finalfunc = rank_final, + finalfunc_extra = true, hypothetical ); alter aggregate my_percentile_disc(float8 ORDER BY anyelement) diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out index b2d671a08c6..42f712790ba 100644 --- a/src/test/regress/expected/opr_sanity.out +++ b/src/test/regress/expected/opr_sanity.out @@ -283,6 +283,38 @@ WHERE p1.prorettype = 'internal'::regtype AND NOT 2304 | internal_in (1 row) +-- Look for functions that return a polymorphic type and do not have any +-- polymorphic argument. Calls of such functions would be unresolvable +-- at parse time. As of 9.4 this query should find only some input functions +-- associated with these pseudotypes. +SELECT p1.oid, p1.proname +FROM pg_proc as p1 +WHERE p1.prorettype IN + ('anyelement'::regtype, 'anyarray'::regtype, 'anynonarray'::regtype, + 'anyenum'::regtype, 'anyrange'::regtype) + AND NOT + ('anyelement'::regtype = ANY (p1.proargtypes) OR + 'anyarray'::regtype = ANY (p1.proargtypes) OR + 'anynonarray'::regtype = ANY (p1.proargtypes) OR + 'anyenum'::regtype = ANY (p1.proargtypes) OR + 'anyrange'::regtype = ANY (p1.proargtypes)) +ORDER BY 2; + oid | proname +------+---------------- + 2296 | anyarray_in + 2502 | anyarray_recv + 2312 | anyelement_in + 3504 | anyenum_in + 2777 | anynonarray_in + 3832 | anyrange_in + 750 | array_in + 2400 | array_recv + 3506 | enum_in + 3532 | enum_recv + 3834 | range_in + 3836 | range_recv +(12 rows) + -- Check for length inconsistencies between the various argument-info arrays. SELECT p1.oid, p1.proname FROM pg_proc as p1 @@ -800,16 +832,16 @@ WHERE a.aggfnoid = p.oid AND (pfn.proretset OR NOT binary_coercible(pfn.prorettype, p.prorettype) OR NOT binary_coercible(a.aggtranstype, pfn.proargtypes[0]) OR - CASE WHEN a.aggkind = 'n' THEN pfn.pronargs != 1 - ELSE pfn.pronargs != p.pronargs + 1 - OR (p.pronargs > 0 AND + CASE WHEN a.aggfinalextra THEN pfn.pronargs != p.pronargs + 1 + ELSE pfn.pronargs != a.aggnumdirectargs + 1 END + OR (pfn.pronargs > 1 AND NOT binary_coercible(p.proargtypes[0], pfn.proargtypes[1])) - OR (p.pronargs > 1 AND + OR (pfn.pronargs > 2 AND NOT binary_coercible(p.proargtypes[1], pfn.proargtypes[2])) - OR (p.pronargs > 2 AND + OR (pfn.pronargs > 3 AND NOT binary_coercible(p.proargtypes[2], pfn.proargtypes[3])) - -- we could carry the check further, but 3 args is enough for now - END); + -- we could carry the check further, but 3 args is enough for now + ); aggfnoid | proname | oid | proname ----------+---------+-----+--------- (0 rows) @@ -909,16 +941,16 @@ WHERE a.aggfnoid = p.oid AND (pfn.proretset OR NOT binary_coercible(pfn.prorettype, p.prorettype) OR NOT binary_coercible(a.aggmtranstype, pfn.proargtypes[0]) OR - CASE WHEN a.aggkind = 'n' THEN pfn.pronargs != 1 - ELSE pfn.pronargs != p.pronargs + 1 - OR (p.pronargs > 0 AND + CASE WHEN a.aggmfinalextra THEN pfn.pronargs != p.pronargs + 1 + ELSE pfn.pronargs != a.aggnumdirectargs + 1 END + OR (pfn.pronargs > 1 AND NOT binary_coercible(p.proargtypes[0], pfn.proargtypes[1])) - OR (p.pronargs > 1 AND + OR (pfn.pronargs > 2 AND NOT binary_coercible(p.proargtypes[1], pfn.proargtypes[2])) - OR (p.pronargs > 2 AND + OR (pfn.pronargs > 3 AND NOT binary_coercible(p.proargtypes[2], pfn.proargtypes[3])) - -- we could carry the check further, but 3 args is enough for now - END); + -- we could carry the check further, but 3 args is enough for now + ); aggfnoid | proname | oid | proname ----------+---------+-----+--------- (0 rows) diff --git a/src/test/regress/sql/create_aggregate.sql b/src/test/regress/sql/create_aggregate.sql index 2b502aca3e7..0ec1572dff6 100644 --- a/src/test/regress/sql/create_aggregate.sql +++ b/src/test/regress/sql/create_aggregate.sql @@ -85,13 +85,15 @@ create aggregate least_agg(variadic items anyarray) ( create aggregate my_percentile_disc(float8 ORDER BY anyelement) ( stype = internal, sfunc = ordered_set_transition, - finalfunc = percentile_disc_final + finalfunc = percentile_disc_final, + finalfunc_extra = true ); create aggregate my_rank(VARIADIC "any" ORDER BY VARIADIC "any") ( stype = internal, sfunc = ordered_set_transition_multi, finalfunc = rank_final, + finalfunc_extra = true, hypothetical ); diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql index dc1acb9eaac..2cf6fc8ac32 100644 --- a/src/test/regress/sql/opr_sanity.sql +++ b/src/test/regress/sql/opr_sanity.sql @@ -226,6 +226,24 @@ FROM pg_proc as p1 WHERE p1.prorettype = 'internal'::regtype AND NOT 'internal'::regtype = ANY (p1.proargtypes); +-- Look for functions that return a polymorphic type and do not have any +-- polymorphic argument. Calls of such functions would be unresolvable +-- at parse time. As of 9.4 this query should find only some input functions +-- associated with these pseudotypes. + +SELECT p1.oid, p1.proname +FROM pg_proc as p1 +WHERE p1.prorettype IN + ('anyelement'::regtype, 'anyarray'::regtype, 'anynonarray'::regtype, + 'anyenum'::regtype, 'anyrange'::regtype) + AND NOT + ('anyelement'::regtype = ANY (p1.proargtypes) OR + 'anyarray'::regtype = ANY (p1.proargtypes) OR + 'anynonarray'::regtype = ANY (p1.proargtypes) OR + 'anyenum'::regtype = ANY (p1.proargtypes) OR + 'anyrange'::regtype = ANY (p1.proargtypes)) +ORDER BY 2; + -- Check for length inconsistencies between the various argument-info arrays. SELECT p1.oid, p1.proname @@ -646,16 +664,16 @@ WHERE a.aggfnoid = p.oid AND (pfn.proretset OR NOT binary_coercible(pfn.prorettype, p.prorettype) OR NOT binary_coercible(a.aggtranstype, pfn.proargtypes[0]) OR - CASE WHEN a.aggkind = 'n' THEN pfn.pronargs != 1 - ELSE pfn.pronargs != p.pronargs + 1 - OR (p.pronargs > 0 AND + CASE WHEN a.aggfinalextra THEN pfn.pronargs != p.pronargs + 1 + ELSE pfn.pronargs != a.aggnumdirectargs + 1 END + OR (pfn.pronargs > 1 AND NOT binary_coercible(p.proargtypes[0], pfn.proargtypes[1])) - OR (p.pronargs > 1 AND + OR (pfn.pronargs > 2 AND NOT binary_coercible(p.proargtypes[1], pfn.proargtypes[2])) - OR (p.pronargs > 2 AND + OR (pfn.pronargs > 3 AND NOT binary_coercible(p.proargtypes[2], pfn.proargtypes[3])) - -- we could carry the check further, but 3 args is enough for now - END); + -- we could carry the check further, but 3 args is enough for now + ); -- If transfn is strict then either initval should be non-NULL, or -- input type should match transtype so that the first non-null input @@ -738,16 +756,16 @@ WHERE a.aggfnoid = p.oid AND (pfn.proretset OR NOT binary_coercible(pfn.prorettype, p.prorettype) OR NOT binary_coercible(a.aggmtranstype, pfn.proargtypes[0]) OR - CASE WHEN a.aggkind = 'n' THEN pfn.pronargs != 1 - ELSE pfn.pronargs != p.pronargs + 1 - OR (p.pronargs > 0 AND + CASE WHEN a.aggmfinalextra THEN pfn.pronargs != p.pronargs + 1 + ELSE pfn.pronargs != a.aggnumdirectargs + 1 END + OR (pfn.pronargs > 1 AND NOT binary_coercible(p.proargtypes[0], pfn.proargtypes[1])) - OR (p.pronargs > 1 AND + OR (pfn.pronargs > 2 AND NOT binary_coercible(p.proargtypes[1], pfn.proargtypes[2])) - OR (p.pronargs > 2 AND + OR (pfn.pronargs > 3 AND NOT binary_coercible(p.proargtypes[2], pfn.proargtypes[3])) - -- we could carry the check further, but 3 args is enough for now - END); + -- we could carry the check further, but 3 args is enough for now + ); -- If mtransfn is strict then either minitval should be non-NULL, or -- input type should match mtranstype so that the first non-null input |
