@@ -184,6 +184,7 @@ typedef struct plperl_call_data
184184typedef struct plperl_query_desc
185185{
186186char qname [24 ];
187+ MemoryContext plan_cxt ;/* context holding this struct */
187188SPIPlanPtr plan ;
188189int nargs ;
189190Oid * 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 ;
32183217MemoryContext oldcontext = CurrentMemoryContext ;
32193218ResourceOwner oldowner = CurrentResourceOwner ;
3219+ MemoryContext work_cxt ;
3220+ bool found ;
3221+ int i ;
32203222
32213223check_spi_usage_allowed ();
32223224
32233225BeginInternalSubTransaction (NULL );
32243226MemoryContextSwitchTo (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-
32373228PG_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)
32563281getTypeInputInfo (typId ,& typInput ,& typIOParam );
32573282
32583283qdesc -> argtypes [i ]= typId ;
3259- perm_fmgr_info (typInput ,& (qdesc -> arginfuncs [i ]));
3284+ fmgr_info_cxt (typInput ,& (qdesc -> arginfuncs [i ]), plan_cxt );
32603285qdesc -> argtypioparams [i ]= typIOParam ;
32613286}
32623287
@@ -3280,6 +3305,17 @@ plperl_spi_prepare(char *query, int argc, SV **argv)
32803305elog (ERROR ,"SPI_keepplan() failed" );
32813306qdesc -> 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 */
32843320ReleaseCurrentSubTransaction ();
32853321MemoryContextSwitchTo (oldcontext );
@@ -3295,16 +3331,21 @@ plperl_spi_prepare(char *query, int argc, SV **argv)
32953331{
32963332ErrorData * edata ;
32973333
3298- free (qdesc -> argtypes );
3299- free (qdesc -> arginfuncs );
3300- free (qdesc -> argtypioparams );
3301- free (qdesc );
3302-
33033334/* Save error info */
33043335MemoryContextSwitchTo (oldcontext );
33053336edata = CopyErrorData ();
33063337FlushErrorState ();
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 */
33093350RollbackAndReleaseCurrentSubTransaction ();
33103351MemoryContextSwitchTo (oldcontext );
@@ -3326,14 +3367,8 @@ plperl_spi_prepare(char *query, int argc, SV **argv)
33263367PG_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-
33373372return 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-
33723406hash_entry = hash_search (plperl_active_interp -> query_hash ,query ,
33733407HASH_FIND ,NULL );
33743408if (hash_entry == NULL )
33753409elog (ERROR ,"spi_exec_prepared: Invalid prepared query passed" );
33763410
33773411qdesc = hash_entry -> query_data ;
3378-
33793412if (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
33823415if (qdesc -> nargs != argc )
33833416elog (ERROR ,"spi_exec_prepared: expected %d argument(s), %d passed" ,
@@ -3509,12 +3542,11 @@ plperl_spi_query_prepared(char *query, int argc, SV **argv)
35093542hash_entry = hash_search (plperl_active_interp -> query_hash ,query ,
35103543HASH_FIND ,NULL );
35113544if (hash_entry == NULL )
3512- elog (ERROR ,"spi_exec_prepared : Invalid prepared query passed" );
3545+ elog (ERROR ,"spi_query_prepared : Invalid prepared query passed" );
35133546
35143547qdesc = hash_entry -> query_data ;
3515-
35163548if (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
35193551if (qdesc -> nargs != argc )
35203552elog (ERROR ,"spi_query_prepared: expected %d argument(s), %d passed" ,
@@ -3619,12 +3651,12 @@ plperl_spi_freeplan(char *query)
36193651hash_entry = hash_search (plperl_active_interp -> query_hash ,query ,
36203652HASH_FIND ,NULL );
36213653if (hash_entry == NULL )
3622- elog (ERROR ,"spi_exec_prepared : Invalid prepared query passed" );
3654+ elog (ERROR ,"spi_freeplan : Invalid prepared query passed" );
36233655
36243656qdesc = hash_entry -> query_data ;
3625-
36263657if (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)
36333665hash_search (plperl_active_interp -> query_hash ,query ,
36343666HASH_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
36423670SPI_freeplan (plan );
36433671}