1
1
/**********************************************************************
2
2
* plpython.c - python as a procedural language for PostgreSQL
3
3
*
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 $
5
5
*
6
6
*********************************************************************
7
7
*/
@@ -79,7 +79,8 @@ typedef PyObject *(*PLyDatumToObFunc) (const char *);
79
79
typedef struct PLyDatumToOb
80
80
{
81
81
PLyDatumToObFunc func ;
82
- FmgrInfo typfunc ;
82
+ FmgrInfo typfunc ; /* The type's output function */
83
+ Oid typoid ; /* The OID of the type */
83
84
Oid typioparam ;
84
85
bool typbyval ;
85
86
} PLyDatumToOb ;
@@ -212,6 +213,7 @@ static void PLy_elog(int, const char *,...);
212
213
static char * PLy_traceback (int * );
213
214
214
215
static void * PLy_malloc (size_t );
216
+ static void * PLy_malloc0 (size_t );
215
217
static char * PLy_strdup (const char * );
216
218
static void PLy_free (void * );
217
219
@@ -231,9 +233,8 @@ static PyObject *PLy_procedure_call(PLyProcedure *, char *, PyObject *);
231
233
static PLyProcedure * PLy_procedure_get (FunctionCallInfo fcinfo ,
232
234
Oid tgreloid );
233
235
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 );
237
238
238
239
static void PLy_procedure_compile (PLyProcedure * , const char * );
239
240
static char * PLy_procedure_munge_source (const char * , const char * );
@@ -1123,16 +1124,32 @@ PLy_procedure_get(FunctionCallInfo fcinfo, Oid tgreloid)
1123
1124
}
1124
1125
1125
1126
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
+ }
1127
1145
1128
1146
ReleaseSysCache (procTup );
1129
1147
1130
1148
return proc ;
1131
1149
}
1132
1150
1133
1151
static PLyProcedure *
1134
- PLy_procedure_create (FunctionCallInfo fcinfo , Oid tgreloid ,
1135
- HeapTuple procTup , char * key )
1152
+ PLy_procedure_create (HeapTuple procTup , Oid tgreloid , char * key )
1136
1153
{
1137
1154
char procName [NAMEDATALEN + 256 ];
1138
1155
Form_pg_proc procStruct ;
@@ -1152,13 +1169,13 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
1152
1169
rv = snprintf (procName , sizeof (procName ),
1153
1170
"__plpython_procedure_%s_%u_trigger_%u" ,
1154
1171
NameStr (procStruct -> proname ),
1155
- fcinfo -> flinfo -> fn_oid ,
1172
+ HeapTupleGetOid ( procTup ) ,
1156
1173
tgreloid );
1157
1174
else
1158
1175
rv = snprintf (procName , sizeof (procName ),
1159
1176
"__plpython_procedure_%s_%u" ,
1160
1177
NameStr (procStruct -> proname ),
1161
- fcinfo -> flinfo -> fn_oid );
1178
+ HeapTupleGetOid ( procTup ) );
1162
1179
if (rv >= sizeof (procName ) || rv < 0 )
1163
1180
elog (ERROR , "procedure name would overrun buffer" );
1164
1181
@@ -1186,7 +1203,7 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
1186
1203
* get information required for output conversion of the return value,
1187
1204
* but only if this isn't a trigger.
1188
1205
*/
1189
- if (!CALLED_AS_TRIGGER ( fcinfo ))
1206
+ if (!OidIsValid ( tgreloid ))
1190
1207
{
1191
1208
HeapTuple rvTypeTup ;
1192
1209
Form_pg_type rvTypeStruct ;
@@ -1228,28 +1245,18 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
1228
1245
1229
1246
ReleaseSysCache (rvTypeTup );
1230
1247
}
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
- }
1242
1248
1243
1249
/*
1244
1250
* now get information required for input conversion of the
1245
1251
* procedure's arguments.
1246
1252
*/
1247
- proc -> nargs = fcinfo -> nargs ;
1253
+ proc -> nargs = procStruct -> pronargs ;
1248
1254
if (proc -> nargs )
1249
1255
{
1250
1256
argnames = SysCacheGetAttr (PROCOID , procTup , Anum_pg_proc_proargnames , & isnull );
1251
1257
if (!isnull )
1252
1258
{
1259
+ /* XXX this code is WRONG if there are any output arguments */
1253
1260
deconstruct_array (DatumGetArrayTypeP (argnames ), TEXTOID , -1 , false, 'i' ,
1254
1261
& elems , NULL , & nelems );
1255
1262
if (nelems != proc -> nargs )
@@ -1260,7 +1267,7 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
1260
1267
memset (proc -> argnames , 0 , sizeof (char * ) * proc -> nargs );
1261
1268
}
1262
1269
}
1263
- for (i = 0 ; i < fcinfo -> nargs ; i ++ )
1270
+ for (i = 0 ; i < proc -> nargs ; i ++ )
1264
1271
{
1265
1272
HeapTuple argTypeTup ;
1266
1273
Form_pg_type argTypeStruct ;
@@ -1453,10 +1460,15 @@ PLy_input_tuple_funcs(PLyTypeInfo * arg, TupleDesc desc)
1453
1460
1454
1461
if (arg -> is_rowtype == 0 )
1455
1462
elog (ERROR , "PLyTypeInfo struct is initialized for a Datum" );
1456
-
1457
1463
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
+ }
1460
1472
1461
1473
for (i = 0 ; i < desc -> natts ; i ++ )
1462
1474
{
@@ -1465,6 +1477,9 @@ PLy_input_tuple_funcs(PLyTypeInfo * arg, TupleDesc desc)
1465
1477
if (desc -> attrs [i ]-> attisdropped )
1466
1478
continue ;
1467
1479
1480
+ if (arg -> in .r .atts [i ].typoid == desc -> attrs [i ]-> atttypid )
1481
+ continue ; /* already set up this entry */
1482
+
1468
1483
typeTup = SearchSysCache (TYPEOID ,
1469
1484
ObjectIdGetDatum (desc -> attrs [i ]-> atttypid ),
1470
1485
0 , 0 , 0 );
@@ -1487,10 +1502,15 @@ PLy_output_tuple_funcs(PLyTypeInfo * arg, TupleDesc desc)
1487
1502
1488
1503
if (arg -> is_rowtype == 0 )
1489
1504
elog (ERROR , "PLyTypeInfo struct is initialized for a Datum" );
1490
-
1491
1505
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
+ }
1494
1514
1495
1515
for (i = 0 ; i < desc -> natts ; i ++ )
1496
1516
{
@@ -1499,6 +1519,9 @@ PLy_output_tuple_funcs(PLyTypeInfo * arg, TupleDesc desc)
1499
1519
if (desc -> attrs [i ]-> attisdropped )
1500
1520
continue ;
1501
1521
1522
+ if (arg -> out .r .atts [i ].typoid == desc -> attrs [i ]-> atttypid )
1523
+ continue ; /* already set up this entry */
1524
+
1502
1525
typeTup = SearchSysCache (TYPEOID ,
1503
1526
ObjectIdGetDatum (desc -> attrs [i ]-> atttypid ),
1504
1527
0 , 0 , 0 );
@@ -1548,6 +1571,7 @@ PLy_input_datum_func2(PLyDatumToOb * arg, Oid typeOid, HeapTuple typeTup)
1548
1571
1549
1572
/* Get the type's conversion information */
1550
1573
perm_fmgr_info (typeStruct -> typoutput , & arg -> typfunc );
1574
+ arg -> typoid = HeapTupleGetOid (typeTup );
1551
1575
arg -> typioparam = getTypeIOParam (typeTup );
1552
1576
arg -> typbyval = typeStruct -> typbyval ;
1553
1577
@@ -3015,6 +3039,15 @@ PLy_malloc(size_t bytes)
3015
3039
return ptr ;
3016
3040
}
3017
3041
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
+
3018
3051
static char *
3019
3052
PLy_strdup (const char * str )
3020
3053
{
0 commit comments