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
282283if (objtype == OBJECT_PROCEDURE )
283284{
284- if (fp -> mode == FUNC_PARAM_OUT || fp -> mode == FUNC_PARAM_INOUT )
285+ if (fp -> mode == FUNC_PARAM_OUT )
285286ereport (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 */
303305if (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 ;
307311outCount ++ ;
308312}
@@ -1003,12 +1007,8 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt)
10031007
10041008if (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- */
10101010Assert (!stmt -> returnType );
1011- prorettype = VOIDOID ;
1011+ prorettype = requiredResultType ? requiredResultType : VOIDOID ;
10121012returnsSet = false;
10131013}
10141014else 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{
22112211ListCell * lc ;
22122212FuncExpr * fexpr ;
@@ -2219,6 +2219,7 @@ ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic)
22192219EState * estate ;
22202220ExprContext * econtext ;
22212221HeapTuple tp ;
2222+ Datum retval ;
22222223
22232224fexpr = stmt -> funcexpr ;
22242225Assert (fexpr );
@@ -2285,7 +2286,51 @@ ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic)
22852286i ++ ;
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
22902335FreeExecutorState (estate );
22912336}