diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/executor/functions.c | 20 | ||||
-rw-r--r-- | src/test/regress/expected/plpgsql.out | 77 | ||||
-rw-r--r-- | src/test/regress/expected/polymorphism.out | 78 | ||||
-rw-r--r-- | src/test/regress/sql/plpgsql.sql | 60 | ||||
-rw-r--r-- | src/test/regress/sql/polymorphism.sql | 58 |
5 files changed, 279 insertions, 14 deletions
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index 9b45a8a9a0e..c53aaaca612 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -1567,13 +1567,16 @@ check_sql_fn_statements(List *queryTreeList) * false even when the declared function return type is a rowtype. * * For a polymorphic function the passed rettype must be the actual resolved - * output type of the function; we should never see a polymorphic pseudotype - * such as ANYELEMENT as rettype. (This means we can't check the type during - * function definition of a polymorphic function.) If the function returns - * composite, the passed rettupdesc should describe the expected output. - * If rettupdesc is NULL, we can't verify that the output matches; that - * should only happen in fmgr_sql_validator(), or when the function returns - * RECORD and the caller doesn't actually care which composite type it is. + * output type of the function. (This means we can't check the type during + * function definition of a polymorphic function.) If we do see a polymorphic + * rettype we'll throw an error, saying it is not a supported rettype. + * + * If the function returns composite, the passed rettupdesc should describe + * the expected output. If rettupdesc is NULL, we can't verify that the + * output matches; that should only happen in fmgr_sql_validator(), or when + * the function returns RECORD and the caller doesn't actually care which + * composite type it is. + * * (Typically, rettype and rettupdesc are computed by get_call_result_type * or a sibling function.) * @@ -1602,9 +1605,6 @@ check_sql_fn_retval(List *queryTreeList, bool upper_tlist_nontrivial = false; ListCell *lc; - /* Caller must have resolved any polymorphism */ - AssertArg(!IsPolymorphicType(rettype)); - if (resultTargetList) *resultTargetList = NIL; /* initialize in case of VOID result */ diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out index cd2c79f4d50..731db2c7760 100644 --- a/src/test/regress/expected/plpgsql.out +++ b/src/test/regress/expected/plpgsql.out @@ -1747,6 +1747,83 @@ SELECT * FROM test_ret_rec_dyn(5) AS (a int, b numeric, c text); (1 row) -- +-- Test some simple polymorphism cases. +-- +create function f1(x anyelement) returns anyelement as $$ +begin + return x + 1; +end$$ language plpgsql; +select f1(42) as int, f1(4.5) as num; + int | num +-----+----- + 43 | 5.5 +(1 row) + +select f1(point(3,4)); -- fail for lack of + operator +ERROR: operator does not exist: point + integer +LINE 1: SELECT x + 1 + ^ +HINT: No operator matches the given name and argument types. You might need to add explicit type casts. +QUERY: SELECT x + 1 +CONTEXT: PL/pgSQL function f1(anyelement) line 3 at RETURN +drop function f1(x anyelement); +create function f1(x anyelement) returns anyarray as $$ +begin + return array[x + 1, x + 2]; +end$$ language plpgsql; +select f1(42) as int, f1(4.5) as num; + int | num +---------+----------- + {43,44} | {5.5,6.5} +(1 row) + +drop function f1(x anyelement); +create function f1(x anyarray) returns anyelement as $$ +begin + return x[1]; +end$$ language plpgsql; +select f1(array[2,4]) as int, f1(array[4.5, 7.7]) as num; + int | num +-----+----- + 2 | 4.5 +(1 row) + +select f1(stavalues1) from pg_statistic; -- fail, can't infer element type +ERROR: argument declared anyarray is not an array but type anyarray +drop function f1(x anyarray); +create function f1(x anyarray) returns anyarray as $$ +begin + return x; +end$$ language plpgsql; +select f1(array[2,4]) as int, f1(array[4.5, 7.7]) as num; + int | num +-------+----------- + {2,4} | {4.5,7.7} +(1 row) + +select f1(stavalues1) from pg_statistic; -- fail, can't infer element type +ERROR: PL/pgSQL functions cannot accept type anyarray +CONTEXT: compilation of PL/pgSQL function "f1" near line 1 +drop function f1(x anyarray); +-- fail, can't infer type: +create function f1(x anyelement) returns anyrange as $$ +begin + return array[x + 1, x + 2]; +end$$ language plpgsql; +ERROR: cannot determine result data type +DETAIL: A function returning "anyrange" must have at least one "anyrange" argument. +create function f1(x anyrange) returns anyarray as $$ +begin + return array[lower(x), upper(x)]; +end$$ language plpgsql; +select f1(int4range(42, 49)) as int, f1(float8range(4.5, 7.8)) as num; + int | num +---------+----------- + {42,49} | {4.5,7.8} +(1 row) + +drop function f1(x anyrange); +-- -- Test handling of OUT parameters, including polymorphic cases. -- Note that RETURN is optional with OUT params; we try both ways. -- diff --git a/src/test/regress/expected/polymorphism.out b/src/test/regress/expected/polymorphism.out index 986417a1881..20f8c511b93 100644 --- a/src/test/regress/expected/polymorphism.out +++ b/src/test/regress/expected/polymorphism.out @@ -1,6 +1,80 @@ --- Currently this tests polymorphic aggregates and indirectly does some --- testing of polymorphic SQL functions. It ought to be extended. +-- +-- Tests for polymorphic SQL functions and aggregates based on them. -- Tests for other features related to function-calling have snuck in, too. +-- +create function polyf(x anyelement) returns anyelement as $$ + select x + 1 +$$ language sql; +select polyf(42) as int, polyf(4.5) as num; + int | num +-----+----- + 43 | 5.5 +(1 row) + +select polyf(point(3,4)); -- fail for lack of + operator +ERROR: operator does not exist: point + integer +LINE 2: select x + 1 + ^ +HINT: No operator matches the given name and argument types. You might need to add explicit type casts. +QUERY: + select x + 1 + +CONTEXT: SQL function "polyf" during inlining +drop function polyf(x anyelement); +create function polyf(x anyelement) returns anyarray as $$ + select array[x + 1, x + 2] +$$ language sql; +select polyf(42) as int, polyf(4.5) as num; + int | num +---------+----------- + {43,44} | {5.5,6.5} +(1 row) + +drop function polyf(x anyelement); +create function polyf(x anyarray) returns anyelement as $$ + select x[1] +$$ language sql; +select polyf(array[2,4]) as int, polyf(array[4.5, 7.7]) as num; + int | num +-----+----- + 2 | 4.5 +(1 row) + +select polyf(stavalues1) from pg_statistic; -- fail, can't infer element type +ERROR: argument declared anyarray is not an array but type anyarray +drop function polyf(x anyarray); +create function polyf(x anyarray) returns anyarray as $$ + select x +$$ language sql; +select polyf(array[2,4]) as int, polyf(array[4.5, 7.7]) as num; + int | num +-------+----------- + {2,4} | {4.5,7.7} +(1 row) + +select polyf(stavalues1) from pg_statistic; -- fail, can't infer element type +ERROR: return type anyarray is not supported for SQL functions +CONTEXT: SQL function "polyf" during inlining +drop function polyf(x anyarray); +-- fail, can't infer type: +create function polyf(x anyelement) returns anyrange as $$ + select array[x + 1, x + 2] +$$ language sql; +ERROR: cannot determine result data type +DETAIL: A function returning "anyrange" must have at least one "anyrange" argument. +create function polyf(x anyrange) returns anyarray as $$ + select array[lower(x), upper(x)] +$$ language sql; +select polyf(int4range(42, 49)) as int, polyf(float8range(4.5, 7.8)) as num; + int | num +---------+----------- + {42,49} | {4.5,7.8} +(1 row) + +drop function polyf(x anyrange); +-- +-- Polymorphic aggregate tests +-- -- Legend: ----------- -- A = type is ANY diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql index d841d8c0f97..c5e6e6e5ede 100644 --- a/src/test/regress/sql/plpgsql.sql +++ b/src/test/regress/sql/plpgsql.sql @@ -1559,6 +1559,66 @@ SELECT * FROM test_ret_rec_dyn(1500) AS (a int, b int, c int); SELECT * FROM test_ret_rec_dyn(5) AS (a int, b numeric, c text); -- +-- Test some simple polymorphism cases. +-- + +create function f1(x anyelement) returns anyelement as $$ +begin + return x + 1; +end$$ language plpgsql; + +select f1(42) as int, f1(4.5) as num; +select f1(point(3,4)); -- fail for lack of + operator + +drop function f1(x anyelement); + +create function f1(x anyelement) returns anyarray as $$ +begin + return array[x + 1, x + 2]; +end$$ language plpgsql; + +select f1(42) as int, f1(4.5) as num; + +drop function f1(x anyelement); + +create function f1(x anyarray) returns anyelement as $$ +begin + return x[1]; +end$$ language plpgsql; + +select f1(array[2,4]) as int, f1(array[4.5, 7.7]) as num; + +select f1(stavalues1) from pg_statistic; -- fail, can't infer element type + +drop function f1(x anyarray); + +create function f1(x anyarray) returns anyarray as $$ +begin + return x; +end$$ language plpgsql; + +select f1(array[2,4]) as int, f1(array[4.5, 7.7]) as num; + +select f1(stavalues1) from pg_statistic; -- fail, can't infer element type + +drop function f1(x anyarray); + +-- fail, can't infer type: +create function f1(x anyelement) returns anyrange as $$ +begin + return array[x + 1, x + 2]; +end$$ language plpgsql; + +create function f1(x anyrange) returns anyarray as $$ +begin + return array[lower(x), upper(x)]; +end$$ language plpgsql; + +select f1(int4range(42, 49)) as int, f1(float8range(4.5, 7.8)) as num; + +drop function f1(x anyrange); + +-- -- Test handling of OUT parameters, including polymorphic cases. -- Note that RETURN is optional with OUT params; we try both ways. -- diff --git a/src/test/regress/sql/polymorphism.sql b/src/test/regress/sql/polymorphism.sql index 03606671d92..9c7b43efebb 100644 --- a/src/test/regress/sql/polymorphism.sql +++ b/src/test/regress/sql/polymorphism.sql @@ -1,8 +1,62 @@ --- Currently this tests polymorphic aggregates and indirectly does some --- testing of polymorphic SQL functions. It ought to be extended. +-- +-- Tests for polymorphic SQL functions and aggregates based on them. -- Tests for other features related to function-calling have snuck in, too. +-- + +create function polyf(x anyelement) returns anyelement as $$ + select x + 1 +$$ language sql; + +select polyf(42) as int, polyf(4.5) as num; +select polyf(point(3,4)); -- fail for lack of + operator + +drop function polyf(x anyelement); + +create function polyf(x anyelement) returns anyarray as $$ + select array[x + 1, x + 2] +$$ language sql; + +select polyf(42) as int, polyf(4.5) as num; + +drop function polyf(x anyelement); + +create function polyf(x anyarray) returns anyelement as $$ + select x[1] +$$ language sql; + +select polyf(array[2,4]) as int, polyf(array[4.5, 7.7]) as num; + +select polyf(stavalues1) from pg_statistic; -- fail, can't infer element type +drop function polyf(x anyarray); +create function polyf(x anyarray) returns anyarray as $$ + select x +$$ language sql; + +select polyf(array[2,4]) as int, polyf(array[4.5, 7.7]) as num; + +select polyf(stavalues1) from pg_statistic; -- fail, can't infer element type + +drop function polyf(x anyarray); + +-- fail, can't infer type: +create function polyf(x anyelement) returns anyrange as $$ + select array[x + 1, x + 2] +$$ language sql; + +create function polyf(x anyrange) returns anyarray as $$ + select array[lower(x), upper(x)] +$$ language sql; + +select polyf(int4range(42, 49)) as int, polyf(float8range(4.5, 7.8)) as num; + +drop function polyf(x anyrange); + + +-- +-- Polymorphic aggregate tests +-- -- Legend: ----------- -- A = type is ANY |