From d4a2749f61525b87d9d9b2d8877f1a8c15656097 Mon Sep 17 00:00:00 2001 From: Anthonin Bonnefoy Date: Wed, 30 Oct 2024 09:11:30 +0100 Subject: Consider pipeline implicit transaction as a transaction block When using pipeline with implicit transaction, a transaction will start from the first command and be committed with the Sync message. Functions like IsInTransactionBlock and PreventInTransactionBlock already assimilate this implicit transaction as a transaction block. However, this is not the case in CheckTransactionBlock. This function is called for things like warning when set local is used outside of a transaction block. This patch changes the transaction state to an implicit transaction block when a new command is processed while pipelining was detected. This remove the need to check for XACT_FLAGS_PIPELINING in IsInTransactionBlock and PreventInTransactionBlock since the transaction state now reflects the ongoing transaction block. This allows to avoid warning when `set local` is called within a pipeline, and makes the detection of transaction block coherent with what's done in IsInTransactionBlock and PreventInTransactionBlock. A known limitation of this patch: the first command won't be detected as part of a transaction block. The implicit block only starts at the second command so the `set local` warnings will still happen if called first. --- src/backend/access/transam/xact.c | 13 ------------- src/backend/tcop/postgres.c | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 004f7e10e55..c83f72cd18a 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -3665,16 +3665,6 @@ PreventInTransactionBlock(bool isTopLevel, const char *stmtType) errmsg("%s cannot run inside a subtransaction", stmtType))); - /* - * inside a pipeline that has started an implicit transaction? - */ - if (MyXactFlags & XACT_FLAGS_PIPELINING) - ereport(ERROR, - (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION), - /* translator: %s represents an SQL statement name */ - errmsg("%s cannot be executed within a pipeline", - stmtType))); - /* * inside a function call? */ @@ -3786,9 +3776,6 @@ IsInTransactionBlock(bool isTopLevel) if (IsSubTransaction()) return true; - if (MyXactFlags & XACT_FLAGS_PIPELINING) - return true; - if (!isTopLevel) return true; diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 8cc23a9cef8..098f9599041 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -2780,6 +2780,17 @@ start_xact_command(void) xact_started = true; } + else if (MyXactFlags & XACT_FLAGS_PIPELINING) + { + /* + * When the first Execute message is completed, following commands + * will be done in an implicit transaction block created via + * pipelining. The transaction state needs to be updated to an + * implicit block if we're not already in a transaction block (like + * one started by an explicit BEGIN). + */ + BeginImplicitTransactionBlock(); + } /* * Start statement timeout if necessary. Note that this'll intentionally @@ -4985,6 +4996,13 @@ PostgresMain(const char *dbname, const char *username) case PqMsg_Sync: pq_getmsgend(&input_message); + + /* + * If pipelining was used, we may be in an implicit + * transaction block. Close it before calling + * finish_xact_command. + */ + EndImplicitTransactionBlock(); finish_xact_command(); valgrind_report_error_query("SYNC message"); send_ready_for_query = true; -- 2.39.5 (Apple Git-154)