@@ -166,12 +166,14 @@ typedef struct tagVariableStatEntry
166166 Variable * variable ;
167167 Package * package ;
168168 Levels levels ;
169+ void * * user_fctx ; /* pointer to funcctx->user_fctx */
169170} VariableStatEntry ;
170171
171172typedef struct tagPackageStatEntry
172173{
173174 HASH_SEQ_STATUS * status ;
174175 Levels levels ;
176+ void * * user_fctx ; /* pointer to funcctx->user_fctx */
175177} PackageStatEntry ;
176178
177179#ifdef PGPRO_EE
@@ -268,6 +270,25 @@ PackageStatEntry_status_ptr(void *entry)
268270 return ((PackageStatEntry * ) entry )-> status ;
269271}
270272
273+ /*
274+ * VariableStatEntry and PackageStatEntry functions for clear function context.
275+ */
276+ static void
277+ VariableStatEntry_clear_fctx (void * entry )
278+ {
279+ VariableStatEntry * e = (VariableStatEntry * ) entry ;
280+ if (e -> user_fctx )
281+ * e -> user_fctx = NULL ;
282+ }
283+
284+ static void
285+ PackageStatEntry_clear_fctx (void * entry )
286+ {
287+ PackageStatEntry * e = (PackageStatEntry * ) entry ;
288+ if (e -> user_fctx )
289+ * e -> user_fctx = NULL ;
290+ }
291+
271292/*
272293 * Generic remove_if algorithm.
273294 *
@@ -289,6 +310,7 @@ typedef struct tagRemoveIfContext
289310 HASH_SEQ_STATUS * (* getter ) (void * ); /* status getter */
290311 bool match_first ; /* return on first match */
291312 bool term ; /* hash_seq_term on match */
313+ void (* clear_fctx ) (void * ); /* clear function context */
292314} RemoveIfContext ;
293315
294316static void
@@ -316,6 +338,8 @@ list_remove_if(RemoveIfContext ctx)
316338 hash_seq_term (ctx .getter (entry ));
317339#endif
318340
341+ ctx .clear_fctx (entry );
342+
319343 pfree (ctx .getter (entry ));
320344 pfree (entry );
321345
@@ -352,6 +376,8 @@ list_remove_if(RemoveIfContext ctx)
352376 hash_seq_term (ctx .getter (entry ));
353377#endif
354378
379+ ctx .clear_fctx (entry );
380+
355381 pfree (ctx .getter (entry ));
356382 pfree (entry );
357383
@@ -375,7 +401,8 @@ remove_variables_status(List **list, HASH_SEQ_STATUS *status)
375401 .eq = VariableStatEntry_status_eq ,
376402 .getter = VariableStatEntry_status_ptr ,
377403 .match_first = true,
378- .term = false
404+ .term = false,
405+ .clear_fctx = VariableStatEntry_clear_fctx
379406 };
380407
381408 list_remove_if (ctx );
@@ -398,7 +425,8 @@ remove_variables_variable(List **list, Variable *variable)
398425 .eq = VariableStatEntry_variable_eq ,
399426 .getter = VariableStatEntry_status_ptr ,
400427 .match_first = false,
401- .term = true
428+ .term = true,
429+ .clear_fctx = VariableStatEntry_clear_fctx
402430 };
403431
404432 list_remove_if (ctx );
@@ -417,7 +445,8 @@ remove_variables_package(List **list, Package *package)
417445 .eq = VariableStatEntry_package_eq ,
418446 .getter = VariableStatEntry_status_ptr ,
419447 .match_first = false,
420- .term = true
448+ .term = true,
449+ .clear_fctx = VariableStatEntry_clear_fctx
421450 };
422451
423452 list_remove_if (ctx );
@@ -436,7 +465,8 @@ remove_variables_level(List **list, Levels *levels)
436465 .eq = VariableStatEntry_level_eq ,
437466 .getter = VariableStatEntry_status_ptr ,
438467 .match_first = false,
439- .term = false
468+ .term = false,
469+ .clear_fctx = VariableStatEntry_clear_fctx
440470 };
441471
442472 list_remove_if (ctx );
@@ -455,7 +485,8 @@ remove_variables_all(List **list)
455485 .eq = VariableStatEntry_eq_all ,
456486 .getter = VariableStatEntry_status_ptr ,
457487 .match_first = false,
458- .term = true
488+ .term = true,
489+ .clear_fctx = VariableStatEntry_clear_fctx
459490 };
460491
461492 list_remove_if (ctx );
@@ -474,7 +505,8 @@ remove_packages_status(List **list, HASH_SEQ_STATUS *status)
474505 .eq = PackageStatEntry_status_eq ,
475506 .getter = PackageStatEntry_status_ptr ,
476507 .match_first = true,
477- .term = false
508+ .term = false,
509+ .clear_fctx = PackageStatEntry_clear_fctx
478510 };
479511
480512 list_remove_if (ctx );
@@ -493,7 +525,8 @@ remove_packages_level(List **list, Levels *levels)
493525 .eq = PackageStatEntry_level_eq ,
494526 .getter = PackageStatEntry_status_ptr ,
495527 .match_first = false,
496- .term = true
528+ .term = true,
529+ .clear_fctx = PackageStatEntry_clear_fctx
497530 };
498531
499532 list_remove_if (ctx );
@@ -513,7 +546,8 @@ remove_variables_transactional(List **list)
513546 .eq = VariableStatEntry_is_transactional ,
514547 .getter = VariableStatEntry_status_ptr ,
515548 .match_first = false,
516- .term = true
549+ .term = true,
550+ .clear_fctx = VariableStatEntry_clear_fctx
517551 };
518552
519553 list_remove_if (ctx );
@@ -1027,6 +1061,7 @@ variable_select(PG_FUNCTION_ARGS)
10271061#ifdef PGPRO_EE
10281062 entry -> levels .atxlevel = getNestLevelATX ();
10291063#endif
1064+ entry -> user_fctx = & funcctx -> user_fctx ;
10301065 variables_stats = lcons ((void * ) entry , variables_stats );
10311066
10321067 MemoryContextSwitchTo (oldcontext );
@@ -1036,6 +1071,15 @@ variable_select(PG_FUNCTION_ARGS)
10361071
10371072 funcctx = SRF_PERCALL_SETUP ();
10381073
1074+ if (funcctx -> user_fctx == NULL )
1075+ {
1076+ /*
1077+ * VariableStatEntry was removed. For example, after call
1078+ * 'ROLLBACK TO SAVEPOINT ...'
1079+ */
1080+ SRF_RETURN_DONE (funcctx );
1081+ }
1082+
10391083 /* Get next hash record */
10401084 rstat = (HASH_SEQ_STATUS * ) funcctx -> user_fctx ;
10411085 item = (HashRecordEntry * ) hash_seq_search (rstat );
@@ -1672,6 +1716,7 @@ get_packages_stats(PG_FUNCTION_ARGS)
16721716#ifdef PGPRO_EE
16731717 entry -> levels .atxlevel = getNestLevelATX ();
16741718#endif
1719+ entry -> user_fctx = & funcctx -> user_fctx ;
16751720 packages_stats = lcons ((void * ) entry , packages_stats );
16761721 MemoryContextSwitchTo (ctx );
16771722 }
0 commit comments