mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	Revert "Handle better implicit transaction state of pipeline mode"
This reverts commit d77f91214f on all stable branches, due to concerns
regarding the compatility side effects this could create in a minor
release.  The change still exists on HEAD.
Discussion: https://postgr.es/m/CA+TgmoZqRgeFTg4+Yf_CMRRXiHuNz1u6ZC4FvVk+rxw0RmOPnw@mail.gmail.com
Backpatch-through: 13
			
			
This commit is contained in:
		@@ -1070,17 +1070,16 @@ SELCT 1/0;<!-- this typo is intentional -->
 | 
			
		||||
 | 
			
		||||
   <para>
 | 
			
		||||
    If the client has not issued an explicit <command>BEGIN</command>,
 | 
			
		||||
    then an implicit transaction block is started and each Sync ordinarily
 | 
			
		||||
    causes an implicit <command>COMMIT</command> if the preceding step(s)
 | 
			
		||||
    succeeded, or an implicit <command>ROLLBACK</command> 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 <command>CREATE DATABASE</command>) 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 <command>COMMIT</command>
 | 
			
		||||
    if the preceding step(s) succeeded, or an
 | 
			
		||||
    implicit <command>ROLLBACK</command> if they failed.  However, there
 | 
			
		||||
    are a few DDL commands (such as <command>CREATE DATABASE</command>)
 | 
			
		||||
    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.
 | 
			
		||||
   </para>
 | 
			
		||||
 | 
			
		||||
   <para>
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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',
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user