(void) get_func_result_type(funcoid, &rettype, &rettupdesc);
- (void) check_sql_fn_retval(querytree_list,
- rettype, rettupdesc,
- false, NULL);
+ (void) check_sql_fn_retval_ext(querytree_list,
+ rettype, rettupdesc,
+ proc->prokind,
+ false, NULL);
}
error_context_stack = sqlerrcontext.previous;
* the rowtype column into multiple columns, since we have no way to
* notify the caller that it should do that.)
*/
- fcache->returnsTuple = check_sql_fn_retval(queryTree_list,
- rettype,
- rettupdesc,
- false,
- &resulttlist);
+ fcache->returnsTuple = check_sql_fn_retval_ext(queryTree_list,
+ rettype,
+ rettupdesc,
+ procedureStruct->prokind,
+ false,
+ &resulttlist);
/*
* Construct a JunkFilter we can use to coerce the returned rowtype to the
Oid rettype, TupleDesc rettupdesc,
bool insertDroppedCols,
List **resultTargetList)
+{
+ /* Wrapper function to preserve ABI compatibility in released branches */
+ return check_sql_fn_retval_ext(queryTreeLists,
+ rettype, rettupdesc,
+ PROKIND_FUNCTION,
+ insertDroppedCols,
+ resultTargetList);
+}
+
+bool
+check_sql_fn_retval_ext(List *queryTreeLists,
+ Oid rettype, TupleDesc rettupdesc,
+ char prokind,
+ bool insertDroppedCols,
+ List **resultTargetList)
{
bool is_tuple_result = false;
Query *parse;
/*
* 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;
* or not the record type really matches. 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);
* needed; that's probably not important, but let's be careful.
*/
querytree_list = list_make1(querytree);
- if (check_sql_fn_retval(list_make1(querytree_list),
- result_type, rettupdesc,
- false, NULL))
+ if (check_sql_fn_retval_ext(list_make1(querytree_list),
+ result_type, rettupdesc,
+ funcform->prokind,
+ false, NULL))
goto fail; /* reject whole-tuple-result cases */
/*
* shows it's returning a whole tuple result; otherwise what it's
* returning is a single composite column which is not what we need.
*/
- if (!check_sql_fn_retval(list_make1(querytree_list),
- fexpr->funcresulttype, rettupdesc,
- true, NULL) &&
+ if (!check_sql_fn_retval_ext(list_make1(querytree_list),
+ fexpr->funcresulttype, rettupdesc,
+ funcform->prokind,
+ true, NULL) &&
(functypclass == TYPEFUNC_COMPOSITE ||
functypclass == TYPEFUNC_COMPOSITE_DOMAIN ||
functypclass == TYPEFUNC_RECORD))
bool insertDroppedCols,
List **resultTargetList);
+extern bool check_sql_fn_retval_ext(List *queryTreeLists,
+ Oid rettype, TupleDesc rettupdesc,
+ char prokind,
+ bool insertDroppedCols,
+ List **resultTargetList);
+
extern DestReceiver *CreateSQLFunctionDestReceiver(void);
#endif /* FUNCTIONS_H */
$$;
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);
+$$;
+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
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);
+$$;
+
+CALL ptest4c(NULL);
+
+DROP PROCEDURE ptest4a, ptest4c;
-- named and default parameters