Fix plpython to generate separate cached procedure data for each
relation, when the same function is used as a trigger on more than one relation. This avoids crashes due to differing rowtypes for different relations. Per bug report from Lance Thomas, 7-Feb-03.
This commit is contained in:
parent
efebe2605e
commit
96e63199f3
@ -29,7 +29,7 @@
|
|||||||
* MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
* MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/pl/plpython/plpython.c,v 1.39 2003/08/04 18:40:50 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/pl/plpython/plpython.c,v 1.40 2003/09/14 17:13:06 tgl Exp $
|
||||||
*
|
*
|
||||||
*********************************************************************
|
*********************************************************************
|
||||||
*/
|
*/
|
||||||
@ -224,13 +224,11 @@ static HeapTuple PLy_modify_tuple(PLyProcedure *, PyObject *,
|
|||||||
|
|
||||||
static PyObject *PLy_procedure_call(PLyProcedure *, char *, PyObject *);
|
static PyObject *PLy_procedure_call(PLyProcedure *, char *, PyObject *);
|
||||||
|
|
||||||
/* returns a cached PLyProcedure, or creates, stores and returns
|
static PLyProcedure *PLy_procedure_get(FunctionCallInfo fcinfo,
|
||||||
* a new PLyProcedure.
|
Oid tgreloid);
|
||||||
*/
|
|
||||||
static PLyProcedure *PLy_procedure_get(FunctionCallInfo fcinfo, bool);
|
|
||||||
|
|
||||||
static PLyProcedure *PLy_procedure_create(FunctionCallInfo fcinfo,
|
static PLyProcedure *PLy_procedure_create(FunctionCallInfo fcinfo,
|
||||||
bool is_trigger,
|
Oid tgreloid,
|
||||||
HeapTuple procTup, char *key);
|
HeapTuple procTup, char *key);
|
||||||
|
|
||||||
static void PLy_procedure_compile(PLyProcedure *, const char *);
|
static void PLy_procedure_compile(PLyProcedure *, const char *);
|
||||||
@ -326,7 +324,6 @@ plpython_call_handler(PG_FUNCTION_ARGS)
|
|||||||
{
|
{
|
||||||
DECLARE_EXC();
|
DECLARE_EXC();
|
||||||
Datum retval;
|
Datum retval;
|
||||||
volatile bool is_trigger;
|
|
||||||
PLyProcedure *volatile proc = NULL;
|
PLyProcedure *volatile proc = NULL;
|
||||||
|
|
||||||
enter();
|
enter();
|
||||||
@ -337,7 +334,6 @@ plpython_call_handler(PG_FUNCTION_ARGS)
|
|||||||
elog(ERROR, "could not connect to SPI manager");
|
elog(ERROR, "could not connect to SPI manager");
|
||||||
|
|
||||||
CALL_LEVEL_INC();
|
CALL_LEVEL_INC();
|
||||||
is_trigger = CALLED_AS_TRIGGER(fcinfo);
|
|
||||||
|
|
||||||
SAVE_EXC();
|
SAVE_EXC();
|
||||||
if (TRAP_EXC())
|
if (TRAP_EXC())
|
||||||
@ -364,16 +360,21 @@ plpython_call_handler(PG_FUNCTION_ARGS)
|
|||||||
* PLy_restart_in_progress);
|
* PLy_restart_in_progress);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
proc = PLy_procedure_get(fcinfo, is_trigger);
|
if (CALLED_AS_TRIGGER(fcinfo))
|
||||||
|
|
||||||
if (is_trigger)
|
|
||||||
{
|
{
|
||||||
HeapTuple trv = PLy_trigger_handler(fcinfo, proc);
|
TriggerData *tdata = (TriggerData *) fcinfo->context;
|
||||||
|
HeapTuple trv;
|
||||||
|
|
||||||
|
proc = PLy_procedure_get(fcinfo,
|
||||||
|
RelationGetRelid(tdata->tg_relation));
|
||||||
|
trv = PLy_trigger_handler(fcinfo, proc);
|
||||||
retval = PointerGetDatum(trv);
|
retval = PointerGetDatum(trv);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
proc = PLy_procedure_get(fcinfo, InvalidOid);
|
||||||
retval = PLy_function_handler(fcinfo, proc);
|
retval = PLy_function_handler(fcinfo, proc);
|
||||||
|
}
|
||||||
|
|
||||||
CALL_LEVEL_DEC();
|
CALL_LEVEL_DEC();
|
||||||
RESTORE_EXC();
|
RESTORE_EXC();
|
||||||
@ -962,10 +963,17 @@ PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure * proc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* PLyProcedure functions
|
/*
|
||||||
|
* PLyProcedure functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* PLy_procedure_get: returns a cached PLyProcedure, or creates, stores and
|
||||||
|
* returns a new PLyProcedure. fcinfo is the call info, tgreloid is the
|
||||||
|
* relation OID when calling a trigger, or InvalidOid (zero) for ordinary
|
||||||
|
* function calls.
|
||||||
*/
|
*/
|
||||||
static PLyProcedure *
|
static PLyProcedure *
|
||||||
PLy_procedure_get(FunctionCallInfo fcinfo, bool is_trigger)
|
PLy_procedure_get(FunctionCallInfo fcinfo, Oid tgreloid)
|
||||||
{
|
{
|
||||||
Oid fn_oid;
|
Oid fn_oid;
|
||||||
HeapTuple procTup;
|
HeapTuple procTup;
|
||||||
@ -983,9 +991,7 @@ PLy_procedure_get(FunctionCallInfo fcinfo, bool is_trigger)
|
|||||||
if (!HeapTupleIsValid(procTup))
|
if (!HeapTupleIsValid(procTup))
|
||||||
elog(ERROR, "cache lookup failed for function %u", fn_oid);
|
elog(ERROR, "cache lookup failed for function %u", fn_oid);
|
||||||
|
|
||||||
rv = snprintf(key, sizeof(key), "%u%s",
|
rv = snprintf(key, sizeof(key), "%u_%u", fn_oid, tgreloid);
|
||||||
fn_oid,
|
|
||||||
is_trigger ? "_trigger" : "");
|
|
||||||
if ((rv >= sizeof(key)) || (rv < 0))
|
if ((rv >= sizeof(key)) || (rv < 0))
|
||||||
elog(ERROR, "key too long");
|
elog(ERROR, "key too long");
|
||||||
|
|
||||||
@ -1012,7 +1018,7 @@ PLy_procedure_get(FunctionCallInfo fcinfo, bool is_trigger)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (proc == NULL)
|
if (proc == NULL)
|
||||||
proc = PLy_procedure_create(fcinfo, is_trigger, procTup, key);
|
proc = PLy_procedure_create(fcinfo, tgreloid, procTup, key);
|
||||||
|
|
||||||
ReleaseSysCache(procTup);
|
ReleaseSysCache(procTup);
|
||||||
|
|
||||||
@ -1020,7 +1026,7 @@ PLy_procedure_get(FunctionCallInfo fcinfo, bool is_trigger)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static PLyProcedure *
|
static PLyProcedure *
|
||||||
PLy_procedure_create(FunctionCallInfo fcinfo, bool is_trigger,
|
PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
|
||||||
HeapTuple procTup, char *key)
|
HeapTuple procTup, char *key)
|
||||||
{
|
{
|
||||||
char procName[NAMEDATALEN + 256];
|
char procName[NAMEDATALEN + 256];
|
||||||
@ -1037,11 +1043,17 @@ PLy_procedure_create(FunctionCallInfo fcinfo, bool is_trigger,
|
|||||||
|
|
||||||
procStruct = (Form_pg_proc) GETSTRUCT(procTup);
|
procStruct = (Form_pg_proc) GETSTRUCT(procTup);
|
||||||
|
|
||||||
rv = snprintf(procName, sizeof(procName),
|
if (OidIsValid(tgreloid))
|
||||||
"__plpython_procedure_%s_%u%s",
|
rv = snprintf(procName, sizeof(procName),
|
||||||
NameStr(procStruct->proname),
|
"__plpython_procedure_%s_%u_trigger_%u",
|
||||||
fcinfo->flinfo->fn_oid,
|
NameStr(procStruct->proname),
|
||||||
is_trigger ? "_trigger" : "");
|
fcinfo->flinfo->fn_oid,
|
||||||
|
tgreloid);
|
||||||
|
else
|
||||||
|
rv = snprintf(procName, sizeof(procName),
|
||||||
|
"__plpython_procedure_%s_%u",
|
||||||
|
NameStr(procStruct->proname),
|
||||||
|
fcinfo->flinfo->fn_oid);
|
||||||
if ((rv >= sizeof(procName)) || (rv < 0))
|
if ((rv >= sizeof(procName)) || (rv < 0))
|
||||||
elog(ERROR, "procedure name would overrun buffer");
|
elog(ERROR, "procedure name would overrun buffer");
|
||||||
|
|
||||||
@ -1073,7 +1085,7 @@ PLy_procedure_create(FunctionCallInfo fcinfo, bool is_trigger,
|
|||||||
* get information required for output conversion of the return value,
|
* get information required for output conversion of the return value,
|
||||||
* but only if this isn't a trigger.
|
* but only if this isn't a trigger.
|
||||||
*/
|
*/
|
||||||
if (!is_trigger)
|
if (!CALLED_AS_TRIGGER(fcinfo))
|
||||||
{
|
{
|
||||||
HeapTuple rvTypeTup;
|
HeapTuple rvTypeTup;
|
||||||
Form_pg_type rvTypeStruct;
|
Form_pg_type rvTypeStruct;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user