11/**********************************************************************
22 * plpython.c - python as a procedural language for PostgreSQL
33 *
4- *$PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.132 2009/11/03 11:05:02 petere Exp $
4+ *$PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.133 2009/12/10 20:43:40 petere Exp $
55 *
66 *********************************************************************
77 */
@@ -89,6 +89,9 @@ typedef struct PLyDatumToOb
8989Oid typoid ;/* The OID of the type */
9090Oid typioparam ;
9191bool typbyval ;
92+ int16 typlen ;
93+ char typalign ;
94+ struct PLyDatumToOb * elm ;
9295}PLyDatumToOb ;
9396
9497typedef struct PLyTupleToOb
@@ -120,6 +123,9 @@ typedef struct PLyObToDatum
120123Oid typoid ;/* The OID of the type */
121124Oid typioparam ;
122125bool typbyval ;
126+ int16 typlen ;
127+ char typalign ;
128+ struct PLyObToDatum * elm ;
123129}PLyObToDatum ;
124130
125131typedef struct PLyObToTuple
@@ -284,6 +290,7 @@ static PyObject *PLyInt_FromInt32(PLyDatumToOb *arg, Datum d);
284290static PyObject * PLyLong_FromInt64 (PLyDatumToOb * arg ,Datum d );
285291static PyObject * PLyString_FromBytea (PLyDatumToOb * arg ,Datum d );
286292static PyObject * PLyString_FromDatum (PLyDatumToOb * arg ,Datum d );
293+ static PyObject * PLyList_FromArray (PLyDatumToOb * arg ,Datum d );
287294
288295static PyObject * PLyDict_FromTuple (PLyTypeInfo * ,HeapTuple ,TupleDesc );
289296
@@ -293,6 +300,8 @@ static Datum PLyObject_ToBytea(PLyTypeInfo *, PLyObToDatum *,
293300PyObject * );
294301static Datum PLyObject_ToDatum (PLyTypeInfo * ,PLyObToDatum * ,
295302PyObject * );
303+ static Datum PLySequence_ToArray (PLyTypeInfo * ,PLyObToDatum * ,
304+ PyObject * );
296305
297306static HeapTuple PLyMapping_ToTuple (PLyTypeInfo * ,PyObject * );
298307static HeapTuple PLySequence_ToTuple (PLyTypeInfo * ,PyObject * );
@@ -1653,18 +1662,21 @@ static void
16531662PLy_output_datum_func2 (PLyObToDatum * arg ,HeapTuple typeTup )
16541663{
16551664Form_pg_type typeStruct = (Form_pg_type )GETSTRUCT (typeTup );
1665+ Oid element_type ;
16561666
16571667perm_fmgr_info (typeStruct -> typinput ,& arg -> typfunc );
16581668arg -> typoid = HeapTupleGetOid (typeTup );
16591669arg -> typioparam = getTypeIOParam (typeTup );
16601670arg -> typbyval = typeStruct -> typbyval ;
16611671
1672+ element_type = get_element_type (arg -> typoid );
1673+
16621674/*
16631675 * Select a conversion function to convert Python objects to
16641676 * PostgreSQL datums. Most data types can go through the generic
16651677 * function.
16661678 */
1667- switch (getBaseType (arg -> typoid ))
1679+ switch (getBaseType (element_type ? element_type : arg -> typoid ))
16681680{
16691681case BOOLOID :
16701682arg -> func = PLyObject_ToBool ;
@@ -1676,6 +1688,29 @@ PLy_output_datum_func2(PLyObToDatum *arg, HeapTuple typeTup)
16761688arg -> func = PLyObject_ToDatum ;
16771689break ;
16781690}
1691+
1692+ if (element_type )
1693+ {
1694+ char dummy_delim ;
1695+ Oid funcid ;
1696+
1697+ if (type_is_rowtype (element_type ))
1698+ ereport (ERROR ,
1699+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
1700+ errmsg ("PL/Python functions cannot return type %s" ,
1701+ format_type_be (arg -> typoid )),
1702+ errdetail ("PL/Python does not support conversion to arrays of row types." )));
1703+
1704+ arg -> elm = PLy_malloc0 (sizeof (* arg -> elm ));
1705+ arg -> elm -> func = arg -> func ;
1706+ arg -> func = PLySequence_ToArray ;
1707+
1708+ arg -> elm -> typoid = element_type ;
1709+ get_type_io_data (element_type ,IOFunc_input ,
1710+ & arg -> elm -> typlen ,& arg -> elm -> typbyval ,& arg -> elm -> typalign ,& dummy_delim ,
1711+ & arg -> elm -> typioparam ,& funcid );
1712+ perm_fmgr_info (funcid ,& arg -> elm -> typfunc );
1713+ }
16791714}
16801715
16811716static void
@@ -1691,15 +1726,17 @@ static void
16911726PLy_input_datum_func2 (PLyDatumToOb * arg ,Oid typeOid ,HeapTuple typeTup )
16921727{
16931728Form_pg_type typeStruct = (Form_pg_type )GETSTRUCT (typeTup );
1729+ Oid element_type = get_element_type (typeOid );
16941730
16951731/* Get the type's conversion information */
16961732perm_fmgr_info (typeStruct -> typoutput ,& arg -> typfunc );
16971733arg -> typoid = HeapTupleGetOid (typeTup );
16981734arg -> typioparam = getTypeIOParam (typeTup );
16991735arg -> typbyval = typeStruct -> typbyval ;
1736+ arg -> typlen = typeStruct -> typlen ;
17001737
17011738/* Determine which kind of Python object we will convert to */
1702- switch (getBaseType (typeOid ))
1739+ switch (getBaseType (element_type ? element_type : typeOid ))
17031740{
17041741case BOOLOID :
17051742arg -> func = PLyBool_FromBool ;
@@ -1729,6 +1766,14 @@ PLy_input_datum_func2(PLyDatumToOb *arg, Oid typeOid, HeapTuple typeTup)
17291766arg -> func = PLyString_FromDatum ;
17301767break ;
17311768}
1769+
1770+ if (element_type )
1771+ {
1772+ arg -> elm = PLy_malloc0 (sizeof (* arg -> elm ));
1773+ arg -> elm -> func = arg -> func ;
1774+ arg -> func = PLyList_FromArray ;
1775+ get_typlenbyvalalign (element_type ,& arg -> elm -> typlen ,& arg -> elm -> typbyval ,& arg -> elm -> typalign );
1776+ }
17321777}
17331778
17341779static void
@@ -1832,6 +1877,45 @@ PLyString_FromDatum(PLyDatumToOb *arg, Datum d)
18321877return r ;
18331878}
18341879
1880+ static PyObject *
1881+ PLyList_FromArray (PLyDatumToOb * arg ,Datum d )
1882+ {
1883+ ArrayType * array = DatumGetArrayTypeP (d );
1884+ PyObject * list ;
1885+ int length ;
1886+ int lbound ;
1887+ int i ;
1888+
1889+ if (ARR_NDIM (array )== 0 )
1890+ return PyList_New (0 );
1891+
1892+ if (ARR_NDIM (array )!= 1 )
1893+ ereport (ERROR ,
1894+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
1895+ errmsg ("cannot convert multidimensional array to Python list" ),
1896+ errdetail ("PL/Python only supports one-dimensional arrays." )));
1897+
1898+ length = ARR_DIMS (array )[0 ];
1899+ lbound = ARR_LBOUND (array )[0 ];
1900+ list = PyList_New (length );
1901+
1902+ for (i = 0 ;i < length ;i ++ )
1903+ {
1904+ Datum elem ;
1905+ bool isnull ;
1906+ int offset ;
1907+
1908+ offset = lbound + i ;
1909+ elem = array_ref (array ,1 ,& offset ,arg -> typlen ,arg -> elm -> typlen ,arg -> elm -> typbyval ,arg -> elm -> typalign ,& isnull );
1910+ if (isnull )
1911+ PyList_SET_ITEM (list ,i ,Py_None );
1912+ else
1913+ PyList_SET_ITEM (list ,i ,arg -> elm -> func (arg ,elem ));
1914+ }
1915+
1916+ return list ;
1917+ }
1918+
18351919static PyObject *
18361920PLyDict_FromTuple (PLyTypeInfo * info ,HeapTuple tuple ,TupleDesc desc )
18371921{
@@ -1994,6 +2078,49 @@ PLyObject_ToDatum(PLyTypeInfo *info,
19942078return rv ;
19952079}
19962080
2081+ static Datum
2082+ PLySequence_ToArray (PLyTypeInfo * info ,
2083+ PLyObToDatum * arg ,
2084+ PyObject * plrv )
2085+ {
2086+ ArrayType * array ;
2087+ int i ;
2088+ Datum * elems ;
2089+ bool * nulls ;
2090+ int len ;
2091+ int lbs ;
2092+
2093+ Assert (plrv != Py_None );
2094+
2095+ if (!PySequence_Check (plrv ))
2096+ PLy_elog (ERROR ,"return value of function with array return type is not a Python sequence" );
2097+
2098+ len = PySequence_Length (plrv );
2099+ elems = palloc (sizeof (* elems )* len );
2100+ nulls = palloc (sizeof (* nulls )* len );
2101+
2102+ for (i = 0 ;i < len ;i ++ )
2103+ {
2104+ PyObject * obj = PySequence_GetItem (plrv ,i );
2105+
2106+ if (obj == Py_None )
2107+ nulls [i ]= true;
2108+ else
2109+ {
2110+ nulls [i ]= false;
2111+ /* We don't support arrays of row types yet, so the first
2112+ * argument can be NULL. */
2113+ elems [i ]= arg -> elm -> func (NULL ,arg -> elm ,obj );
2114+ }
2115+ Py_XDECREF (obj );
2116+ }
2117+
2118+ lbs = 1 ;
2119+ array = construct_md_array (elems ,nulls ,1 ,& len ,& lbs ,
2120+ get_element_type (arg -> typoid ),arg -> elm -> typlen ,arg -> elm -> typbyval ,arg -> elm -> typalign );
2121+ return PointerGetDatum (array );
2122+ }
2123+
19972124static HeapTuple
19982125PLyMapping_ToTuple (PLyTypeInfo * info ,PyObject * mapping )
19992126{