diff options
author | Michael Paquier <michael@paquier.xyz> | 2025-06-13 10:15:17 +0900 |
---|---|---|
committer | Michael Paquier <michael@paquier.xyz> | 2025-06-13 10:15:17 +0900 |
commit | 6e951f279beab566efa267151d028c3684f6095e (patch) | |
tree | 8f4e9b75d2b2b6cc6620cb348b102f7a76460020 /src/bin/psql/t/001_basic.pl | |
parent | 2c76c6ac470fb0b5bcaec095c1ed90e45cebba75 (diff) | |
download | postgresql-6e951f279beab566efa267151d028c3684f6095e.tar.gz postgresql-6e951f279beab566efa267151d028c3684f6095e.zip |
psql: Forbid use of COPY and \copy while in a pipeline
Running COPY within a pipeline can break protocol synchronization in
multiple ways. psql is limited in terms of result processing if mixing
COPY commands with normal queries while controlling a pipeline with the
new meta-commands, as an effect of the following reasons:
- In COPY mode, the backend ignores additional Sync messages and will
not send a matching ReadyForQuery expected by the frontend. Doing a
\syncpipeline just after COPY will leave the frontend waiting for a
ReadyForQuery message that won't be sent, leaving psql out-of-sync.
- libpq automatically sends a Sync with the Copy message which is not
tracked in the command queue, creating an unexpected synchronisation
point that psql cannot really know about. While it is possible to track
such activity for a \copy, this cannot really be done sanely with plain
COPY queries. Backend failures during a COPY would leave the pipeline
in an aborted state while the backend would be in a clean state, ready
to process commands.
At the end, fixing those issues would require modifications in how libpq
handles pipeline and COPY. So, rather than implementing workarounds in
psql to shortcut the libpq internals (with command queue handling for
one), and because meta-commands for pipelines in psql are a new feature
with COPY in a pipeline having a limited impact compared to other
queries, this commit forbids the use of COPY within a pipeline to avoid
possible break of protocol synchronisation within psql. If there is a
use-case for COPY support within pipelines in libpq, this could always
be added in the future, if necessary.
Most of the changes of this commit impacts the tests for psql pipelines,
removing the tests related to COPY. Some TAP tests still exist for COPY
TO/FROM and \copy to/from, to check that that connections are aborted
when this operation is attempted.
Reported-by: Nikita Kalinin <n.kalinin@postgrespro.ru>
Author: Anthonin Bonnefoy <anthonin.bonnefoy@datadoghq.com>
Discussion: https://postgr.es/m/AC468509-06E8-4E2A-A4B1-63046A4AC6AB@postgrespro.ru
Diffstat (limited to 'src/bin/psql/t/001_basic.pl')
-rw-r--r-- | src/bin/psql/t/001_basic.pl | 46 |
1 files changed, 17 insertions, 29 deletions
diff --git a/src/bin/psql/t/001_basic.pl b/src/bin/psql/t/001_basic.pl index ae5c1d66405..f42c3961e09 100644 --- a/src/bin/psql/t/001_basic.pl +++ b/src/bin/psql/t/001_basic.pl @@ -483,8 +483,8 @@ psql_like($node, "copy (values ('foo'),('bar')) to stdout \\g | $pipe_cmd", my $c4 = slurp_file($g_file); like($c4, qr/foo.*bar/s); -# Tests with pipelines. These trigger FATAL failures in the backend, -# so they cannot be tested via SQL. +# Test COPY within pipelines. These abort the connection from +# the frontend so they cannot be tested via SQL. $node->safe_psql('postgres', 'CREATE TABLE psql_pipeline()'); my $log_location = -s $node->logfile; psql_fails_like( @@ -493,53 +493,41 @@ psql_fails_like( COPY psql_pipeline FROM STDIN; SELECT 'val1'; \\syncpipeline -\\getresults \\endpipeline}, - qr/server closed the connection unexpectedly/, - 'protocol sync loss in pipeline: direct COPY, SELECT, sync and getresult' -); + qr/COPY in a pipeline is not supported, aborting connection/, + 'COPY FROM in pipeline: fails'); $node->wait_for_log( qr/FATAL: .*terminating connection because protocol synchronization was lost/, $log_location); +# Remove \syncpipeline here. psql_fails_like( $node, qq{\\startpipeline -COPY psql_pipeline FROM STDIN \\bind \\sendpipeline -SELECT 'val1' \\bind \\sendpipeline -\\syncpipeline -\\getresults -\\endpipeline}, - qr/server closed the connection unexpectedly/, - 'protocol sync loss in pipeline: bind COPY, SELECT, sync and getresult'); - -# This time, test without the \getresults and \syncpipeline. -psql_fails_like( - $node, - qq{\\startpipeline -COPY psql_pipeline FROM STDIN; +COPY psql_pipeline TO STDOUT; SELECT 'val1'; \\endpipeline}, - qr/server closed the connection unexpectedly/, - 'protocol sync loss in pipeline: COPY, SELECT and sync'); + qr/COPY in a pipeline is not supported, aborting connection/, + 'COPY TO in pipeline: fails'); -# Tests sending a sync after a COPY TO/FROM. These abort the connection -# from the frontend. psql_fails_like( $node, qq{\\startpipeline -COPY psql_pipeline FROM STDIN; +\\copy psql_pipeline from stdin; +SELECT 'val1'; \\syncpipeline \\endpipeline}, - qr/\\syncpipeline after COPY is not supported, aborting connection/, - 'sending sync after COPY FROM'); + qr/COPY in a pipeline is not supported, aborting connection/, + '\copy from in pipeline: fails'); + +# Sync attempt after a COPY TO/FROM. psql_fails_like( $node, qq{\\startpipeline -COPY psql_pipeline TO STDOUT; +\\copy psql_pipeline to stdout; \\syncpipeline \\endpipeline}, - qr/\\syncpipeline after COPY is not supported, aborting connection/, - 'sending sync after COPY TO'); + qr/COPY in a pipeline is not supported, aborting connection/, + '\copy to in pipeline: fails'); done_testing(); |