@@ -228,10 +228,17 @@ typedef struct PLyProcedure
228
228
}PLyProcedure ;
229
229
230
230
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
+
231
238
/* the procedure cache entry */
232
239
typedef struct PLyProcedureEntry
233
240
{
234
- Oid fn_oid ; /* hash key */
241
+ PLyProcedureKey key ; /* hash key */
235
242
PLyProcedure * proc ;
236
243
}PLyProcedureEntry ;
237
244
@@ -371,7 +378,7 @@ static HeapTuple PLy_modify_tuple(PLyProcedure *, PyObject *,
371
378
372
379
static PyObject * PLy_procedure_call (PLyProcedure * ,char * ,PyObject * );
373
380
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 );
375
382
376
383
static PLyProcedure * PLy_procedure_create (HeapTuple procTup ,
377
384
Oid fn_oid ,bool is_trigger );
@@ -427,7 +434,6 @@ static List *explicit_subtransactions = NIL;
427
434
static PyObject * PLy_interp_globals = NULL ;
428
435
static PyObject * PLy_interp_safe_globals = NULL ;
429
436
static HTAB * PLy_procedure_cache = NULL ;
430
- static HTAB * PLy_trigger_cache = NULL ;
431
437
432
438
/* Python exceptions */
433
439
static PyObject * PLy_exc_error = NULL ;
@@ -528,7 +534,8 @@ plpython_validator(PG_FUNCTION_ARGS)
528
534
529
535
ReleaseSysCache (tuple );
530
536
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 );
532
539
533
540
PG_RETURN_VOID ();
534
541
}
@@ -554,20 +561,22 @@ plpython_call_handler(PG_FUNCTION_ARGS)
554
561
555
562
PG_TRY ();
556
563
{
564
+ Oid funcoid = fcinfo -> flinfo -> fn_oid ;
557
565
PLyProcedure * proc ;
558
566
559
567
if (CALLED_AS_TRIGGER (fcinfo ))
560
568
{
569
+ Relation tgrel = ((TriggerData * )fcinfo -> context )-> tg_relation ;
561
570
HeapTuple trv ;
562
571
563
- proc = PLy_procedure_get (fcinfo -> flinfo -> fn_oid , true);
572
+ proc = PLy_procedure_get (funcoid , RelationGetRelid ( tgrel ) , true);
564
573
PLy_curr_procedure = proc ;
565
574
trv = PLy_trigger_handler (fcinfo ,proc );
566
575
retval = PointerGetDatum (trv );
567
576
}
568
577
else
569
578
{
570
- proc = PLy_procedure_get (fcinfo -> flinfo -> fn_oid , false);
579
+ proc = PLy_procedure_get (funcoid , InvalidOid , false);
571
580
PLy_curr_procedure = proc ;
572
581
retval = PLy_function_handler (fcinfo ,proc );
573
582
}
@@ -1516,62 +1525,76 @@ PLy_procedure_valid(PLyProcedure *proc, HeapTuple procTup)
1516
1525
* PLyProcedure functions
1517
1526
*/
1518
1527
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.
1523
1539
*/
1524
1540
static PLyProcedure *
1525
- PLy_procedure_get (Oid fn_oid ,bool is_trigger )
1541
+ PLy_procedure_get (Oid fn_oid ,Oid fn_rel , bool is_trigger )
1526
1542
{
1543
+ bool use_cache = !(is_trigger && fn_rel == InvalidOid );
1527
1544
HeapTuple 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;
1530
1549
1531
1550
procTup = SearchSysCache1 (PROCOID ,ObjectIdGetDatum (fn_oid ));
1532
1551
if (!HeapTupleIsValid (procTup ))
1533
1552
elog (ERROR ,"cache lookup failed for function %u" ,fn_oid );
1534
1553
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
+ }
1542
1566
1543
1567
PG_TRY ();
1544
1568
{
1545
1569
if (!found )
1546
1570
{
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 ;
1549
1575
}
1550
- else if (!PLy_procedure_valid (entry -> proc ,procTup ))
1576
+ else if (!PLy_procedure_valid (proc ,procTup ))
1551
1577
{
1552
1578
/* 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 ;
1556
1583
}
1557
1584
/* Found it and it's valid, it's fine to use it */
1558
1585
}
1559
1586
PG_CATCH ();
1560
1587
{
1561
1588
/* 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 );
1568
1591
PG_RE_THROW ();
1569
1592
}
1570
1593
PG_END_TRY ();
1571
1594
1572
1595
ReleaseSysCache (procTup );
1573
1596
1574
- return entry -> proc ;
1597
+ return proc ;
1575
1598
}
1576
1599
1577
1600
/*
@@ -4115,19 +4138,12 @@ _PG_init(void)
4115
4138
PLy_elog (FATAL ,"untrapped error in initialization" );
4116
4139
4117
4140
memset (& hash_ctl ,0 ,sizeof (hash_ctl ));
4118
- hash_ctl .keysize = sizeof (Oid );
4141
+ hash_ctl .keysize = sizeof (PLyProcedureKey );
4119
4142
hash_ctl .entrysize = sizeof (PLyProcedureEntry );
4120
- hash_ctl .hash = oid_hash ;
4143
+ hash_ctl .hash = tag_hash ;
4121
4144
PLy_procedure_cache = hash_create ("PL/Python procedures" ,32 ,& hash_ctl ,
4122
4145
HASH_ELEM |HASH_FUNCTION );
4123
4146
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
-
4131
4147
explicit_subtransactions = NIL ;
4132
4148
4133
4149
inited = true;