aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/executor/functions.c5
-rw-r--r--src/backend/optimizer/util/clauses.c5
-rw-r--r--src/test/regress/expected/rangefuncs.out20
-rw-r--r--src/test/regress/sql/rangefuncs.sql19
4 files changed, 49 insertions, 0 deletions
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index 498bcba5816..11f92adbb06 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -1171,6 +1171,11 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
* This can happen, for example, where the body of the function is
* 'SELECT func2()', where func2 has the same composite return type as
* the function that's calling it.
+ *
+ * XXX Note that if rettype is RECORD, the IsBinaryCoercible check
+ * will succeed for any composite restype. For the moment we rely on
+ * runtime type checking to catch any discrepancy, but it'd be nice to
+ * do better at parse time.
*/
if (tlistlen == 1)
{
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index de2e66b0f16..80dfaad736f 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -3677,6 +3677,10 @@ evaluate_function(Oid funcid, Oid result_type, int32 result_typmod, List *args,
* We must also beware of changing the volatility or strictness status of
* functions by inlining them.
*
+ * Also, at the moment we can't inline functions returning RECORD. This
+ * doesn't work in the general case because it discards information such
+ * as OUT-parameter declarations.
+ *
* Returns a simplified expression if successful, or NULL if cannot
* simplify the function.
*/
@@ -3709,6 +3713,7 @@ inline_function(Oid funcid, Oid result_type, List *args,
if (funcform->prolang != SQLlanguageId ||
funcform->prosecdef ||
funcform->proretset ||
+ funcform->prorettype == RECORDOID ||
!heap_attisnull(func_tuple, Anum_pg_proc_proconfig) ||
funcform->pronargs != list_length(args))
return NULL;
diff --git a/src/test/regress/expected/rangefuncs.out b/src/test/regress/expected/rangefuncs.out
index f1466e0d442..51d561b28fa 100644
--- a/src/test/regress/expected/rangefuncs.out
+++ b/src/test/regress/expected/rangefuncs.out
@@ -898,3 +898,23 @@ select * from foobar();
(2 rows)
drop function foobar();
+-- check handling of a SQL function with multiple OUT params (bug #5777)
+create or replace function foobar(out integer, out numeric) as
+$$ select (1, 2.1) $$ language sql;
+select * from foobar();
+ column1 | column2
+---------+---------
+ 1 | 2.1
+(1 row)
+
+create or replace function foobar(out integer, out numeric) as
+$$ select (1, 2) $$ language sql;
+select * from foobar(); -- fail
+ERROR: function return row and query-specified return row do not match
+DETAIL: Returned type integer at ordinal position 2, but query expects numeric.
+create or replace function foobar(out integer, out numeric) as
+$$ select (1, 2.1, 3) $$ language sql;
+select * from foobar(); -- fail
+ERROR: function return row and query-specified return row do not match
+DETAIL: Returned row contains 3 attributes, but query expects 2.
+drop function foobar();
diff --git a/src/test/regress/sql/rangefuncs.sql b/src/test/regress/sql/rangefuncs.sql
index d1b9db7e513..54cfc178c05 100644
--- a/src/test/regress/sql/rangefuncs.sql
+++ b/src/test/regress/sql/rangefuncs.sql
@@ -429,3 +429,22 @@ select foobar();
select * from foobar();
drop function foobar();
+
+-- check handling of a SQL function with multiple OUT params (bug #5777)
+
+create or replace function foobar(out integer, out numeric) as
+$$ select (1, 2.1) $$ language sql;
+
+select * from foobar();
+
+create or replace function foobar(out integer, out numeric) as
+$$ select (1, 2) $$ language sql;
+
+select * from foobar(); -- fail
+
+create or replace function foobar(out integer, out numeric) as
+$$ select (1, 2.1, 3) $$ language sql;
+
+select * from foobar(); -- fail
+
+drop function foobar();