6868#include "utils/memutils.h"
6969#include "utils/rel.h"
7070#include "utils/syscache.h"
71+ #include "utils/typcache.h"
7172#include "utils/tqual.h"
7273
7374/*
@@ -281,10 +282,11 @@ interpret_function_parameter_list(ParseState *pstate,
281282
282283 if (objtype == OBJECT_PROCEDURE )
283284 {
284- if (fp -> mode == FUNC_PARAM_OUT || fp -> mode == FUNC_PARAM_INOUT )
285+ if (fp -> mode == FUNC_PARAM_OUT )
285286 ereport (ERROR ,
286287 (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
287- (errmsg ("procedures cannot have OUT parameters" ))));
288+ (errmsg ("procedures cannot have OUT arguments" ),
289+ errhint ("INOUT arguments are permitted." ))));
288290 }
289291
290292 /* handle input parameters */
@@ -302,7 +304,9 @@ interpret_function_parameter_list(ParseState *pstate,
302304 /* handle output parameters */
303305 if (fp -> mode != FUNC_PARAM_IN && fp -> mode != FUNC_PARAM_VARIADIC )
304306 {
305- if (outCount == 0 ) /* save first output param's type */
307+ if (objtype == OBJECT_PROCEDURE )
308+ * requiredResultType = RECORDOID ;
309+ else if (outCount == 0 ) /* save first output param's type */
306310 * requiredResultType = toid ;
307311 outCount ++ ;
308312 }
@@ -1003,12 +1007,8 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt)
10031007
10041008 if (stmt -> is_procedure )
10051009 {
1006- /*
1007- * Sometime in the future, procedures might be allowed to return
1008- * results; for now, they all return VOID.
1009- */
10101010 Assert (!stmt -> returnType );
1011- prorettype = VOIDOID ;
1011+ prorettype = requiredResultType ? requiredResultType : VOIDOID ;
10121012 returnsSet = false;
10131013 }
10141014 else if (stmt -> returnType )
@@ -2206,7 +2206,7 @@ ExecuteDoStmt(DoStmt *stmt, bool atomic)
22062206 * commits that might occur inside the procedure.
22072207 */
22082208void
2209- ExecuteCallStmt (CallStmt * stmt , ParamListInfo params , bool atomic )
2209+ ExecuteCallStmt (CallStmt * stmt , ParamListInfo params , bool atomic , DestReceiver * dest )
22102210{
22112211 ListCell * lc ;
22122212 FuncExpr * fexpr ;
@@ -2219,6 +2219,7 @@ ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic)
22192219 EState * estate ;
22202220 ExprContext * econtext ;
22212221 HeapTuple tp ;
2222+ Datum retval ;
22222223
22232224 fexpr = stmt -> funcexpr ;
22242225 Assert (fexpr );
@@ -2285,7 +2286,51 @@ ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic)
22852286 i ++ ;
22862287 }
22872288
2288- FunctionCallInvoke (& fcinfo );
2289+ retval = FunctionCallInvoke (& fcinfo );
2290+
2291+ if (fexpr -> funcresulttype == VOIDOID )
2292+ {
2293+ /* do nothing */
2294+ }
2295+ else if (fexpr -> funcresulttype == RECORDOID )
2296+ {
2297+ /*
2298+ * send tuple to client
2299+ */
2300+
2301+ HeapTupleHeader td ;
2302+ Oid tupType ;
2303+ int32 tupTypmod ;
2304+ TupleDesc retdesc ;
2305+ HeapTupleData rettupdata ;
2306+ TupOutputState * tstate ;
2307+ TupleTableSlot * slot ;
2308+
2309+ if (fcinfo .isnull )
2310+ elog (ERROR , "procedure returned null record" );
2311+
2312+ td = DatumGetHeapTupleHeader (retval );
2313+ tupType = HeapTupleHeaderGetTypeId (td );
2314+ tupTypmod = HeapTupleHeaderGetTypMod (td );
2315+ retdesc = lookup_rowtype_tupdesc (tupType , tupTypmod );
2316+
2317+ tstate = begin_tup_output_tupdesc (dest , retdesc );
2318+
2319+ rettupdata .t_len = HeapTupleHeaderGetDatumLength (td );
2320+ ItemPointerSetInvalid (& (rettupdata .t_self ));
2321+ rettupdata .t_tableOid = InvalidOid ;
2322+ rettupdata .t_data = td ;
2323+
2324+ slot = ExecStoreTuple (& rettupdata , tstate -> slot , InvalidBuffer , false);
2325+ tstate -> dest -> receiveSlot (slot , tstate -> dest );
2326+
2327+ end_tup_output (tstate );
2328+
2329+ ReleaseTupleDesc (retdesc );
2330+ }
2331+ else
2332+ elog (ERROR , "unexpected result type for procedure: %u" ,
2333+ fexpr -> funcresulttype );
22892334
22902335 FreeExecutorState (estate );
22912336}
0 commit comments