aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/catalog/pg_proc.c7
-rw-r--r--src/backend/executor/functions.c34
-rw-r--r--src/backend/optimizer/util/clauses.c12
-rw-r--r--src/include/executor/functions.h6
-rw-r--r--src/test/regress/expected/create_procedure.out14
-rw-r--r--src/test/regress/sql/create_procedure.sql11
6 files changed, 67 insertions, 17 deletions
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index c3e33e0f9c6..ea026572f95 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -945,9 +945,10 @@ fmgr_sql_validator(PG_FUNCTION_ARGS)
}
check_sql_fn_statements(querytree_list);
- (void) check_sql_fn_retval(funcoid, proc->prorettype,
- querytree_list,
- NULL, NULL);
+ (void) check_sql_fn_retval_ext(funcoid, proc->prorettype,
+ proc->prokind,
+ querytree_list,
+ NULL, NULL);
}
error_context_stack = sqlerrcontext.previous;
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index c7a3739dad7..2e4d5d9f454 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -744,11 +744,12 @@ init_sql_fcache(FmgrInfo *finfo, Oid collation, bool lazyEvalOK)
* coerce the returned rowtype to the desired form (unless the result type
* is VOID, in which case there's nothing to coerce to).
*/
- fcache->returnsTuple = check_sql_fn_retval(foid,
- rettype,
- flat_query_list,
- NULL,
- &fcache->junkFilter);
+ fcache->returnsTuple = check_sql_fn_retval_ext(foid,
+ rettype,
+ procedureStruct->prokind,
+ flat_query_list,
+ NULL,
+ &fcache->junkFilter);
if (fcache->returnsTuple)
{
@@ -1591,6 +1592,20 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
bool *modifyTargetList,
JunkFilter **junkFilter)
{
+ /* Wrapper function to preserve ABI compatibility in released branches */
+ return check_sql_fn_retval_ext(func_id, rettype,
+ PROKIND_FUNCTION,
+ queryTreeList,
+ modifyTargetList,
+ junkFilter);
+}
+
+bool
+check_sql_fn_retval_ext(Oid func_id, Oid rettype, char prokind,
+ List *queryTreeList,
+ bool *modifyTargetList,
+ JunkFilter **junkFilter)
+{
Query *parse;
List **tlist_ptr;
List *tlist;
@@ -1608,7 +1623,7 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
/*
* If it's declared to return VOID, we don't care what's in the function.
- * (This takes care of the procedure case, as well.)
+ * (This takes care of procedures with no output parameters, as well.)
*/
if (rettype == VOIDOID)
return false;
@@ -1753,8 +1768,13 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
* 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.
+ *
+ * We must *not* do this for a procedure, however. Procedures with
+ * output parameter(s) have rettype RECORD, and the CALL code expects
+ * to get results corresponding to the list of output parameters, even
+ * when there's just one parameter that's composite.
*/
- if (tlistlen == 1)
+ if (tlistlen == 1 && prokind != PROKIND_PROCEDURE)
{
TargetEntry *tle = (TargetEntry *) linitial(tlist);
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 519dbd0dcbc..b2a7f6609a0 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -4624,8 +4624,9 @@ inline_function(Oid funcid, Oid result_type, Oid result_collid,
* Note: we do not try this until we have verified that no rewriting was
* needed; that's probably not important, but let's be careful.
*/
- if (check_sql_fn_retval(funcid, result_type, list_make1(querytree),
- &modifyTargetList, NULL))
+ if (check_sql_fn_retval_ext(funcid, result_type, funcform->prokind,
+ list_make1(querytree),
+ &modifyTargetList, NULL))
goto fail; /* reject whole-tuple-result cases */
/* Now we can grab the tlist expression */
@@ -5149,9 +5150,10 @@ inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte)
* check_sql_fn_retval, we deliberately exclude domains over composite
* here.)
*/
- if (!check_sql_fn_retval(func_oid, fexpr->funcresulttype,
- querytree_list,
- &modifyTargetList, NULL) &&
+ if (!check_sql_fn_retval_ext(func_oid, fexpr->funcresulttype,
+ funcform->prokind,
+ querytree_list,
+ &modifyTargetList, NULL) &&
(get_typtype(fexpr->funcresulttype) == TYPTYPE_COMPOSITE ||
fexpr->funcresulttype == RECORDOID))
goto fail; /* reject not-whole-tuple-result cases */
diff --git a/src/include/executor/functions.h b/src/include/executor/functions.h
index 99131bfadb4..24701bfb383 100644
--- a/src/include/executor/functions.h
+++ b/src/include/executor/functions.h
@@ -36,6 +36,12 @@ extern bool check_sql_fn_retval(Oid func_id, Oid rettype,
bool *modifyTargetList,
JunkFilter **junkFilter);
+extern bool check_sql_fn_retval_ext(Oid func_id, Oid rettype,
+ char prokind,
+ List *queryTreeList,
+ bool *modifyTargetList,
+ JunkFilter **junkFilter);
+
extern DestReceiver *CreateSQLFunctionDestReceiver(void);
#endif /* FUNCTIONS_H */
diff --git a/src/test/regress/expected/create_procedure.out b/src/test/regress/expected/create_procedure.out
index 211a42cefa0..13e3470f42f 100644
--- a/src/test/regress/expected/create_procedure.out
+++ b/src/test/regress/expected/create_procedure.out
@@ -106,7 +106,19 @@ CALL ptest4a(a, b); -- error, not supported
$$;
ERROR: calling procedures with output arguments is not supported in SQL functions
CONTEXT: SQL function "ptest4b"
-DROP PROCEDURE ptest4a;
+-- we used to get confused by a single output argument that is composite
+CREATE PROCEDURE ptest4c(INOUT comp int8_tbl)
+LANGUAGE SQL
+AS $$
+SELECT ROW(1, 2)::int8_tbl;
+$$;
+CALL ptest4c(NULL);
+ comp
+-------
+ (1,2)
+(1 row)
+
+DROP PROCEDURE ptest4a, ptest4c;
-- named and default parameters
CREATE OR REPLACE PROCEDURE ptest5(a int, b text, c int default 100)
LANGUAGE SQL
diff --git a/src/test/regress/sql/create_procedure.sql b/src/test/regress/sql/create_procedure.sql
index 89b96d580ff..74140903729 100644
--- a/src/test/regress/sql/create_procedure.sql
+++ b/src/test/regress/sql/create_procedure.sql
@@ -68,7 +68,16 @@ AS $$
CALL ptest4a(a, b); -- error, not supported
$$;
-DROP PROCEDURE ptest4a;
+-- we used to get confused by a single output argument that is composite
+CREATE PROCEDURE ptest4c(INOUT comp int8_tbl)
+LANGUAGE SQL
+AS $$
+SELECT ROW(1, 2)::int8_tbl;
+$$;
+
+CALL ptest4c(NULL);
+
+DROP PROCEDURE ptest4a, ptest4c;
-- named and default parameters