11/**********************************************************************
22 * plpython.c - python as a procedural language for PostgreSQL
33 *
4- * $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.77 2006/04/04 19:35:37 tgl Exp $
4+ * $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.78 2006/04/27 01:05:05 momjian Exp $
55 *
66 *********************************************************************
77 */
1919#include "catalog/pg_type.h"
2020#include "commands/trigger.h"
2121#include "executor/spi.h"
22+ #include "funcapi.h"
2223#include "fmgr.h"
2324#include "nodes/makefuncs.h"
2425#include "parser/parse_type.h"
@@ -108,6 +109,11 @@ typedef struct PLyProcedure
108109 bool fn_readonly ;
109110 PLyTypeInfo result ; /* also used to store info for trigger tuple
110111 * type */
112+ bool is_setof ; /* true, if procedure returns result set */
113+ PyObject * setof ; /* contents of result set. */
114+ int setof_count ; /* numbef of items to return in result set */
115+ int setof_current ; /* current item in result set */
116+ char * * argnames ; /* Argument names */
111117 PLyTypeInfo args [FUNC_MAX_ARGS ];
112118 int nargs ;
113119 PyObject * code ; /* compiled procedure code */
@@ -184,6 +190,7 @@ static Datum PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure *);
184190static HeapTuple PLy_trigger_handler (FunctionCallInfo fcinfo , PLyProcedure * );
185191
186192static PyObject * PLy_function_build_args (FunctionCallInfo fcinfo , PLyProcedure * );
193+ static void PLy_function_delete_args (PLyProcedure * );
187194static PyObject * PLy_trigger_build_args (FunctionCallInfo fcinfo , PLyProcedure * ,
188195 HeapTuple * );
189196static HeapTuple PLy_modify_tuple (PLyProcedure * , PyObject * ,
@@ -218,6 +225,7 @@ static PyObject *PLyFloat_FromString(const char *);
218225static PyObject * PLyInt_FromString (const char * );
219226static PyObject * PLyLong_FromString (const char * );
220227static PyObject * PLyString_FromString (const char * );
228+ static HeapTuple PLyDict_ToTuple (PLyTypeInfo * , PyObject * );
221229
222230
223231/* global data */
@@ -726,11 +734,17 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure * proc)
726734
727735 PG_TRY ();
728736 {
729- plargs = PLy_function_build_args (fcinfo , proc );
730- plrv = PLy_procedure_call (proc , "args" , plargs );
731-
732- Assert (plrv != NULL );
733- Assert (!PLy_error_in_progress );
737+ if (!proc -> is_setof || proc -> setof_count == -1 )
738+ {
739+ /* python function not called yet, do it */
740+ plargs = PLy_function_build_args (fcinfo , proc );
741+ plrv = PLy_procedure_call (proc , "args" , plargs );
742+ if (!proc -> is_setof )
743+ /* SETOF function parameters are deleted when called last row is returned */
744+ PLy_function_delete_args (proc );
745+ Assert (plrv != NULL );
746+ Assert (!PLy_error_in_progress );
747+ }
734748
735749 /*
736750 * Disconnect from SPI manager and then create the return values datum
@@ -741,6 +755,76 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure * proc)
741755 if (SPI_finish () != SPI_OK_FINISH )
742756 elog (ERROR , "SPI_finish failed" );
743757
758+ if (proc -> is_setof )
759+ {
760+ bool is_done = false;
761+ ReturnSetInfo * rsi = (ReturnSetInfo * )fcinfo -> resultinfo ;
762+
763+ if (proc -> setof_current == -1 )
764+ {
765+ /* first time -- do checks and setup */
766+ if (!rsi || !IsA (rsi , ReturnSetInfo ) ||
767+ (rsi -> allowedModes & SFRM_ValuePerCall ) == 0 )
768+ {
769+ ereport (ERROR ,
770+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
771+ errmsg ("only value per call is allowed" )));
772+ }
773+ rsi -> returnMode = SFRM_ValuePerCall ;
774+
775+ /* fetch information about returned object */
776+ proc -> setof = plrv ;
777+ plrv = NULL ;
778+ if (PyList_Check (proc -> setof ))
779+ /* SETOF as list */
780+ proc -> setof_count = PyList_GET_SIZE (proc -> setof );
781+ else if (PyIter_Check (proc -> setof ))
782+ /* SETOF as iterator, unknown number of items */
783+ proc -> setof_current = proc -> setof_count = 0 ;
784+ else
785+ {
786+ ereport (ERROR ,
787+ (errcode (ERRCODE_INVALID_BINARY_REPRESENTATION ),
788+ errmsg ("SETOF must be returned as list or iterator" )));
789+ }
790+ }
791+
792+ Assert (proc -> setof != NULL );
793+
794+ /* Fetch next of SETOF */
795+ if (PyList_Check (proc -> setof ))
796+ {
797+ is_done = ++ proc -> setof_current == proc -> setof_count ;
798+ if (!is_done )
799+ plrv = PyList_GET_ITEM (proc -> setof , proc -> setof_current );
800+ }
801+ else if (PyIter_Check (proc -> setof ))
802+ {
803+ plrv = PyIter_Next (proc -> setof );
804+ is_done = plrv == NULL ;
805+ }
806+
807+ if (!is_done )
808+ {
809+ rsi -> isDone = ExprMultipleResult ;
810+ }
811+ else
812+ {
813+ rsi -> isDone = ExprEndResult ;
814+ proc -> setof_count = proc -> setof_current = -1 ;
815+ Py_DECREF (proc -> setof );
816+ proc -> setof = NULL ;
817+
818+ Py_XDECREF (plargs );
819+ Py_XDECREF (plrv );
820+ Py_XDECREF (plrv_so );
821+
822+ PLy_function_delete_args (proc );
823+ fcinfo -> isnull = true;
824+ return (Datum )NULL ;
825+ }
826+ }
827+
744828 /*
745829 * If the function is declared to return void, the Python
746830 * return value must be None. For void-returning functions, we
@@ -767,6 +851,26 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure * proc)
767851 proc -> result .out .d .typioparam ,
768852 -1 );
769853 }
854+ else if (proc -> result .is_rowtype >= 1 )
855+ {
856+ HeapTuple tuple ;
857+
858+ /* returning composite type */
859+ if (!PyDict_Check (plrv ))
860+ elog (ERROR , "tuple must be returned as dictionary" );
861+
862+ tuple = PLyDict_ToTuple (& proc -> result , plrv );
863+ if (tuple != NULL )
864+ {
865+ fcinfo -> isnull = false;
866+ rv = HeapTupleGetDatum (tuple );
867+ }
868+ else
869+ {
870+ fcinfo -> isnull = true;
871+ rv = (Datum ) NULL ;
872+ }
873+ }
770874 else
771875 {
772876 fcinfo -> isnull = false;
@@ -893,6 +997,7 @@ PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure * proc)
893997 * FIXME -- error check this
894998 */
895999 PyList_SetItem (args , i , arg );
1000+ PyDict_SetItemString (proc -> globals , proc -> argnames [i ], arg );
8961001 arg = NULL ;
8971002 }
8981003 }
@@ -909,6 +1014,16 @@ PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure * proc)
9091014}
9101015
9111016
1017+ static void
1018+ PLy_function_delete_args (PLyProcedure * proc )
1019+ {
1020+ int i ;
1021+
1022+ for (i = 0 ; i < proc -> nargs ; i ++ )
1023+ PyDict_DelItemString (proc -> globals , proc -> argnames [i ]);
1024+ }
1025+
1026+
9121027/*
9131028 * PLyProcedure functions
9141029 */
@@ -979,6 +1094,9 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
9791094 bool isnull ;
9801095 int i ,
9811096 rv ;
1097+ Datum argnames ;
1098+ Datum * elems ;
1099+ int nelems ;
9821100
9831101 procStruct = (Form_pg_proc ) GETSTRUCT (procTup );
9841102
@@ -1010,6 +1128,10 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
10101128 proc -> nargs = 0 ;
10111129 proc -> code = proc -> statics = NULL ;
10121130 proc -> globals = proc -> me = NULL ;
1131+ proc -> is_setof = procStruct -> proretset ;
1132+ proc -> setof = NULL ;
1133+ proc -> setof_count = proc -> setof_current = -1 ;
1134+ proc -> argnames = NULL ;
10131135
10141136 PG_TRY ();
10151137 {
@@ -1046,9 +1168,11 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
10461168 }
10471169
10481170 if (rvTypeStruct -> typtype == 'c' )
1049- ereport (ERROR ,
1050- (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
1051- errmsg ("plpython functions cannot return tuples yet" )));
1171+ {
1172+ /* Tuple: set up later, during first call to PLy_function_handler */
1173+ proc -> result .out .d .typoid = procStruct -> prorettype ;
1174+ proc -> result .is_rowtype = 2 ;
1175+ }
10521176 else
10531177 PLy_output_datum_func (& proc -> result , rvTypeTup );
10541178
@@ -1071,6 +1195,21 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
10711195 * arguments.
10721196 */
10731197 proc -> nargs = fcinfo -> nargs ;
1198+ proc -> argnames = NULL ;
1199+ if (proc -> nargs )
1200+ {
1201+ argnames = SysCacheGetAttr (PROCOID , procTup , Anum_pg_proc_proargnames , & isnull );
1202+ if (!isnull )
1203+ {
1204+ deconstruct_array (DatumGetArrayTypeP (argnames ), TEXTOID , -1 , false, 'i' ,
1205+ & elems , NULL , & nelems );
1206+ if (nelems != proc -> nargs )
1207+ elog (ERROR ,
1208+ "proargnames must have the same number of elements "
1209+ "as the function has arguments" );
1210+ proc -> argnames = (char * * ) PLy_malloc (sizeof (char * )* proc -> nargs );
1211+ }
1212+ }
10741213 for (i = 0 ; i < fcinfo -> nargs ; i ++ )
10751214 {
10761215 HeapTuple argTypeTup ;
@@ -1099,8 +1238,11 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
10991238 proc -> args [i ].is_rowtype = 2 ; /* still need to set I/O funcs */
11001239
11011240 ReleaseSysCache (argTypeTup );
1102- }
11031241
1242+ /* Fetch argument name */
1243+ if (proc -> argnames )
1244+ proc -> argnames [i ] = PLy_strdup (DatumGetCString (DirectFunctionCall1 (textout , elems [i ])));
1245+ }
11041246
11051247 /*
11061248 * get the text of the function.
@@ -1236,13 +1378,19 @@ PLy_procedure_delete(PLyProcedure * proc)
12361378 if (proc -> pyname )
12371379 PLy_free (proc -> pyname );
12381380 for (i = 0 ; i < proc -> nargs ; i ++ )
1381+ {
12391382 if (proc -> args [i ].is_rowtype == 1 )
12401383 {
12411384 if (proc -> args [i ].in .r .atts )
12421385 PLy_free (proc -> args [i ].in .r .atts );
12431386 if (proc -> args [i ].out .r .atts )
12441387 PLy_free (proc -> args [i ].out .r .atts );
12451388 }
1389+ if (proc -> argnames && proc -> argnames [i ])
1390+ PLy_free (proc -> argnames [i ]);
1391+ }
1392+ if (proc -> argnames )
1393+ PLy_free (proc -> argnames );
12461394}
12471395
12481396/* conversion functions. remember output from python is
@@ -1501,6 +1649,78 @@ PLyDict_FromTuple(PLyTypeInfo * info, HeapTuple tuple, TupleDesc desc)
15011649 return dict ;
15021650}
15031651
1652+
1653+ static HeapTuple
1654+ PLyDict_ToTuple (PLyTypeInfo * info , PyObject * dict )
1655+ {
1656+ TupleDesc desc ;
1657+ HeapTuple tuple ;
1658+ Datum * values ;
1659+ char * nulls ;
1660+ int i ;
1661+
1662+ desc = CreateTupleDescCopy (lookup_rowtype_tupdesc (info -> out .d .typoid , -1 ));
1663+
1664+ /* Set up tuple type, if neccessary */
1665+ if (info -> is_rowtype == 2 )
1666+ {
1667+ PLy_output_tuple_funcs (info , desc );
1668+ info -> is_rowtype = 1 ;
1669+ }
1670+ Assert (info -> is_rowtype == 1 );
1671+
1672+ /* Build tuple */
1673+ values = palloc (sizeof (Datum )* desc -> natts );
1674+ nulls = palloc (sizeof (char )* desc -> natts );
1675+ for (i = 0 ; i < desc -> natts ; ++ i )
1676+ {
1677+ char * key ;
1678+ PyObject * value ,
1679+ * so ;
1680+
1681+ key = NameStr (desc -> attrs [i ]-> attname );
1682+ value = so = NULL ;
1683+ PG_TRY ();
1684+ {
1685+ value = PyDict_GetItemString (dict , key );
1686+ if (value != Py_None && value != NULL )
1687+ {
1688+ char * valuestr ;
1689+
1690+ so = PyObject_Str (value );
1691+ valuestr = PyString_AsString (so );
1692+ values [i ] = InputFunctionCall (& info -> out .r .atts [i ].typfunc
1693+ , valuestr
1694+ , info -> out .r .atts [i ].typioparam
1695+ , -1 );
1696+ Py_DECREF (so );
1697+ value = so = NULL ;
1698+ nulls [i ] = ' ' ;
1699+ }
1700+ else
1701+ {
1702+ value = NULL ;
1703+ values [i ] = (Datum ) NULL ;
1704+ nulls [i ] = 'n' ;
1705+ }
1706+ }
1707+ PG_CATCH ();
1708+ {
1709+ Py_XDECREF (value );
1710+ Py_XDECREF (so );
1711+ PG_RE_THROW ();
1712+ }
1713+ PG_END_TRY ();
1714+ }
1715+
1716+ tuple = heap_formtuple (desc , values , nulls );
1717+ FreeTupleDesc (desc );
1718+ pfree (values );
1719+ pfree (nulls );
1720+
1721+ return tuple ;
1722+ }
1723+
15041724/* initialization, some python variables function declared here */
15051725
15061726/* interface to postgresql elog */
@@ -2644,3 +2864,4 @@ PLy_free(void *ptr)
26442864{
26452865 free (ptr );
26462866}
2867+ /* vim: set noexpandtab nosmarttab shiftwidth=8 cinoptions=l1j1: */
0 commit comments