@@ -180,6 +180,7 @@ typedef struct plperl_call_data
180
180
typedef struct plperl_query_desc
181
181
{
182
182
char qname [24 ];
183
+ MemoryContext plan_cxt ; /* context holding this struct */
183
184
void * plan ;
184
185
int nargs ;
185
186
Oid * argtypes ;
@@ -2716,33 +2717,57 @@ plperl_spi_cursor_close(char *cursor)
2716
2717
SV *
2717
2718
plperl_spi_prepare (char * query , int argc , SV * * argv )
2718
2719
{
2719
- plperl_query_desc * qdesc ;
2720
- plperl_query_entry * hash_entry ;
2721
- bool found ;
2722
- void * plan ;
2723
- int i ;
2724
-
2720
+ void * volatile plan = NULL ;
2721
+ volatile MemoryContext plan_cxt = NULL ;
2722
+ plperl_query_desc * volatile qdesc = NULL ;
2723
+ plperl_query_entry * volatile hash_entry = NULL ;
2725
2724
MemoryContext oldcontext = CurrentMemoryContext ;
2726
2725
ResourceOwner oldowner = CurrentResourceOwner ;
2726
+ MemoryContext work_cxt;
2727
+ bool found ;
2728
+ int i ;
2727
2729
2728
2730
check_spi_usage_allowed ();
2729
2731
2730
2732
BeginInternalSubTransaction (NULL );
2731
2733
MemoryContextSwitchTo (oldcontext );
2732
2734
2733
- /************************************************************
2734
- * Allocate the new querydesc structure
2735
- ************************************************************/
2736
- qdesc = (plperl_query_desc * ) malloc (sizeof (plperl_query_desc ));
2737
- MemSet (qdesc , 0 , sizeof (plperl_query_desc ));
2738
- snprintf (qdesc -> qname , sizeof (qdesc -> qname ), "%p" , qdesc );
2739
- qdesc -> nargs = argc ;
2740
- qdesc -> argtypes = (Oid * ) malloc (argc * sizeof (Oid ));
2741
- qdesc -> arginfuncs = (FmgrInfo * ) malloc (argc * sizeof (FmgrInfo ));
2742
- qdesc -> argtypioparams = (Oid * ) malloc (argc * sizeof (Oid ));
2743
-
2744
2735
PG_TRY ();
2745
2736
{
2737
+ CHECK_FOR_INTERRUPTS ();
2738
+
2739
+ /************************************************************
2740
+ * Allocate the new querydesc structure
2741
+ *
2742
+ * The qdesc struct, as well as all its subsidiary data, lives in its
2743
+ * plan_cxt. But note that the SPIPlan does not.
2744
+ ************************************************************/
2745
+ plan_cxt = AllocSetContextCreate (TopMemoryContext ,
2746
+ "PL/Perl spi_prepare query" ,
2747
+ ALLOCSET_SMALL_MINSIZE ,
2748
+ ALLOCSET_SMALL_INITSIZE ,
2749
+ ALLOCSET_SMALL_MAXSIZE );
2750
+ MemoryContextSwitchTo (plan_cxt );
2751
+ qdesc = (plperl_query_desc * ) palloc0 (sizeof (plperl_query_desc ));
2752
+ snprintf (qdesc -> qname , sizeof (qdesc -> qname ), "%p" , qdesc );
2753
+ qdesc -> plan_cxt = plan_cxt ;
2754
+ qdesc -> nargs = argc ;
2755
+ qdesc -> argtypes = (Oid * ) palloc (argc * sizeof (Oid ));
2756
+ qdesc -> arginfuncs = (FmgrInfo * ) palloc (argc * sizeof (FmgrInfo ));
2757
+ qdesc -> argtypioparams = (Oid * ) palloc (argc * sizeof (Oid ));
2758
+ MemoryContextSwitchTo (oldcontext );
2759
+
2760
+ /************************************************************
2761
+ * Do the following work in a short-lived context so that we don't
2762
+ * leak a lot of memory in the PL/Perl function's SPI Proc context.
2763
+ ************************************************************/
2764
+ work_cxt = AllocSetContextCreate (CurrentMemoryContext ,
2765
+ "PL/Perl spi_prepare workspace" ,
2766
+ ALLOCSET_DEFAULT_MINSIZE ,
2767
+ ALLOCSET_DEFAULT_INITSIZE ,
2768
+ ALLOCSET_DEFAULT_MAXSIZE );
2769
+ MemoryContextSwitchTo (work_cxt );
2770
+
2746
2771
/************************************************************
2747
2772
* Resolve argument type names and then look them up by oid
2748
2773
* in the system cache, and remember the required information
@@ -2760,7 +2785,7 @@ plperl_spi_prepare(char *query, int argc, SV **argv)
2760
2785
getTypeInputInfo (typId , & typInput , & typIOParam );
2761
2786
2762
2787
qdesc -> argtypes [i ] = typId ;
2763
- perm_fmgr_info (typInput , & (qdesc -> arginfuncs [i ]));
2788
+ fmgr_info_cxt (typInput , & (qdesc -> arginfuncs [i ]), plan_cxt );
2764
2789
qdesc -> argtypioparams [i ] = typIOParam ;
2765
2790
}
2766
2791
@@ -2788,6 +2813,17 @@ plperl_spi_prepare(char *query, int argc, SV **argv)
2788
2813
/* Release the procCxt copy to avoid within-function memory leak */
2789
2814
SPI_freeplan (plan );
2790
2815
2816
+ /************************************************************
2817
+ * Insert a hashtable entry for the plan.
2818
+ ************************************************************/
2819
+ hash_entry = hash_search (plperl_active_interp -> query_hash ,
2820
+ qdesc -> qname ,
2821
+ HASH_ENTER , & found );
2822
+ hash_entry -> query_data = qdesc ;
2823
+
2824
+ /* Get rid of workspace */
2825
+ MemoryContextDelete (work_cxt );
2826
+
2791
2827
/* Commit the inner transaction, return to outer xact context */
2792
2828
ReleaseCurrentSubTransaction ();
2793
2829
MemoryContextSwitchTo (oldcontext );
@@ -2803,16 +2839,21 @@ plperl_spi_prepare(char *query, int argc, SV **argv)
2803
2839
{
2804
2840
ErrorData * edata ;
2805
2841
2806
- free (qdesc -> argtypes );
2807
- free (qdesc -> arginfuncs );
2808
- free (qdesc -> argtypioparams );
2809
- free (qdesc );
2810
-
2811
2842
/* Save error info */
2812
2843
MemoryContextSwitchTo (oldcontext );
2813
2844
edata = CopyErrorData ();
2814
2845
FlushErrorState ();
2815
2846
2847
+ /* Drop anything we managed to allocate */
2848
+ if (hash_entry )
2849
+ hash_search (plperl_active_interp -> query_hash ,
2850
+ qdesc -> qname ,
2851
+ HASH_REMOVE , NULL );
2852
+ if (plan_cxt )
2853
+ MemoryContextDelete (plan_cxt );
2854
+ if (plan )
2855
+ SPI_freeplan (plan );
2856
+
2816
2857
/* Abort the inner transaction */
2817
2858
RollbackAndReleaseCurrentSubTransaction ();
2818
2859
MemoryContextSwitchTo (oldcontext );
@@ -2834,14 +2875,8 @@ plperl_spi_prepare(char *query, int argc, SV **argv)
2834
2875
PG_END_TRY ();
2835
2876
2836
2877
/************************************************************
2837
- * Insert a hashtable entry for the plan and return
2838
- * the key to the caller.
2878
+ * Return the query's hash key to the caller.
2839
2879
************************************************************/
2840
-
2841
- hash_entry = hash_search (plperl_active_interp -> query_hash , qdesc -> qname ,
2842
- HASH_ENTER , & found );
2843
- hash_entry -> query_data = qdesc ;
2844
-
2845
2880
return newSVstring (qdesc -> qname );
2846
2881
}
2847
2882
@@ -2876,16 +2911,14 @@ plperl_spi_exec_prepared(char *query, HV *attr, int argc, SV **argv)
2876
2911
/************************************************************
2877
2912
* Fetch the saved plan descriptor, see if it's o.k.
2878
2913
************************************************************/
2879
-
2880
2914
hash_entry = hash_search (plperl_active_interp -> query_hash , query ,
2881
2915
HASH_FIND , NULL );
2882
2916
if (hash_entry == NULL )
2883
2917
elog (ERROR , "spi_exec_prepared: Invalid prepared query passed" );
2884
2918
2885
2919
qdesc = hash_entry -> query_data ;
2886
-
2887
2920
if (qdesc == NULL )
2888
- elog (ERROR , "spi_exec_prepared: panic - plperl query_hash value vanished" );
2921
+ elog (ERROR , "spi_exec_prepared: plperl query_hash value vanished" );
2889
2922
2890
2923
if (qdesc -> nargs != argc )
2891
2924
elog (ERROR , "spi_exec_prepared: expected %d argument(s), %d passed" ,
@@ -3023,12 +3056,11 @@ plperl_spi_query_prepared(char *query, int argc, SV **argv)
3023
3056
hash_entry = hash_search (plperl_active_interp -> query_hash , query ,
3024
3057
HASH_FIND , NULL );
3025
3058
if (hash_entry == NULL )
3026
- elog (ERROR , "spi_exec_prepared : Invalid prepared query passed" );
3059
+ elog (ERROR , "spi_query_prepared : Invalid prepared query passed" );
3027
3060
3028
3061
qdesc = hash_entry -> query_data ;
3029
-
3030
3062
if (qdesc == NULL )
3031
- elog (ERROR , "spi_query_prepared: panic - plperl query_hash value vanished" );
3063
+ elog (ERROR , "spi_query_prepared: plperl query_hash value vanished" );
3032
3064
3033
3065
if (qdesc -> nargs != argc )
3034
3066
elog (ERROR , "spi_query_prepared: expected %d argument(s), %d passed" ,
@@ -3139,12 +3171,12 @@ plperl_spi_freeplan(char *query)
3139
3171
hash_entry = hash_search (plperl_active_interp -> query_hash , query ,
3140
3172
HASH_FIND , NULL );
3141
3173
if (hash_entry == NULL )
3142
- elog (ERROR , "spi_exec_prepared : Invalid prepared query passed" );
3174
+ elog (ERROR , "spi_freeplan : Invalid prepared query passed" );
3143
3175
3144
3176
qdesc = hash_entry -> query_data ;
3145
-
3146
3177
if (qdesc == NULL )
3147
- elog (ERROR , "spi_exec_freeplan: panic - plperl query_hash value vanished" );
3178
+ elog (ERROR , "spi_freeplan: plperl query_hash value vanished" );
3179
+ plan = qdesc -> plan ;
3148
3180
3149
3181
/*
3150
3182
* free all memory before SPI_freeplan, so if it dies, nothing will be
@@ -3153,11 +3185,7 @@ plperl_spi_freeplan(char *query)
3153
3185
hash_search (plperl_active_interp -> query_hash , query ,
3154
3186
HASH_REMOVE , NULL );
3155
3187
3156
- plan = qdesc -> plan ;
3157
- free (qdesc -> argtypes );
3158
- free (qdesc -> arginfuncs );
3159
- free (qdesc -> argtypioparams );
3160
- free (qdesc );
3188
+ MemoryContextDelete (qdesc -> plan_cxt );
3161
3189
3162
3190
SPI_freeplan (plan );
3163
3191
}
0 commit comments