]> granicus.if.org Git - postgresql/commitdiff
Fix plpython to generate separate cached procedure data for each
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 14 Sep 2003 17:13:06 +0000 (17:13 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 14 Sep 2003 17:13:06 +0000 (17:13 +0000)
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.

src/pl/plpython/plpython.c

index e7a47e9ef4e3e09073cdcd25678a967ffafecfce..f526cce01001b7bf84cc1ed49e92f86679ab4344 100644 (file)
@@ -29,7 +29,7 @@
  * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * 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 *);
 
-/* returns a cached PLyProcedure, or creates, stores and returns
- * a new PLyProcedure.
- */
-static PLyProcedure *PLy_procedure_get(FunctionCallInfo fcinfo, bool);
+static PLyProcedure *PLy_procedure_get(FunctionCallInfo fcinfo,
+                                                                          Oid tgreloid);
 
 static PLyProcedure *PLy_procedure_create(FunctionCallInfo fcinfo,
-                                        bool is_trigger,
+                                        Oid tgreloid,
                                         HeapTuple procTup, char *key);
 
 static void PLy_procedure_compile(PLyProcedure *, const char *);
@@ -326,7 +324,6 @@ plpython_call_handler(PG_FUNCTION_ARGS)
 {
        DECLARE_EXC();
        Datum           retval;
-       volatile bool is_trigger;
        PLyProcedure *volatile proc = NULL;
 
        enter();
@@ -337,7 +334,6 @@ plpython_call_handler(PG_FUNCTION_ARGS)
                elog(ERROR, "could not connect to SPI manager");
 
        CALL_LEVEL_INC();
-       is_trigger = CALLED_AS_TRIGGER(fcinfo);
 
        SAVE_EXC();
        if (TRAP_EXC())
@@ -364,16 +360,21 @@ plpython_call_handler(PG_FUNCTION_ARGS)
         * PLy_restart_in_progress);
         */
 
-       proc = PLy_procedure_get(fcinfo, is_trigger);
-
-       if (is_trigger)
+       if (CALLED_AS_TRIGGER(fcinfo))
        {
-               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);
        }
        else
+       {
+               proc = PLy_procedure_get(fcinfo, InvalidOid);
                retval = PLy_function_handler(fcinfo, proc);
+       }
 
        CALL_LEVEL_DEC();
        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 *
-PLy_procedure_get(FunctionCallInfo fcinfo, bool is_trigger)
+PLy_procedure_get(FunctionCallInfo fcinfo, Oid tgreloid)
 {
        Oid                     fn_oid;
        HeapTuple       procTup;
@@ -983,9 +991,7 @@ PLy_procedure_get(FunctionCallInfo fcinfo, bool is_trigger)
        if (!HeapTupleIsValid(procTup))
                elog(ERROR, "cache lookup failed for function %u", fn_oid);
 
-       rv = snprintf(key, sizeof(key), "%u%s",
-                                 fn_oid,
-                                 is_trigger ? "_trigger" : "");
+       rv = snprintf(key, sizeof(key), "%u_%u", fn_oid, tgreloid);
        if ((rv >= sizeof(key)) || (rv < 0))
                elog(ERROR, "key too long");
 
@@ -1012,7 +1018,7 @@ PLy_procedure_get(FunctionCallInfo fcinfo, bool is_trigger)
        }
 
        if (proc == NULL)
-               proc = PLy_procedure_create(fcinfo, is_trigger, procTup, key);
+               proc = PLy_procedure_create(fcinfo, tgreloid, procTup, key);
 
        ReleaseSysCache(procTup);
 
@@ -1020,7 +1026,7 @@ PLy_procedure_get(FunctionCallInfo fcinfo, bool is_trigger)
 }
 
 static PLyProcedure *
-PLy_procedure_create(FunctionCallInfo fcinfo, bool is_trigger,
+PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
                                         HeapTuple procTup, char *key)
 {
        char            procName[NAMEDATALEN + 256];
@@ -1037,11 +1043,17 @@ PLy_procedure_create(FunctionCallInfo fcinfo, bool is_trigger,
 
        procStruct = (Form_pg_proc) GETSTRUCT(procTup);
 
-       rv = snprintf(procName, sizeof(procName),
-                                 "__plpython_procedure_%s_%u%s",
-                                 NameStr(procStruct->proname),
-                                 fcinfo->flinfo->fn_oid,
-                                 is_trigger ? "_trigger" : "");
+       if (OidIsValid(tgreloid))
+               rv = snprintf(procName, sizeof(procName),
+                                         "__plpython_procedure_%s_%u_trigger_%u",
+                                         NameStr(procStruct->proname),
+                                         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))
                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,
         * but only if this isn't a trigger.
         */
-       if (!is_trigger)
+       if (!CALLED_AS_TRIGGER(fcinfo))
        {
                HeapTuple       rvTypeTup;
                Form_pg_type rvTypeStruct;