* 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.)
*
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 */
50 | 5 | xxx
(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.
--- 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
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.
--- 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