mirror of
https://github.com/postgres/postgres.git
synced 2025-12-19 17:02:53 +03:00
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
This commit is contained in:
@@ -228,192 +228,6 @@ BEGIN \bind \sendpipeline
|
||||
INSERT INTO psql_pipeline VALUES ($1) \bind 1 \sendpipeline
|
||||
COMMIT \bind \sendpipeline
|
||||
\endpipeline
|
||||
-- COPY FROM STDIN
|
||||
-- with \sendpipeline and \bind
|
||||
\startpipeline
|
||||
SELECT $1 \bind 'val1' \sendpipeline
|
||||
COPY psql_pipeline FROM STDIN \bind \sendpipeline
|
||||
\endpipeline
|
||||
?column?
|
||||
----------
|
||||
val1
|
||||
(1 row)
|
||||
|
||||
-- with semicolon
|
||||
\startpipeline
|
||||
SELECT 'val1';
|
||||
COPY psql_pipeline FROM STDIN;
|
||||
\endpipeline
|
||||
?column?
|
||||
----------
|
||||
val1
|
||||
(1 row)
|
||||
|
||||
-- COPY FROM STDIN with \flushrequest + \getresults
|
||||
-- with \sendpipeline and \bind
|
||||
\startpipeline
|
||||
SELECT $1 \bind 'val1' \sendpipeline
|
||||
COPY psql_pipeline FROM STDIN \bind \sendpipeline
|
||||
\flushrequest
|
||||
\getresults
|
||||
?column?
|
||||
----------
|
||||
val1
|
||||
(1 row)
|
||||
|
||||
message type 0x5a arrived from server while idle
|
||||
\endpipeline
|
||||
-- with semicolon
|
||||
\startpipeline
|
||||
SELECT 'val1';
|
||||
COPY psql_pipeline FROM STDIN;
|
||||
\flushrequest
|
||||
\getresults
|
||||
?column?
|
||||
----------
|
||||
val1
|
||||
(1 row)
|
||||
|
||||
message type 0x5a arrived from server while idle
|
||||
\endpipeline
|
||||
-- COPY FROM STDIN with \syncpipeline + \getresults
|
||||
-- with \bind and \sendpipeline
|
||||
\startpipeline
|
||||
SELECT $1 \bind 'val1' \sendpipeline
|
||||
COPY psql_pipeline FROM STDIN \bind \sendpipeline
|
||||
\syncpipeline
|
||||
\getresults
|
||||
?column?
|
||||
----------
|
||||
val1
|
||||
(1 row)
|
||||
|
||||
\endpipeline
|
||||
-- with semicolon
|
||||
\startpipeline
|
||||
SELECT 'val1';
|
||||
COPY psql_pipeline FROM STDIN;
|
||||
\syncpipeline
|
||||
\getresults
|
||||
?column?
|
||||
----------
|
||||
val1
|
||||
(1 row)
|
||||
|
||||
\endpipeline
|
||||
-- COPY TO STDOUT
|
||||
-- with \bind and \sendpipeline
|
||||
\startpipeline
|
||||
SELECT $1 \bind 'val1' \sendpipeline
|
||||
copy psql_pipeline TO STDOUT \bind \sendpipeline
|
||||
\endpipeline
|
||||
?column?
|
||||
----------
|
||||
val1
|
||||
(1 row)
|
||||
|
||||
1 \N
|
||||
2 test2
|
||||
20 test2
|
||||
3 test3
|
||||
30 test3
|
||||
4 test4
|
||||
40 test4
|
||||
-- with semicolon
|
||||
\startpipeline
|
||||
SELECT 'val1';
|
||||
copy psql_pipeline TO STDOUT;
|
||||
\endpipeline
|
||||
?column?
|
||||
----------
|
||||
val1
|
||||
(1 row)
|
||||
|
||||
1 \N
|
||||
2 test2
|
||||
20 test2
|
||||
3 test3
|
||||
30 test3
|
||||
4 test4
|
||||
40 test4
|
||||
-- COPY TO STDOUT with \flushrequest + \getresults
|
||||
-- with \bind and \sendpipeline
|
||||
\startpipeline
|
||||
SELECT $1 \bind 'val1' \sendpipeline
|
||||
copy psql_pipeline TO STDOUT \bind \sendpipeline
|
||||
\flushrequest
|
||||
\getresults
|
||||
?column?
|
||||
----------
|
||||
val1
|
||||
(1 row)
|
||||
|
||||
1 \N
|
||||
2 test2
|
||||
20 test2
|
||||
3 test3
|
||||
30 test3
|
||||
4 test4
|
||||
40 test4
|
||||
\endpipeline
|
||||
-- with semicolon
|
||||
\startpipeline
|
||||
SELECT 'val1';
|
||||
copy psql_pipeline TO STDOUT;
|
||||
\flushrequest
|
||||
\getresults
|
||||
?column?
|
||||
----------
|
||||
val1
|
||||
(1 row)
|
||||
|
||||
1 \N
|
||||
2 test2
|
||||
20 test2
|
||||
3 test3
|
||||
30 test3
|
||||
4 test4
|
||||
40 test4
|
||||
\endpipeline
|
||||
-- COPY TO STDOUT with \syncpipeline + \getresults
|
||||
-- with \bind and \sendpipeline
|
||||
\startpipeline
|
||||
SELECT $1 \bind 'val1' \sendpipeline
|
||||
copy psql_pipeline TO STDOUT \bind \sendpipeline
|
||||
\syncpipeline
|
||||
\getresults
|
||||
?column?
|
||||
----------
|
||||
val1
|
||||
(1 row)
|
||||
|
||||
1 \N
|
||||
2 test2
|
||||
20 test2
|
||||
3 test3
|
||||
30 test3
|
||||
4 test4
|
||||
40 test4
|
||||
\endpipeline
|
||||
-- with semicolon
|
||||
\startpipeline
|
||||
SELECT 'val1';
|
||||
copy psql_pipeline TO STDOUT;
|
||||
\syncpipeline
|
||||
\getresults
|
||||
?column?
|
||||
----------
|
||||
val1
|
||||
(1 row)
|
||||
|
||||
1 \N
|
||||
2 test2
|
||||
20 test2
|
||||
3 test3
|
||||
30 test3
|
||||
4 test4
|
||||
40 test4
|
||||
\endpipeline
|
||||
-- Use \parse and \bind_named
|
||||
\startpipeline
|
||||
SELECT $1 \parse ''
|
||||
@@ -740,7 +554,7 @@ SELECT COUNT(*) FROM psql_pipeline \bind \sendpipeline
|
||||
|
||||
count
|
||||
-------
|
||||
7
|
||||
1
|
||||
(1 row)
|
||||
|
||||
-- After an error, pipeline is aborted and requires \syncpipeline to be
|
||||
|
||||
@@ -105,106 +105,6 @@ INSERT INTO psql_pipeline VALUES ($1) \bind 1 \sendpipeline
|
||||
COMMIT \bind \sendpipeline
|
||||
\endpipeline
|
||||
|
||||
-- COPY FROM STDIN
|
||||
-- with \sendpipeline and \bind
|
||||
\startpipeline
|
||||
SELECT $1 \bind 'val1' \sendpipeline
|
||||
COPY psql_pipeline FROM STDIN \bind \sendpipeline
|
||||
\endpipeline
|
||||
2 test2
|
||||
\.
|
||||
-- with semicolon
|
||||
\startpipeline
|
||||
SELECT 'val1';
|
||||
COPY psql_pipeline FROM STDIN;
|
||||
\endpipeline
|
||||
20 test2
|
||||
\.
|
||||
|
||||
-- COPY FROM STDIN with \flushrequest + \getresults
|
||||
-- with \sendpipeline and \bind
|
||||
\startpipeline
|
||||
SELECT $1 \bind 'val1' \sendpipeline
|
||||
COPY psql_pipeline FROM STDIN \bind \sendpipeline
|
||||
\flushrequest
|
||||
\getresults
|
||||
3 test3
|
||||
\.
|
||||
\endpipeline
|
||||
-- with semicolon
|
||||
\startpipeline
|
||||
SELECT 'val1';
|
||||
COPY psql_pipeline FROM STDIN;
|
||||
\flushrequest
|
||||
\getresults
|
||||
30 test3
|
||||
\.
|
||||
\endpipeline
|
||||
|
||||
-- COPY FROM STDIN with \syncpipeline + \getresults
|
||||
-- with \bind and \sendpipeline
|
||||
\startpipeline
|
||||
SELECT $1 \bind 'val1' \sendpipeline
|
||||
COPY psql_pipeline FROM STDIN \bind \sendpipeline
|
||||
\syncpipeline
|
||||
\getresults
|
||||
4 test4
|
||||
\.
|
||||
\endpipeline
|
||||
-- with semicolon
|
||||
\startpipeline
|
||||
SELECT 'val1';
|
||||
COPY psql_pipeline FROM STDIN;
|
||||
\syncpipeline
|
||||
\getresults
|
||||
40 test4
|
||||
\.
|
||||
\endpipeline
|
||||
|
||||
-- COPY TO STDOUT
|
||||
-- with \bind and \sendpipeline
|
||||
\startpipeline
|
||||
SELECT $1 \bind 'val1' \sendpipeline
|
||||
copy psql_pipeline TO STDOUT \bind \sendpipeline
|
||||
\endpipeline
|
||||
-- with semicolon
|
||||
\startpipeline
|
||||
SELECT 'val1';
|
||||
copy psql_pipeline TO STDOUT;
|
||||
\endpipeline
|
||||
|
||||
-- COPY TO STDOUT with \flushrequest + \getresults
|
||||
-- with \bind and \sendpipeline
|
||||
\startpipeline
|
||||
SELECT $1 \bind 'val1' \sendpipeline
|
||||
copy psql_pipeline TO STDOUT \bind \sendpipeline
|
||||
\flushrequest
|
||||
\getresults
|
||||
\endpipeline
|
||||
-- with semicolon
|
||||
\startpipeline
|
||||
SELECT 'val1';
|
||||
copy psql_pipeline TO STDOUT;
|
||||
\flushrequest
|
||||
\getresults
|
||||
\endpipeline
|
||||
|
||||
-- COPY TO STDOUT with \syncpipeline + \getresults
|
||||
-- with \bind and \sendpipeline
|
||||
\startpipeline
|
||||
SELECT $1 \bind 'val1' \sendpipeline
|
||||
copy psql_pipeline TO STDOUT \bind \sendpipeline
|
||||
\syncpipeline
|
||||
\getresults
|
||||
\endpipeline
|
||||
-- with semicolon
|
||||
\startpipeline
|
||||
SELECT 'val1';
|
||||
copy psql_pipeline TO STDOUT;
|
||||
\syncpipeline
|
||||
\getresults
|
||||
\endpipeline
|
||||
|
||||
-- Use \parse and \bind_named
|
||||
\startpipeline
|
||||
SELECT $1 \parse ''
|
||||
|
||||
Reference in New Issue
Block a user