v20251208-0011-subtransaction-support-for-session-variables-DDL-CRE.patch
application/x-patch
Filename: v20251208-0011-subtransaction-support-for-session-variables-DDL-CRE.patch
Type: application/x-patch
Part: 10
Message:
Re: proposal: schema variables
From e23aed26916a01079639d37c6bdc4e0e16d9f417 Mon Sep 17 00:00:00 2001
From: "okbob@github.com" <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 36e243b3ed5..09f3ffa7b20 100644
--- a/src/backend/commands/session_variable.c
+++ b/src/backend/commands/session_variable.c
@@ -15,6 +15,7 @@
#include "postgres.h"
#include "access/htup_details.h"
+#include "access/xact.h"
#include "catalog/pg_language.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
@@ -64,6 +65,8 @@ typedef struct SVariableData
bool stacked;
LocalTransactionId created_lxid;
LocalTransactionId dropped_lxid;
+ SubTransactionId created_subid;
+ SubTransactionId dropped_subid;
} SVariableData;
typedef SVariableData *SVariable;
@@ -372,6 +375,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;
}
@@ -408,6 +413,7 @@ DropVariableByName(DropSessionVarStmt *stmt)
stmt->name)));
svar->dropped_lxid = MyProc->vxid.lxid;
+ svar->dropped_subid = GetCurrentSubTransactionId();
created_or_dropped_lxid = MyProc->vxid.lxid;
}
@@ -477,6 +483,7 @@ AtPreEOXact_SessionVariables(bool isCommit)
free_stacked_svars(svar->prev);
svar->prev = NULL;
svar->created_lxid = InvalidLocalTransactionId;
+ svar->created_subid = InvalidSubTransactionId;
}
}
else
@@ -523,6 +530,7 @@ AtPreEOXact_SessionVariables(bool isCommit)
/* revert dropped flag */
svar->dropped_lxid = InvalidLocalTransactionId;
+ svar->dropped_subid = InvalidSubTransactionId;
}
}
}
@@ -532,6 +540,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