Declare assorted array functions using anycompatible not anyelement.

Convert array_append, array_prepend, array_cat, array_position,
array_positions, array_remove, array_replace, and width_bucket
to use anycompatiblearray.  This is a simple extension of commit
5c292e6b9 to hit some other places where there's a pretty obvious
gain in usability from doing so.

Ideally we'd also modify other functions taking multiple old-style
polymorphic arguments.  But most of the remainder are tied into one
or more operator classes, making any such change a much larger can of
worms than I desire to open right now.

Discussion: https://postgr.es/m/77675130-89da-dab1-51dd-492c93dcf5d1@postgresfriends.org
This commit is contained in:
Tom Lane 2020-11-04 16:09:55 -05:00
parent 5c292e6b90
commit 9e38c2bb50
9 changed files with 86 additions and 57 deletions

View File

@ -1756,7 +1756,7 @@ repeat('Pg', 4) <returnvalue>PgPgPgPg</returnvalue>
<row>
<entry role="func_table_entry"><para role="func_signature">
<function>width_bucket</function> ( <parameter>operand</parameter> <type>anyelement</type>, <parameter>thresholds</parameter> <type>anyarray</type> )
<function>width_bucket</function> ( <parameter>operand</parameter> <type>anycompatible</type>, <parameter>thresholds</parameter> <type>anycompatiblearray</type> )
<returnvalue>integer</returnvalue>
</para>
<para>
@ -17448,29 +17448,31 @@ SELECT NULLIF(value, '(none)') ...
<row>
<entry role="func_table_entry"><para role="func_signature">
<type>anyarray</type> <literal>||</literal> <type>anyarray</type>
<returnvalue>anyarray</returnvalue>
<type>anycompatiblearray</type> <literal>||</literal> <type>anycompatiblearray</type>
<returnvalue>anycompatiblearray</returnvalue>
</para>
<para>
Concatenates the two arrays. Concatenating a null or empty array is a
no-op; otherwise the arrays must have the same number of dimensions
(as illustrated by the first example) or differ in number of
dimensions by one (as illustrated by the second).
If the arrays are not of identical element types, they will be coerced
to a common type (see <xref linkend="typeconv-union-case"/>).
</para>
<para>
<literal>ARRAY[1,2,3] || ARRAY[4,5,6,7]</literal>
<returnvalue>{1,2,3,4,5,6,7}</returnvalue>
</para>
<para>
<literal>ARRAY[1,2,3] || ARRAY[[4,5,6],[7,8,9]]</literal>
<returnvalue>{{1,2,3},{4,5,6},{7,8,9}}</returnvalue>
<literal>ARRAY[1,2,3] || ARRAY[[4,5,6],[7,8,9.9]]</literal>
<returnvalue>{{1,2,3},{4,5,6},{7,8,9.9}}</returnvalue>
</para></entry>
</row>
<row>
<entry role="func_table_entry"><para role="func_signature">
<type>anyelement</type> <literal>||</literal> <type>anyarray</type>
<returnvalue>anyarray</returnvalue>
<type>anycompatible</type> <literal>||</literal> <type>anycompatiblearray</type>
<returnvalue>anycompatiblearray</returnvalue>
</para>
<para>
Concatenates an element onto the front of an array (which must be
@ -17484,8 +17486,8 @@ SELECT NULLIF(value, '(none)') ...
<row>
<entry role="func_table_entry"><para role="func_signature">
<type>anyarray</type> <literal>||</literal> <type>anyelement</type>
<returnvalue>anyarray</returnvalue>
<type>anycompatiblearray</type> <literal>||</literal> <type>anycompatible</type>
<returnvalue>anycompatiblearray</returnvalue>
</para>
<para>
Concatenates an element onto the end of an array (which must be
@ -17535,12 +17537,12 @@ SELECT NULLIF(value, '(none)') ...
<indexterm>
<primary>array_append</primary>
</indexterm>
<function>array_append</function> ( <type>anyarray</type>, <type>anyelement</type> )
<returnvalue>anyarray</returnvalue>
<function>array_append</function> ( <type>anycompatiblearray</type>, <type>anycompatible</type> )
<returnvalue>anycompatiblearray</returnvalue>
</para>
<para>
Appends an element to the end of an array (same as
the <type>anyarray</type> <literal>||</literal> <type>anyelement</type>
the <type>anycompatiblearray</type> <literal>||</literal> <type>anycompatible</type>
operator).
</para>
<para>
@ -17554,12 +17556,12 @@ SELECT NULLIF(value, '(none)') ...
<indexterm>
<primary>array_cat</primary>
</indexterm>
<function>array_cat</function> ( <type>anyarray</type>, <type>anyarray</type> )
<returnvalue>anyarray</returnvalue>
<function>array_cat</function> ( <type>anycompatiblearray</type>, <type>anycompatiblearray</type> )
<returnvalue>anycompatiblearray</returnvalue>
</para>
<para>
Concatenates two arrays (same as
the <type>anyarray</type> <literal>||</literal> <type>anyarray</type>
the <type>anycompatiblearray</type> <literal>||</literal> <type>anycompatiblearray</type>
operator).
</para>
<para>
@ -17666,7 +17668,7 @@ SELECT NULLIF(value, '(none)') ...
<indexterm>
<primary>array_position</primary>
</indexterm>
<function>array_position</function> ( <type>anyarray</type>, <type>anyelement</type> <optional>, <type>integer</type> </optional> )
<function>array_position</function> ( <type>anycompatiblearray</type>, <type>anycompatible</type> <optional>, <type>integer</type> </optional> )
<returnvalue>integer</returnvalue>
</para>
<para>
@ -17688,7 +17690,7 @@ SELECT NULLIF(value, '(none)') ...
<indexterm>
<primary>array_positions</primary>
</indexterm>
<function>array_positions</function> ( <type>anyarray</type>, <type>anyelement</type> )
<function>array_positions</function> ( <type>anycompatiblearray</type>, <type>anycompatible</type> )
<returnvalue>integer[]</returnvalue>
</para>
<para>
@ -17712,12 +17714,12 @@ SELECT NULLIF(value, '(none)') ...
<indexterm>
<primary>array_prepend</primary>
</indexterm>
<function>array_prepend</function> ( <type>anyelement</type>, <type>anyarray</type> )
<returnvalue>anyarray</returnvalue>
<function>array_prepend</function> ( <type>anycompatible</type>, <type>anycompatiblearray</type> )
<returnvalue>anycompatiblearray</returnvalue>
</para>
<para>
Prepends an element to the beginning of an array (same as
the <type>anyelement</type> <literal>||</literal> <type>anyarray</type>
the <type>anycompatible</type> <literal>||</literal> <type>anycompatiblearray</type>
operator).
</para>
<para>
@ -17731,8 +17733,8 @@ SELECT NULLIF(value, '(none)') ...
<indexterm>
<primary>array_remove</primary>
</indexterm>
<function>array_remove</function> ( <type>anyarray</type>, <type>anyelement</type> )
<returnvalue>anyarray</returnvalue>
<function>array_remove</function> ( <type>anycompatiblearray</type>, <type>anycompatible</type> )
<returnvalue>anycompatiblearray</returnvalue>
</para>
<para>
Removes all elements equal to the given value from the array.
@ -17751,8 +17753,8 @@ SELECT NULLIF(value, '(none)') ...
<indexterm>
<primary>array_replace</primary>
</indexterm>
<function>array_replace</function> ( <type>anyarray</type>, <type>anyelement</type>, <type>anyelement</type> )
<returnvalue>anyarray</returnvalue>
<function>array_replace</function> ( <type>anycompatiblearray</type>, <type>anycompatible</type>, <type>anycompatible</type> )
<returnvalue>anycompatiblearray</returnvalue>
</para>
<para>
Replaces each array element equal to the second argument with the

View File

@ -298,10 +298,10 @@ FROM (VALUES (1, 1.0e20::float8),
Here is an example of a polymorphic aggregate:
<programlisting>
CREATE AGGREGATE array_accum (anyelement)
CREATE AGGREGATE array_accum (anycompatible)
(
sfunc = array_append,
stype = anyarray,
stype = anycompatiblearray,
initcond = '{}'
);
</programlisting>

View File

@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 202011043
#define CATALOG_VERSION_NO 202011044
#endif

View File

@ -168,14 +168,15 @@
oprcode => 'textnename', oprrest => 'neqsel', oprjoin => 'neqjoinsel' },
{ oid => '349', descr => 'append element onto end of array',
oprname => '||', oprleft => 'anyarray', oprright => 'anyelement',
oprresult => 'anyarray', oprcode => 'array_append' },
oprname => '||', oprleft => 'anycompatiblearray', oprright => 'anycompatible',
oprresult => 'anycompatiblearray', oprcode => 'array_append' },
{ oid => '374', descr => 'prepend element onto front of array',
oprname => '||', oprleft => 'anyelement', oprright => 'anyarray',
oprresult => 'anyarray', oprcode => 'array_prepend' },
oprname => '||', oprleft => 'anycompatible', oprright => 'anycompatiblearray',
oprresult => 'anycompatiblearray', oprcode => 'array_prepend' },
{ oid => '375', descr => 'concatenate',
oprname => '||', oprleft => 'anyarray', oprright => 'anyarray',
oprresult => 'anyarray', oprcode => 'array_cat' },
oprname => '||', oprleft => 'anycompatiblearray',
oprright => 'anycompatiblearray', oprresult => 'anycompatiblearray',
oprcode => 'array_cat' },
{ oid => '352', descr => 'equal',
oprname => '=', oprcanhash => 't', oprleft => 'xid', oprright => 'xid',

View File

@ -1548,14 +1548,19 @@
proname => 'cardinality', prorettype => 'int4', proargtypes => 'anyarray',
prosrc => 'array_cardinality' },
{ oid => '378', descr => 'append element onto end of array',
proname => 'array_append', proisstrict => 'f', prorettype => 'anyarray',
proargtypes => 'anyarray anyelement', prosrc => 'array_append' },
proname => 'array_append', proisstrict => 'f',
prorettype => 'anycompatiblearray',
proargtypes => 'anycompatiblearray anycompatible', prosrc => 'array_append' },
{ oid => '379', descr => 'prepend element onto front of array',
proname => 'array_prepend', proisstrict => 'f', prorettype => 'anyarray',
proargtypes => 'anyelement anyarray', prosrc => 'array_prepend' },
proname => 'array_prepend', proisstrict => 'f',
prorettype => 'anycompatiblearray',
proargtypes => 'anycompatible anycompatiblearray',
prosrc => 'array_prepend' },
{ oid => '383',
proname => 'array_cat', proisstrict => 'f', prorettype => 'anyarray',
proargtypes => 'anyarray anyarray', prosrc => 'array_cat' },
proname => 'array_cat', proisstrict => 'f',
prorettype => 'anycompatiblearray',
proargtypes => 'anycompatiblearray anycompatiblearray',
prosrc => 'array_cat' },
{ oid => '394', descr => 'split delimited text',
proname => 'string_to_array', proisstrict => 'f', prorettype => '_text',
proargtypes => 'text text', prosrc => 'text_to_array' },
@ -1587,15 +1592,18 @@
proargtypes => 'anyarray anyarray', prosrc => 'array_smaller' },
{ oid => '3277', descr => 'returns an offset of value in array',
proname => 'array_position', proisstrict => 'f', prorettype => 'int4',
proargtypes => 'anyarray anyelement', prosrc => 'array_position' },
proargtypes => 'anycompatiblearray anycompatible',
prosrc => 'array_position' },
{ oid => '3278',
descr => 'returns an offset of value in array with start index',
proname => 'array_position', proisstrict => 'f', prorettype => 'int4',
proargtypes => 'anyarray anyelement int4', prosrc => 'array_position_start' },
proargtypes => 'anycompatiblearray anycompatible int4',
prosrc => 'array_position_start' },
{ oid => '3279',
descr => 'returns an array of offsets of some value in array',
proname => 'array_positions', proisstrict => 'f', prorettype => '_int4',
proargtypes => 'anyarray anyelement', prosrc => 'array_positions' },
proargtypes => 'anycompatiblearray anycompatible',
prosrc => 'array_positions' },
{ oid => '1191', descr => 'array subscripts generator',
proname => 'generate_subscripts', prorows => '1000', proretset => 't',
prorettype => 'int4', proargtypes => 'anyarray int4 bool',
@ -1620,11 +1628,14 @@
proargtypes => 'internal', prosrc => 'array_unnest_support' },
{ oid => '3167',
descr => 'remove any occurrences of an element from an array',
proname => 'array_remove', proisstrict => 'f', prorettype => 'anyarray',
proargtypes => 'anyarray anyelement', prosrc => 'array_remove' },
proname => 'array_remove', proisstrict => 'f',
prorettype => 'anycompatiblearray',
proargtypes => 'anycompatiblearray anycompatible', prosrc => 'array_remove' },
{ oid => '3168', descr => 'replace any occurrences of an element in an array',
proname => 'array_replace', proisstrict => 'f', prorettype => 'anyarray',
proargtypes => 'anyarray anyelement anyelement', prosrc => 'array_replace' },
proname => 'array_replace', proisstrict => 'f',
prorettype => 'anycompatiblearray',
proargtypes => 'anycompatiblearray anycompatible anycompatible',
prosrc => 'array_replace' },
{ oid => '2333', descr => 'aggregate transition function',
proname => 'array_agg_transfn', proisstrict => 'f', prorettype => 'internal',
proargtypes => 'internal anynonarray', prosrc => 'array_agg_transfn' },
@ -1650,7 +1661,8 @@
{ oid => '3218',
descr => 'bucket number of operand given a sorted array of bucket lower bounds',
proname => 'width_bucket', prorettype => 'int4',
proargtypes => 'anyelement anyarray', prosrc => 'width_bucket_array' },
proargtypes => 'anycompatible anycompatiblearray',
prosrc => 'width_bucket_array' },
{ oid => '3816', descr => 'array typanalyze',
proname => 'array_typanalyze', provolatile => 's', prorettype => 'bool',
proargtypes => 'internal', prosrc => 'array_typanalyze' },

View File

@ -726,6 +726,12 @@ SELECT 0 || ARRAY[1,2] || 3 AS "{0,1,2,3}";
{0,1,2,3}
(1 row)
SELECT ARRAY[1.1] || ARRAY[2,3,4];
?column?
-------------
{1.1,2,3,4}
(1 row)
SELECT * FROM array_op_test WHERE i @> '{32}' ORDER BY seqno;
seqno | i | t
-------+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------
@ -2146,6 +2152,12 @@ select array_remove(array['A','CC','D','C','RR'], 'RR');
{A,CC,D,C}
(1 row)
select array_remove(array[1.0, 2.1, 3.3], 1);
array_remove
--------------
{2.1,3.3}
(1 row)
select array_remove('{{1,2,2},{1,4,3}}', 2); -- not allowed
ERROR: removing elements from multidimensional arrays is not supported
select array_remove(array['X','X','X'], 'X') = '{}';

View File

@ -729,10 +729,10 @@ select q2, sql_if(q2 > 0, q2, q2 + 1) from int8_tbl;
(5 rows)
-- another sort of polymorphic aggregate
CREATE AGGREGATE array_cat_accum (anyarray)
CREATE AGGREGATE array_cat_accum (anycompatiblearray)
(
sfunc = array_cat,
stype = anyarray,
stype = anycompatiblearray,
initcond = '{}'
);
SELECT array_cat_accum(i)
@ -786,16 +786,16 @@ create aggregate build_group(int8, integer) (
STYPE = int8[]
);
-- check proper resolution of data types for polymorphic transfn/finalfn
create function first_el(anyarray) returns anyelement as
create function first_el(anycompatiblearray) returns anycompatible as
'select $1[1]' language sql strict immutable;
create aggregate first_el_agg_f8(float8) (
SFUNC = array_append,
STYPE = float8[],
FINALFUNC = first_el
);
create aggregate first_el_agg_any(anyelement) (
create aggregate first_el_agg_any(anycompatible) (
SFUNC = array_append,
STYPE = anyarray,
STYPE = anycompatiblearray,
FINALFUNC = first_el
);
select first_el_agg_f8(x::float8) from generate_series(1,10) x;

View File

@ -311,6 +311,7 @@ SELECT ARRAY[[['hello','world']]] || ARRAY[[['happy','birthday']]] AS "ARRAY";
SELECT ARRAY[[1,2],[3,4]] || ARRAY[5,6] AS "{{1,2},{3,4},{5,6}}";
SELECT ARRAY[0,0] || ARRAY[1,1] || ARRAY[2,2] AS "{0,0,1,1,2,2}";
SELECT 0 || ARRAY[1,2] || 3 AS "{0,1,2,3}";
SELECT ARRAY[1.1] || ARRAY[2,3,4];
SELECT * FROM array_op_test WHERE i @> '{32}' ORDER BY seqno;
SELECT * FROM array_op_test WHERE i && '{32}' ORDER BY seqno;
@ -616,6 +617,7 @@ select array_remove(array[1,2,2,3], 2);
select array_remove(array[1,2,2,3], 5);
select array_remove(array[1,NULL,NULL,3], NULL);
select array_remove(array['A','CC','D','C','RR'], 'RR');
select array_remove(array[1.0, 2.1, 3.3], 1);
select array_remove('{{1,2,2},{1,4,3}}', 2); -- not allowed
select array_remove(array['X','X','X'], 'X') = '{}';
select array_replace(array[1,2,5,4],5,3);

View File

@ -498,10 +498,10 @@ select q2, sql_if(q2 > 0, q2, q2 + 1) from int8_tbl;
-- another sort of polymorphic aggregate
CREATE AGGREGATE array_cat_accum (anyarray)
CREATE AGGREGATE array_cat_accum (anycompatiblearray)
(
sfunc = array_cat,
stype = anyarray,
stype = anycompatiblearray,
initcond = '{}'
);
@ -549,7 +549,7 @@ create aggregate build_group(int8, integer) (
-- check proper resolution of data types for polymorphic transfn/finalfn
create function first_el(anyarray) returns anyelement as
create function first_el(anycompatiblearray) returns anycompatible as
'select $1[1]' language sql strict immutable;
create aggregate first_el_agg_f8(float8) (
@ -558,9 +558,9 @@ create aggregate first_el_agg_f8(float8) (
FINALFUNC = first_el
);
create aggregate first_el_agg_any(anyelement) (
create aggregate first_el_agg_any(anycompatible) (
SFUNC = array_append,
STYPE = anyarray,
STYPE = anycompatiblearray,
FINALFUNC = first_el
);