1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-27 23:21:58 +03:00

Handle better implicit transaction state of pipeline mode

When using a pipeline, a transaction starts from the first command and
is committed with a Sync message or when the pipeline ends.

Functions like IsInTransactionBlock() or PreventInTransactionBlock()
were already able to understand a pipeline as being in a transaction
block, but it was not the case of CheckTransactionBlock().  This
function is called for example to generate a WARNING for SET LOCAL,
complaining that it is used outside of a transaction block.

The current state of the code caused multiple problems, like:
- SET LOCAL executed at any stage of a pipeline issued a WARNING, even
if the command was at least second in line where the pipeline is in a
transaction state.
- LOCK TABLE failed when invoked at any step of a pipeline, even if it
should be able to work within a transaction block.

The pipeline protocol assumes that the first command of a pipeline is
not part of a transaction block, and that any follow-up commands is
considered as within a transaction block.

This commit changes the backend so as an implicit transaction block is
started each time the first Execute message of a pipeline has finished
processing, with this implicit transaction block ended once a sync is
processed.  The checks based on XACT_FLAGS_PIPELINING in the routines
checking if we are in a transaction block are not necessary: it is
enough to rely on the existing ones.

Some tests are added to pgbench, that can be backpatched down to v17
when \syncpipeline is involved and down to v14 where \startpipeline and
\endpipeline are available.  This is unfortunately limited regarding the
error patterns that can be checked, but it provides coverage for various
pipeline combinations to check if these succeed or fail.  These tests
are able to capture the case of SET LOCAL's WARNING.  The author has
proposed a different feature to improve the coverage by adding similar
meta-commands to psql where error messages could be checked, something
more useful for the cases where commands cannot be used in transaction
blocks, like REINDEX CONCURRENTLY or VACUUM.  This is considered as
future work for v18~.

Author: Anthonin Bonnefoy
Reviewed-by: Jelte Fennema-Nio, Michael Paquier
Discussion: https://postgr.es/m/CAO6_XqrWO8uNBQrSu5r6jh+vTGi5Oiyk4y8yXDORdE2jbzw8xw@mail.gmail.com
Backpatch-through: 13
This commit is contained in:
Michael Paquier
2024-11-27 09:31:37 +09:00
parent e00c1e249f
commit d77f91214f
4 changed files with 203 additions and 23 deletions

View File

@ -1070,16 +1070,17 @@ SELCT 1/0;<!-- this typo is intentional -->
<para>
If the client has not issued an explicit <command>BEGIN</command>,
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.
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.
</para>
<para>