Skip to content

Commit baecbb9

Browse files
committed
Fix plpython's overoptimistic caching of information about the rowtype of
a trigger's target table. The rowtype could change from one call to the next, so cope in such cases, while avoiding doing repetitive catalog lookups. Per bug #3847 from Mark Reid. Backpatch to 8.2.x. Likely this fix should go further back, but I can't test it because I no longer have a machine with a pre-2.5 Python installation. (Maybe we should rethink that idea about not supporting Python 2.5 in the older branches.)
1 parent 14b5eaa commit baecbb9

File tree

1 file changed

+63
-30
lines changed

1 file changed

+63
-30
lines changed

src/pl/plpython/plpython.c

Lines changed: 63 additions & 30 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.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 *);
7979
typedef 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 *,...);
212213
static char *PLy_traceback(int *);
213214

214215
static void *PLy_malloc(size_t);
216+
static void *PLy_malloc0(size_t);
215217
static char *PLy_strdup(const char *);
216218
static void PLy_free(void *);
217219

@@ -231,9 +233,8 @@ static PyObject *PLy_procedure_call(PLyProcedure *, char *, PyObject *);
231233
static 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

238239
static void PLy_procedure_compile(PLyProcedure *, const char *);
239240
static 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

11331151
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)
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+
30183051
static char *
30193052
PLy_strdup(const char *str)
30203053
{

0 commit comments

Comments
 (0)