@@ -228,10 +228,17 @@ typedef struct PLyProcedure
228228}PLyProcedure ;
229229
230230
231+ /* the procedure cache key */
232+ typedef struct PLyProcedureKey
233+ {
234+ Oid fn_oid ;/* function OID */
235+ Oid fn_rel ;/* triggered-on relation or InvalidOid */
236+ }PLyProcedureKey ;
237+
231238/* the procedure cache entry */
232239typedef struct PLyProcedureEntry
233240{
234- Oid fn_oid ; /* hash key */
241+ PLyProcedureKey key ; /* hash key */
235242PLyProcedure * proc ;
236243}PLyProcedureEntry ;
237244
@@ -371,7 +378,7 @@ static HeapTuple PLy_modify_tuple(PLyProcedure *, PyObject *,
371378
372379static PyObject * PLy_procedure_call (PLyProcedure * ,char * ,PyObject * );
373380
374- static PLyProcedure * PLy_procedure_get (Oid fn_oid ,bool is_trigger );
381+ static PLyProcedure * PLy_procedure_get (Oid fn_oid ,Oid fn_rel , bool is_trigger );
375382
376383static PLyProcedure * PLy_procedure_create (HeapTuple procTup ,
377384Oid fn_oid ,bool is_trigger );
@@ -427,7 +434,6 @@ static List *explicit_subtransactions = NIL;
427434static PyObject * PLy_interp_globals = NULL ;
428435static PyObject * PLy_interp_safe_globals = NULL ;
429436static HTAB * PLy_procedure_cache = NULL ;
430- static HTAB * PLy_trigger_cache = NULL ;
431437
432438/* Python exceptions */
433439static PyObject * PLy_exc_error = NULL ;
@@ -528,7 +534,8 @@ plpython_validator(PG_FUNCTION_ARGS)
528534
529535ReleaseSysCache (tuple );
530536
531- PLy_procedure_get (funcoid ,is_trigger );
537+ /* We can't validate triggers against any particular table ... */
538+ PLy_procedure_get (funcoid ,InvalidOid ,is_trigger );
532539
533540PG_RETURN_VOID ();
534541}
@@ -554,20 +561,22 @@ plpython_call_handler(PG_FUNCTION_ARGS)
554561
555562PG_TRY ();
556563{
564+ Oid funcoid = fcinfo -> flinfo -> fn_oid ;
557565PLyProcedure * proc ;
558566
559567if (CALLED_AS_TRIGGER (fcinfo ))
560568{
569+ Relation tgrel = ((TriggerData * )fcinfo -> context )-> tg_relation ;
561570HeapTuple trv ;
562571
563- proc = PLy_procedure_get (fcinfo -> flinfo -> fn_oid , true);
572+ proc = PLy_procedure_get (funcoid , RelationGetRelid ( tgrel ) , true);
564573PLy_curr_procedure = proc ;
565574trv = PLy_trigger_handler (fcinfo ,proc );
566575retval = PointerGetDatum (trv );
567576}
568577else
569578{
570- proc = PLy_procedure_get (fcinfo -> flinfo -> fn_oid , false);
579+ proc = PLy_procedure_get (funcoid , InvalidOid , false);
571580PLy_curr_procedure = proc ;
572581retval = PLy_function_handler (fcinfo ,proc );
573582}
@@ -1516,62 +1525,76 @@ PLy_procedure_valid(PLyProcedure *proc, HeapTuple procTup)
15161525 * PLyProcedure functions
15171526 */
15181527
1519- /* PLy_procedure_get: returns a cached PLyProcedure, or creates, stores and
1520- * returns a new PLyProcedure.fcinfo is the call info, tgreloid is the
1521- * relation OID when calling a trigger, or InvalidOid (zero) for ordinary
1522- * function calls.
1528+ /*
1529+ * PLy_procedure_get: returns a cached PLyProcedure, or creates, stores and
1530+ * returns a new PLyProcedure.
1531+ *
1532+ * fn_oid is the OID of the function requested
1533+ * fn_rel is InvalidOid or the relation this function triggers on
1534+ * is_trigger denotes whether the function is a trigger function
1535+ *
1536+ * The reason that both fn_rel and is_trigger need to be passed is that when
1537+ * trigger functions get validated we don't know which relation(s) they'll
1538+ * be used with, so no sensible fn_rel can be passed.
15231539 */
15241540static PLyProcedure *
1525- PLy_procedure_get (Oid fn_oid ,bool is_trigger )
1541+ PLy_procedure_get (Oid fn_oid ,Oid fn_rel , bool is_trigger )
15261542{
1543+ bool use_cache = !(is_trigger && fn_rel == InvalidOid );
15271544HeapTuple procTup ;
1528- PLyProcedureEntry * volatile entry ;
1529- bool found ;
1545+ PLyProcedureKey key ;
1546+ PLyProcedureEntry * volatile entry = NULL ;
1547+ PLyProcedure * volatile proc = NULL ;
1548+ bool found = false;
15301549
15311550procTup = SearchSysCache1 (PROCOID ,ObjectIdGetDatum (fn_oid ));
15321551if (!HeapTupleIsValid (procTup ))
15331552elog (ERROR ,"cache lookup failed for function %u" ,fn_oid );
15341553
1535- /* Look for the function in the corresponding cache */
1536- if (is_trigger )
1537- entry = hash_search (PLy_trigger_cache ,
1538- & fn_oid ,HASH_ENTER ,& found );
1539- else
1540- entry = hash_search (PLy_procedure_cache ,
1541- & fn_oid ,HASH_ENTER ,& found );
1554+ /*
1555+ * Look for the function in the cache, unless we don't have the necessary
1556+ * information (e.g. during validation). In that case we just don't cache
1557+ * anything.
1558+ */
1559+ if (use_cache )
1560+ {
1561+ key .fn_oid = fn_oid ;
1562+ key .fn_rel = fn_rel ;
1563+ entry = hash_search (PLy_procedure_cache ,& key ,HASH_ENTER ,& found );
1564+ proc = entry -> proc ;
1565+ }
15421566
15431567PG_TRY ();
15441568{
15451569if (!found )
15461570{
1547- /* Haven't found it, create a new cache entry */
1548- entry -> proc = PLy_procedure_create (procTup ,fn_oid ,is_trigger );
1571+ /* Haven't found it, create a new procedure */
1572+ proc = PLy_procedure_create (procTup ,fn_oid ,is_trigger );
1573+ if (use_cache )
1574+ entry -> proc = proc ;
15491575}
1550- else if (!PLy_procedure_valid (entry -> proc ,procTup ))
1576+ else if (!PLy_procedure_valid (proc ,procTup ))
15511577{
15521578/* Found it, but it's invalid, free and reuse the cache entry */
1553- PLy_procedure_delete (entry -> proc );
1554- PLy_free (entry -> proc );
1555- entry -> proc = PLy_procedure_create (procTup ,fn_oid ,is_trigger );
1579+ PLy_procedure_delete (proc );
1580+ PLy_free (proc );
1581+ proc = PLy_procedure_create (procTup ,fn_oid ,is_trigger );
1582+ entry -> proc = proc ;
15561583}
15571584/* Found it and it's valid, it's fine to use it */
15581585}
15591586PG_CATCH ();
15601587{
15611588/* Do not leave an uninitialised entry in the cache */
1562- if (is_trigger )
1563- hash_search (PLy_trigger_cache ,
1564- & fn_oid ,HASH_REMOVE ,NULL );
1565- else
1566- hash_search (PLy_procedure_cache ,
1567- & fn_oid ,HASH_REMOVE ,NULL );
1589+ if (use_cache )
1590+ hash_search (PLy_procedure_cache ,& key ,HASH_REMOVE ,NULL );
15681591PG_RE_THROW ();
15691592}
15701593PG_END_TRY ();
15711594
15721595ReleaseSysCache (procTup );
15731596
1574- return entry -> proc ;
1597+ return proc ;
15751598}
15761599
15771600/*
@@ -4115,19 +4138,12 @@ _PG_init(void)
41154138PLy_elog (FATAL ,"untrapped error in initialization" );
41164139
41174140memset (& hash_ctl ,0 ,sizeof (hash_ctl ));
4118- hash_ctl .keysize = sizeof (Oid );
4141+ hash_ctl .keysize = sizeof (PLyProcedureKey );
41194142hash_ctl .entrysize = sizeof (PLyProcedureEntry );
4120- hash_ctl .hash = oid_hash ;
4143+ hash_ctl .hash = tag_hash ;
41214144PLy_procedure_cache = hash_create ("PL/Python procedures" ,32 ,& hash_ctl ,
41224145HASH_ELEM |HASH_FUNCTION );
41234146
4124- memset (& hash_ctl ,0 ,sizeof (hash_ctl ));
4125- hash_ctl .keysize = sizeof (Oid );
4126- hash_ctl .entrysize = sizeof (PLyProcedureEntry );
4127- hash_ctl .hash = oid_hash ;
4128- PLy_trigger_cache = hash_create ("PL/Python triggers" ,32 ,& hash_ctl ,
4129- HASH_ELEM |HASH_FUNCTION );
4130-
41314147explicit_subtransactions = NIL ;
41324148
41334149inited = true;