diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml index 812c07e500f..9a5b7eeb4a8 100644 --- a/doc/src/sgml/protocol.sgml +++ b/doc/src/sgml/protocol.sgml @@ -1088,16 +1088,17 @@ SELCT 1/0; If the client has not issued an explicit BEGIN, - then each Sync ordinarily causes an implicit COMMIT - if the preceding step(s) succeeded, or an - implicit ROLLBACK if they failed. However, there - are a few DDL commands (such as CREATE DATABASE) - that cannot be executed inside a transaction block. If one of - these is executed in a pipeline, it will fail unless it is the first - command in the pipeline. Furthermore, upon success it will force an - immediate commit to preserve database consistency. Thus a Sync - immediately following one of these commands has no effect except to - respond with ReadyForQuery. + then an implicit transaction block is started and each Sync ordinarily + causes an implicit COMMIT if the preceding step(s) + succeeded, or an implicit ROLLBACK if they failed. + This implicit transaction block will only be detected by the server + when the first command ends without a sync. There are a few DDL + commands (such as CREATE DATABASE) that cannot be + executed inside a transaction block. If one of these is executed in a + pipeline, it will fail unless it is the first command after a Sync. + Furthermore, upon success it will force an immediate commit to preserve + database consistency. Thus a Sync immediately following one of these + commands has no effect except to respond with ReadyForQuery. diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index ffe26e26f66..423545e6038 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -3405,16 +3405,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? */ @@ -3526,9 +3516,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 ec630b44916..d375d845b97 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -2656,6 +2656,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 @@ -4605,6 +4616,13 @@ PostgresMain(int argc, char *argv[], case 'S': /* 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(); send_ready_for_query = true; break;