Skip to content

Commit afdef54

Browse files
committed
[PGPRO-7614] Fix crash by using cursor after rollback of cursor creation
Tags: pg_variables
1 parent 02d5dac commit afdef54

File tree

4 files changed

+171
-8
lines changed

4 files changed

+171
-8
lines changed

expected/pg_variables_trans.out

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3834,3 +3834,51 @@ SELECT pgv_free();
38343834
--
38353835
SELECT pgv_insert('test', 'x5', ROW ((2::int, 1::int)), TRUE);
38363836
ERROR: could not identify a hash function for type record
3837+
--
3838+
-- Test case for PGPRO-7614: crash by using cursor after rollback of cursor
3839+
-- creation.
3840+
--
3841+
BEGIN;
3842+
SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), true);
3843+
pgv_insert
3844+
------------
3845+
3846+
(1 row)
3847+
3848+
DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x');
3849+
SAVEPOINT sp1;
3850+
FETCH 1 in r1_cur;
3851+
pgv_select
3852+
------------
3853+
(1,2)
3854+
(1 row)
3855+
3856+
ROLLBACK TO SAVEPOINT sp1;
3857+
FETCH 1 in r1_cur;
3858+
pgv_select
3859+
------------
3860+
(0 rows)
3861+
3862+
ROLLBACK;
3863+
BEGIN;
3864+
SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE);
3865+
pgv_insert
3866+
------------
3867+
3868+
(1 row)
3869+
3870+
DECLARE r1_cur CURSOR FOR SELECT pgv_stats();
3871+
SAVEPOINT sp1;
3872+
FETCH 1 in r1_cur;
3873+
pgv_stats
3874+
--------------
3875+
(test,32768)
3876+
(1 row)
3877+
3878+
ROLLBACK TO SAVEPOINT sp1;
3879+
FETCH 1 in r1_cur;
3880+
pgv_stats
3881+
-----------
3882+
(0 rows)
3883+
3884+
ROLLBACK;

expected/pg_variables_trans_0.out

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3838,3 +3838,51 @@ SELECT pgv_insert('test', 'x5', ROW ((2::int, 1::int)), TRUE);
38383838

38393839
(1 row)
38403840

3841+
--
3842+
-- Test case for PGPRO-7614: crash by using cursor after rollback of cursor
3843+
-- creation.
3844+
--
3845+
BEGIN;
3846+
SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), true);
3847+
pgv_insert
3848+
------------
3849+
3850+
(1 row)
3851+
3852+
DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x');
3853+
SAVEPOINT sp1;
3854+
FETCH 1 in r1_cur;
3855+
pgv_select
3856+
------------
3857+
(1,2)
3858+
(1 row)
3859+
3860+
ROLLBACK TO SAVEPOINT sp1;
3861+
FETCH 1 in r1_cur;
3862+
pgv_select
3863+
------------
3864+
(0 rows)
3865+
3866+
ROLLBACK;
3867+
BEGIN;
3868+
SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE);
3869+
pgv_insert
3870+
------------
3871+
3872+
(1 row)
3873+
3874+
DECLARE r1_cur CURSOR FOR SELECT pgv_stats();
3875+
SAVEPOINT sp1;
3876+
FETCH 1 in r1_cur;
3877+
pgv_stats
3878+
--------------
3879+
(test,32768)
3880+
(1 row)
3881+
3882+
ROLLBACK TO SAVEPOINT sp1;
3883+
FETCH 1 in r1_cur;
3884+
pgv_stats
3885+
-----------
3886+
(0 rows)
3887+
3888+
ROLLBACK;

pg_variables.c

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -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

171172
typedef 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

294316
static 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
}

sql/pg_variables_trans.sql

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,3 +1169,25 @@ SELECT pgv_free();
11691169
-- Test case for issue #38 [PGPRO-4676]
11701170
--
11711171
SELECT pgv_insert('test', 'x5', ROW ((2::int, 1::int)), TRUE);
1172+
1173+
--
1174+
-- Test case for PGPRO-7614: crash by using cursor after rollback of cursor
1175+
-- creation.
1176+
--
1177+
BEGIN;
1178+
SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), true);
1179+
DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x');
1180+
SAVEPOINT sp1;
1181+
FETCH 1 in r1_cur;
1182+
ROLLBACK TO SAVEPOINT sp1;
1183+
FETCH 1 in r1_cur;
1184+
ROLLBACK;
1185+
1186+
BEGIN;
1187+
SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE);
1188+
DECLARE r1_cur CURSOR FOR SELECT pgv_stats();
1189+
SAVEPOINT sp1;
1190+
FETCH 1 in r1_cur;
1191+
ROLLBACK TO SAVEPOINT sp1;
1192+
FETCH 1 in r1_cur;
1193+
ROLLBACK;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy