mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-27 08:39:28 +08:00
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.)
This commit is contained in:
parent
e7de331eb5
commit
65d1c2dc33
@ -1,7 +1,7 @@
|
||||
/**********************************************************************
|
||||
* plpython.c - python as a procedural language for PostgreSQL
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.90.2.3 2007/11/23 01:46:58 alvherre Exp $
|
||||
* $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.90.2.4 2008/01/02 03:10:34 tgl Exp $
|
||||
*
|
||||
*********************************************************************
|
||||
*/
|
||||
@ -66,7 +66,8 @@ typedef PyObject *(*PLyDatumToObFunc) (const char *);
|
||||
typedef struct PLyDatumToOb
|
||||
{
|
||||
PLyDatumToObFunc func;
|
||||
FmgrInfo typfunc;
|
||||
FmgrInfo typfunc; /* The type's output function */
|
||||
Oid typoid; /* The OID of the type */
|
||||
Oid typioparam;
|
||||
bool typbyval;
|
||||
} PLyDatumToOb;
|
||||
@ -199,6 +200,7 @@ static void PLy_elog(int, const char *,...);
|
||||
static char *PLy_traceback(int *);
|
||||
|
||||
static void *PLy_malloc(size_t);
|
||||
static void *PLy_malloc0(size_t);
|
||||
static char *PLy_strdup(const char *);
|
||||
static void PLy_free(void *);
|
||||
|
||||
@ -218,9 +220,8 @@ static PyObject *PLy_procedure_call(PLyProcedure *, char *, PyObject *);
|
||||
static PLyProcedure *PLy_procedure_get(FunctionCallInfo fcinfo,
|
||||
Oid tgreloid);
|
||||
|
||||
static PLyProcedure *PLy_procedure_create(FunctionCallInfo fcinfo,
|
||||
Oid tgreloid,
|
||||
HeapTuple procTup, char *key);
|
||||
static PLyProcedure *PLy_procedure_create(HeapTuple procTup, Oid tgreloid,
|
||||
char *key);
|
||||
|
||||
static void PLy_procedure_compile(PLyProcedure *, const char *);
|
||||
static char *PLy_procedure_munge_source(const char *, const char *);
|
||||
@ -1110,7 +1111,24 @@ PLy_procedure_get(FunctionCallInfo fcinfo, Oid tgreloid)
|
||||
}
|
||||
|
||||
if (proc == NULL)
|
||||
proc = PLy_procedure_create(fcinfo, tgreloid, procTup, key);
|
||||
proc = PLy_procedure_create(procTup, tgreloid, key);
|
||||
|
||||
if (OidIsValid(tgreloid))
|
||||
{
|
||||
/*
|
||||
* Input/output conversion for trigger tuples. Use the result
|
||||
* TypeInfo variable to store the tuple conversion info. We
|
||||
* do this over again on each call to cover the possibility that
|
||||
* the relation's tupdesc changed since the trigger was last called.
|
||||
* PLy_input_tuple_funcs and PLy_output_tuple_funcs are responsible
|
||||
* for not doing repetitive work.
|
||||
*/
|
||||
TriggerData *tdata = (TriggerData *) fcinfo->context;
|
||||
|
||||
Assert(CALLED_AS_TRIGGER(fcinfo));
|
||||
PLy_input_tuple_funcs(&(proc->result), tdata->tg_relation->rd_att);
|
||||
PLy_output_tuple_funcs(&(proc->result), tdata->tg_relation->rd_att);
|
||||
}
|
||||
|
||||
ReleaseSysCache(procTup);
|
||||
|
||||
@ -1118,8 +1136,7 @@ PLy_procedure_get(FunctionCallInfo fcinfo, Oid tgreloid)
|
||||
}
|
||||
|
||||
static PLyProcedure *
|
||||
PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
|
||||
HeapTuple procTup, char *key)
|
||||
PLy_procedure_create(HeapTuple procTup, Oid tgreloid, char *key)
|
||||
{
|
||||
char procName[NAMEDATALEN + 256];
|
||||
Form_pg_proc procStruct;
|
||||
@ -1139,13 +1156,13 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
|
||||
rv = snprintf(procName, sizeof(procName),
|
||||
"__plpython_procedure_%s_%u_trigger_%u",
|
||||
NameStr(procStruct->proname),
|
||||
fcinfo->flinfo->fn_oid,
|
||||
HeapTupleGetOid(procTup),
|
||||
tgreloid);
|
||||
else
|
||||
rv = snprintf(procName, sizeof(procName),
|
||||
"__plpython_procedure_%s_%u",
|
||||
NameStr(procStruct->proname),
|
||||
fcinfo->flinfo->fn_oid);
|
||||
HeapTupleGetOid(procTup));
|
||||
if (rv >= sizeof(procName) || rv < 0)
|
||||
elog(ERROR, "procedure name would overrun buffer");
|
||||
|
||||
@ -1173,7 +1190,7 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
|
||||
* get information required for output conversion of the return value,
|
||||
* but only if this isn't a trigger.
|
||||
*/
|
||||
if (!CALLED_AS_TRIGGER(fcinfo))
|
||||
if (!OidIsValid(tgreloid))
|
||||
{
|
||||
HeapTuple rvTypeTup;
|
||||
Form_pg_type rvTypeStruct;
|
||||
@ -1215,28 +1232,18 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
|
||||
|
||||
ReleaseSysCache(rvTypeTup);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* input/output conversion for trigger tuples. use the result
|
||||
* TypeInfo variable to store the tuple conversion info.
|
||||
*/
|
||||
TriggerData *tdata = (TriggerData *) fcinfo->context;
|
||||
|
||||
PLy_input_tuple_funcs(&(proc->result), tdata->tg_relation->rd_att);
|
||||
PLy_output_tuple_funcs(&(proc->result), tdata->tg_relation->rd_att);
|
||||
}
|
||||
|
||||
/*
|
||||
* now get information required for input conversion of the
|
||||
* procedure's arguments.
|
||||
*/
|
||||
proc->nargs = fcinfo->nargs;
|
||||
proc->nargs = procStruct->pronargs;
|
||||
if (proc->nargs)
|
||||
{
|
||||
argnames = SysCacheGetAttr(PROCOID, procTup, Anum_pg_proc_proargnames, &isnull);
|
||||
if (!isnull)
|
||||
{
|
||||
/* XXX this code is WRONG if there are any output arguments */
|
||||
deconstruct_array(DatumGetArrayTypeP(argnames), TEXTOID, -1, false, 'i',
|
||||
&elems, NULL, &nelems);
|
||||
if (nelems != proc->nargs)
|
||||
@ -1247,7 +1254,7 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
|
||||
memset(proc->argnames, 0, sizeof(char *) * proc->nargs);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < fcinfo->nargs; i++)
|
||||
for (i = 0; i < proc->nargs; i++)
|
||||
{
|
||||
HeapTuple argTypeTup;
|
||||
Form_pg_type argTypeStruct;
|
||||
@ -1440,10 +1447,15 @@ PLy_input_tuple_funcs(PLyTypeInfo * arg, TupleDesc desc)
|
||||
|
||||
if (arg->is_rowtype == 0)
|
||||
elog(ERROR, "PLyTypeInfo struct is initialized for a Datum");
|
||||
|
||||
arg->is_rowtype = 1;
|
||||
arg->in.r.natts = desc->natts;
|
||||
arg->in.r.atts = PLy_malloc(desc->natts * sizeof(PLyDatumToOb));
|
||||
|
||||
if (arg->in.r.natts != desc->natts)
|
||||
{
|
||||
if (arg->in.r.atts)
|
||||
PLy_free(arg->in.r.atts);
|
||||
arg->in.r.natts = desc->natts;
|
||||
arg->in.r.atts = PLy_malloc0(desc->natts * sizeof(PLyDatumToOb));
|
||||
}
|
||||
|
||||
for (i = 0; i < desc->natts; i++)
|
||||
{
|
||||
@ -1452,6 +1464,9 @@ PLy_input_tuple_funcs(PLyTypeInfo * arg, TupleDesc desc)
|
||||
if (desc->attrs[i]->attisdropped)
|
||||
continue;
|
||||
|
||||
if (arg->in.r.atts[i].typoid == desc->attrs[i]->atttypid)
|
||||
continue; /* already set up this entry */
|
||||
|
||||
typeTup = SearchSysCache(TYPEOID,
|
||||
ObjectIdGetDatum(desc->attrs[i]->atttypid),
|
||||
0, 0, 0);
|
||||
@ -1474,10 +1489,15 @@ PLy_output_tuple_funcs(PLyTypeInfo * arg, TupleDesc desc)
|
||||
|
||||
if (arg->is_rowtype == 0)
|
||||
elog(ERROR, "PLyTypeInfo struct is initialized for a Datum");
|
||||
|
||||
arg->is_rowtype = 1;
|
||||
arg->out.r.natts = desc->natts;
|
||||
arg->out.r.atts = PLy_malloc(desc->natts * sizeof(PLyDatumToOb));
|
||||
|
||||
if (arg->out.r.natts != desc->natts)
|
||||
{
|
||||
if (arg->out.r.atts)
|
||||
PLy_free(arg->out.r.atts);
|
||||
arg->out.r.natts = desc->natts;
|
||||
arg->out.r.atts = PLy_malloc0(desc->natts * sizeof(PLyDatumToOb));
|
||||
}
|
||||
|
||||
for (i = 0; i < desc->natts; i++)
|
||||
{
|
||||
@ -1486,6 +1506,9 @@ PLy_output_tuple_funcs(PLyTypeInfo * arg, TupleDesc desc)
|
||||
if (desc->attrs[i]->attisdropped)
|
||||
continue;
|
||||
|
||||
if (arg->out.r.atts[i].typoid == desc->attrs[i]->atttypid)
|
||||
continue; /* already set up this entry */
|
||||
|
||||
typeTup = SearchSysCache(TYPEOID,
|
||||
ObjectIdGetDatum(desc->attrs[i]->atttypid),
|
||||
0, 0, 0);
|
||||
@ -1535,6 +1558,7 @@ PLy_input_datum_func2(PLyDatumToOb * arg, Oid typeOid, HeapTuple typeTup)
|
||||
|
||||
/* Get the type's conversion information */
|
||||
perm_fmgr_info(typeStruct->typoutput, &arg->typfunc);
|
||||
arg->typoid = HeapTupleGetOid(typeTup);
|
||||
arg->typioparam = getTypeIOParam(typeTup);
|
||||
arg->typbyval = typeStruct->typbyval;
|
||||
|
||||
@ -2989,6 +3013,15 @@ PLy_malloc(size_t bytes)
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void *
|
||||
PLy_malloc0(size_t bytes)
|
||||
{
|
||||
void *ptr = PLy_malloc(bytes);
|
||||
|
||||
MemSet(ptr, 0, bytes);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static char *
|
||||
PLy_strdup(const char *str)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user