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{
8181 PLyDatumToObFunc func ;
82- FmgrInfo typfunc ;
82+ FmgrInfo typfunc ; /* The type's output function */
83+ Oid typoid ; /* The OID of the type */
8384 Oid typioparam ;
8485 bool 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 ,
232234 Oid 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
11251126 if (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
11281146 ReleaseSysCache (procTup );
11291147
11301148 return 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{
11371154 char procName [NAMEDATALEN + 256 ];
11381155 Form_pg_proc procStruct ;
@@ -1152,13 +1169,13 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
11521169 rv = snprintf (procName , sizeof (procName ),
11531170 "__plpython_procedure_%s_%u_trigger_%u" ,
11541171 NameStr (procStruct -> proname ),
1155- fcinfo -> flinfo -> fn_oid ,
1172+ HeapTupleGetOid ( procTup ) ,
11561173 tgreloid );
11571174 else
11581175 rv = snprintf (procName , sizeof (procName ),
11591176 "__plpython_procedure_%s_%u" ,
11601177 NameStr (procStruct -> proname ),
1161- fcinfo -> flinfo -> fn_oid );
1178+ HeapTupleGetOid ( procTup ) );
11621179 if (rv >= sizeof (procName ) || rv < 0 )
11631180 elog (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 {
11911208 HeapTuple rvTypeTup ;
11921209 Form_pg_type rvTypeStruct ;
@@ -1228,28 +1245,18 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
12281245
12291246 ReleaseSysCache (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 ;
12481254 if (proc -> nargs )
12491255 {
12501256 argnames = SysCacheGetAttr (PROCOID , procTup , Anum_pg_proc_proargnames , & isnull );
12511257 if (!isnull )
12521258 {
1259+ /* XXX this code is WRONG if there are any output arguments */
12531260 deconstruct_array (DatumGetArrayTypeP (argnames ), TEXTOID , -1 , false, 'i' ,
12541261 & elems , NULL , & nelems );
12551262 if (nelems != proc -> nargs )
@@ -1260,7 +1267,7 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
12601267 memset (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 {
12651272 HeapTuple argTypeTup ;
12661273 Form_pg_type argTypeStruct ;
@@ -1453,10 +1460,15 @@ PLy_input_tuple_funcs(PLyTypeInfo * arg, TupleDesc desc)
14531460
14541461 if (arg -> is_rowtype == 0 )
14551462 elog (ERROR , "PLyTypeInfo struct is initialized for a Datum" );
1456-
14571463 arg -> 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
14611473 for (i = 0 ; i < desc -> natts ; i ++ )
14621474 {
@@ -1465,6 +1477,9 @@ PLy_input_tuple_funcs(PLyTypeInfo * arg, TupleDesc desc)
14651477 if (desc -> attrs [i ]-> attisdropped )
14661478 continue ;
14671479
1480+ if (arg -> in .r .atts [i ].typoid == desc -> attrs [i ]-> atttypid )
1481+ continue ; /* already set up this entry */
1482+
14681483 typeTup = SearchSysCache (TYPEOID ,
14691484 ObjectIdGetDatum (desc -> attrs [i ]-> atttypid ),
14701485 0 , 0 , 0 );
@@ -1487,10 +1502,15 @@ PLy_output_tuple_funcs(PLyTypeInfo * arg, TupleDesc desc)
14871502
14881503 if (arg -> is_rowtype == 0 )
14891504 elog (ERROR , "PLyTypeInfo struct is initialized for a Datum" );
1490-
14911505 arg -> 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
14951515 for (i = 0 ; i < desc -> natts ; i ++ )
14961516 {
@@ -1499,6 +1519,9 @@ PLy_output_tuple_funcs(PLyTypeInfo * arg, TupleDesc desc)
14991519 if (desc -> attrs [i ]-> attisdropped )
15001520 continue ;
15011521
1522+ if (arg -> out .r .atts [i ].typoid == desc -> attrs [i ]-> atttypid )
1523+ continue ; /* already set up this entry */
1524+
15021525 typeTup = SearchSysCache (TYPEOID ,
15031526 ObjectIdGetDatum (desc -> attrs [i ]-> atttypid ),
15041527 0 , 0 , 0 );
@@ -1548,6 +1571,7 @@ PLy_input_datum_func2(PLyDatumToOb * arg, Oid typeOid, HeapTuple typeTup)
15481571
15491572 /* Get the type's conversion information */
15501573 perm_fmgr_info (typeStruct -> typoutput , & arg -> typfunc );
1574+ arg -> typoid = HeapTupleGetOid (typeTup );
15511575 arg -> typioparam = getTypeIOParam (typeTup );
15521576 arg -> typbyval = typeStruct -> typbyval ;
15531577
@@ -3015,6 +3039,15 @@ PLy_malloc(size_t bytes)
30153039 return 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{
0 commit comments