@@ -182,6 +182,7 @@ typedef struct plperl_call_data
182
182
typedef struct plperl_query_desc
183
183
{
184
184
char qname [24 ];
185
+ MemoryContext plan_cxt ;/* context holding this struct */
185
186
void * plan ;
186
187
int nargs ;
187
188
Oid * argtypes ;
@@ -3199,33 +3200,57 @@ plperl_spi_cursor_close(char *cursor)
3199
3200
SV *
3200
3201
plperl_spi_prepare (char * query ,int argc ,SV * * argv )
3201
3202
{
3202
- plperl_query_desc * qdesc ;
3203
- plperl_query_entry * hash_entry ;
3204
- bool found ;
3205
- void * plan ;
3206
- int i ;
3207
-
3203
+ void * volatile plan = NULL ;
3204
+ volatile MemoryContext plan_cxt = NULL ;
3205
+ plperl_query_desc * volatile qdesc = NULL ;
3206
+ plperl_query_entry * volatile hash_entry = NULL ;
3208
3207
MemoryContext oldcontext = CurrentMemoryContext ;
3209
3208
ResourceOwner oldowner = CurrentResourceOwner ;
3209
+ MemoryContext work_cxt ;
3210
+ bool found ;
3211
+ int i ;
3210
3212
3211
3213
check_spi_usage_allowed ();
3212
3214
3213
3215
BeginInternalSubTransaction (NULL );
3214
3216
MemoryContextSwitchTo (oldcontext );
3215
3217
3216
- /************************************************************
3217
- * Allocate the new querydesc structure
3218
- ************************************************************/
3219
- qdesc = (plperl_query_desc * )malloc (sizeof (plperl_query_desc ));
3220
- MemSet (qdesc ,0 ,sizeof (plperl_query_desc ));
3221
- snprintf (qdesc -> qname ,sizeof (qdesc -> qname ),"%p" ,qdesc );
3222
- qdesc -> nargs = argc ;
3223
- qdesc -> argtypes = (Oid * )malloc (argc * sizeof (Oid ));
3224
- qdesc -> arginfuncs = (FmgrInfo * )malloc (argc * sizeof (FmgrInfo ));
3225
- qdesc -> argtypioparams = (Oid * )malloc (argc * sizeof (Oid ));
3226
-
3227
3218
PG_TRY ();
3228
3219
{
3220
+ CHECK_FOR_INTERRUPTS ();
3221
+
3222
+ /************************************************************
3223
+ * Allocate the new querydesc structure
3224
+ *
3225
+ * The qdesc struct, as well as all its subsidiary data, lives in its
3226
+ * plan_cxt. But note that the SPIPlan does not.
3227
+ ************************************************************/
3228
+ plan_cxt = AllocSetContextCreate (TopMemoryContext ,
3229
+ "PL/Perl spi_prepare query" ,
3230
+ ALLOCSET_SMALL_MINSIZE ,
3231
+ ALLOCSET_SMALL_INITSIZE ,
3232
+ ALLOCSET_SMALL_MAXSIZE );
3233
+ MemoryContextSwitchTo (plan_cxt );
3234
+ qdesc = (plperl_query_desc * )palloc0 (sizeof (plperl_query_desc ));
3235
+ snprintf (qdesc -> qname ,sizeof (qdesc -> qname ),"%p" ,qdesc );
3236
+ qdesc -> plan_cxt = plan_cxt ;
3237
+ qdesc -> nargs = argc ;
3238
+ qdesc -> argtypes = (Oid * )palloc (argc * sizeof (Oid ));
3239
+ qdesc -> arginfuncs = (FmgrInfo * )palloc (argc * sizeof (FmgrInfo ));
3240
+ qdesc -> argtypioparams = (Oid * )palloc (argc * sizeof (Oid ));
3241
+ MemoryContextSwitchTo (oldcontext );
3242
+
3243
+ /************************************************************
3244
+ * Do the following work in a short-lived context so that we don't
3245
+ * leak a lot of memory in the PL/Perl function's SPI Proc context.
3246
+ ************************************************************/
3247
+ work_cxt = AllocSetContextCreate (CurrentMemoryContext ,
3248
+ "PL/Perl spi_prepare workspace" ,
3249
+ ALLOCSET_DEFAULT_MINSIZE ,
3250
+ ALLOCSET_DEFAULT_INITSIZE ,
3251
+ ALLOCSET_DEFAULT_MAXSIZE );
3252
+ MemoryContextSwitchTo (work_cxt );
3253
+
3229
3254
/************************************************************
3230
3255
* Resolve argument type names and then look them up by oid
3231
3256
* in the system cache, and remember the required information
@@ -3246,7 +3271,7 @@ plperl_spi_prepare(char *query, int argc, SV **argv)
3246
3271
getTypeInputInfo (typId ,& typInput ,& typIOParam );
3247
3272
3248
3273
qdesc -> argtypes [i ]= typId ;
3249
- perm_fmgr_info (typInput ,& (qdesc -> arginfuncs [i ]));
3274
+ fmgr_info_cxt (typInput ,& (qdesc -> arginfuncs [i ]), plan_cxt );
3250
3275
qdesc -> argtypioparams [i ]= typIOParam ;
3251
3276
}
3252
3277
@@ -3274,6 +3299,17 @@ plperl_spi_prepare(char *query, int argc, SV **argv)
3274
3299
/* Release the procCxt copy to avoid within-function memory leak */
3275
3300
SPI_freeplan (plan );
3276
3301
3302
+ /************************************************************
3303
+ * Insert a hashtable entry for the plan.
3304
+ ************************************************************/
3305
+ hash_entry = hash_search (plperl_active_interp -> query_hash ,
3306
+ qdesc -> qname ,
3307
+ HASH_ENTER ,& found );
3308
+ hash_entry -> query_data = qdesc ;
3309
+
3310
+ /* Get rid of workspace */
3311
+ MemoryContextDelete (work_cxt );
3312
+
3277
3313
/* Commit the inner transaction, return to outer xact context */
3278
3314
ReleaseCurrentSubTransaction ();
3279
3315
MemoryContextSwitchTo (oldcontext );
@@ -3289,16 +3325,21 @@ plperl_spi_prepare(char *query, int argc, SV **argv)
3289
3325
{
3290
3326
ErrorData * edata ;
3291
3327
3292
- free (qdesc -> argtypes );
3293
- free (qdesc -> arginfuncs );
3294
- free (qdesc -> argtypioparams );
3295
- free (qdesc );
3296
-
3297
3328
/* Save error info */
3298
3329
MemoryContextSwitchTo (oldcontext );
3299
3330
edata = CopyErrorData ();
3300
3331
FlushErrorState ();
3301
3332
3333
+ /* Drop anything we managed to allocate */
3334
+ if (hash_entry )
3335
+ hash_search (plperl_active_interp -> query_hash ,
3336
+ qdesc -> qname ,
3337
+ HASH_REMOVE ,NULL );
3338
+ if (plan_cxt )
3339
+ MemoryContextDelete (plan_cxt );
3340
+ if (plan )
3341
+ SPI_freeplan (plan );
3342
+
3302
3343
/* Abort the inner transaction */
3303
3344
RollbackAndReleaseCurrentSubTransaction ();
3304
3345
MemoryContextSwitchTo (oldcontext );
@@ -3320,14 +3361,8 @@ plperl_spi_prepare(char *query, int argc, SV **argv)
3320
3361
PG_END_TRY ();
3321
3362
3322
3363
/************************************************************
3323
- * Insert a hashtable entry for the plan and return
3324
- * the key to the caller.
3364
+ * Return the query's hash key to the caller.
3325
3365
************************************************************/
3326
-
3327
- hash_entry = hash_search (plperl_active_interp -> query_hash ,qdesc -> qname ,
3328
- HASH_ENTER ,& found );
3329
- hash_entry -> query_data = qdesc ;
3330
-
3331
3366
return cstr2sv (qdesc -> qname );
3332
3367
}
3333
3368
@@ -3362,16 +3397,14 @@ plperl_spi_exec_prepared(char *query, HV *attr, int argc, SV **argv)
3362
3397
/************************************************************
3363
3398
* Fetch the saved plan descriptor, see if it's o.k.
3364
3399
************************************************************/
3365
-
3366
3400
hash_entry = hash_search (plperl_active_interp -> query_hash ,query ,
3367
3401
HASH_FIND ,NULL );
3368
3402
if (hash_entry == NULL )
3369
3403
elog (ERROR ,"spi_exec_prepared: Invalid prepared query passed" );
3370
3404
3371
3405
qdesc = hash_entry -> query_data ;
3372
-
3373
3406
if (qdesc == NULL )
3374
- elog (ERROR ,"spi_exec_prepared:panic - plperl query_hash value vanished" );
3407
+ elog (ERROR ,"spi_exec_prepared: plperl query_hash value vanished" );
3375
3408
3376
3409
if (qdesc -> nargs != argc )
3377
3410
elog (ERROR ,"spi_exec_prepared: expected %d argument(s), %d passed" ,
@@ -3503,12 +3536,11 @@ plperl_spi_query_prepared(char *query, int argc, SV **argv)
3503
3536
hash_entry = hash_search (plperl_active_interp -> query_hash ,query ,
3504
3537
HASH_FIND ,NULL );
3505
3538
if (hash_entry == NULL )
3506
- elog (ERROR ,"spi_exec_prepared : Invalid prepared query passed" );
3539
+ elog (ERROR ,"spi_query_prepared : Invalid prepared query passed" );
3507
3540
3508
3541
qdesc = hash_entry -> query_data ;
3509
-
3510
3542
if (qdesc == NULL )
3511
- elog (ERROR ,"spi_query_prepared:panic - plperl query_hash value vanished" );
3543
+ elog (ERROR ,"spi_query_prepared: plperl query_hash value vanished" );
3512
3544
3513
3545
if (qdesc -> nargs != argc )
3514
3546
elog (ERROR ,"spi_query_prepared: expected %d argument(s), %d passed" ,
@@ -3613,12 +3645,12 @@ plperl_spi_freeplan(char *query)
3613
3645
hash_entry = hash_search (plperl_active_interp -> query_hash ,query ,
3614
3646
HASH_FIND ,NULL );
3615
3647
if (hash_entry == NULL )
3616
- elog (ERROR ,"spi_exec_prepared : Invalid prepared query passed" );
3648
+ elog (ERROR ,"spi_freeplan : Invalid prepared query passed" );
3617
3649
3618
3650
qdesc = hash_entry -> query_data ;
3619
-
3620
3651
if (qdesc == NULL )
3621
- elog (ERROR ,"spi_exec_freeplan: panic - plperl query_hash value vanished" );
3652
+ elog (ERROR ,"spi_freeplan: plperl query_hash value vanished" );
3653
+ plan = qdesc -> plan ;
3622
3654
3623
3655
/*
3624
3656
* free all memory before SPI_freeplan, so if it dies, nothing will be
@@ -3627,11 +3659,7 @@ plperl_spi_freeplan(char *query)
3627
3659
hash_search (plperl_active_interp -> query_hash ,query ,
3628
3660
HASH_REMOVE ,NULL );
3629
3661
3630
- plan = qdesc -> plan ;
3631
- free (qdesc -> argtypes );
3632
- free (qdesc -> arginfuncs );
3633
- free (qdesc -> argtypioparams );
3634
- free (qdesc );
3662
+ MemoryContextDelete (qdesc -> plan_cxt );
3635
3663
3636
3664
SPI_freeplan (plan );
3637
3665
}