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