@@ -130,7 +130,8 @@ static dlist_head *changesStack = NULL;
130130static MemoryContext changesStackContext = NULL ;
131131
132132/*
133- * List to store all the running hash_seq_search scan for hash table.
133+ * List to store all the running hash_seq_search, variable and package scan for
134+ * hash table.
134135 *
135136 * NOTE: In function variable_select we use hash_seq_search to find next tuple.
136137 * So, in case user do not get all the data from set at once (use cursors or
@@ -143,10 +144,116 @@ static MemoryContext changesStackContext = NULL;
143144 * TopTransactionContext is handy here, becouse it wount be reset by the time
144145 * pgvTransCallback is called.
145146 */
146- static List * variables_stats = NIL ;
147+ static List * variables_stats = NIL ;
147148static List * packages_stats = NIL ;
148149
149- static void freeStatsLists (bool deep );
150+ typedef struct tagHtabToStat {
151+ HTAB * hash ;
152+ HASH_SEQ_STATUS * status ;
153+ Variable * variable ;
154+ Package * package ;
155+ }HtabToStat ;
156+
157+ /*
158+ * A bunch of comp functions for HtabToStat members here.
159+ */
160+ static bool
161+ HtabToStat_status_eq (HtabToStat * entry ,void * value )
162+ {
163+ return entry -> status == (HASH_SEQ_STATUS * )value ;
164+ }
165+
166+ static bool
167+ HtabToStat_variable_eq (HtabToStat * entry ,void * value )
168+ {
169+ return entry -> variable == (Variable * )value ;
170+ }
171+
172+ static bool
173+ HtabToStat_package_eq (HtabToStat * entry ,void * value )
174+ {
175+ return entry -> package == (Package * )value ;
176+ }
177+
178+ static bool
179+ HtabToStat_eq_all (HtabToStat * entry ,void * value )
180+ {
181+ return true;
182+ }
183+
184+ /*
185+ * Generic remove_if algorithm for HtabToStat.
186+ *
187+ * + eq if function pointer used to compare list entry to the value.
188+ * + if match_first is true return on first match.
189+ */
190+ static void
191+ HtabToStat_remove_if (List * * l ,void * value ,
192+ bool (* eq )(HtabToStat * ,void * ),
193+ bool match_first )
194+ {
195+ ListCell * cell ,* next ,* prev = NULL ;
196+ HtabToStat * entry = NULL ;
197+
198+ for (cell = list_head (* l );cell ;cell = next )
199+ {
200+ entry = (HtabToStat * )lfirst (cell );
201+ next = lnext (cell );
202+
203+ if (eq (entry ,value ))
204+ {
205+ * l = list_delete_cell (* l ,cell ,prev );
206+ pfree (entry -> status );
207+ pfree (entry );
208+
209+ if (match_first )
210+ return ;
211+ }
212+ else
213+ {
214+ prev = cell ;
215+ }
216+ }
217+ }
218+
219+ /*
220+ * Remove first entry for status.
221+ */
222+ static void
223+ remove_variables_status (List * * l ,HASH_SEQ_STATUS * status )
224+ {
225+ HtabToStat_remove_if (l ,status ,HtabToStat_status_eq , true);
226+ }
227+
228+ /*
229+ * Remove first entry for variable.
230+ */
231+ static void
232+ remove_variables_variable (List * * l ,Variable * variable )
233+ {
234+ HtabToStat_remove_if (l ,variable ,HtabToStat_variable_eq , true);
235+ }
236+
237+ /*
238+ * Remove all the entrys for package.
239+ */
240+ static void
241+ remove_variables_package (List * * l ,Package * package )
242+ {
243+ HtabToStat_remove_if (l ,package ,HtabToStat_package_eq , false);
244+ }
245+
246+ /*
247+ * Remove all.
248+ */
249+ static void
250+ remove_variables_all (List * * l )
251+ {
252+ HtabToStat_remove_if (l ,NULL ,HtabToStat_eq_all , false);
253+ * l = NIL ;
254+ }
255+
256+ static void freeStatsLists (void );
150257/* Returns a lists of packages and variables changed at current subxact level */
151258#define get_actual_changes_list () \
152259( \
@@ -632,6 +739,7 @@ variable_select(PG_FUNCTION_ARGS)
632739{
633740MemoryContext oldcontext ;
634741RecordVar * record ;
742+ HtabToStat * htab_to_stat ;
635743
636744record = & (GetActualValue (variable ).record );
637745funcctx = SRF_FIRSTCALL_INIT ();
@@ -644,7 +752,12 @@ variable_select(PG_FUNCTION_ARGS)
644752hash_seq_init (rstat ,record -> rhash );
645753funcctx -> user_fctx = rstat ;
646754
647- variables_stats = lcons ((void * )rstat ,variables_stats );
755+ htab_to_stat = palloc0 (sizeof (HtabToStat ));
756+ htab_to_stat -> hash = record -> rhash ;
757+ htab_to_stat -> status = rstat ;
758+ htab_to_stat -> variable = variable ;
759+ htab_to_stat -> package = package ;
760+ variables_stats = lcons ((void * )htab_to_stat ,variables_stats );
648761
649762MemoryContextSwitchTo (oldcontext );
650763PG_FREE_IF_COPY (package_name ,0 );
@@ -665,8 +778,7 @@ variable_select(PG_FUNCTION_ARGS)
665778}
666779else
667780{
668- variables_stats = list_delete (variables_stats ,rstat );
669- pfree (rstat );
781+ remove_variables_status (& variables_stats ,rstat );
670782SRF_RETURN_DONE (funcctx );
671783}
672784}
@@ -968,6 +1080,8 @@ remove_package(PG_FUNCTION_ARGS)
9681080
9691081resetVariablesCache ();
9701082
1083+ remove_variables_package (& variables_stats ,package );
1084+
9711085PG_FREE_IF_COPY (package_name ,0 );
9721086PG_RETURN_VOID ();
9731087}
@@ -1063,6 +1177,7 @@ remove_packages(PG_FUNCTION_ARGS)
10631177}
10641178
10651179resetVariablesCache ();
1180+ remove_variables_all (& variables_stats );
10661181
10671182PG_RETURN_VOID ();
10681183}
@@ -1317,7 +1432,7 @@ get_packages_stats(PG_FUNCTION_ARGS)
13171432else
13181433{
13191434packages_stats = list_delete (packages_stats ,rstat );
1320- pfree (rstat );
1435+ // pfree(rstat);
13211436SRF_RETURN_DONE (funcctx );
13221437}
13231438}
@@ -1777,6 +1892,7 @@ removeObject(TransObject *object, TransObjectType type)
17771892
17781893/* Remove object from hash table */
17791894hash_search (hash ,object -> name ,HASH_REMOVE ,& found );
1895+ remove_variables_variable (& variables_stats , (Variable * )object );
17801896
17811897/* Remove package if it became empty */
17821898if (type == TRANS_VARIABLE && isPackageEmpty (package ))
@@ -2227,7 +2343,7 @@ pgvTransCallback(XactEvent event, void *arg)
22272343}
22282344
22292345if (event == XACT_EVENT_PRE_COMMIT || event == XACT_EVENT_ABORT )
2230- freeStatsLists (true );
2346+ freeStatsLists ();
22312347}
22322348
22332349/*
@@ -2241,25 +2357,23 @@ variable_ExecutorEnd(QueryDesc *queryDesc)
22412357else
22422358standard_ExecutorEnd (queryDesc );
22432359
2244- freeStatsLists (false );
2360+ freeStatsLists ();
22452361}
22462362
22472363/*
22482364 * Free hash_seq_search scans
22492365 */
2250- void
2251- freeStatsLists (bool deep )
2366+ static void
2367+ freeStatsLists (void )
22522368{
22532369ListCell * cell ;
22542370HASH_SEQ_STATUS * status ;
2371+ HtabToStat * htab_to_stat ;
22552372
22562373foreach (cell ,variables_stats )
22572374{
2258- status = (HASH_SEQ_STATUS * )lfirst (cell );
2259- hash_seq_term (status );
2260-
2261- if (deep )
2262- pfree (status );
2375+ htab_to_stat = (HtabToStat * )lfirst (cell );
2376+ hash_seq_term (htab_to_stat -> status );
22632377}
22642378
22652379variables_stats = NIL ;
@@ -2268,8 +2382,6 @@ freeStatsLists(bool deep)
22682382{
22692383status = (HASH_SEQ_STATUS * )lfirst (cell );
22702384hash_seq_term (status );
2271-
2272- pfree (status );
22732385}
22742386
22752387packages_stats = NIL ;