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
108109bool fn_readonly ;
109110PLyTypeInfo 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 */
111117PLyTypeInfo args [FUNC_MAX_ARGS ];
112118int nargs ;
113119PyObject * 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 * ,
188195HeapTuple * );
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
727735PG_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)
741755if (SPI_finish ()!= SPI_OK_FINISH )
742756elog (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)
767851proc -> 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+ }
770874else
771875{
772876fcinfo -> isnull = false;
@@ -893,6 +997,7 @@ PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure * proc)
893997 * FIXME -- error check this
894998 */
895999PyList_SetItem (args ,i ,arg );
1000+ PyDict_SetItemString (proc -> globals ,proc -> argnames [i ],arg );
8961001arg = 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,
9791094bool isnull ;
9801095int i ,
9811096rv ;
1097+ Datum argnames ;
1098+ Datum * elems ;
1099+ int nelems ;
9821100
9831101procStruct = (Form_pg_proc )GETSTRUCT (procTup );
9841102
@@ -1010,6 +1128,10 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
10101128proc -> nargs = 0 ;
10111129proc -> code = proc -> statics = NULL ;
10121130proc -> 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
10141136PG_TRY ();
10151137{
@@ -1046,9 +1168,11 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
10461168}
10471169
10481170if (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+ }
10521176else
10531177PLy_output_datum_func (& proc -> result ,rvTypeTup );
10541178
@@ -1071,6 +1195,21 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
10711195 * arguments.
10721196 */
10731197proc -> 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+ }
10741213for (i = 0 ;i < fcinfo -> nargs ;i ++ )
10751214{
10761215HeapTuple argTypeTup ;
@@ -1099,8 +1238,11 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
10991238proc -> args [i ].is_rowtype = 2 ;/* still need to set I/O funcs */
11001239
11011240ReleaseSysCache (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)
12361378if (proc -> pyname )
12371379PLy_free (proc -> pyname );
12381380for (i = 0 ;i < proc -> nargs ;i ++ )
1381+ {
12391382if (proc -> args [i ].is_rowtype == 1 )
12401383{
12411384if (proc -> args [i ].in .r .atts )
12421385PLy_free (proc -> args [i ].in .r .atts );
12431386if (proc -> args [i ].out .r .atts )
12441387PLy_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)
15011649return 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{
26452865free (ptr );
26462866}
2867+ /* vim: set noexpandtab nosmarttab shiftwidth=8 cinoptions=l1j1: */