Commit 96e63199 authored by Tom Lane's avatar Tom Lane

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.
parent efebe260
...@@ -29,7 +29,7 @@ ...@@ -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 *, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment