diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml index b0fea8f5d5d..5a3d6fdb5a3 100644 --- a/doc/src/sgml/protocol.sgml +++ b/doc/src/sgml/protocol.sgml @@ -1070,17 +1070,16 @@ SELCT 1/0; If the client has not issued an explicit BEGIN, - 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. + 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. diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index ed83cc493b8..4cecf630060 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -3603,6 +3603,16 @@ 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? */ @@ -3714,6 +3724,9 @@ 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 147baaa054c..a750dc800b6 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -2775,17 +2775,6 @@ 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 @@ -4971,13 +4960,6 @@ 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; diff --git a/src/bin/pgbench/t/001_pgbench_with_server.pl b/src/bin/pgbench/t/001_pgbench_with_server.pl index 0bc5c0042eb..956e290f3ef 100644 --- a/src/bin/pgbench/t/001_pgbench_with_server.pl +++ b/src/bin/pgbench/t/001_pgbench_with_server.pl @@ -968,180 +968,6 @@ $node->pgbench( } }); -# Try SET LOCAL as first pipeline command. This succeeds and the first -# command is not executed inside an implicit transaction block, causing -# a WARNING. -$node->pgbench( - '-t 1 -n -M extended', - 0, - [], - [qr{WARNING: SET LOCAL can only be used in transaction blocks}], - 'SET LOCAL outside implicit transaction block of pipeline', - { - '001_pgbench_pipeline_set_local_1' => q{ -\startpipeline -SET LOCAL statement_timeout='1h'; -\endpipeline -} - }); - -# Try SET LOCAL as second pipeline command. This succeeds and the second -# command does not cause a WARNING to be generated. -$node->pgbench( - '-t 1 -n -M extended', - 0, - [], - [qr{^$}], - 'SET LOCAL inside implicit transaction block of pipeline', - { - '001_pgbench_pipeline_set_local_2' => q{ -\startpipeline -SELECT 1; -SET LOCAL statement_timeout='1h'; -\endpipeline -} - }); - -# Try SET LOCAL with \syncpipeline. This succeeds and the command -# launched after the sync is outside the implicit transaction block -# of the pipeline, causing a WARNING. -$node->pgbench( - '-t 1 -n -M extended', - 0, - [], - [qr{WARNING: SET LOCAL can only be used in transaction blocks}], - 'SET LOCAL and \syncpipeline', - { - '001_pgbench_pipeline_set_local_3' => q{ -\startpipeline -SELECT 1; -\syncpipeline -SET LOCAL statement_timeout='1h'; -\endpipeline -} - }); - -# Try REINDEX CONCURRENTLY as first pipeline command. This succeeds -# as the first command is outside the implicit transaction block of -# a pipeline. -$node->pgbench( - '-t 1 -n -M extended', - 0, - [], - [], - 'REINDEX CONCURRENTLY outside implicit transaction block of pipeline', - { - '001_pgbench_pipeline_reindex_1' => q{ -\startpipeline -REINDEX TABLE CONCURRENTLY pgbench_accounts; -SELECT 1; -\endpipeline -} - }); - -# Try REINDEX CONCURRENTLY as second pipeline command. This fails -# as the second command is inside an implicit transaction block. -$node->pgbench( - '-t 1 -n -M extended', - 2, - [], - [], - 'error: REINDEX CONCURRENTLY inside implicit transaction block of pipeline', - { - '001_pgbench_pipeline_reindex_2' => q{ -\startpipeline -SELECT 1; -REINDEX TABLE CONCURRENTLY pgbench_accounts; -\endpipeline -} - }); - -# Try VACUUM as first pipeline command. Like REINDEX CONCURRENTLY, this -# succeeds as this is outside the implicit transaction block of a pipeline. -$node->pgbench( - '-t 1 -n -M extended', - 0, - [], - [], - 'VACUUM outside implicit transaction block of pipeline', - { - '001_pgbench_pipeline_vacuum_1' => q{ -\startpipeline -VACUUM pgbench_accounts; -\endpipeline -} - }); - -# Try VACUUM as second pipeline command. This fails, as the second command -# of a pipeline is inside an implicit transaction block. -$node->pgbench( - '-t 1 -n -M extended', - 2, - [], - [], - 'error: VACUUM inside implicit transaction block of pipeline', - { - '001_pgbench_pipeline_vacuum_2' => q{ -\startpipeline -SELECT 1; -VACUUM pgbench_accounts; -\endpipeline -} - }); - -# Try subtransactions in a pipeline. These are forbidden in implicit -# transaction blocks. -$node->pgbench( - '-t 1 -n -M extended', - 2, - [], - [], - 'error: subtransactions not allowed in pipeline', - { - '001_pgbench_pipeline_subtrans' => q{ -\startpipeline -SAVEPOINT a; -SELECT 1; -ROLLBACK TO SAVEPOINT a; -SELECT 2; -\endpipeline -} - }); - -# Try LOCK TABLE as first pipeline command. This fails as LOCK is outside -# an implicit transaction block. -$node->pgbench( - '-t 1 -n -M extended', - 2, - [], - [], - 'error: LOCK TABLE outside implicit transaction block of pipeline', - { - '001_pgbench_pipeline_lock_1' => q{ -\startpipeline -LOCK pgbench_accounts; -SELECT 1; -\endpipeline -} - }); - -# Try LOCK TABLE as second pipeline command. This succeeds as LOCK is inside -# an implicit transaction block. -$node->pgbench( - '-t 1 -n -M extended', - 0, - [], - [], - 'LOCK TABLE inside implicit transaction block of pipeline', - { - '001_pgbench_pipeline_lock_2' => q{ -\startpipeline -SELECT 1; -LOCK pgbench_accounts; -\endpipeline -} - }); - # Working \startpipeline in prepared query mode with serializable $node->pgbench( '-c4 -t 10 -n -M prepared',