Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit1a84275

Browse files
committed
plpython improvements:
1) named parameters additionally to args[]2) return composite-types from plpython as dictionary3) return result-set from plpython as list, iterator or generatorHannu KrosingSven Suursoho
1 parentf66a3ca commit1a84275

File tree

1 file changed

+231
-10
lines changed

1 file changed

+231
-10
lines changed

‎src/pl/plpython/plpython.c

Lines changed: 231 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
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
*/
@@ -19,6 +19,7 @@
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
boolfn_readonly;
109110
PLyTypeInforesult;/* also used to store info for trigger tuple
110111
* type */
112+
boolis_setof;/* true, if procedure returns result set */
113+
PyObject*setof;/* contents of result set. */
114+
intsetof_count;/* numbef of items to return in result set */
115+
intsetof_current;/* current item in result set */
116+
char**argnames;/* Argument names */
111117
PLyTypeInfoargs[FUNC_MAX_ARGS];
112118
intnargs;
113119
PyObject*code;/* compiled procedure code */
@@ -184,6 +190,7 @@ static Datum PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure *);
184190
staticHeapTuplePLy_trigger_handler(FunctionCallInfofcinfo,PLyProcedure*);
185191

186192
staticPyObject*PLy_function_build_args(FunctionCallInfofcinfo,PLyProcedure*);
193+
staticvoidPLy_function_delete_args(PLyProcedure*);
187194
staticPyObject*PLy_trigger_build_args(FunctionCallInfofcinfo,PLyProcedure*,
188195
HeapTuple*);
189196
staticHeapTuplePLy_modify_tuple(PLyProcedure*,PyObject*,
@@ -218,6 +225,7 @@ static PyObject *PLyFloat_FromString(const char *);
218225
staticPyObject*PLyInt_FromString(constchar*);
219226
staticPyObject*PLyLong_FromString(constchar*);
220227
staticPyObject*PLyString_FromString(constchar*);
228+
staticHeapTuplePLyDict_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+
boolis_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+
elseif (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+
elseif (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+
elseif (proc->result.is_rowtype >=1)
855+
{
856+
HeapTupletuple;
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+
staticvoid
1018+
PLy_function_delete_args(PLyProcedure*proc)
1019+
{
1020+
inti;
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
boolisnull;
9801095
inti,
9811096
rv;
1097+
Datumargnames;
1098+
Datum*elems;
1099+
intnelems;
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
HeapTupleargTypeTup;
@@ -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
returndict;
15021650
}
15031651

1652+
1653+
staticHeapTuple
1654+
PLyDict_ToTuple(PLyTypeInfo*info,PyObject*dict)
1655+
{
1656+
TupleDescdesc;
1657+
HeapTupletuple;
1658+
Datum*values;
1659+
char*nulls;
1660+
inti;
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+
returntuple;
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

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp