11/**********************************************************************
22 * plpython.c - python as a procedural language for PostgreSQL
33 *
4- *$PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.105 2007/11/23 01:46:34 alvherre Exp $
4+ *$PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.106 2008/01/02 03:10:27 tgl Exp $
55 *
66 *********************************************************************
77 */
@@ -79,7 +79,8 @@ typedef PyObject *(*PLyDatumToObFunc) (const char *);
7979typedef struct PLyDatumToOb
8080{
8181PLyDatumToObFunc func ;
82- FmgrInfo typfunc ;
82+ FmgrInfo typfunc ;/* The type's output function */
83+ Oid typoid ;/* The OID of the type */
8384Oid typioparam ;
8485bool typbyval ;
8586}PLyDatumToOb ;
@@ -212,6 +213,7 @@ static void PLy_elog(int, const char *,...);
212213static char * PLy_traceback (int * );
213214
214215static void * PLy_malloc (size_t );
216+ static void * PLy_malloc0 (size_t );
215217static char * PLy_strdup (const char * );
216218static void PLy_free (void * );
217219
@@ -231,9 +233,8 @@ static PyObject *PLy_procedure_call(PLyProcedure *, char *, PyObject *);
231233static PLyProcedure * PLy_procedure_get (FunctionCallInfo fcinfo ,
232234Oid tgreloid );
233235
234- static PLyProcedure * PLy_procedure_create (FunctionCallInfo fcinfo ,
235- Oid tgreloid ,
236- HeapTuple procTup ,char * key );
236+ static PLyProcedure * PLy_procedure_create (HeapTuple procTup ,Oid tgreloid ,
237+ char * key );
237238
238239static void PLy_procedure_compile (PLyProcedure * ,const char * );
239240static char * PLy_procedure_munge_source (const char * ,const char * );
@@ -1123,16 +1124,32 @@ PLy_procedure_get(FunctionCallInfo fcinfo, Oid tgreloid)
11231124}
11241125
11251126if (proc == NULL )
1126- proc = PLy_procedure_create (fcinfo ,tgreloid ,procTup ,key );
1127+ proc = PLy_procedure_create (procTup ,tgreloid ,key );
1128+
1129+ if (OidIsValid (tgreloid ))
1130+ {
1131+ /*
1132+ * Input/output conversion for trigger tuples.Use the result
1133+ * TypeInfo variable to store the tuple conversion info. We
1134+ * do this over again on each call to cover the possibility that
1135+ * the relation's tupdesc changed since the trigger was last called.
1136+ * PLy_input_tuple_funcs and PLy_output_tuple_funcs are responsible
1137+ * for not doing repetitive work.
1138+ */
1139+ TriggerData * tdata = (TriggerData * )fcinfo -> context ;
1140+
1141+ Assert (CALLED_AS_TRIGGER (fcinfo ));
1142+ PLy_input_tuple_funcs (& (proc -> result ),tdata -> tg_relation -> rd_att );
1143+ PLy_output_tuple_funcs (& (proc -> result ),tdata -> tg_relation -> rd_att );
1144+ }
11271145
11281146ReleaseSysCache (procTup );
11291147
11301148return proc ;
11311149}
11321150
11331151static PLyProcedure *
1134- PLy_procedure_create (FunctionCallInfo fcinfo ,Oid tgreloid ,
1135- HeapTuple procTup ,char * key )
1152+ PLy_procedure_create (HeapTuple procTup ,Oid tgreloid ,char * key )
11361153{
11371154char procName [NAMEDATALEN + 256 ];
11381155Form_pg_proc procStruct ;
@@ -1152,13 +1169,13 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
11521169rv = snprintf (procName ,sizeof (procName ),
11531170"__plpython_procedure_%s_%u_trigger_%u" ,
11541171NameStr (procStruct -> proname ),
1155- fcinfo -> flinfo -> fn_oid ,
1172+ HeapTupleGetOid ( procTup ) ,
11561173tgreloid );
11571174else
11581175rv = snprintf (procName ,sizeof (procName ),
11591176"__plpython_procedure_%s_%u" ,
11601177NameStr (procStruct -> proname ),
1161- fcinfo -> flinfo -> fn_oid );
1178+ HeapTupleGetOid ( procTup ) );
11621179if (rv >=sizeof (procName )|| rv < 0 )
11631180elog (ERROR ,"procedure name would overrun buffer" );
11641181
@@ -1186,7 +1203,7 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
11861203 * get information required for output conversion of the return value,
11871204 * but only if this isn't a trigger.
11881205 */
1189- if (!CALLED_AS_TRIGGER ( fcinfo ))
1206+ if (!OidIsValid ( tgreloid ))
11901207{
11911208HeapTuple rvTypeTup ;
11921209Form_pg_type rvTypeStruct ;
@@ -1228,28 +1245,18 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
12281245
12291246ReleaseSysCache (rvTypeTup );
12301247}
1231- else
1232- {
1233- /*
1234- * input/output conversion for trigger tuples.use the result
1235- * TypeInfo variable to store the tuple conversion info.
1236- */
1237- TriggerData * tdata = (TriggerData * )fcinfo -> context ;
1238-
1239- PLy_input_tuple_funcs (& (proc -> result ),tdata -> tg_relation -> rd_att );
1240- PLy_output_tuple_funcs (& (proc -> result ),tdata -> tg_relation -> rd_att );
1241- }
12421248
12431249/*
12441250 * now get information required for input conversion of the
12451251 * procedure's arguments.
12461252 */
1247- proc -> nargs = fcinfo -> nargs ;
1253+ proc -> nargs = procStruct -> pronargs ;
12481254if (proc -> nargs )
12491255{
12501256argnames = SysCacheGetAttr (PROCOID ,procTup ,Anum_pg_proc_proargnames ,& isnull );
12511257if (!isnull )
12521258{
1259+ /* XXX this code is WRONG if there are any output arguments */
12531260deconstruct_array (DatumGetArrayTypeP (argnames ),TEXTOID ,-1 , false,'i' ,
12541261& elems ,NULL ,& nelems );
12551262if (nelems != proc -> nargs )
@@ -1260,7 +1267,7 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
12601267memset (proc -> argnames ,0 ,sizeof (char * )* proc -> nargs );
12611268}
12621269}
1263- for (i = 0 ;i < fcinfo -> nargs ;i ++ )
1270+ for (i = 0 ;i < proc -> nargs ;i ++ )
12641271{
12651272HeapTuple argTypeTup ;
12661273Form_pg_type argTypeStruct ;
@@ -1453,10 +1460,15 @@ PLy_input_tuple_funcs(PLyTypeInfo * arg, TupleDesc desc)
14531460
14541461if (arg -> is_rowtype == 0 )
14551462elog (ERROR ,"PLyTypeInfo struct is initialized for a Datum" );
1456-
14571463arg -> is_rowtype = 1 ;
1458- arg -> in .r .natts = desc -> natts ;
1459- arg -> in .r .atts = PLy_malloc (desc -> natts * sizeof (PLyDatumToOb ));
1464+
1465+ if (arg -> in .r .natts != desc -> natts )
1466+ {
1467+ if (arg -> in .r .atts )
1468+ PLy_free (arg -> in .r .atts );
1469+ arg -> in .r .natts = desc -> natts ;
1470+ arg -> in .r .atts = PLy_malloc0 (desc -> natts * sizeof (PLyDatumToOb ));
1471+ }
14601472
14611473for (i = 0 ;i < desc -> natts ;i ++ )
14621474{
@@ -1465,6 +1477,9 @@ PLy_input_tuple_funcs(PLyTypeInfo * arg, TupleDesc desc)
14651477if (desc -> attrs [i ]-> attisdropped )
14661478continue ;
14671479
1480+ if (arg -> in .r .atts [i ].typoid == desc -> attrs [i ]-> atttypid )
1481+ continue ;/* already set up this entry */
1482+
14681483typeTup = SearchSysCache (TYPEOID ,
14691484ObjectIdGetDatum (desc -> attrs [i ]-> atttypid ),
147014850 ,0 ,0 );
@@ -1487,10 +1502,15 @@ PLy_output_tuple_funcs(PLyTypeInfo * arg, TupleDesc desc)
14871502
14881503if (arg -> is_rowtype == 0 )
14891504elog (ERROR ,"PLyTypeInfo struct is initialized for a Datum" );
1490-
14911505arg -> is_rowtype = 1 ;
1492- arg -> out .r .natts = desc -> natts ;
1493- arg -> out .r .atts = PLy_malloc (desc -> natts * sizeof (PLyDatumToOb ));
1506+
1507+ if (arg -> out .r .natts != desc -> natts )
1508+ {
1509+ if (arg -> out .r .atts )
1510+ PLy_free (arg -> out .r .atts );
1511+ arg -> out .r .natts = desc -> natts ;
1512+ arg -> out .r .atts = PLy_malloc0 (desc -> natts * sizeof (PLyDatumToOb ));
1513+ }
14941514
14951515for (i = 0 ;i < desc -> natts ;i ++ )
14961516{
@@ -1499,6 +1519,9 @@ PLy_output_tuple_funcs(PLyTypeInfo * arg, TupleDesc desc)
14991519if (desc -> attrs [i ]-> attisdropped )
15001520continue ;
15011521
1522+ if (arg -> out .r .atts [i ].typoid == desc -> attrs [i ]-> atttypid )
1523+ continue ;/* already set up this entry */
1524+
15021525typeTup = SearchSysCache (TYPEOID ,
15031526ObjectIdGetDatum (desc -> attrs [i ]-> atttypid ),
150415270 ,0 ,0 );
@@ -1548,6 +1571,7 @@ PLy_input_datum_func2(PLyDatumToOb * arg, Oid typeOid, HeapTuple typeTup)
15481571
15491572/* Get the type's conversion information */
15501573perm_fmgr_info (typeStruct -> typoutput ,& arg -> typfunc );
1574+ arg -> typoid = HeapTupleGetOid (typeTup );
15511575arg -> typioparam = getTypeIOParam (typeTup );
15521576arg -> typbyval = typeStruct -> typbyval ;
15531577
@@ -3015,6 +3039,15 @@ PLy_malloc(size_t bytes)
30153039return ptr ;
30163040}
30173041
3042+ static void *
3043+ PLy_malloc0 (size_t bytes )
3044+ {
3045+ void * ptr = PLy_malloc (bytes );
3046+
3047+ MemSet (ptr ,0 ,bytes );
3048+ return ptr ;
3049+ }
3050+
30183051static char *
30193052PLy_strdup (const char * str )
30203053{