@@ -69,6 +69,7 @@ PG_MODULE_MAGIC;
69
69
*
70
70
* The plperl_interp_desc structs are kept in a Postgres hash table indexed
71
71
* by userid OID, with OID 0 used for the single untrusted interpreter.
72
+ * Once created, an interpreter is kept for the life of the process.
72
73
*
73
74
* We start out by creating a "held" interpreter, which we initialize
74
75
* only as far as we can do without deciding if it will be trusted or
@@ -94,28 +95,44 @@ typedef struct plperl_interp_desc
94
95
95
96
/**********************************************************************
96
97
* The information we cache about loaded procedures
98
+ *
99
+ * The refcount field counts the struct's reference from the hash table shown
100
+ * below, plus one reference for each function call level that is using the
101
+ * struct. We can release the struct, and the associated Perl sub, when the
102
+ * refcount goes to zero.
97
103
**********************************************************************/
98
104
typedef struct plperl_proc_desc
99
105
{
100
106
char * proname ; /* user name of procedure */
101
- TransactionId fn_xmin ;
107
+ TransactionId fn_xmin ; /* xmin/TID of procedure's pg_proc tuple */
102
108
ItemPointerData fn_tid ;
109
+ int refcount ; /* reference count of this struct */
110
+ SV * reference ; /* CODE reference for Perl sub */
103
111
plperl_interp_desc * interp ; /* interpreter it's created in */
104
- bool fn_readonly ;
105
- bool lanpltrusted ;
112
+ bool fn_readonly ; /* is function readonly (not volatile)? */
113
+ bool lanpltrusted ; /* is it plperl, rather than plperlu? */
106
114
bool fn_retistuple ; /* true, if function returns tuple */
107
115
bool fn_retisset ; /* true, if function returns set */
108
116
bool fn_retisarray ; /* true if function returns array */
117
+ /* Conversion info for function's result type: */
109
118
Oid result_oid ; /* Oid of result type */
110
119
FmgrInfo result_in_func ; /* I/O function and arg for result type */
111
120
Oid result_typioparam ;
121
+ /* Conversion info for function's argument types: */
112
122
int nargs ;
113
123
FmgrInfo arg_out_func [FUNC_MAX_ARGS ];
114
124
bool arg_is_rowtype [FUNC_MAX_ARGS ];
115
125
Oid arg_arraytype [FUNC_MAX_ARGS ]; /* InvalidOid if not an array */
116
- SV * reference ;
117
126
} plperl_proc_desc ;
118
127
128
+ #define increment_prodesc_refcount (prodesc ) \
129
+ ((prodesc)->refcount++)
130
+ #define decrement_prodesc_refcount (prodesc ) \
131
+ do { \
132
+ if (--((prodesc)->refcount) <= 0) \
133
+ free_plperl_function(prodesc); \
134
+ } while(0)
135
+
119
136
/**********************************************************************
120
137
* For speedy lookup, we maintain a hash table mapping from
121
138
* function OID + trigger flag + user OID to plperl_proc_desc pointers.
@@ -237,6 +254,8 @@ static void set_interp_require(bool trusted);
237
254
static Datum plperl_func_handler (PG_FUNCTION_ARGS );
238
255
static Datum plperl_trigger_handler (PG_FUNCTION_ARGS );
239
256
257
+ static void free_plperl_function (plperl_proc_desc * prodesc );
258
+
240
259
static plperl_proc_desc * compile_plperl_function (Oid fn_oid , bool is_trigger );
241
260
242
261
static SV * plperl_hash_from_tuple (HeapTuple tuple , TupleDesc tupdesc );
@@ -1680,19 +1699,24 @@ plperl_call_handler(PG_FUNCTION_ARGS)
1680
1699
1681
1700
PG_TRY ();
1682
1701
{
1702
+ current_call_data = NULL ;
1683
1703
if (CALLED_AS_TRIGGER (fcinfo ))
1684
1704
retval = PointerGetDatum (plperl_trigger_handler (fcinfo ));
1685
1705
else
1686
1706
retval = plperl_func_handler (fcinfo );
1687
1707
}
1688
1708
PG_CATCH ();
1689
1709
{
1710
+ if (current_call_data && current_call_data -> prodesc )
1711
+ decrement_prodesc_refcount (current_call_data -> prodesc );
1690
1712
current_call_data = save_call_data ;
1691
1713
activate_interpreter (oldinterp );
1692
1714
PG_RE_THROW ();
1693
1715
}
1694
1716
PG_END_TRY ();
1695
1717
1718
+ if (current_call_data && current_call_data -> prodesc )
1719
+ decrement_prodesc_refcount (current_call_data -> prodesc );
1696
1720
current_call_data = save_call_data ;
1697
1721
activate_interpreter (oldinterp );
1698
1722
return retval ;
@@ -1744,14 +1768,15 @@ plperl_inline_handler(PG_FUNCTION_ARGS)
1744
1768
desc .nargs = 0 ;
1745
1769
desc .reference = NULL ;
1746
1770
1747
- current_call_data = (plperl_call_data * ) palloc0 (sizeof (plperl_call_data ));
1748
- current_call_data -> fcinfo = & fake_fcinfo ;
1749
- current_call_data -> prodesc = & desc ;
1750
-
1751
1771
PG_TRY ();
1752
1772
{
1753
1773
SV * perlret ;
1754
1774
1775
+ current_call_data = (plperl_call_data * ) palloc0 (sizeof (plperl_call_data ));
1776
+ current_call_data -> fcinfo = & fake_fcinfo ;
1777
+ current_call_data -> prodesc = & desc ;
1778
+ /* we do not bother with refcounting the fake prodesc */
1779
+
1755
1780
if (SPI_connect () != SPI_OK_CONNECT )
1756
1781
elog (ERROR , "could not connect to SPI manager" );
1757
1782
@@ -2145,6 +2170,7 @@ plperl_func_handler(PG_FUNCTION_ARGS)
2145
2170
2146
2171
prodesc = compile_plperl_function (fcinfo -> flinfo -> fn_oid , false);
2147
2172
current_call_data -> prodesc = prodesc ;
2173
+ increment_prodesc_refcount (prodesc );
2148
2174
2149
2175
/* Set a callback for error reporting */
2150
2176
pl_error_context .callback = plperl_exec_callback ;
@@ -2265,6 +2291,7 @@ plperl_trigger_handler(PG_FUNCTION_ARGS)
2265
2291
/* Find or compile the function */
2266
2292
prodesc = compile_plperl_function (fcinfo -> flinfo -> fn_oid , true);
2267
2293
current_call_data -> prodesc = prodesc ;
2294
+ increment_prodesc_refcount (prodesc );
2268
2295
2269
2296
/* Set a callback for error reporting */
2270
2297
pl_error_context .callback = plperl_exec_callback ;
@@ -2374,23 +2401,35 @@ validate_plperl_function(plperl_proc_ptr *proc_ptr, HeapTuple procTup)
2374
2401
2375
2402
/* Otherwise, unlink the obsoleted entry from the hashtable ... */
2376
2403
proc_ptr -> proc_ptr = NULL ;
2377
- /* ... and throw it away */
2378
- if (prodesc -> reference )
2379
- {
2380
- plperl_interp_desc * oldinterp = plperl_active_interp ;
2381
-
2382
- activate_interpreter (prodesc -> interp );
2383
- SvREFCNT_dec (prodesc -> reference );
2384
- activate_interpreter (oldinterp );
2385
- }
2386
- free (prodesc -> proname );
2387
- free (prodesc );
2404
+ /* ... and release the corresponding refcount, probably deleting it */
2405
+ decrement_prodesc_refcount (prodesc );
2388
2406
}
2389
2407
2390
2408
return false;
2391
2409
}
2392
2410
2393
2411
2412
+ static void
2413
+ free_plperl_function (plperl_proc_desc * prodesc )
2414
+ {
2415
+ Assert (prodesc -> refcount <= 0 );
2416
+ /* Release CODE reference, if we have one, from the appropriate interp */
2417
+ if (prodesc -> reference )
2418
+ {
2419
+ plperl_interp_desc * oldinterp = plperl_active_interp ;
2420
+
2421
+ activate_interpreter (prodesc -> interp );
2422
+ SvREFCNT_dec (prodesc -> reference );
2423
+ activate_interpreter (oldinterp );
2424
+ }
2425
+ /* Get rid of what we conveniently can of our own structs */
2426
+ /* (FmgrInfo subsidiary info will get leaked ...) */
2427
+ if (prodesc -> proname )
2428
+ free (prodesc -> proname );
2429
+ free (prodesc );
2430
+ }
2431
+
2432
+
2394
2433
static plperl_proc_desc *
2395
2434
compile_plperl_function (Oid fn_oid , bool is_trigger )
2396
2435
{
@@ -2461,12 +2500,17 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
2461
2500
ereport (ERROR ,
2462
2501
(errcode (ERRCODE_OUT_OF_MEMORY ),
2463
2502
errmsg ("out of memory" )));
2503
+ /* Initialize all fields to 0 so free_plperl_function is safe */
2464
2504
MemSet (prodesc , 0 , sizeof (plperl_proc_desc ));
2505
+
2465
2506
prodesc -> proname = strdup (NameStr (procStruct -> proname ));
2466
2507
if (prodesc -> proname == NULL )
2508
+ {
2509
+ free_plperl_function (prodesc );
2467
2510
ereport (ERROR ,
2468
2511
(errcode (ERRCODE_OUT_OF_MEMORY ),
2469
2512
errmsg ("out of memory" )));
2513
+ }
2470
2514
prodesc -> fn_xmin = HeapTupleHeaderGetXmin (procTup -> t_data );
2471
2515
prodesc -> fn_tid = procTup -> t_self ;
2472
2516
@@ -2481,8 +2525,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
2481
2525
ObjectIdGetDatum (procStruct -> prolang ));
2482
2526
if (!HeapTupleIsValid (langTup ))
2483
2527
{
2484
- free (prodesc -> proname );
2485
- free (prodesc );
2528
+ free_plperl_function (prodesc );
2486
2529
elog (ERROR , "cache lookup failed for language %u" ,
2487
2530
procStruct -> prolang );
2488
2531
}
@@ -2501,8 +2544,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
2501
2544
ObjectIdGetDatum (procStruct -> prorettype ));
2502
2545
if (!HeapTupleIsValid (typeTup ))
2503
2546
{
2504
- free (prodesc -> proname );
2505
- free (prodesc );
2547
+ free_plperl_function (prodesc );
2506
2548
elog (ERROR , "cache lookup failed for type %u" ,
2507
2549
procStruct -> prorettype );
2508
2550
}
@@ -2516,17 +2558,15 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
2516
2558
/* okay */ ;
2517
2559
else if (procStruct -> prorettype == TRIGGEROID )
2518
2560
{
2519
- free (prodesc -> proname );
2520
- free (prodesc );
2561
+ free_plperl_function (prodesc );
2521
2562
ereport (ERROR ,
2522
2563
(errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
2523
2564
errmsg ("trigger functions can only be called "
2524
2565
"as triggers" )));
2525
2566
}
2526
2567
else
2527
2568
{
2528
- free (prodesc -> proname );
2529
- free (prodesc );
2569
+ free_plperl_function (prodesc );
2530
2570
ereport (ERROR ,
2531
2571
(errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
2532
2572
errmsg ("PL/Perl functions cannot return type %s" ,
@@ -2561,8 +2601,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
2561
2601
ObjectIdGetDatum (procStruct -> proargtypes .values [i ]));
2562
2602
if (!HeapTupleIsValid (typeTup ))
2563
2603
{
2564
- free (prodesc -> proname );
2565
- free (prodesc );
2604
+ free_plperl_function (prodesc );
2566
2605
elog (ERROR , "cache lookup failed for type %u" ,
2567
2606
procStruct -> proargtypes .values [i ]);
2568
2607
}
@@ -2572,8 +2611,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
2572
2611
if (typeStruct -> typtype == TYPTYPE_PSEUDO &&
2573
2612
procStruct -> proargtypes .values [i ] != RECORDOID )
2574
2613
{
2575
- free (prodesc -> proname );
2576
- free (prodesc );
2614
+ free_plperl_function (prodesc );
2577
2615
ereport (ERROR ,
2578
2616
(errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
2579
2617
errmsg ("PL/Perl functions cannot accept type %s" ,
@@ -2626,8 +2664,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
2626
2664
pfree (proc_source );
2627
2665
if (!prodesc -> reference ) /* can this happen? */
2628
2666
{
2629
- free (prodesc -> proname );
2630
- free (prodesc );
2667
+ free_plperl_function (prodesc );
2631
2668
elog (ERROR , "could not create PL/Perl internal procedure" );
2632
2669
}
2633
2670
@@ -2639,6 +2676,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
2639
2676
proc_ptr = hash_search (plperl_proc_hash , & proc_key ,
2640
2677
HASH_ENTER , NULL );
2641
2678
proc_ptr -> proc_ptr = prodesc ;
2679
+ increment_prodesc_refcount (prodesc );
2642
2680
}
2643
2681
2644
2682
/* restore previous error callback */
0 commit comments