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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy