Skip to content

Commit 2b5fd99

Browse files
committed
[PGPRO-7614] Fix error caused by unchanged package state's ATX-level at autonomous transaction commit
Tags: pg_variables, atx
1 parent 9873756 commit 2b5fd99

File tree

4 files changed

+120
-17
lines changed

4 files changed

+120
-17
lines changed

expected/pg_variables_atx_pkg.out

+33-1
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ ERROR: unrecognized package "test"
345345
ROLLBACK;
346346
--
347347
--
348-
-- Test for case: pgv_set() created regular a variable; rollback
348+
-- Test for case: pgv_set() created a regular variable; rollback
349349
-- removes package state and creates a new state to make package valid.
350350
-- Commit of next autonomous transaction should not replace this new
351351
-- state (this is not allowed for autonomous transaction).
@@ -374,6 +374,38 @@ SELECT pgv_remove('vars', 'int1');
374374

375375
(1 row)
376376

377+
--
378+
--
379+
-- Test for case: pgv_set() created a regular variable and package with
380+
-- (atxlevel=1, level=1). COMMIT changes this level to (atxlevel=1, level=0).
381+
-- In the next autonomous transaction (atxlevel=1, level=1) we erroneously
382+
-- detect that the package changed in upper transaction and remove the
383+
-- package state (this is not allowed for autonomous transaction).
384+
--
385+
BEGIN;
386+
BEGIN AUTONOMOUS;
387+
SELECT pgv_set('vars', 'int1', 2);
388+
pgv_set
389+
---------
390+
391+
(1 row)
392+
393+
COMMIT;
394+
BEGIN AUTONOMOUS;
395+
SELECT pgv_free();
396+
pgv_free
397+
----------
398+
399+
(1 row)
400+
401+
SELECT pgv_set('vars', 'int1', 2, true);
402+
pgv_set
403+
---------
404+
405+
(1 row)
406+
407+
COMMIT;
408+
ROLLBACK;
377409
SELECT pgv_free();
378410
pgv_free
379411
----------

expected/pg_variables_atx_pkg_1.out

+37-1
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ ROLLBACK;
377377
WARNING: there is no transaction in progress
378378
--
379379
--
380-
-- Test for case: pgv_set() created regular a variable; rollback
380+
-- Test for case: pgv_set() created a regular variable; rollback
381381
-- removes package state and creates a new state to make package valid.
382382
-- Commit of next autonomous transaction should not replace this new
383383
-- state (this is not allowed for autonomous transaction).
@@ -410,6 +410,42 @@ SELECT pgv_remove('vars', 'int1');
410410

411411
(1 row)
412412

413+
--
414+
--
415+
-- Test for case: pgv_set() created a regular variable and package with
416+
-- (atxlevel=1, level=1). COMMIT changes this level to (atxlevel=1, level=0).
417+
-- In the next autonomous transaction (atxlevel=1, level=1) we erroneously
418+
-- detect that the package changed in upper transaction and remove the
419+
-- package state (this is not allowed for autonomous transaction).
420+
--
421+
BEGIN;
422+
BEGIN AUTONOMOUS;
423+
ERROR: syntax error at or near "AUTONOMOUS"
424+
LINE 1: BEGIN AUTONOMOUS;
425+
^
426+
SELECT pgv_set('vars', 'int1', 2);
427+
ERROR: current transaction is aborted, commands ignored until end of transaction block
428+
COMMIT;
429+
BEGIN AUTONOMOUS;
430+
ERROR: syntax error at or near "AUTONOMOUS"
431+
LINE 1: BEGIN AUTONOMOUS;
432+
^
433+
SELECT pgv_free();
434+
pgv_free
435+
----------
436+
437+
(1 row)
438+
439+
SELECT pgv_set('vars', 'int1', 2, true);
440+
pgv_set
441+
---------
442+
443+
(1 row)
444+
445+
COMMIT;
446+
WARNING: there is no transaction in progress
447+
ROLLBACK;
448+
WARNING: there is no transaction in progress
413449
SELECT pgv_free();
414450
pgv_free
415451
----------

pg_variables.c

+32-14
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ static void resetVariablesCache(void);
6464

6565
/* Functions to work with transactional objects */
6666
static void createSavepoint(TransObject *object, TransObjectType type);
67-
static void releaseSavepoint(TransObject *object, TransObjectType type);
67+
static void releaseSavepoint(TransObject *object, TransObjectType type, bool sub);
6868
static void rollbackSavepoint(TransObject *object, TransObjectType type);
6969

7070
static void copyValue(VarState *src, VarState *dest, Variable *destVar);
@@ -2408,11 +2408,14 @@ rollbackSavepoint(TransObject *object, TransObjectType type)
24082408
* Remove previous state of object
24092409
*/
24102410
static void
2411-
releaseSavepoint(TransObject *object, TransObjectType type)
2411+
releaseSavepoint(TransObject *object, TransObjectType type, bool sub)
24122412
{
24132413
dlist_head *states = &object->states;
24142414

24152415
Assert(GetActualState(object)->levels.level == GetCurrentTransactionNestLevel());
2416+
#ifdef PGPRO_EE
2417+
Assert(GetActualState(object)->levels.atxlevel == getNestLevelATX());
2418+
#endif
24162419

24172420
/*
24182421
* If the object is not valid and does not exist at a higher level (or if
@@ -2438,6 +2441,15 @@ releaseSavepoint(TransObject *object, TransObjectType type)
24382441

24392442
nodeToDelete = dlist_next_node(states, dlist_head_node(states));
24402443
stateToDelete = dlist_container(TransState, node, nodeToDelete);
2444+
#ifdef PGPRO_EE
2445+
/*
2446+
* We can not delete package state inside autonomous transaction
2447+
* because the state can be used in pgvRestoreContext().
2448+
* Exception: the state was created within this autonomous transaction.
2449+
*/
2450+
Assert(type != TRANS_PACKAGE || getNestLevelATX() == 0 ||
2451+
stateToDelete->levels.atxlevel == getNestLevelATX());
2452+
#endif
24412453
removeState(object, type, stateToDelete);
24422454
}
24432455

@@ -2450,6 +2462,12 @@ releaseSavepoint(TransObject *object, TransObjectType type)
24502462

24512463
/* Change subxact level due to release */
24522464
GetActualState(object)->levels.level--;
2465+
2466+
#ifdef PGPRO_EE
2467+
/* Change ATX level due to finish autonomous transaction */
2468+
if (!sub && getNestLevelATX() > 0)
2469+
GetActualState(object)->levels.atxlevel = 0;
2470+
#endif
24532471
}
24542472

24552473
static void
@@ -2647,7 +2665,7 @@ typedef enum Action
26472665
* Apply savepoint actions on list of variables or packages.
26482666
*/
26492667
static void
2650-
applyAction(Action action, TransObjectType type, dlist_head *list)
2668+
applyAction(Action action, TransObjectType type, dlist_head *list, bool sub)
26512669
{
26522670
dlist_iter iter;
26532671

@@ -2677,7 +2695,7 @@ applyAction(Action action, TransObjectType type, dlist_head *list)
26772695
GetActualState(variable)->is_valid = false;
26782696
}
26792697

2680-
releaseSavepoint(object, type);
2698+
releaseSavepoint(object, type, sub);
26812699
break;
26822700
}
26832701
}
@@ -2688,7 +2706,7 @@ applyAction(Action action, TransObjectType type, dlist_head *list)
26882706
* apply corresponding action on them
26892707
*/
26902708
static void
2691-
processChanges(Action action)
2709+
processChanges(Action action, bool sub)
26922710
{
26932711
ChangesStackNode *bottom_list;
26942712

@@ -2697,8 +2715,8 @@ processChanges(Action action)
26972715
bottom_list = dlist_container(ChangesStackNode, node,
26982716
dlist_pop_head_node(changesStack));
26992717

2700-
applyAction(action, TRANS_VARIABLE, bottom_list->changedVarsList);
2701-
applyAction(action, TRANS_PACKAGE, bottom_list->changedPacksList);
2718+
applyAction(action, TRANS_VARIABLE, bottom_list->changedVarsList, sub);
2719+
applyAction(action, TRANS_PACKAGE, bottom_list->changedPacksList, sub);
27022720

27032721
/* Remove changes list of current level */
27042722
MemoryContextDelete(bottom_list->ctx);
@@ -2866,10 +2884,10 @@ pgvRestoreContext()
28662884
/* Remove all package states, generated in ATX transaction */
28672885
while ((state = GetActualState(object)) != context->state)
28682886
{
2887+
removeState(object, TRANS_PACKAGE, state);
28692888
if (dlist_is_empty(&object->states))
28702889
elog(ERROR, "pg_variables extension can not find "
28712890
"transaction state for package");
2872-
removeState(object, TRANS_PACKAGE, state);
28732891
}
28742892

28752893
/*
@@ -2935,10 +2953,10 @@ pgvSubTransCallback(SubXactEvent event, SubTransactionId mySubid,
29352953
compatibility_check();
29362954
break;
29372955
case SUBXACT_EVENT_COMMIT_SUB:
2938-
processChanges(RELEASE_SAVEPOINT);
2956+
processChanges(RELEASE_SAVEPOINT, true);
29392957
break;
29402958
case SUBXACT_EVENT_ABORT_SUB:
2941-
processChanges(ROLLBACK_TO_SAVEPOINT);
2959+
processChanges(ROLLBACK_TO_SAVEPOINT, true);
29422960
break;
29432961
case SUBXACT_EVENT_PRE_COMMIT_SUB:
29442962
break;
@@ -2965,16 +2983,16 @@ pgvTransCallback(XactEvent event, void *arg)
29652983
{
29662984
case XACT_EVENT_PRE_COMMIT:
29672985
compatibility_check();
2968-
processChanges(RELEASE_SAVEPOINT);
2986+
processChanges(RELEASE_SAVEPOINT, false);
29692987
break;
29702988
case XACT_EVENT_ABORT:
2971-
processChanges(ROLLBACK_TO_SAVEPOINT);
2989+
processChanges(ROLLBACK_TO_SAVEPOINT, false);
29722990
break;
29732991
case XACT_EVENT_PARALLEL_PRE_COMMIT:
2974-
processChanges(RELEASE_SAVEPOINT);
2992+
processChanges(RELEASE_SAVEPOINT, false);
29752993
break;
29762994
case XACT_EVENT_PARALLEL_ABORT:
2977-
processChanges(ROLLBACK_TO_SAVEPOINT);
2995+
processChanges(ROLLBACK_TO_SAVEPOINT, false);
29782996
break;
29792997
default:
29802998
break;

sql/pg_variables_atx_pkg.sql

+18-1
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ BEGIN;
168168
ROLLBACK;
169169
--
170170
--
171-
-- Test for case: pgv_set() created regular a variable; rollback
171+
-- Test for case: pgv_set() created a regular variable; rollback
172172
-- removes package state and creates a new state to make package valid.
173173
-- Commit of next autonomous transaction should not replace this new
174174
-- state (this is not allowed for autonomous transaction).
@@ -182,5 +182,22 @@ BEGIN;
182182
COMMIT;
183183
ROLLBACK;
184184
SELECT pgv_remove('vars', 'int1');
185+
--
186+
--
187+
-- Test for case: pgv_set() created a regular variable and package with
188+
-- (atxlevel=1, level=1). COMMIT changes this level to (atxlevel=1, level=0).
189+
-- In the next autonomous transaction (atxlevel=1, level=1) we erroneously
190+
-- detect that the package changed in upper transaction and remove the
191+
-- package state (this is not allowed for autonomous transaction).
192+
--
193+
BEGIN;
194+
BEGIN AUTONOMOUS;
195+
SELECT pgv_set('vars', 'int1', 2);
196+
COMMIT;
197+
BEGIN AUTONOMOUS;
198+
SELECT pgv_free();
199+
SELECT pgv_set('vars', 'int1', 2, true);
200+
COMMIT;
201+
ROLLBACK;
185202

186203
SELECT pgv_free();

0 commit comments

Comments
 (0)