@@ -184,6 +184,7 @@ typedef struct plperl_call_data
184184typedef struct plperl_query_desc
185185{
186186 char qname [24 ];
187+ MemoryContext plan_cxt ; /* context holding this struct */
187188 SPIPlanPtr plan ;
188189 int nargs ;
189190 Oid * argtypes ;
@@ -3209,33 +3210,57 @@ plperl_spi_cursor_close(char *cursor)
32093210SV *
32103211plperl_spi_prepare (char * query , int argc , SV * * argv )
32113212{
3212- plperl_query_desc * qdesc ;
3213- plperl_query_entry * hash_entry ;
3214- bool found ;
3215- SPIPlanPtr plan ;
3216- int i ;
3217-
3213+ volatile SPIPlanPtr plan = NULL ;
3214+ volatile MemoryContext plan_cxt = NULL ;
3215+ plperl_query_desc * volatile qdesc = NULL ;
3216+ plperl_query_entry * volatile hash_entry = NULL ;
32183217 MemoryContext oldcontext = CurrentMemoryContext ;
32193218 ResourceOwner oldowner = CurrentResourceOwner ;
3219+ MemoryContext work_cxt ;
3220+ bool found ;
3221+ int i ;
32203222
32213223 check_spi_usage_allowed ();
32223224
32233225 BeginInternalSubTransaction (NULL );
32243226 MemoryContextSwitchTo (oldcontext );
32253227
3226- /************************************************************
3227- * Allocate the new querydesc structure
3228- ************************************************************/
3229- qdesc = (plperl_query_desc * ) malloc (sizeof (plperl_query_desc ));
3230- MemSet (qdesc , 0 , sizeof (plperl_query_desc ));
3231- snprintf (qdesc -> qname , sizeof (qdesc -> qname ), "%p" , qdesc );
3232- qdesc -> nargs = argc ;
3233- qdesc -> argtypes = (Oid * ) malloc (argc * sizeof (Oid ));
3234- qdesc -> arginfuncs = (FmgrInfo * ) malloc (argc * sizeof (FmgrInfo ));
3235- qdesc -> argtypioparams = (Oid * ) malloc (argc * sizeof (Oid ));
3236-
32373228 PG_TRY ();
32383229 {
3230+ CHECK_FOR_INTERRUPTS ();
3231+
3232+ /************************************************************
3233+ * Allocate the new querydesc structure
3234+ *
3235+ * The qdesc struct, as well as all its subsidiary data, lives in its
3236+ * plan_cxt. But note that the SPIPlan does not.
3237+ ************************************************************/
3238+ plan_cxt = AllocSetContextCreate (TopMemoryContext ,
3239+ "PL/Perl spi_prepare query" ,
3240+ ALLOCSET_SMALL_MINSIZE ,
3241+ ALLOCSET_SMALL_INITSIZE ,
3242+ ALLOCSET_SMALL_MAXSIZE );
3243+ MemoryContextSwitchTo (plan_cxt );
3244+ qdesc = (plperl_query_desc * ) palloc0 (sizeof (plperl_query_desc ));
3245+ snprintf (qdesc -> qname , sizeof (qdesc -> qname ), "%p" , qdesc );
3246+ qdesc -> plan_cxt = plan_cxt ;
3247+ qdesc -> nargs = argc ;
3248+ qdesc -> argtypes = (Oid * ) palloc (argc * sizeof (Oid ));
3249+ qdesc -> arginfuncs = (FmgrInfo * ) palloc (argc * sizeof (FmgrInfo ));
3250+ qdesc -> argtypioparams = (Oid * ) palloc (argc * sizeof (Oid ));
3251+ MemoryContextSwitchTo (oldcontext );
3252+
3253+ /************************************************************
3254+ * Do the following work in a short-lived context so that we don't
3255+ * leak a lot of memory in the PL/Perl function's SPI Proc context.
3256+ ************************************************************/
3257+ work_cxt = AllocSetContextCreate (CurrentMemoryContext ,
3258+ "PL/Perl spi_prepare workspace" ,
3259+ ALLOCSET_DEFAULT_MINSIZE ,
3260+ ALLOCSET_DEFAULT_INITSIZE ,
3261+ ALLOCSET_DEFAULT_MAXSIZE );
3262+ MemoryContextSwitchTo (work_cxt );
3263+
32393264 /************************************************************
32403265 * Resolve argument type names and then look them up by oid
32413266 * in the system cache, and remember the required information
@@ -3256,7 +3281,7 @@ plperl_spi_prepare(char *query, int argc, SV **argv)
32563281 getTypeInputInfo (typId , & typInput , & typIOParam );
32573282
32583283 qdesc -> argtypes [i ] = typId ;
3259- perm_fmgr_info (typInput , & (qdesc -> arginfuncs [i ]));
3284+ fmgr_info_cxt (typInput , & (qdesc -> arginfuncs [i ]), plan_cxt );
32603285 qdesc -> argtypioparams [i ] = typIOParam ;
32613286 }
32623287
@@ -3280,6 +3305,17 @@ plperl_spi_prepare(char *query, int argc, SV **argv)
32803305 elog (ERROR , "SPI_keepplan() failed" );
32813306 qdesc -> plan = plan ;
32823307
3308+ /************************************************************
3309+ * Insert a hashtable entry for the plan.
3310+ ************************************************************/
3311+ hash_entry = hash_search (plperl_active_interp -> query_hash ,
3312+ qdesc -> qname ,
3313+ HASH_ENTER , & found );
3314+ hash_entry -> query_data = qdesc ;
3315+
3316+ /* Get rid of workspace */
3317+ MemoryContextDelete (work_cxt );
3318+
32833319 /* Commit the inner transaction, return to outer xact context */
32843320 ReleaseCurrentSubTransaction ();
32853321 MemoryContextSwitchTo (oldcontext );
@@ -3295,16 +3331,21 @@ plperl_spi_prepare(char *query, int argc, SV **argv)
32953331 {
32963332 ErrorData * edata ;
32973333
3298- free (qdesc -> argtypes );
3299- free (qdesc -> arginfuncs );
3300- free (qdesc -> argtypioparams );
3301- free (qdesc );
3302-
33033334 /* Save error info */
33043335 MemoryContextSwitchTo (oldcontext );
33053336 edata = CopyErrorData ();
33063337 FlushErrorState ();
33073338
3339+ /* Drop anything we managed to allocate */
3340+ if (hash_entry )
3341+ hash_search (plperl_active_interp -> query_hash ,
3342+ qdesc -> qname ,
3343+ HASH_REMOVE , NULL );
3344+ if (plan_cxt )
3345+ MemoryContextDelete (plan_cxt );
3346+ if (plan )
3347+ SPI_freeplan (plan );
3348+
33083349 /* Abort the inner transaction */
33093350 RollbackAndReleaseCurrentSubTransaction ();
33103351 MemoryContextSwitchTo (oldcontext );
@@ -3326,14 +3367,8 @@ plperl_spi_prepare(char *query, int argc, SV **argv)
33263367 PG_END_TRY ();
33273368
33283369 /************************************************************
3329- * Insert a hashtable entry for the plan and return
3330- * the key to the caller.
3370+ * Return the query's hash key to the caller.
33313371 ************************************************************/
3332-
3333- hash_entry = hash_search (plperl_active_interp -> query_hash , qdesc -> qname ,
3334- HASH_ENTER , & found );
3335- hash_entry -> query_data = qdesc ;
3336-
33373372 return cstr2sv (qdesc -> qname );
33383373}
33393374
@@ -3368,16 +3403,14 @@ plperl_spi_exec_prepared(char *query, HV *attr, int argc, SV **argv)
33683403 /************************************************************
33693404 * Fetch the saved plan descriptor, see if it's o.k.
33703405 ************************************************************/
3371-
33723406 hash_entry = hash_search (plperl_active_interp -> query_hash , query ,
33733407 HASH_FIND , NULL );
33743408 if (hash_entry == NULL )
33753409 elog (ERROR , "spi_exec_prepared: Invalid prepared query passed" );
33763410
33773411 qdesc = hash_entry -> query_data ;
3378-
33793412 if (qdesc == NULL )
3380- elog (ERROR , "spi_exec_prepared: panic - plperl query_hash value vanished" );
3413+ elog (ERROR , "spi_exec_prepared: plperl query_hash value vanished" );
33813414
33823415 if (qdesc -> nargs != argc )
33833416 elog (ERROR , "spi_exec_prepared: expected %d argument(s), %d passed" ,
@@ -3509,12 +3542,11 @@ plperl_spi_query_prepared(char *query, int argc, SV **argv)
35093542 hash_entry = hash_search (plperl_active_interp -> query_hash , query ,
35103543 HASH_FIND , NULL );
35113544 if (hash_entry == NULL )
3512- elog (ERROR , "spi_exec_prepared : Invalid prepared query passed" );
3545+ elog (ERROR , "spi_query_prepared : Invalid prepared query passed" );
35133546
35143547 qdesc = hash_entry -> query_data ;
3515-
35163548 if (qdesc == NULL )
3517- elog (ERROR , "spi_query_prepared: panic - plperl query_hash value vanished" );
3549+ elog (ERROR , "spi_query_prepared: plperl query_hash value vanished" );
35183550
35193551 if (qdesc -> nargs != argc )
35203552 elog (ERROR , "spi_query_prepared: expected %d argument(s), %d passed" ,
@@ -3619,12 +3651,12 @@ plperl_spi_freeplan(char *query)
36193651 hash_entry = hash_search (plperl_active_interp -> query_hash , query ,
36203652 HASH_FIND , NULL );
36213653 if (hash_entry == NULL )
3622- elog (ERROR , "spi_exec_prepared : Invalid prepared query passed" );
3654+ elog (ERROR , "spi_freeplan : Invalid prepared query passed" );
36233655
36243656 qdesc = hash_entry -> query_data ;
3625-
36263657 if (qdesc == NULL )
3627- elog (ERROR , "spi_exec_freeplan: panic - plperl query_hash value vanished" );
3658+ elog (ERROR , "spi_freeplan: plperl query_hash value vanished" );
3659+ plan = qdesc -> plan ;
36283660
36293661 /*
36303662 * free all memory before SPI_freeplan, so if it dies, nothing will be
@@ -3633,11 +3665,7 @@ plperl_spi_freeplan(char *query)
36333665 hash_search (plperl_active_interp -> query_hash , query ,
36343666 HASH_REMOVE , NULL );
36353667
3636- plan = qdesc -> plan ;
3637- free (qdesc -> argtypes );
3638- free (qdesc -> arginfuncs );
3639- free (qdesc -> argtypioparams );
3640- free (qdesc );
3668+ MemoryContextDelete (qdesc -> plan_cxt );
36413669
36423670 SPI_freeplan (plan );
36433671}
0 commit comments