From b0db6011b23fcad02a4c5d76df0e1ddc4831399b Mon Sep 17 00:00:00 2001 From: "okbob@github.com" Date: Mon, 8 Dec 2025 05:00:12 +0100 Subject: [PATCH 11/11] subtransaction support for session variables DDL (CREATE, DROP) --- src/backend/access/transam/xact.c | 4 + src/backend/commands/session_variable.c | 109 ++++++++++++++++++ src/include/commands/session_variable.h | 3 + .../expected/session_variables_ddl.out | 21 ++++ .../regress/sql/session_variables_ddl.sql | 12 ++ 5 files changed, 149 insertions(+) diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 8a80e9c00af..57ee8da6d1f 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -5208,6 +5208,8 @@ CommitSubTransaction(void) AtEOSubXact_SPI(true, s->subTransactionId); AtEOSubXact_on_commit_actions(true, s->subTransactionId, s->parent->subTransactionId); + AtEOSubXact_SessionVariables(true, s->subTransactionId, + s->parent->subTransactionId); AtEOSubXact_Namespace(true, s->subTransactionId, s->parent->subTransactionId); AtEOSubXact_Files(true, s->subTransactionId, @@ -5377,6 +5379,8 @@ AbortSubTransaction(void) AtEOSubXact_SPI(false, s->subTransactionId); AtEOSubXact_on_commit_actions(false, s->subTransactionId, s->parent->subTransactionId); + AtEOSubXact_SessionVariables(false, s->subTransactionId, + s->parent->subTransactionId); AtEOSubXact_Namespace(false, s->subTransactionId, s->parent->subTransactionId); AtEOSubXact_Files(false, s->subTransactionId, diff --git a/src/backend/commands/session_variable.c b/src/backend/commands/session_variable.c index 28dd23172f6..a27a91c2362 100644 --- a/src/backend/commands/session_variable.c +++ b/src/backend/commands/session_variable.c @@ -14,6 +14,7 @@ */ #include "postgres.h" +#include "access/xact.h" #include "catalog/pg_language.h" #include "commands/session_variable.h" #include "executor/executor.h" @@ -59,6 +60,8 @@ typedef struct SVariableData bool stacked; LocalTransactionId created_lxid; LocalTransactionId dropped_lxid; + SubTransactionId created_subid; + SubTransactionId dropped_subid; } SVariableData; typedef SVariableData *SVariable; @@ -349,6 +352,8 @@ CreateVariable(ParseState *pstate, CreateSessionVarStmt *stmt) svar->stacked = false; svar->dropped_lxid = InvalidLocalTransactionId; svar->created_lxid = MyProc->vxid.lxid; + svar->dropped_subid = InvalidSubTransactionId; + svar->created_subid = GetCurrentSubTransactionId(); created_or_dropped_lxid = MyProc->vxid.lxid; } @@ -385,6 +390,7 @@ DropVariableByName(DropSessionVarStmt *stmt) stmt->name))); svar->dropped_lxid = MyProc->vxid.lxid; + svar->dropped_subid = GetCurrentSubTransactionId(); created_or_dropped_lxid = MyProc->vxid.lxid; } @@ -454,6 +460,7 @@ AtPreEOXact_SessionVariables(bool isCommit) free_stacked_svars(svar->prev); svar->prev = NULL; svar->created_lxid = InvalidLocalTransactionId; + svar->created_subid = InvalidSubTransactionId; } } else @@ -500,6 +507,7 @@ AtPreEOXact_SessionVariables(bool isCommit) /* revert dropped flag */ svar->dropped_lxid = InvalidLocalTransactionId; + svar->dropped_subid = InvalidSubTransactionId; } } } @@ -509,6 +517,107 @@ AtPreEOXact_SessionVariables(bool isCommit) } } +/* + * Post-subcommit or post-subabort cleanup + * + * During subabort, we can immediately remove entries created during this + * subtransaction. During subcommit, just transfer entries marked during + * this subtransaction as being the parent's responsibility. + */ +void +AtEOSubXact_SessionVariables(bool isCommit, + SubTransactionId mySubid, + SubTransactionId parentSubid) +{ + if (created_or_dropped_lxid != InvalidLocalTransactionId) + { + HASH_SEQ_STATUS status; + SVariable svar; + + Assert(created_or_dropped_lxid == MyProc->vxid.lxid); + Assert(sessionvars); + + hash_seq_init(&status, sessionvars); + + while ((svar = (SVariable) hash_seq_search(&status)) != NULL) + { + if ((svar->dropped_lxid != InvalidLocalTransactionId) || + (svar->created_lxid != InvalidLocalTransactionId)) + { + if (!isCommit) + { + SVariable iterator = svar; + SVariable last = NULL; + SVariable first = NULL; + + /* remove entries or flags by current subtransactions */ + while (iterator) + { + SVariable current = iterator; + + iterator = current->prev; + + if (current->dropped_subid == mySubid) + { + current->dropped_lxid = InvalidLocalTransactionId; + current->dropped_subid = InvalidSubTransactionId; + } + + if (current->created_subid == mySubid) + { + free_svar_value(current); + if (current->stacked) + pfree(current); + } + else + { + /* remember first not deleted svar */ + if (first == NULL) + first = current; + + if (last) + last->prev = current; + + last = current; + } + } + + /* Some svars was removed - set hashtab entry or remove it */ + if (!first) + { + /* we have to remove entry from hash table */ + (void) hash_search(sessionvars, + NameStr(svar->varname), + HASH_REMOVE, + NULL); + } + else if (first->stacked) + { + memcpy(svar, first, sizeof(SVariableData)); + svar->stacked = false; + pfree(first); + } + } + else + { + SVariable iterator = svar; + + /* transfer responsibility to parent */ + while (iterator) + { + if (iterator->dropped_subid == mySubid) + iterator->dropped_subid = parentSubid; + if (iterator->created_subid == mySubid) + iterator->created_subid = parentSubid; + + iterator = iterator->prev; + } + } + } + } + } +} + /* * Assign the result of the evaluated expression to the session variable */ diff --git a/src/include/commands/session_variable.h b/src/include/commands/session_variable.h index 1218c566767..45ccbe2f046 100644 --- a/src/include/commands/session_variable.h +++ b/src/include/commands/session_variable.h @@ -40,5 +40,8 @@ extern void ExecuteLetStmt(ParseState *pstate, LetStmt *stmt, ParamListInfo para extern void ResetSessionVariables(void); extern void AtPreEOXact_SessionVariables(bool isCommit); +extern void AtEOSubXact_SessionVariables(bool isCommit, + SubTransactionId mySubid, + SubTransactionId parentSubid); #endif diff --git a/src/test/regress/expected/session_variables_ddl.out b/src/test/regress/expected/session_variables_ddl.out index c10680512ce..af8e0b51444 100644 --- a/src/test/regress/expected/session_variables_ddl.out +++ b/src/test/regress/expected/session_variables_ddl.out @@ -107,4 +107,25 @@ SELECT VARIABLE(x); Hi (1 row) +BEGIN; +SAVEPOINT s1; +DROP VARIABLE x; +CREATE TEMP VARIABLE x AS varchar; +DROP VARIABLE x; +CREATE TEMP VARIABLE x AS varchar; +LET x = 'Hello'; +SELECT VARIABLE(x); + x +------- + Hello +(1 row) + +ROLLBACK TO s1; +SELECT VARIABLE(x); + x +---- + Hi +(1 row) + +COMMIT; DROP VARIABLE x; diff --git a/src/test/regress/sql/session_variables_ddl.sql b/src/test/regress/sql/session_variables_ddl.sql index 9e79feed92b..a522eb95b54 100644 --- a/src/test/regress/sql/session_variables_ddl.sql +++ b/src/test/regress/sql/session_variables_ddl.sql @@ -98,4 +98,16 @@ SELECT VARIABLE(x); ROLLBACK; SELECT VARIABLE(x); +BEGIN; +SAVEPOINT s1; +DROP VARIABLE x; +CREATE TEMP VARIABLE x AS varchar; +DROP VARIABLE x; +CREATE TEMP VARIABLE x AS varchar; +LET x = 'Hello'; +SELECT VARIABLE(x); +ROLLBACK TO s1; +SELECT VARIABLE(x); +COMMIT; + DROP VARIABLE x; -- 2.52.0