From 24e2885ee304cb6a94fdfc25a1a108344ed9f4f7 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 19 Mar 2020 11:43:11 -0400 Subject: Introduce "anycompatible" family of polymorphic types. This patch adds the pseudo-types anycompatible, anycompatiblearray, anycompatiblenonarray, and anycompatiblerange. They work much like anyelement, anyarray, anynonarray, and anyrange respectively, except that the actual input values need not match precisely in type. Instead, if we can find a common supertype (using the same rules as for UNION/CASE type resolution), then the parser automatically promotes the input values to that type. For example, "myfunc(anycompatible, anycompatible)" can match a call with one integer and one bigint argument, with the integer automatically promoted to bigint. With anyelement in the definition, the user would have had to cast the integer explicitly. The new types also provide a second, independent set of type variables for function matching; thus with "myfunc(anyelement, anyelement, anycompatible) returns anycompatible" the first two arguments are constrained to be the same type, but the third can be some other type, and the result has the type of the third argument. The need for more than one set of type variables was foreseen back when we first invented the polymorphic types, but we never did anything about it. Pavel Stehule, revised a bit by me Discussion: https://postgr.es/m/CAFj8pRDna7VqNi8gR+Tt2Ktmz0cq5G93guc3Sbn_NVPLdXAkqA@mail.gmail.com --- src/test/regress/expected/aggregates.out | 24 ++ src/test/regress/expected/create_aggregate.out | 28 ++- src/test/regress/expected/opr_sanity.out | 52 ++++- src/test/regress/expected/plpgsql.out | 101 ++++++++ src/test/regress/expected/polymorphism.out | 311 +++++++++++++++++++++++++ src/test/regress/expected/rangefuncs.out | 53 +++++ src/test/regress/expected/rangetypes.out | 26 +++ src/test/regress/expected/type_sanity.out | 10 +- src/test/regress/sql/aggregates.sql | 4 + src/test/regress/sql/create_aggregate.sql | 34 ++- src/test/regress/sql/opr_sanity.sql | 33 ++- src/test/regress/sql/plpgsql.sql | 68 ++++++ src/test/regress/sql/polymorphism.sql | 159 +++++++++++++ src/test/regress/sql/rangefuncs.sql | 21 ++ src/test/regress/sql/rangetypes.sql | 16 ++ src/test/regress/sql/type_sanity.sql | 10 +- 16 files changed, 934 insertions(+), 16 deletions(-) (limited to 'src/test') diff --git a/src/test/regress/expected/aggregates.out b/src/test/regress/expected/aggregates.out index 0073072a36..3259a22516 100644 --- a/src/test/regress/expected/aggregates.out +++ b/src/test/regress/expected/aggregates.out @@ -1950,6 +1950,30 @@ select least_agg(variadic array[q1,q2]) from int8_tbl; -4567890123456789 (1 row) +select cleast_agg(q1,q2) from int8_tbl; + cleast_agg +------------------- + -4567890123456789 +(1 row) + +select cleast_agg(4.5,f1) from int4_tbl; + cleast_agg +------------- + -2147483647 +(1 row) + +select cleast_agg(variadic array[4.5,f1]) from int4_tbl; + cleast_agg +------------- + -2147483647 +(1 row) + +select pg_typeof(cleast_agg(variadic array[4.5,f1])) from int4_tbl; + pg_typeof +----------- + numeric +(1 row) + -- test aggregates with common transition functions share the same states begin work; create type avg_state as (total bigint, count bigint); diff --git a/src/test/regress/expected/create_aggregate.out b/src/test/regress/expected/create_aggregate.out index a2eb9996e1..dcf6909423 100644 --- a/src/test/regress/expected/create_aggregate.out +++ b/src/test/regress/expected/create_aggregate.out @@ -59,13 +59,39 @@ create aggregate aggfns(integer,integer,text) ( sfunc = aggfns_trans, stype = aggtype[], sspace = 10000, initcond = '{}' ); --- variadic aggregate +-- check error cases that would require run-time type coercion +create function least_accum(int8, int8) returns int8 language sql as + 'select least($1, $2)'; +create aggregate least_agg(int4) ( + stype = int8, sfunc = least_accum +); -- fails +ERROR: function least_accum(bigint, bigint) requires run-time type coercion +drop function least_accum(int8, int8); +create function least_accum(anycompatible, anycompatible) +returns anycompatible language sql as + 'select least($1, $2)'; +create aggregate least_agg(int4) ( + stype = int8, sfunc = least_accum +); -- fails +ERROR: function least_accum(bigint, bigint) requires run-time type coercion +create aggregate least_agg(int8) ( + stype = int8, sfunc = least_accum +); +drop function least_accum(anycompatible, anycompatible) cascade; +NOTICE: drop cascades to function least_agg(bigint) +-- variadic aggregates 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 ); +create function cleast_accum(anycompatible, variadic anycompatiblearray) +returns anycompatible language sql as + 'select least($1, min($2[i])) from generate_subscripts($2,1) g(i)'; +create aggregate cleast_agg(variadic items anycompatiblearray) ( + stype = anycompatible, sfunc = cleast_accum +); -- test ordered-set aggs using built-in support functions create aggregate my_percentile_disc(float8 ORDER BY anyelement) ( stype = internal, diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out index 40468e8f49..3c0b21d633 100644 --- a/src/test/regress/expected/opr_sanity.out +++ b/src/test/regress/expected/opr_sanity.out @@ -329,7 +329,7 @@ SELECT p1.oid, p1.proname FROM pg_proc as p1 WHERE p1.prorettype IN ('anyelement'::regtype, 'anyarray'::regtype, 'anynonarray'::regtype, - 'anyenum'::regtype, 'anyrange'::regtype) + 'anyenum'::regtype) AND NOT ('anyelement'::regtype = ANY (p1.proargtypes) OR 'anyarray'::regtype = ANY (p1.proargtypes) OR @@ -337,22 +337,64 @@ WHERE p1.prorettype IN 'anyenum'::regtype = ANY (p1.proargtypes) OR 'anyrange'::regtype = ANY (p1.proargtypes)) ORDER BY 2; - oid | proname -------+------------------ + 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 +(9 rows) + +-- anyrange is tighter than the rest, can only resolve from anyrange input +SELECT p1.oid, p1.proname +FROM pg_proc as p1 +WHERE p1.prorettype = 'anyrange'::regtype + AND NOT + 'anyrange'::regtype = ANY (p1.proargtypes) +ORDER BY 2; + oid | proname +------+------------------ + 3832 | anyrange_in 3876 | range_gist_union 3834 | range_in 3836 | range_recv -(13 rows) +(4 rows) + +-- similarly for the anycompatible family +SELECT p1.oid, p1.proname +FROM pg_proc as p1 +WHERE p1.prorettype IN + ('anycompatible'::regtype, 'anycompatiblearray'::regtype, + 'anycompatiblenonarray'::regtype) + AND NOT + ('anycompatible'::regtype = ANY (p1.proargtypes) OR + 'anycompatiblearray'::regtype = ANY (p1.proargtypes) OR + 'anycompatiblenonarray'::regtype = ANY (p1.proargtypes) OR + 'anycompatiblerange'::regtype = ANY (p1.proargtypes)) +ORDER BY 2; + oid | proname +------+-------------------------- + 9559 | anycompatible_in + 9561 | anycompatiblearray_in + 9563 | anycompatiblearray_recv + 9565 | anycompatiblenonarray_in +(4 rows) + +SELECT p1.oid, p1.proname +FROM pg_proc as p1 +WHERE p1.prorettype = 'anycompatiblerange'::regtype + AND NOT + 'anycompatiblerange'::regtype = ANY (p1.proargtypes) +ORDER BY 2; + oid | proname +------+----------------------- + 9567 | anycompatiblerange_in +(1 row) -- Look for functions that accept cstring and are neither datatype input -- functions nor encoding conversion functions. It's almost never a good diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out index dfc10e3242..d0a6b630b8 100644 --- a/src/test/regress/expected/plpgsql.out +++ b/src/test/regress/expected/plpgsql.out @@ -1823,6 +1823,88 @@ select f1(int4range(42, 49)) as int, f1(float8range(4.5, 7.8)) as num; (1 row) drop function f1(x anyrange); +create function f1(x anycompatible, y anycompatible) returns anycompatiblearray as $$ +begin + return array[x, y]; +end$$ language plpgsql; +select f1(2, 4) as int, f1(2, 4.5) as num; + int | num +-------+--------- + {2,4} | {2,4.5} +(1 row) + +drop function f1(x anycompatible, y anycompatible); +create function f1(x anycompatiblerange, y anycompatible, z anycompatible) returns anycompatiblearray as $$ +begin + return array[lower(x), upper(x), y, z]; +end$$ language plpgsql; +select f1(int4range(42, 49), 11, 2::smallint) as int, f1(float8range(4.5, 7.8), 7.8, 11::real) as num; + int | num +--------------+------------------ + {42,49,11,2} | {4.5,7.8,7.8,11} +(1 row) + +select f1(int4range(42, 49), 11, 4.5) as fail; -- range type doesn't fit +ERROR: function f1(int4range, integer, numeric) does not exist +LINE 1: select f1(int4range(42, 49), 11, 4.5) as fail; + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +drop function f1(x anycompatiblerange, y anycompatible, z anycompatible); +-- fail, can't infer type: +create function f1(x anycompatible) returns anycompatiblerange as $$ +begin + return array[x + 1, x + 2]; +end$$ language plpgsql; +ERROR: cannot determine result data type +DETAIL: A result of type anycompatiblerange requires at least one input of type anycompatiblerange. +create function f1(x anycompatiblerange, y anycompatiblearray) returns anycompatiblerange as $$ +begin + return x; +end$$ language plpgsql; +select f1(int4range(42, 49), array[11]) as int, f1(float8range(4.5, 7.8), array[7]) as num; + int | num +---------+----------- + [42,49) | [4.5,7.8) +(1 row) + +drop function f1(x anycompatiblerange, y anycompatiblearray); +create function f1(a anyelement, b anyarray, + c anycompatible, d anycompatible, + OUT x anyarray, OUT y anycompatiblearray) +as $$ +begin + x := a || b; + y := array[c, d]; +end$$ language plpgsql; +select x, pg_typeof(x), y, pg_typeof(y) + from f1(11, array[1, 2], 42, 34.5); + x | pg_typeof | y | pg_typeof +----------+-----------+-----------+----------- + {11,1,2} | integer[] | {42,34.5} | numeric[] +(1 row) + +select x, pg_typeof(x), y, pg_typeof(y) + from f1(11, array[1, 2], point(1,2), point(3,4)); + x | pg_typeof | y | pg_typeof +----------+-----------+-------------------+----------- + {11,1,2} | integer[] | {"(1,2)","(3,4)"} | point[] +(1 row) + +select x, pg_typeof(x), y, pg_typeof(y) + from f1(11, '{1,2}', point(1,2), '(3,4)'); + x | pg_typeof | y | pg_typeof +----------+-----------+-------------------+----------- + {11,1,2} | integer[] | {"(1,2)","(3,4)"} | point[] +(1 row) + +select x, pg_typeof(x), y, pg_typeof(y) + from f1(11, array[1, 2.2], 42, 34.5); -- fail +ERROR: function f1(integer, numeric[], integer, numeric) does not exist +LINE 2: from f1(11, array[1, 2.2], 42, 34.5); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +drop function f1(a anyelement, b anyarray, + c anycompatible, d anycompatible); -- -- Test handling of OUT parameters, including polymorphic cases. -- Note that RETURN is optional with OUT params; we try both ways. @@ -1940,6 +2022,25 @@ select * from duplic('foo'::text); (1 row) drop function duplic(anyelement); +create function duplic(in i anycompatiblerange, out j anycompatible, out k anycompatiblearray) as $$ +begin + j := lower(i); + k := array[lower(i),upper(i)]; + return; +end$$ language plpgsql; +select * from duplic(int4range(42,49)); + j | k +----+--------- + 42 | {42,49} +(1 row) + +select * from duplic(textrange('aaa', 'bbb')); + j | k +-----+----------- + aaa | {aaa,bbb} +(1 row) + +drop function duplic(anycompatiblerange); -- -- test PERFORM -- diff --git a/src/test/regress/expected/polymorphism.out b/src/test/regress/expected/polymorphism.out index 331562de19..d86a7004a6 100644 --- a/src/test/regress/expected/polymorphism.out +++ b/src/test/regress/expected/polymorphism.out @@ -72,6 +72,82 @@ select polyf(int4range(42, 49)) as int, polyf(float8range(4.5, 7.8)) as num; (1 row) drop function polyf(x anyrange); +create function polyf(x anycompatible, y anycompatible) returns anycompatiblearray as $$ + select array[x, y] +$$ language sql; +select polyf(2, 4) as int, polyf(2, 4.5) as num; + int | num +-------+--------- + {2,4} | {2,4.5} +(1 row) + +drop function polyf(x anycompatible, y anycompatible); +create function polyf(x anycompatiblerange, y anycompatible, z anycompatible) returns anycompatiblearray as $$ + select array[lower(x), upper(x), y, z] +$$ language sql; +select polyf(int4range(42, 49), 11, 2::smallint) as int, polyf(float8range(4.5, 7.8), 7.8, 11::real) as num; + int | num +--------------+------------------ + {42,49,11,2} | {4.5,7.8,7.8,11} +(1 row) + +select polyf(int4range(42, 49), 11, 4.5) as fail; -- range type doesn't fit +ERROR: function polyf(int4range, integer, numeric) does not exist +LINE 1: select polyf(int4range(42, 49), 11, 4.5) as fail; + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +drop function polyf(x anycompatiblerange, y anycompatible, z anycompatible); +-- fail, can't infer type: +create function polyf(x anycompatible) returns anycompatiblerange as $$ + select array[x + 1, x + 2] +$$ language sql; +ERROR: cannot determine result data type +DETAIL: A result of type anycompatiblerange requires at least one input of type anycompatiblerange. +create function polyf(x anycompatiblerange, y anycompatiblearray) returns anycompatiblerange as $$ + select x +$$ language sql; +select polyf(int4range(42, 49), array[11]) as int, polyf(float8range(4.5, 7.8), array[7]) as num; + int | num +---------+----------- + [42,49) | [4.5,7.8) +(1 row) + +drop function polyf(x anycompatiblerange, y anycompatiblearray); +create function polyf(a anyelement, b anyarray, + c anycompatible, d anycompatible, + OUT x anyarray, OUT y anycompatiblearray) +as $$ + select a || b, array[c, d] +$$ language sql; +select x, pg_typeof(x), y, pg_typeof(y) + from polyf(11, array[1, 2], 42, 34.5); + x | pg_typeof | y | pg_typeof +----------+-----------+-----------+----------- + {11,1,2} | integer[] | {42,34.5} | numeric[] +(1 row) + +select x, pg_typeof(x), y, pg_typeof(y) + from polyf(11, array[1, 2], point(1,2), point(3,4)); + x | pg_typeof | y | pg_typeof +----------+-----------+-------------------+----------- + {11,1,2} | integer[] | {"(1,2)","(3,4)"} | point[] +(1 row) + +select x, pg_typeof(x), y, pg_typeof(y) + from polyf(11, '{1,2}', point(1,2), '(3,4)'); + x | pg_typeof | y | pg_typeof +----------+-----------+-------------------+----------- + {11,1,2} | integer[] | {"(1,2)","(3,4)"} | point[] +(1 row) + +select x, pg_typeof(x), y, pg_typeof(y) + from polyf(11, array[1, 2.2], 42, 34.5); -- fail +ERROR: function polyf(integer, numeric[], integer, numeric) does not exist +LINE 2: from polyf(11, array[1, 2.2], 42, 34.5); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +drop function polyf(a anyelement, b anyarray, + c anycompatible, d anycompatible); -- -- Polymorphic aggregate tests -- @@ -1621,3 +1697,238 @@ View definition: drop view dfview; drop function dfunc(anyelement, anyelement, bool); +-- +-- Tests for ANYCOMPATIBLE polymorphism family +-- +create function anyctest(anycompatible, anycompatible) +returns anycompatible as $$ + select greatest($1, $2) +$$ language sql; +select x, pg_typeof(x) from anyctest(11, 12) x; + x | pg_typeof +----+----------- + 12 | integer +(1 row) + +select x, pg_typeof(x) from anyctest(11, 12.3) x; + x | pg_typeof +------+----------- + 12.3 | numeric +(1 row) + +select x, pg_typeof(x) from anyctest(11, point(1,2)) x; -- fail +ERROR: function anyctest(integer, point) does not exist +LINE 1: select x, pg_typeof(x) from anyctest(11, point(1,2)) x; + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +select x, pg_typeof(x) from anyctest('11', '12.3') x; -- defaults to text + x | pg_typeof +------+----------- + 12.3 | text +(1 row) + +drop function anyctest(anycompatible, anycompatible); +create function anyctest(anycompatible, anycompatible) +returns anycompatiblearray as $$ + select array[$1, $2] +$$ language sql; +select x, pg_typeof(x) from anyctest(11, 12) x; + x | pg_typeof +---------+----------- + {11,12} | integer[] +(1 row) + +select x, pg_typeof(x) from anyctest(11, 12.3) x; + x | pg_typeof +-----------+----------- + {11,12.3} | numeric[] +(1 row) + +select x, pg_typeof(x) from anyctest(11, array[1,2]) x; -- fail +ERROR: function anyctest(integer, integer[]) does not exist +LINE 1: select x, pg_typeof(x) from anyctest(11, array[1,2]) x; + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +drop function anyctest(anycompatible, anycompatible); +create function anyctest(anycompatible, anycompatiblearray) +returns anycompatiblearray as $$ + select array[$1] || $2 +$$ language sql; +select x, pg_typeof(x) from anyctest(11, array[12]) x; + x | pg_typeof +---------+----------- + {11,12} | integer[] +(1 row) + +select x, pg_typeof(x) from anyctest(11, array[12.3]) x; + x | pg_typeof +-----------+----------- + {11,12.3} | numeric[] +(1 row) + +select x, pg_typeof(x) from anyctest(12.3, array[13]) x; + x | pg_typeof +-----------+----------- + {12.3,13} | numeric[] +(1 row) + +select x, pg_typeof(x) from anyctest(12.3, '{13,14.4}') x; + x | pg_typeof +----------------+----------- + {12.3,13,14.4} | numeric[] +(1 row) + +select x, pg_typeof(x) from anyctest(11, array[point(1,2)]) x; -- fail +ERROR: function anyctest(integer, point[]) does not exist +LINE 1: select x, pg_typeof(x) from anyctest(11, array[point(1,2)]) ... + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +select x, pg_typeof(x) from anyctest(11, 12) x; -- fail +ERROR: function anyctest(integer, integer) does not exist +LINE 1: select x, pg_typeof(x) from anyctest(11, 12) x; + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +drop function anyctest(anycompatible, anycompatiblearray); +create function anyctest(anycompatible, anycompatiblerange) +returns anycompatiblerange as $$ + select $2 +$$ language sql; +select x, pg_typeof(x) from anyctest(11, int4range(4,7)) x; + x | pg_typeof +-------+----------- + [4,7) | int4range +(1 row) + +select x, pg_typeof(x) from anyctest(11, numrange(4,7)) x; + x | pg_typeof +-------+----------- + [4,7) | numrange +(1 row) + +select x, pg_typeof(x) from anyctest(11, 12) x; -- fail +ERROR: function anyctest(integer, integer) does not exist +LINE 1: select x, pg_typeof(x) from anyctest(11, 12) x; + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +select x, pg_typeof(x) from anyctest(11.2, int4range(4,7)) x; -- fail +ERROR: function anyctest(numeric, int4range) does not exist +LINE 1: select x, pg_typeof(x) from anyctest(11.2, int4range(4,7)) x... + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +select x, pg_typeof(x) from anyctest(11.2, '[4,7)') x; -- fail +ERROR: could not determine polymorphic type anycompatiblerange because input has type unknown +drop function anyctest(anycompatible, anycompatiblerange); +create function anyctest(anycompatiblerange, anycompatiblerange) +returns anycompatible as $$ + select lower($1) + upper($2) +$$ language sql; +select x, pg_typeof(x) from anyctest(int4range(11,12), int4range(4,7)) x; + x | pg_typeof +----+----------- + 18 | integer +(1 row) + +select x, pg_typeof(x) from anyctest(int4range(11,12), numrange(4,7)) x; -- fail +ERROR: function anyctest(int4range, numrange) does not exist +LINE 1: select x, pg_typeof(x) from anyctest(int4range(11,12), numra... + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +drop function anyctest(anycompatiblerange, anycompatiblerange); +-- fail, can't infer result type: +create function anyctest(anycompatible) +returns anycompatiblerange as $$ + select $1 +$$ language sql; +ERROR: cannot determine result data type +DETAIL: A result of type anycompatiblerange requires at least one input of type anycompatiblerange. +create function anyctest(anycompatiblenonarray, anycompatiblenonarray) +returns anycompatiblearray as $$ + select array[$1, $2] +$$ language sql; +select x, pg_typeof(x) from anyctest(11, 12) x; + x | pg_typeof +---------+----------- + {11,12} | integer[] +(1 row) + +select x, pg_typeof(x) from anyctest(11, 12.3) x; + x | pg_typeof +-----------+----------- + {11,12.3} | numeric[] +(1 row) + +select x, pg_typeof(x) from anyctest(array[11], array[1,2]) x; -- fail +ERROR: function anyctest(integer[], integer[]) does not exist +LINE 1: select x, pg_typeof(x) from anyctest(array[11], array[1,2]) ... + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +drop function anyctest(anycompatiblenonarray, anycompatiblenonarray); +create function anyctest(a anyelement, b anyarray, + c anycompatible, d anycompatible) +returns anycompatiblearray as $$ + select array[c, d] +$$ language sql; +select x, pg_typeof(x) from anyctest(11, array[1, 2], 42, 34.5) x; + x | pg_typeof +-----------+----------- + {42,34.5} | numeric[] +(1 row) + +select x, pg_typeof(x) from anyctest(11, array[1, 2], point(1,2), point(3,4)) x; + x | pg_typeof +-------------------+----------- + {"(1,2)","(3,4)"} | point[] +(1 row) + +select x, pg_typeof(x) from anyctest(11, '{1,2}', point(1,2), '(3,4)') x; + x | pg_typeof +-------------------+----------- + {"(1,2)","(3,4)"} | point[] +(1 row) + +select x, pg_typeof(x) from anyctest(11, array[1, 2.2], 42, 34.5) x; -- fail +ERROR: function anyctest(integer, numeric[], integer, numeric) does not exist +LINE 1: select x, pg_typeof(x) from anyctest(11, array[1, 2.2], 42, ... + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +drop function anyctest(a anyelement, b anyarray, + c anycompatible, d anycompatible); +create function anyctest(variadic anycompatiblearray) +returns anycompatiblearray as $$ + select $1 +$$ language sql; +select x, pg_typeof(x) from anyctest(11, 12) x; + x | pg_typeof +---------+----------- + {11,12} | integer[] +(1 row) + +select x, pg_typeof(x) from anyctest(11, 12.2) x; + x | pg_typeof +-----------+----------- + {11,12.2} | numeric[] +(1 row) + +select x, pg_typeof(x) from anyctest(11, '12') x; + x | pg_typeof +---------+----------- + {11,12} | integer[] +(1 row) + +select x, pg_typeof(x) from anyctest(11, '12.2') x; -- fail +ERROR: invalid input syntax for type integer: "12.2" +LINE 1: select x, pg_typeof(x) from anyctest(11, '12.2') x; + ^ +select x, pg_typeof(x) from anyctest(variadic array[11, 12]) x; + x | pg_typeof +---------+----------- + {11,12} | integer[] +(1 row) + +select x, pg_typeof(x) from anyctest(variadic array[11, 12.2]) x; + x | pg_typeof +-----------+----------- + {11,12.2} | numeric[] +(1 row) + +drop function anyctest(variadic anycompatiblearray); diff --git a/src/test/regress/expected/rangefuncs.out b/src/test/regress/expected/rangefuncs.out index cdfc43e854..7eced28452 100644 --- a/src/test/regress/expected/rangefuncs.out +++ b/src/test/regress/expected/rangefuncs.out @@ -1557,6 +1557,59 @@ CREATE FUNCTION bad (f1 int, out f2 anyelement, out f3 anyarray) AS 'select $1, array[$1,$1]' LANGUAGE sql; ERROR: cannot determine result data type DETAIL: A result of type anyelement requires at least one input of type anyelement, anyarray, anynonarray, anyenum, or anyrange. +CREATE FUNCTION dup (f1 anycompatible, f2 anycompatiblearray, f3 out anycompatible, f4 out anycompatiblearray) +AS 'select $1, $2' LANGUAGE sql; +SELECT dup(22, array[44]); + dup +----------- + (22,{44}) +(1 row) + +SELECT dup(4.5, array[44]); + dup +------------ + (4.5,{44}) +(1 row) + +SELECT dup(22, array[44::bigint]); + dup +----------- + (22,{44}) +(1 row) + +SELECT *, pg_typeof(f3), pg_typeof(f4) FROM dup(22, array[44::bigint]); + f3 | f4 | pg_typeof | pg_typeof +----+------+-----------+----------- + 22 | {44} | bigint | bigint[] +(1 row) + +DROP FUNCTION dup(f1 anycompatible, f2 anycompatiblearray); +CREATE FUNCTION dup (f1 anycompatiblerange, f2 out anycompatible, f3 out anycompatiblearray, f4 out anycompatiblerange) +AS 'select lower($1), array[lower($1), upper($1)], $1' LANGUAGE sql; +SELECT dup(int4range(4,7)); + dup +--------------------- + (4,"{4,7}","[4,7)") +(1 row) + +SELECT dup(numrange(4,7)); + dup +--------------------- + (4,"{4,7}","[4,7)") +(1 row) + +SELECT dup(textrange('aaa', 'bbb')); + dup +------------------------------- + (aaa,"{aaa,bbb}","[aaa,bbb)") +(1 row) + +DROP FUNCTION dup(f1 anycompatiblerange); +-- fails, no way to deduce outputs +CREATE FUNCTION bad (f1 anyarray, out f2 anycompatible, out f3 anycompatiblearray) +AS 'select $1, array[$1,$1]' LANGUAGE sql; +ERROR: cannot determine result data type +DETAIL: A result of type anycompatible requires at least one input of type anycompatible, anycompatiblearray, anycompatiblenonarray, or anycompatiblerange. -- -- table functions -- diff --git a/src/test/regress/expected/rangetypes.out b/src/test/regress/expected/rangetypes.out index a28741a888..c421f5394f 100644 --- a/src/test/regress/expected/rangetypes.out +++ b/src/test/regress/expected/rangetypes.out @@ -1405,6 +1405,32 @@ ERROR: function rangetypes_sql(numrange, integer[]) does not exist LINE 1: select rangetypes_sql(numrange(1,10), ARRAY[2,20]); ^ HINT: No function matches the given name and argument types. You might need to add explicit type casts. +create function anycompatiblearray_anycompatiblerange_func(a anycompatiblearray, r anycompatiblerange) + returns anycompatible as 'select $1[1] + lower($2);' language sql; +select anycompatiblearray_anycompatiblerange_func(ARRAY[1,2], int4range(10,20)); + anycompatiblearray_anycompatiblerange_func +-------------------------------------------- + 11 +(1 row) + +select anycompatiblearray_anycompatiblerange_func(ARRAY[1,2], numrange(10,20)); + anycompatiblearray_anycompatiblerange_func +-------------------------------------------- + 11 +(1 row) + +-- should fail +select anycompatiblearray_anycompatiblerange_func(ARRAY[1.1,2], int4range(10,20)); +ERROR: function anycompatiblearray_anycompatiblerange_func(numeric[], int4range) does not exist +LINE 1: select anycompatiblearray_anycompatiblerange_func(ARRAY[1.1,... + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +drop function anycompatiblearray_anycompatiblerange_func(anycompatiblearray, anycompatiblerange); +-- should fail +create function bogus_func(anycompatible) + returns anycompatiblerange as 'select int4range(1,10)' language sql; +ERROR: cannot determine result data type +DETAIL: A result of type anycompatiblerange requires at least one input of type anycompatiblerange. -- -- Arrays of ranges -- diff --git a/src/test/regress/expected/type_sanity.out b/src/test/regress/expected/type_sanity.out index cd7fc03b04..274130e706 100644 --- a/src/test/regress/expected/type_sanity.out +++ b/src/test/regress/expected/type_sanity.out @@ -131,14 +131,16 @@ WHERE p1.typinput = p2.oid AND NOT -- Check for type of the variadic array parameter's elements. -- provariadic should be ANYOID if the type of the last element is ANYOID, --- ANYELEMENTOID if the type of the last element is ANYARRAYOID, and otherwise --- the element type corresponding to the array type. +-- ANYELEMENTOID if the type of the last element is ANYARRAYOID, +-- ANYCOMPATIBLEOID if the type of the last element is ANYCOMPATIBLEARRAYOID, +-- and otherwise the element type corresponding to the array type. SELECT oid::regprocedure, provariadic::regtype, proargtypes::regtype[] FROM pg_proc WHERE provariadic != 0 AND case proargtypes[array_length(proargtypes, 1)-1] - WHEN 2276 THEN 2276 -- any -> any - WHEN 2277 THEN 2283 -- anyarray -> anyelement + WHEN '"any"'::regtype THEN '"any"'::regtype + WHEN 'anyarray'::regtype THEN 'anyelement'::regtype + WHEN 'anycompatiblearray'::regtype THEN 'anycompatible'::regtype ELSE (SELECT t.oid FROM pg_type t WHERE t.typarray = proargtypes[array_length(proargtypes, 1)-1]) diff --git a/src/test/regress/sql/aggregates.sql b/src/test/regress/sql/aggregates.sql index 02578330a6..5da6f4152b 100644 --- a/src/test/regress/sql/aggregates.sql +++ b/src/test/regress/sql/aggregates.sql @@ -740,6 +740,10 @@ drop view aggordview1; select least_agg(q1,q2) from int8_tbl; select least_agg(variadic array[q1,q2]) from int8_tbl; +select cleast_agg(q1,q2) from int8_tbl; +select cleast_agg(4.5,f1) from int4_tbl; +select cleast_agg(variadic array[4.5,f1]) from int4_tbl; +select pg_typeof(cleast_agg(variadic array[4.5,f1])) from int4_tbl; -- test aggregates with common transition functions share the same states begin work; diff --git a/src/test/regress/sql/create_aggregate.sql b/src/test/regress/sql/create_aggregate.sql index fd7cd400c1..d4b4036fd7 100644 --- a/src/test/regress/sql/create_aggregate.sql +++ b/src/test/regress/sql/create_aggregate.sql @@ -72,7 +72,31 @@ create aggregate aggfns(integer,integer,text) ( initcond = '{}' ); --- variadic aggregate +-- check error cases that would require run-time type coercion +create function least_accum(int8, int8) returns int8 language sql as + 'select least($1, $2)'; + +create aggregate least_agg(int4) ( + stype = int8, sfunc = least_accum +); -- fails + +drop function least_accum(int8, int8); + +create function least_accum(anycompatible, anycompatible) +returns anycompatible language sql as + 'select least($1, $2)'; + +create aggregate least_agg(int4) ( + stype = int8, sfunc = least_accum +); -- fails + +create aggregate least_agg(int8) ( + stype = int8, sfunc = least_accum +); + +drop function least_accum(anycompatible, anycompatible) cascade; + +-- variadic aggregates 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)'; @@ -81,6 +105,14 @@ create aggregate least_agg(variadic items anyarray) ( stype = anyelement, sfunc = least_accum ); +create function cleast_accum(anycompatible, variadic anycompatiblearray) +returns anycompatible language sql as + 'select least($1, min($2[i])) from generate_subscripts($2,1) g(i)'; + +create aggregate cleast_agg(variadic items anycompatiblearray) ( + stype = anycompatible, sfunc = cleast_accum +); + -- test ordered-set aggs using built-in support functions create aggregate my_percentile_disc(float8 ORDER BY anyelement) ( stype = internal, diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql index f06f245db3..389d5b2464 100644 --- a/src/test/regress/sql/opr_sanity.sql +++ b/src/test/regress/sql/opr_sanity.sql @@ -273,7 +273,7 @@ SELECT p1.oid, p1.proname FROM pg_proc as p1 WHERE p1.prorettype IN ('anyelement'::regtype, 'anyarray'::regtype, 'anynonarray'::regtype, - 'anyenum'::regtype, 'anyrange'::regtype) + 'anyenum'::regtype) AND NOT ('anyelement'::regtype = ANY (p1.proargtypes) OR 'anyarray'::regtype = ANY (p1.proargtypes) OR @@ -282,6 +282,37 @@ WHERE p1.prorettype IN 'anyrange'::regtype = ANY (p1.proargtypes)) ORDER BY 2; +-- anyrange is tighter than the rest, can only resolve from anyrange input + +SELECT p1.oid, p1.proname +FROM pg_proc as p1 +WHERE p1.prorettype = 'anyrange'::regtype + AND NOT + 'anyrange'::regtype = ANY (p1.proargtypes) +ORDER BY 2; + +-- similarly for the anycompatible family + +SELECT p1.oid, p1.proname +FROM pg_proc as p1 +WHERE p1.prorettype IN + ('anycompatible'::regtype, 'anycompatiblearray'::regtype, + 'anycompatiblenonarray'::regtype) + AND NOT + ('anycompatible'::regtype = ANY (p1.proargtypes) OR + 'anycompatiblearray'::regtype = ANY (p1.proargtypes) OR + 'anycompatiblenonarray'::regtype = ANY (p1.proargtypes) OR + 'anycompatiblerange'::regtype = ANY (p1.proargtypes)) +ORDER BY 2; + +SELECT p1.oid, p1.proname +FROM pg_proc as p1 +WHERE p1.prorettype = 'anycompatiblerange'::regtype + AND NOT + 'anycompatiblerange'::regtype = ANY (p1.proargtypes) +ORDER BY 2; + + -- Look for functions that accept cstring and are neither datatype input -- functions nor encoding conversion functions. It's almost never a good -- idea to use cstring input for a function meant to be called from SQL; diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql index c5e6e6e5ed..07c60c80e4 100644 --- a/src/test/regress/sql/plpgsql.sql +++ b/src/test/regress/sql/plpgsql.sql @@ -1618,6 +1618,62 @@ select f1(int4range(42, 49)) as int, f1(float8range(4.5, 7.8)) as num; drop function f1(x anyrange); +create function f1(x anycompatible, y anycompatible) returns anycompatiblearray as $$ +begin + return array[x, y]; +end$$ language plpgsql; + +select f1(2, 4) as int, f1(2, 4.5) as num; + +drop function f1(x anycompatible, y anycompatible); + +create function f1(x anycompatiblerange, y anycompatible, z anycompatible) returns anycompatiblearray as $$ +begin + return array[lower(x), upper(x), y, z]; +end$$ language plpgsql; + +select f1(int4range(42, 49), 11, 2::smallint) as int, f1(float8range(4.5, 7.8), 7.8, 11::real) as num; + +select f1(int4range(42, 49), 11, 4.5) as fail; -- range type doesn't fit + +drop function f1(x anycompatiblerange, y anycompatible, z anycompatible); + +-- fail, can't infer type: +create function f1(x anycompatible) returns anycompatiblerange as $$ +begin + return array[x + 1, x + 2]; +end$$ language plpgsql; + +create function f1(x anycompatiblerange, y anycompatiblearray) returns anycompatiblerange as $$ +begin + return x; +end$$ language plpgsql; + +select f1(int4range(42, 49), array[11]) as int, f1(float8range(4.5, 7.8), array[7]) as num; + +drop function f1(x anycompatiblerange, y anycompatiblearray); + +create function f1(a anyelement, b anyarray, + c anycompatible, d anycompatible, + OUT x anyarray, OUT y anycompatiblearray) +as $$ +begin + x := a || b; + y := array[c, d]; +end$$ language plpgsql; + +select x, pg_typeof(x), y, pg_typeof(y) + from f1(11, array[1, 2], 42, 34.5); +select x, pg_typeof(x), y, pg_typeof(y) + from f1(11, array[1, 2], point(1,2), point(3,4)); +select x, pg_typeof(x), y, pg_typeof(y) + from f1(11, '{1,2}', point(1,2), '(3,4)'); +select x, pg_typeof(x), y, pg_typeof(y) + from f1(11, array[1, 2.2], 42, 34.5); -- fail + +drop function f1(a anyelement, b anyarray, + c anycompatible, d anycompatible); + -- -- Test handling of OUT parameters, including polymorphic cases. -- Note that RETURN is optional with OUT params; we try both ways. @@ -1699,6 +1755,18 @@ select * from duplic('foo'::text); drop function duplic(anyelement); +create function duplic(in i anycompatiblerange, out j anycompatible, out k anycompatiblearray) as $$ +begin + j := lower(i); + k := array[lower(i),upper(i)]; + return; +end$$ language plpgsql; + +select * from duplic(int4range(42,49)); +select * from duplic(textrange('aaa', 'bbb')); + +drop function duplic(anycompatiblerange); + -- -- test PERFORM -- diff --git a/src/test/regress/sql/polymorphism.sql b/src/test/regress/sql/polymorphism.sql index 9c7b43efeb..b57591f69f 100644 --- a/src/test/regress/sql/polymorphism.sql +++ b/src/test/regress/sql/polymorphism.sql @@ -53,6 +53,56 @@ select polyf(int4range(42, 49)) as int, polyf(float8range(4.5, 7.8)) as num; drop function polyf(x anyrange); +create function polyf(x anycompatible, y anycompatible) returns anycompatiblearray as $$ + select array[x, y] +$$ language sql; + +select polyf(2, 4) as int, polyf(2, 4.5) as num; + +drop function polyf(x anycompatible, y anycompatible); + +create function polyf(x anycompatiblerange, y anycompatible, z anycompatible) returns anycompatiblearray as $$ + select array[lower(x), upper(x), y, z] +$$ language sql; + +select polyf(int4range(42, 49), 11, 2::smallint) as int, polyf(float8range(4.5, 7.8), 7.8, 11::real) as num; + +select polyf(int4range(42, 49), 11, 4.5) as fail; -- range type doesn't fit + +drop function polyf(x anycompatiblerange, y anycompatible, z anycompatible); + +-- fail, can't infer type: +create function polyf(x anycompatible) returns anycompatiblerange as $$ + select array[x + 1, x + 2] +$$ language sql; + +create function polyf(x anycompatiblerange, y anycompatiblearray) returns anycompatiblerange as $$ + select x +$$ language sql; + +select polyf(int4range(42, 49), array[11]) as int, polyf(float8range(4.5, 7.8), array[7]) as num; + +drop function polyf(x anycompatiblerange, y anycompatiblearray); + +create function polyf(a anyelement, b anyarray, + c anycompatible, d anycompatible, + OUT x anyarray, OUT y anycompatiblearray) +as $$ + select a || b, array[c, d] +$$ language sql; + +select x, pg_typeof(x), y, pg_typeof(y) + from polyf(11, array[1, 2], 42, 34.5); +select x, pg_typeof(x), y, pg_typeof(y) + from polyf(11, array[1, 2], point(1,2), point(3,4)); +select x, pg_typeof(x), y, pg_typeof(y) + from polyf(11, '{1,2}', point(1,2), '(3,4)'); +select x, pg_typeof(x), y, pg_typeof(y) + from polyf(11, array[1, 2.2], 42, 34.5); -- fail + +drop function polyf(a anyelement, b anyarray, + c anycompatible, d anycompatible); + -- -- Polymorphic aggregate tests @@ -868,3 +918,112 @@ select * from dfview; drop view dfview; drop function dfunc(anyelement, anyelement, bool); + +-- +-- Tests for ANYCOMPATIBLE polymorphism family +-- + +create function anyctest(anycompatible, anycompatible) +returns anycompatible as $$ + select greatest($1, $2) +$$ language sql; + +select x, pg_typeof(x) from anyctest(11, 12) x; +select x, pg_typeof(x) from anyctest(11, 12.3) x; +select x, pg_typeof(x) from anyctest(11, point(1,2)) x; -- fail +select x, pg_typeof(x) from anyctest('11', '12.3') x; -- defaults to text + +drop function anyctest(anycompatible, anycompatible); + +create function anyctest(anycompatible, anycompatible) +returns anycompatiblearray as $$ + select array[$1, $2] +$$ language sql; + +select x, pg_typeof(x) from anyctest(11, 12) x; +select x, pg_typeof(x) from anyctest(11, 12.3) x; +select x, pg_typeof(x) from anyctest(11, array[1,2]) x; -- fail + +drop function anyctest(anycompatible, anycompatible); + +create function anyctest(anycompatible, anycompatiblearray) +returns anycompatiblearray as $$ + select array[$1] || $2 +$$ language sql; + +select x, pg_typeof(x) from anyctest(11, array[12]) x; +select x, pg_typeof(x) from anyctest(11, array[12.3]) x; +select x, pg_typeof(x) from anyctest(12.3, array[13]) x; +select x, pg_typeof(x) from anyctest(12.3, '{13,14.4}') x; +select x, pg_typeof(x) from anyctest(11, array[point(1,2)]) x; -- fail +select x, pg_typeof(x) from anyctest(11, 12) x; -- fail + +drop function anyctest(anycompatible, anycompatiblearray); + +create function anyctest(anycompatible, anycompatiblerange) +returns anycompatiblerange as $$ + select $2 +$$ language sql; + +select x, pg_typeof(x) from anyctest(11, int4range(4,7)) x; +select x, pg_typeof(x) from anyctest(11, numrange(4,7)) x; +select x, pg_typeof(x) from anyctest(11, 12) x; -- fail +select x, pg_typeof(x) from anyctest(11.2, int4range(4,7)) x; -- fail +select x, pg_typeof(x) from anyctest(11.2, '[4,7)') x; -- fail + +drop function anyctest(anycompatible, anycompatiblerange); + +create function anyctest(anycompatiblerange, anycompatiblerange) +returns anycompatible as $$ + select lower($1) + upper($2) +$$ language sql; + +select x, pg_typeof(x) from anyctest(int4range(11,12), int4range(4,7)) x; +select x, pg_typeof(x) from anyctest(int4range(11,12), numrange(4,7)) x; -- fail + +drop function anyctest(anycompatiblerange, anycompatiblerange); + +-- fail, can't infer result type: +create function anyctest(anycompatible) +returns anycompatiblerange as $$ + select $1 +$$ language sql; + +create function anyctest(anycompatiblenonarray, anycompatiblenonarray) +returns anycompatiblearray as $$ + select array[$1, $2] +$$ language sql; + +select x, pg_typeof(x) from anyctest(11, 12) x; +select x, pg_typeof(x) from anyctest(11, 12.3) x; +select x, pg_typeof(x) from anyctest(array[11], array[1,2]) x; -- fail + +drop function anyctest(anycompatiblenonarray, anycompatiblenonarray); + +create function anyctest(a anyelement, b anyarray, + c anycompatible, d anycompatible) +returns anycompatiblearray as $$ + select array[c, d] +$$ language sql; + +select x, pg_typeof(x) from anyctest(11, array[1, 2], 42, 34.5) x; +select x, pg_typeof(x) from anyctest(11, array[1, 2], point(1,2), point(3,4)) x; +select x, pg_typeof(x) from anyctest(11, '{1,2}', point(1,2), '(3,4)') x; +select x, pg_typeof(x) from anyctest(11, array[1, 2.2], 42, 34.5) x; -- fail + +drop function anyctest(a anyelement, b anyarray, + c anycompatible, d anycompatible); + +create function anyctest(variadic anycompatiblearray) +returns anycompatiblearray as $$ + select $1 +$$ language sql; + +select x, pg_typeof(x) from anyctest(11, 12) x; +select x, pg_typeof(x) from anyctest(11, 12.2) x; +select x, pg_typeof(x) from anyctest(11, '12') x; +select x, pg_typeof(x) from anyctest(11, '12.2') x; -- fail +select x, pg_typeof(x) from anyctest(variadic array[11, 12]) x; +select x, pg_typeof(x) from anyctest(variadic array[11, 12.2]) x; + +drop function anyctest(variadic anycompatiblearray); diff --git a/src/test/regress/sql/rangefuncs.sql b/src/test/regress/sql/rangefuncs.sql index 476b4f27e2..ae3119a959 100644 --- a/src/test/regress/sql/rangefuncs.sql +++ b/src/test/regress/sql/rangefuncs.sql @@ -407,6 +407,27 @@ DROP FUNCTION dup(anyelement); CREATE FUNCTION bad (f1 int, out f2 anyelement, out f3 anyarray) AS 'select $1, array[$1,$1]' LANGUAGE sql; +CREATE FUNCTION dup (f1 anycompatible, f2 anycompatiblearray, f3 out anycompatible, f4 out anycompatiblearray) +AS 'select $1, $2' LANGUAGE sql; +SELECT dup(22, array[44]); +SELECT dup(4.5, array[44]); +SELECT dup(22, array[44::bigint]); +SELECT *, pg_typeof(f3), pg_typeof(f4) FROM dup(22, array[44::bigint]); + +DROP FUNCTION dup(f1 anycompatible, f2 anycompatiblearray); + +CREATE FUNCTION dup (f1 anycompatiblerange, f2 out anycompatible, f3 out anycompatiblearray, f4 out anycompatiblerange) +AS 'select lower($1), array[lower($1), upper($1)], $1' LANGUAGE sql; +SELECT dup(int4range(4,7)); +SELECT dup(numrange(4,7)); +SELECT dup(textrange('aaa', 'bbb')); + +DROP FUNCTION dup(f1 anycompatiblerange); + +-- fails, no way to deduce outputs +CREATE FUNCTION bad (f1 anyarray, out f2 anycompatible, out f3 anycompatiblearray) +AS 'select $1, array[$1,$1]' LANGUAGE sql; + -- -- table functions -- diff --git a/src/test/regress/sql/rangetypes.sql b/src/test/regress/sql/rangetypes.sql index 85eaa9b34c..4048b1d185 100644 --- a/src/test/regress/sql/rangetypes.sql +++ b/src/test/regress/sql/rangetypes.sql @@ -456,6 +456,22 @@ create function rangetypes_sql(q anyrange, b anyarray, out c anyelement) select rangetypes_sql(int4range(1,10), ARRAY[2,20]); select rangetypes_sql(numrange(1,10), ARRAY[2,20]); -- match failure +create function anycompatiblearray_anycompatiblerange_func(a anycompatiblearray, r anycompatiblerange) + returns anycompatible as 'select $1[1] + lower($2);' language sql; + +select anycompatiblearray_anycompatiblerange_func(ARRAY[1,2], int4range(10,20)); + +select anycompatiblearray_anycompatiblerange_func(ARRAY[1,2], numrange(10,20)); + +-- should fail +select anycompatiblearray_anycompatiblerange_func(ARRAY[1.1,2], int4range(10,20)); + +drop function anycompatiblearray_anycompatiblerange_func(anycompatiblearray, anycompatiblerange); + +-- should fail +create function bogus_func(anycompatible) + returns anycompatiblerange as 'select int4range(1,10)' language sql; + -- -- Arrays of ranges -- diff --git a/src/test/regress/sql/type_sanity.sql b/src/test/regress/sql/type_sanity.sql index fed413bf98..4b492ce062 100644 --- a/src/test/regress/sql/type_sanity.sql +++ b/src/test/regress/sql/type_sanity.sql @@ -106,15 +106,17 @@ WHERE p1.typinput = p2.oid AND NOT -- Check for type of the variadic array parameter's elements. -- provariadic should be ANYOID if the type of the last element is ANYOID, --- ANYELEMENTOID if the type of the last element is ANYARRAYOID, and otherwise --- the element type corresponding to the array type. +-- ANYELEMENTOID if the type of the last element is ANYARRAYOID, +-- ANYCOMPATIBLEOID if the type of the last element is ANYCOMPATIBLEARRAYOID, +-- and otherwise the element type corresponding to the array type. SELECT oid::regprocedure, provariadic::regtype, proargtypes::regtype[] FROM pg_proc WHERE provariadic != 0 AND case proargtypes[array_length(proargtypes, 1)-1] - WHEN 2276 THEN 2276 -- any -> any - WHEN 2277 THEN 2283 -- anyarray -> anyelement + WHEN '"any"'::regtype THEN '"any"'::regtype + WHEN 'anyarray'::regtype THEN 'anyelement'::regtype + WHEN 'anycompatiblearray'::regtype THEN 'anycompatible'::regtype ELSE (SELECT t.oid FROM pg_type t WHERE t.typarray = proargtypes[array_length(proargtypes, 1)-1]) -- cgit v1.2.3