@@ -166,12 +166,14 @@ typedef struct tagVariableStatEntry
166
166
Variable * variable ;
167
167
Package * package ;
168
168
Levels levels ;
169
+ void * * user_fctx ; /* pointer to funcctx->user_fctx */
169
170
} VariableStatEntry ;
170
171
171
172
typedef struct tagPackageStatEntry
172
173
{
173
174
HASH_SEQ_STATUS * status ;
174
175
Levels levels ;
176
+ void * * user_fctx ; /* pointer to funcctx->user_fctx */
175
177
} PackageStatEntry ;
176
178
177
179
#ifdef PGPRO_EE
@@ -268,6 +270,25 @@ PackageStatEntry_status_ptr(void *entry)
268
270
return ((PackageStatEntry * ) entry )-> status ;
269
271
}
270
272
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
+
271
292
/*
272
293
* Generic remove_if algorithm.
273
294
*
@@ -289,6 +310,7 @@ typedef struct tagRemoveIfContext
289
310
HASH_SEQ_STATUS * (* getter ) (void * ); /* status getter */
290
311
bool match_first ; /* return on first match */
291
312
bool term ; /* hash_seq_term on match */
313
+ void (* clear_fctx ) (void * ); /* clear function context */
292
314
} RemoveIfContext ;
293
315
294
316
static void
@@ -316,6 +338,8 @@ list_remove_if(RemoveIfContext ctx)
316
338
hash_seq_term (ctx .getter (entry ));
317
339
#endif
318
340
341
+ ctx .clear_fctx (entry );
342
+
319
343
pfree (ctx .getter (entry ));
320
344
pfree (entry );
321
345
@@ -352,6 +376,8 @@ list_remove_if(RemoveIfContext ctx)
352
376
hash_seq_term (ctx .getter (entry ));
353
377
#endif
354
378
379
+ ctx .clear_fctx (entry );
380
+
355
381
pfree (ctx .getter (entry ));
356
382
pfree (entry );
357
383
@@ -375,7 +401,8 @@ remove_variables_status(List **list, HASH_SEQ_STATUS *status)
375
401
.eq = VariableStatEntry_status_eq ,
376
402
.getter = VariableStatEntry_status_ptr ,
377
403
.match_first = true,
378
- .term = false
404
+ .term = false,
405
+ .clear_fctx = VariableStatEntry_clear_fctx
379
406
};
380
407
381
408
list_remove_if (ctx );
@@ -398,7 +425,8 @@ remove_variables_variable(List **list, Variable *variable)
398
425
.eq = VariableStatEntry_variable_eq ,
399
426
.getter = VariableStatEntry_status_ptr ,
400
427
.match_first = false,
401
- .term = true
428
+ .term = true,
429
+ .clear_fctx = VariableStatEntry_clear_fctx
402
430
};
403
431
404
432
list_remove_if (ctx );
@@ -417,7 +445,8 @@ remove_variables_package(List **list, Package *package)
417
445
.eq = VariableStatEntry_package_eq ,
418
446
.getter = VariableStatEntry_status_ptr ,
419
447
.match_first = false,
420
- .term = true
448
+ .term = true,
449
+ .clear_fctx = VariableStatEntry_clear_fctx
421
450
};
422
451
423
452
list_remove_if (ctx );
@@ -436,7 +465,8 @@ remove_variables_level(List **list, Levels *levels)
436
465
.eq = VariableStatEntry_level_eq ,
437
466
.getter = VariableStatEntry_status_ptr ,
438
467
.match_first = false,
439
- .term = false
468
+ .term = false,
469
+ .clear_fctx = VariableStatEntry_clear_fctx
440
470
};
441
471
442
472
list_remove_if (ctx );
@@ -455,7 +485,8 @@ remove_variables_all(List **list)
455
485
.eq = VariableStatEntry_eq_all ,
456
486
.getter = VariableStatEntry_status_ptr ,
457
487
.match_first = false,
458
- .term = true
488
+ .term = true,
489
+ .clear_fctx = VariableStatEntry_clear_fctx
459
490
};
460
491
461
492
list_remove_if (ctx );
@@ -474,7 +505,8 @@ remove_packages_status(List **list, HASH_SEQ_STATUS *status)
474
505
.eq = PackageStatEntry_status_eq ,
475
506
.getter = PackageStatEntry_status_ptr ,
476
507
.match_first = true,
477
- .term = false
508
+ .term = false,
509
+ .clear_fctx = PackageStatEntry_clear_fctx
478
510
};
479
511
480
512
list_remove_if (ctx );
@@ -493,7 +525,8 @@ remove_packages_level(List **list, Levels *levels)
493
525
.eq = PackageStatEntry_level_eq ,
494
526
.getter = PackageStatEntry_status_ptr ,
495
527
.match_first = false,
496
- .term = true
528
+ .term = true,
529
+ .clear_fctx = PackageStatEntry_clear_fctx
497
530
};
498
531
499
532
list_remove_if (ctx );
@@ -513,7 +546,8 @@ remove_variables_transactional(List **list)
513
546
.eq = VariableStatEntry_is_transactional ,
514
547
.getter = VariableStatEntry_status_ptr ,
515
548
.match_first = false,
516
- .term = true
549
+ .term = true,
550
+ .clear_fctx = VariableStatEntry_clear_fctx
517
551
};
518
552
519
553
list_remove_if (ctx );
@@ -1027,6 +1061,7 @@ variable_select(PG_FUNCTION_ARGS)
1027
1061
#ifdef PGPRO_EE
1028
1062
entry -> levels .atxlevel = getNestLevelATX ();
1029
1063
#endif
1064
+ entry -> user_fctx = & funcctx -> user_fctx ;
1030
1065
variables_stats = lcons ((void * ) entry , variables_stats );
1031
1066
1032
1067
MemoryContextSwitchTo (oldcontext );
@@ -1036,6 +1071,15 @@ variable_select(PG_FUNCTION_ARGS)
1036
1071
1037
1072
funcctx = SRF_PERCALL_SETUP ();
1038
1073
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
+
1039
1083
/* Get next hash record */
1040
1084
rstat = (HASH_SEQ_STATUS * ) funcctx -> user_fctx ;
1041
1085
item = (HashRecordEntry * ) hash_seq_search (rstat );
@@ -1672,6 +1716,7 @@ get_packages_stats(PG_FUNCTION_ARGS)
1672
1716
#ifdef PGPRO_EE
1673
1717
entry -> levels .atxlevel = getNestLevelATX ();
1674
1718
#endif
1719
+ entry -> user_fctx = & funcctx -> user_fctx ;
1675
1720
packages_stats = lcons ((void * ) entry , packages_stats );
1676
1721
MemoryContextSwitchTo (ctx );
1677
1722
}
0 commit comments