aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/executor/functions.c20
-rw-r--r--src/test/regress/expected/plpgsql.out77
-rw-r--r--src/test/regress/expected/polymorphism.out78
-rw-r--r--src/test/regress/sql/plpgsql.sql60
-rw-r--r--src/test/regress/sql/polymorphism.sql58
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