diff options
author | Michael Paquier <michael@paquier.xyz> | 2025-03-18 09:41:21 +0900 |
---|---|---|
committer | Michael Paquier <michael@paquier.xyz> | 2025-03-18 09:41:21 +0900 |
commit | 17caf6644546eccb4a1f6e0137ea1d0f58da8c16 (patch) | |
tree | a753c92789023f00ab93edc3323b9fe196919fbf | |
parent | da7226993fd4b73d8b40abb7167d124eada97f2e (diff) | |
download | postgresql-17caf6644546eccb4a1f6e0137ea1d0f58da8c16.tar.gz postgresql-17caf6644546eccb4a1f6e0137ea1d0f58da8c16.zip |
psql: Add \sendpipeline to send query buffers while in a pipeline
In the initial pipeline support for psql added in 41625ab8ea3d, \g was
used as the way to push extended query into an ongoing pipeline. \gx
was blocked.
These two meta-commands have format-related options that can be applied
when fetching a query result (expanded, etc.). As the results of a
pipeline are fetched asynchronously, not at the moment of the
meta-command execution but at the moment of a \getresults or a
\endpipeline, authorizing \g while blocking \gx leads to a confusing
implementation, making one think that psql should be smart enough to
remember the output format options defined from the time when \g or \gx
were executed. Doing so would lead to more code complications when
retrieving a batch of results. There is an extra argument other than
simplicity here: the output format options defined at the point of a
\getresults or a \endpipeline execution should be what affect the output
format for a batch of results.
To avoid any confusion, we have settled to the introduction of a new
meta-command called \sendpipeline, replacing \g when within a pipeline.
An advantage of this design is that it is possible to add new options
specific to pipelines when sending a query buffer, independent of \g
and \gx, should it prove to be necessary.
Most of the changes of this commit happen in the regression tests, where
\g is replaced by \sendpipeline. More tests are added to check that \g
is not allowed.
Per discussion between the author, Daniel Vérité and me.
Author: Anthonin Bonnefoy <anthonin.bonnefoy@datadoghq.com>
Discussion: https://postgr.es/m/ad4b9f1a-f7fe-4ab8-8546-90754726d0be@manitou-mail.org
-rw-r--r-- | doc/src/sgml/ref/psql-ref.sgml | 11 | ||||
-rw-r--r-- | src/bin/psql/command.c | 45 | ||||
-rw-r--r-- | src/bin/psql/help.c | 1 | ||||
-rw-r--r-- | src/bin/psql/tab-complete.in.c | 3 | ||||
-rw-r--r-- | src/test/regress/expected/psql.out | 1 | ||||
-rw-r--r-- | src/test/regress/expected/psql_pipeline.out | 237 | ||||
-rw-r--r-- | src/test/regress/sql/psql.sql | 1 | ||||
-rw-r--r-- | src/test/regress/sql/psql_pipeline.sql | 231 |
8 files changed, 305 insertions, 225 deletions
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml index cedccc14129..cddf6e07531 100644 --- a/doc/src/sgml/ref/psql-ref.sgml +++ b/doc/src/sgml/ref/psql-ref.sgml @@ -3677,6 +3677,7 @@ testdb=> <userinput>\setenv LESS -imx4F</userinput> <varlistentry id="app-psql-meta-command-pipeline"> <term><literal>\startpipeline</literal></term> + <term><literal>\sendpipeline</literal></term> <term><literal>\syncpipeline</literal></term> <term><literal>\endpipeline</literal></term> <term><literal>\flushrequest</literal></term> @@ -3701,10 +3702,10 @@ testdb=> <userinput>\setenv LESS -imx4F</userinput> queries need to be sent using the meta-commands <literal>\bind</literal>, <literal>\bind_named</literal>, <literal>\close</literal> or <literal>\parse</literal>. While a - pipeline is ongoing, <literal>\g</literal> will append the current - query buffer to the pipeline. Other meta-commands like - <literal>\gx</literal> or <literal>\gdesc</literal> are not allowed - in pipeline mode. + pipeline is ongoing, <literal>\sendpipeline</literal> will append the + current query buffer to the pipeline. Other meta-commands like + <literal>\g</literal>, <literal>\gx</literal> or <literal>\gdesc</literal> + are not allowed in pipeline mode. </para> <para> @@ -3738,7 +3739,7 @@ testdb=> <userinput>\setenv LESS -imx4F</userinput> Example: <programlisting> \startpipeline -SELECT 1 \bind \g +SELECT 1 \bind \sendpipeline \flushrequest \getresults \endpipeline diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index fb0b27568c5..a87ff7e4597 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -131,6 +131,7 @@ static backslashResult exec_command_quit(PsqlScanState scan_state, bool active_b static backslashResult exec_command_reset(PsqlScanState scan_state, bool active_branch, PQExpBuffer query_buf); static backslashResult exec_command_s(PsqlScanState scan_state, bool active_branch); +static backslashResult exec_command_sendpipeline(PsqlScanState scan_state, bool active_branch); static backslashResult exec_command_set(PsqlScanState scan_state, bool active_branch); static backslashResult exec_command_setenv(PsqlScanState scan_state, bool active_branch, const char *cmd); @@ -417,6 +418,8 @@ exec_command(const char *cmd, status = exec_command_reset(scan_state, active_branch, query_buf); else if (strcmp(cmd, "s") == 0) status = exec_command_s(scan_state, active_branch); + else if (strcmp(cmd, "sendpipeline") == 0) + status = exec_command_sendpipeline(scan_state, active_branch); else if (strcmp(cmd, "set") == 0) status = exec_command_set(scan_state, active_branch); else if (strcmp(cmd, "setenv") == 0) @@ -1734,10 +1737,9 @@ exec_command_g(PsqlScanState scan_state, bool active_branch, const char *cmd) if (status == PSQL_CMD_SKIP_LINE && active_branch) { - if (strcmp(cmd, "gx") == 0 && - PQpipelineStatus(pset.db) != PQ_PIPELINE_OFF) + if (PQpipelineStatus(pset.db) != PQ_PIPELINE_OFF) { - pg_log_error("\\gx not allowed in pipeline mode"); + pg_log_error("\\%s not allowed in pipeline mode", cmd); clean_extended_state(); free(fname); return PSQL_CMD_ERROR; @@ -2777,6 +2779,43 @@ exec_command_s(PsqlScanState scan_state, bool active_branch) } /* + * \sendpipeline -- send an extended query to an ongoing pipeline + */ +static backslashResult +exec_command_sendpipeline(PsqlScanState scan_state, bool active_branch) +{ + backslashResult status = PSQL_CMD_SKIP_LINE; + + if (active_branch) + { + if (PQpipelineStatus(pset.db) != PQ_PIPELINE_OFF) + { + if (pset.send_mode == PSQL_SEND_EXTENDED_QUERY_PREPARED || + pset.send_mode == PSQL_SEND_EXTENDED_QUERY_PARAMS) + { + status = PSQL_CMD_SEND; + } + else + { + pg_log_error("\\sendpipeline must be used after \\bind or \\bind_named"); + clean_extended_state(); + return PSQL_CMD_ERROR; + } + } + else + { + pg_log_error("\\sendpipeline not allowed outside of pipeline mode"); + clean_extended_state(); + return PSQL_CMD_ERROR; + } + } + else + ignore_slash_options(scan_state); + + return status; +} + +/* * \set -- set variable */ static backslashResult diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c index 714b8619233..e47cad24de9 100644 --- a/src/bin/psql/help.c +++ b/src/bin/psql/help.c @@ -181,6 +181,7 @@ slashUsage(unsigned short int pager) HELP0(" \\gx [(OPTIONS)] [FILE] as \\g, but forces expanded output mode\n"); HELP0(" \\parse STMT_NAME create a prepared statement\n"); HELP0(" \\q quit psql\n"); + HELP0(" \\sendpipeline send an extended query to an ongoing pipeline\n"); HELP0(" \\startpipeline enter pipeline mode\n"); HELP0(" \\syncpipeline add a synchronisation point to an ongoing pipeline\n"); HELP0(" \\watch [[i=]SEC] [c=N] [m=MIN]\n" diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c index 8432be641ac..9a4d993e2bc 100644 --- a/src/bin/psql/tab-complete.in.c +++ b/src/bin/psql/tab-complete.in.c @@ -1895,7 +1895,8 @@ psql_completion(const char *text, int start, int end) "\\parse", "\\password", "\\print", "\\prompt", "\\pset", "\\qecho", "\\quit", "\\reset", - "\\s", "\\set", "\\setenv", "\\sf", "\\startpipeline", "\\sv", "\\syncpipeline", + "\\s", "\\sendpipeline", "\\set", "\\setenv", "\\sf", + "\\startpipeline", "\\sv", "\\syncpipeline", "\\t", "\\T", "\\timing", "\\unset", "\\x", diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out index 6543e90de75..8687ffe2750 100644 --- a/src/test/regress/expected/psql.out +++ b/src/test/regress/expected/psql.out @@ -4706,6 +4706,7 @@ invalid command \lo \q \reset \s arg1 + \sendpipeline \set arg1 arg2 arg3 arg4 arg5 arg6 arg7 \setenv arg1 arg2 \sf whole_line diff --git a/src/test/regress/expected/psql_pipeline.out b/src/test/regress/expected/psql_pipeline.out index 3df2415a840..68e3c19ea05 100644 --- a/src/test/regress/expected/psql_pipeline.out +++ b/src/test/regress/expected/psql_pipeline.out @@ -4,7 +4,7 @@ CREATE TABLE psql_pipeline(a INTEGER PRIMARY KEY, s TEXT); -- Single query \startpipeline -SELECT $1 \bind 'val1' \g +SELECT $1 \bind 'val1' \sendpipeline \endpipeline ?column? ---------- @@ -13,9 +13,9 @@ SELECT $1 \bind 'val1' \g -- Multiple queries \startpipeline -SELECT $1 \bind 'val1' \g -SELECT $1, $2 \bind 'val2' 'val3' \g -SELECT $1, $2 \bind 'val2' 'val3' \g +SELECT $1 \bind 'val1' \sendpipeline +SELECT $1, $2 \bind 'val2' 'val3' \sendpipeline +SELECT $1, $2 \bind 'val2' 'val3' \sendpipeline \endpipeline ?column? ---------- @@ -35,10 +35,10 @@ SELECT $1, $2 \bind 'val2' 'val3' \g -- Test \flush \startpipeline \flush -SELECT $1 \bind 'val1' \g +SELECT $1 \bind 'val1' \sendpipeline \flush -SELECT $1, $2 \bind 'val2' 'val3' \g -SELECT $1, $2 \bind 'val2' 'val3' \g +SELECT $1, $2 \bind 'val2' 'val3' \sendpipeline +SELECT $1, $2 \bind 'val2' 'val3' \sendpipeline \endpipeline ?column? ---------- @@ -63,12 +63,12 @@ SELECT $1, $2 \bind 'val2' 'val3' \g 0 \echo :PIPELINE_RESULT_COUNT 0 -SELECT $1 \bind 'val1' \g +SELECT $1 \bind 'val1' \sendpipeline \syncpipeline \syncpipeline -SELECT $1, $2 \bind 'val2' 'val3' \g +SELECT $1, $2 \bind 'val2' 'val3' \sendpipeline \syncpipeline -SELECT $1, $2 \bind 'val4' 'val5' \g +SELECT $1, $2 \bind 'val4' 'val5' \sendpipeline \echo :PIPELINE_COMMAND_COUNT 1 \echo :PIPELINE_SYNC_COUNT @@ -94,7 +94,7 @@ SELECT $1, $2 \bind 'val4' 'val5' \g -- \startpipeline should not have any effect if already in a pipeline. \startpipeline \startpipeline -SELECT $1 \bind 'val1' \g +SELECT $1 \bind 'val1' \sendpipeline \endpipeline ?column? ---------- @@ -103,24 +103,24 @@ SELECT $1 \bind 'val1' \g -- Convert an implicit transaction block to an explicit transaction block. \startpipeline -INSERT INTO psql_pipeline VALUES ($1) \bind 1 \g -BEGIN \bind \g -INSERT INTO psql_pipeline VALUES ($1) \bind 2 \g -ROLLBACK \bind \g +INSERT INTO psql_pipeline VALUES ($1) \bind 1 \sendpipeline +BEGIN \bind \sendpipeline +INSERT INTO psql_pipeline VALUES ($1) \bind 2 \sendpipeline +ROLLBACK \bind \sendpipeline \endpipeline -- Multiple explicit transactions \startpipeline -BEGIN \bind \g -INSERT INTO psql_pipeline VALUES ($1) \bind 1 \g -ROLLBACK \bind \g -BEGIN \bind \g -INSERT INTO psql_pipeline VALUES ($1) \bind 1 \g -COMMIT \bind \g +BEGIN \bind \sendpipeline +INSERT INTO psql_pipeline VALUES ($1) \bind 1 \sendpipeline +ROLLBACK \bind \sendpipeline +BEGIN \bind \sendpipeline +INSERT INTO psql_pipeline VALUES ($1) \bind 1 \sendpipeline +COMMIT \bind \sendpipeline \endpipeline -- COPY FROM STDIN \startpipeline -SELECT $1 \bind 'val1' \g -COPY psql_pipeline FROM STDIN \bind \g +SELECT $1 \bind 'val1' \sendpipeline +COPY psql_pipeline FROM STDIN \bind \sendpipeline \endpipeline ?column? ---------- @@ -129,8 +129,8 @@ COPY psql_pipeline FROM STDIN \bind \g -- COPY FROM STDIN with \flushrequest + \getresults \startpipeline -SELECT $1 \bind 'val1' \g -COPY psql_pipeline FROM STDIN \bind \g +SELECT $1 \bind 'val1' \sendpipeline +COPY psql_pipeline FROM STDIN \bind \sendpipeline \flushrequest \getresults ?column? @@ -142,8 +142,8 @@ message type 0x5a arrived from server while idle \endpipeline -- COPY FROM STDIN with \syncpipeline + \getresults \startpipeline -SELECT $1 \bind 'val1' \g -COPY psql_pipeline FROM STDIN \bind \g +SELECT $1 \bind 'val1' \sendpipeline +COPY psql_pipeline FROM STDIN \bind \sendpipeline \syncpipeline \getresults ?column? @@ -154,8 +154,8 @@ COPY psql_pipeline FROM STDIN \bind \g \endpipeline -- COPY TO STDOUT \startpipeline -SELECT $1 \bind 'val1' \g -copy psql_pipeline TO STDOUT \bind \g +SELECT $1 \bind 'val1' \sendpipeline +copy psql_pipeline TO STDOUT \bind \sendpipeline \endpipeline ?column? ---------- @@ -168,8 +168,8 @@ copy psql_pipeline TO STDOUT \bind \g 4 test4 -- COPY TO STDOUT with \flushrequest + \getresults \startpipeline -SELECT $1 \bind 'val1' \g -copy psql_pipeline TO STDOUT \bind \g +SELECT $1 \bind 'val1' \sendpipeline +copy psql_pipeline TO STDOUT \bind \sendpipeline \flushrequest \getresults ?column? @@ -184,8 +184,8 @@ copy psql_pipeline TO STDOUT \bind \g \endpipeline -- COPY TO STDOUT with \syncpipeline + \getresults \startpipeline -SELECT $1 \bind 'val1' \g -copy psql_pipeline TO STDOUT \bind \g +SELECT $1 \bind 'val1' \sendpipeline +copy psql_pipeline TO STDOUT \bind \sendpipeline \syncpipeline \getresults ?column? @@ -203,14 +203,14 @@ copy psql_pipeline TO STDOUT \bind \g SELECT $1 \parse '' SELECT $1, $2 \parse '' SELECT $2 \parse pipeline_1 -\bind_named '' 1 2 \g -\bind_named pipeline_1 2 \g +\bind_named '' 1 2 \sendpipeline +\bind_named pipeline_1 2 \sendpipeline \endpipeline ERROR: could not determine data type of parameter $1 -- \getresults displays all results preceding a \flushrequest. \startpipeline -SELECT $1 \bind 1 \g -SELECT $1 \bind 2 \g +SELECT $1 \bind 1 \sendpipeline +SELECT $1 \bind 2 \sendpipeline \flushrequest \getresults ?column? @@ -226,8 +226,8 @@ SELECT $1 \bind 2 \g \endpipeline -- \getresults displays all results preceding a \syncpipeline. \startpipeline -SELECT $1 \bind 1 \g -SELECT $1 \bind 2 \g +SELECT $1 \bind 1 \sendpipeline +SELECT $1 \bind 2 \sendpipeline \syncpipeline \getresults ?column? @@ -245,7 +245,7 @@ SELECT $1 \bind 2 \g \startpipeline \getresults No pending results to get -SELECT $1 \bind 2 \g +SELECT $1 \bind 2 \sendpipeline \getresults No pending results to get \flushrequest @@ -259,9 +259,9 @@ No pending results to get No pending results to get -- \getresults only fetches results preceding a \flushrequest. \startpipeline -SELECT $1 \bind 2 \g +SELECT $1 \bind 2 \sendpipeline \flushrequest -SELECT $1 \bind 2 \g +SELECT $1 \bind 2 \sendpipeline \getresults ?column? ---------- @@ -276,9 +276,9 @@ SELECT $1 \bind 2 \g -- \getresults only fetches results preceding a \syncpipeline. \startpipeline -SELECT $1 \bind 2 \g +SELECT $1 \bind 2 \sendpipeline \syncpipeline -SELECT $1 \bind 2 \g +SELECT $1 \bind 2 \sendpipeline \getresults ?column? ---------- @@ -294,7 +294,7 @@ SELECT $1 \bind 2 \g -- Use pipeline with chunked results for both \getresults and \endpipeline. \startpipeline \set FETCH_COUNT 10 -SELECT $1 \bind 2 \g +SELECT $1 \bind 2 \sendpipeline \flushrequest \getresults ?column? @@ -302,7 +302,7 @@ SELECT $1 \bind 2 \g 2 (1 row) -SELECT $1 \bind 2 \g +SELECT $1 \bind 2 \sendpipeline \endpipeline ?column? ---------- @@ -312,9 +312,9 @@ SELECT $1 \bind 2 \g \unset FETCH_COUNT -- \getresults with specific number of requested results. \startpipeline -SELECT $1 \bind 1 \g -SELECT $1 \bind 2 \g -SELECT $1 \bind 3 \g +SELECT $1 \bind 1 \sendpipeline +SELECT $1 \bind 2 \sendpipeline +SELECT $1 \bind 3 \sendpipeline \echo :PIPELINE_SYNC_COUNT 0 \syncpipeline @@ -330,7 +330,7 @@ SELECT $1 \bind 3 \g \echo :PIPELINE_RESULT_COUNT 2 -SELECT $1 \bind 4 \g +SELECT $1 \bind 4 \sendpipeline \getresults 3 ?column? ---------- @@ -354,7 +354,7 @@ SELECT $1 \bind 4 \g \startpipeline \syncpipeline \syncpipeline -SELECT $1 \bind 1 \g +SELECT $1 \bind 1 \sendpipeline \flushrequest \getresults 2 \getresults 1 @@ -366,9 +366,9 @@ SELECT $1 \bind 1 \g \endpipeline -- \getresults 0 should get all the results. \startpipeline -SELECT $1 \bind 1 \g -SELECT $1 \bind 2 \g -SELECT $1 \bind 3 \g +SELECT $1 \bind 1 \sendpipeline +SELECT $1 \bind 2 \sendpipeline +SELECT $1 \bind 3 \sendpipeline \syncpipeline \getresults 0 ?column? @@ -398,7 +398,7 @@ cannot send pipeline when not in pipeline mode \startpipeline SELECT 1; PQsendQuery not allowed in pipeline mode -SELECT $1 \bind 'val1' \g +SELECT $1 \bind 'val1' \sendpipeline \endpipeline ?column? ---------- @@ -408,9 +408,9 @@ SELECT $1 \bind 'val1' \g -- After an aborted pipeline, commands after a \syncpipeline should be -- displayed. \startpipeline -SELECT $1 \bind \g +SELECT $1 \bind \sendpipeline \syncpipeline -SELECT $1 \bind 1 \g +SELECT $1 \bind 1 \sendpipeline \endpipeline ERROR: bind message supplies 0 parameters, but prepared statement "" requires 1 ?column? @@ -421,23 +421,23 @@ ERROR: bind message supplies 0 parameters, but prepared statement "" requires 1 -- For an incorrect number of parameters, the pipeline is aborted and -- the following queries will not be executed. \startpipeline -SELECT \bind 'val1' \g -SELECT $1 \bind 'val1' \g +SELECT \bind 'val1' \sendpipeline +SELECT $1 \bind 'val1' \sendpipeline \endpipeline ERROR: bind message supplies 1 parameters, but prepared statement "" requires 0 -- An explicit transaction with an error needs to be rollbacked after -- the pipeline. \startpipeline -BEGIN \bind \g -INSERT INTO psql_pipeline VALUES ($1) \bind 1 \g -ROLLBACK \bind \g +BEGIN \bind \sendpipeline +INSERT INTO psql_pipeline VALUES ($1) \bind 1 \sendpipeline +ROLLBACK \bind \sendpipeline \endpipeline ERROR: duplicate key value violates unique constraint "psql_pipeline_pkey" DETAIL: Key (a)=(1) already exists. ROLLBACK; -- \watch sends a simple query, something not allowed within a pipeline. \startpipeline -SELECT \bind \g +SELECT \bind \sendpipeline \watch 1 PQsendQuery not allowed in pipeline mode @@ -450,7 +450,7 @@ PQsendQuery not allowed in pipeline mode \startpipeline SELECT $1 \bind 1 \gdesc synchronous command execution functions are not allowed in pipeline mode -SELECT $1 \bind 1 \g +SELECT $1 \bind 1 \sendpipeline \endpipeline ?column? ---------- @@ -465,42 +465,63 @@ SELECT $1 as k, $2 as l \parse 'second' \gset not allowed in pipeline mode \bind_named second 1 2 \gset pref02_ \echo :pref02_i :pref02_j \gset not allowed in pipeline mode -\bind_named '' 1 2 \g +\bind_named '' 1 2 \sendpipeline \endpipeline i | j ---+--- 1 | 2 (1 row) --- \gx is not allowed, pipeline should still be usable. +-- \g and \gx are not allowed, pipeline should still be usable. \startpipeline +SELECT $1 \bind 1 \g +\g not allowed in pipeline mode +SELECT $1 \bind 1 \g (format=unaligned tuples_only=on) +\g not allowed in pipeline mode SELECT $1 \bind 1 \gx \gx not allowed in pipeline mode +SELECT $1 \bind 1 \gx (format=unaligned tuples_only=on) +\gx not allowed in pipeline mode \reset -SELECT $1 \bind 1 \g +SELECT $1 \bind 1 \sendpipeline \endpipeline ?column? ---------- 1 (1 row) --- \gx warning should be emitted in an aborted pipeline, with +-- \g and \gx warnings should be emitted in an aborted pipeline, with -- pipeline still usable. \startpipeline -SELECT $1 \bind \g +SELECT $1 \bind \sendpipeline \flushrequest \getresults ERROR: bind message supplies 0 parameters, but prepared statement "" requires 1 +SELECT $1 \bind 1 \g +\g not allowed in pipeline mode SELECT $1 \bind 1 \gx \gx not allowed in pipeline mode \endpipeline +-- \sendpipeline is not allowed outside of a pipeline +\sendpipeline +\sendpipeline not allowed outside of pipeline mode +SELECT $1 \bind 1 \sendpipeline +\sendpipeline not allowed outside of pipeline mode +\reset +-- \sendpipeline is not allowed if not preceded by \bind or \bind_named +\startpipeline +\sendpipeline +\sendpipeline must be used after \bind or \bind_named +SELECT 1 \sendpipeline +\sendpipeline must be used after \bind or \bind_named +\endpipeline -- \gexec is not allowed, pipeline should still be usable. \startpipeline SELECT 'INSERT INTO psql_pipeline(a) SELECT generate_series(1, 10)' \parse 'insert_stmt' \bind_named insert_stmt \gexec \gexec not allowed in pipeline mode -\bind_named insert_stmt \g -SELECT COUNT(*) FROM psql_pipeline \bind \g +\bind_named insert_stmt \sendpipeline +SELECT COUNT(*) FROM psql_pipeline \bind \sendpipeline \endpipeline ?column? ------------------------------------------------------------ @@ -515,26 +536,26 @@ SELECT COUNT(*) FROM psql_pipeline \bind \g -- After an error, pipeline is aborted and requires \syncpipeline to be -- reusable. \startpipeline -SELECT $1 \bind \g -SELECT $1 \bind 1 \g +SELECT $1 \bind \sendpipeline +SELECT $1 \bind 1 \sendpipeline SELECT $1 \parse a -\bind_named a 1 \g +\bind_named a 1 \sendpipeline \close a \flushrequest \getresults ERROR: bind message supplies 0 parameters, but prepared statement "" requires 1 -- Pipeline is aborted. -SELECT $1 \bind 1 \g +SELECT $1 \bind 1 \sendpipeline SELECT $1 \parse a -\bind_named a 1 \g +\bind_named a 1 \sendpipeline \close a -- Sync allows pipeline to recover. \syncpipeline \getresults Pipeline aborted, command did not run -SELECT $1 \bind 1 \g +SELECT $1 \bind 1 \sendpipeline SELECT $1 \parse a -\bind_named a 1 \g +\bind_named a 1 \sendpipeline \close a \flushrequest \getresults @@ -551,10 +572,10 @@ SELECT $1 \parse a \endpipeline -- In an aborted pipeline, \getresults 1 aborts commands one at a time. \startpipeline -SELECT $1 \bind \g -SELECT $1 \bind 1 \g +SELECT $1 \bind \sendpipeline +SELECT $1 \bind 1 \sendpipeline SELECT $1 \parse a -\bind_named a 1 \g +\bind_named a 1 \sendpipeline \syncpipeline \getresults 1 ERROR: bind message supplies 0 parameters, but prepared statement "" requires 1 @@ -569,11 +590,11 @@ Pipeline aborted, command did not run -- Test chunked results with an aborted pipeline. \startpipeline \set FETCH_COUNT 10 -SELECT $1 \bind \g +SELECT $1 \bind \sendpipeline \flushrequest \getresults ERROR: bind message supplies 0 parameters, but prepared statement "" requires 1 -SELECT $1 \bind \g +SELECT $1 \bind \sendpipeline \endpipeline fetching results in chunked mode failed Pipeline aborted, command did not run @@ -595,7 +616,7 @@ select 1; -- Error messages accumulate and are repeated. \startpipeline -SELECT 1 \bind \g +SELECT 1 \bind \sendpipeline SELECT 1; PQsendQuery not allowed in pipeline mode SELECT 1; @@ -616,12 +637,12 @@ PQsendQuery not allowed in pipeline mode -- commit the implicit transaction block. The first command after a -- sync will not be seen as belonging to a pipeline. \startpipeline -SET LOCAL statement_timeout='1h' \bind \g -SHOW statement_timeout \bind \g +SET LOCAL statement_timeout='1h' \bind \sendpipeline +SHOW statement_timeout \bind \sendpipeline \syncpipeline -SHOW statement_timeout \bind \g -SET LOCAL statement_timeout='2h' \bind \g -SHOW statement_timeout \bind \g +SHOW statement_timeout \bind \sendpipeline +SET LOCAL statement_timeout='2h' \bind \sendpipeline +SHOW statement_timeout \bind \sendpipeline \endpipeline WARNING: SET LOCAL can only be used in transaction blocks statement_timeout @@ -641,9 +662,9 @@ WARNING: SET LOCAL can only be used in transaction blocks -- REINDEX CONCURRENTLY fails if not the first command in a pipeline. \startpipeline -SELECT $1 \bind 1 \g -REINDEX TABLE CONCURRENTLY psql_pipeline \bind \g -SELECT $1 \bind 2 \g +SELECT $1 \bind 1 \sendpipeline +REINDEX TABLE CONCURRENTLY psql_pipeline \bind \sendpipeline +SELECT $1 \bind 2 \sendpipeline \endpipeline ?column? ---------- @@ -653,8 +674,8 @@ SELECT $1 \bind 2 \g ERROR: REINDEX CONCURRENTLY cannot run inside a transaction block -- REINDEX CONCURRENTLY works if it is the first command in a pipeline. \startpipeline -REINDEX TABLE CONCURRENTLY psql_pipeline \bind \g -SELECT $1 \bind 2 \g +REINDEX TABLE CONCURRENTLY psql_pipeline \bind \sendpipeline +SELECT $1 \bind 2 \sendpipeline \endpipeline ?column? ---------- @@ -663,25 +684,25 @@ SELECT $1 \bind 2 \g -- Subtransactions are not allowed in a pipeline. \startpipeline -SAVEPOINT a \bind \g -SELECT $1 \bind 1 \g -ROLLBACK TO SAVEPOINT a \bind \g -SELECT $1 \bind 2 \g +SAVEPOINT a \bind \sendpipeline +SELECT $1 \bind 1 \sendpipeline +ROLLBACK TO SAVEPOINT a \bind \sendpipeline +SELECT $1 \bind 2 \sendpipeline \endpipeline ERROR: SAVEPOINT can only be used in transaction blocks -- LOCK fails as the first command in a pipeline, as not seen in an -- implicit transaction block. \startpipeline -LOCK psql_pipeline \bind \g -SELECT $1 \bind 2 \g +LOCK psql_pipeline \bind \sendpipeline +SELECT $1 \bind 2 \sendpipeline \endpipeline ERROR: LOCK TABLE can only be used in transaction blocks -- LOCK succeeds as it is not the first command in a pipeline, -- seen in an implicit transaction block. \startpipeline -SELECT $1 \bind 1 \g -LOCK psql_pipeline \bind \g -SELECT $1 \bind 2 \g +SELECT $1 \bind 1 \sendpipeline +LOCK psql_pipeline \bind \sendpipeline +SELECT $1 \bind 2 \sendpipeline \endpipeline ?column? ---------- @@ -695,12 +716,12 @@ SELECT $1 \bind 2 \g -- VACUUM works as the first command in a pipeline. \startpipeline -VACUUM psql_pipeline \bind \g +VACUUM psql_pipeline \bind \sendpipeline \endpipeline -- VACUUM fails when not the first command in a pipeline. \startpipeline -SELECT 1 \bind \g -VACUUM psql_pipeline \bind \g +SELECT 1 \bind \sendpipeline +VACUUM psql_pipeline \bind \sendpipeline \endpipeline ?column? ---------- @@ -710,9 +731,9 @@ VACUUM psql_pipeline \bind \g ERROR: VACUUM cannot run inside a transaction block -- VACUUM works after a \syncpipeline. \startpipeline -SELECT 1 \bind \g +SELECT 1 \bind \sendpipeline \syncpipeline -VACUUM psql_pipeline \bind \g +VACUUM psql_pipeline \bind \sendpipeline \endpipeline ?column? ---------- diff --git a/src/test/regress/sql/psql.sql b/src/test/regress/sql/psql.sql index 97d1be3aac3..1a8a83462f0 100644 --- a/src/test/regress/sql/psql.sql +++ b/src/test/regress/sql/psql.sql @@ -1074,6 +1074,7 @@ select \if false \\ (bogus \else \\ 42 \endif \\ forty_two; \q \reset \s arg1 + \sendpipeline \set arg1 arg2 arg3 arg4 arg5 arg6 arg7 \setenv arg1 arg2 \sf whole_line diff --git a/src/test/regress/sql/psql_pipeline.sql b/src/test/regress/sql/psql_pipeline.sql index 6517ebb71f8..e4d7e614af3 100644 --- a/src/test/regress/sql/psql_pipeline.sql +++ b/src/test/regress/sql/psql_pipeline.sql @@ -6,23 +6,23 @@ CREATE TABLE psql_pipeline(a INTEGER PRIMARY KEY, s TEXT); -- Single query \startpipeline -SELECT $1 \bind 'val1' \g +SELECT $1 \bind 'val1' \sendpipeline \endpipeline -- Multiple queries \startpipeline -SELECT $1 \bind 'val1' \g -SELECT $1, $2 \bind 'val2' 'val3' \g -SELECT $1, $2 \bind 'val2' 'val3' \g +SELECT $1 \bind 'val1' \sendpipeline +SELECT $1, $2 \bind 'val2' 'val3' \sendpipeline +SELECT $1, $2 \bind 'val2' 'val3' \sendpipeline \endpipeline -- Test \flush \startpipeline \flush -SELECT $1 \bind 'val1' \g +SELECT $1 \bind 'val1' \sendpipeline \flush -SELECT $1, $2 \bind 'val2' 'val3' \g -SELECT $1, $2 \bind 'val2' 'val3' \g +SELECT $1, $2 \bind 'val2' 'val3' \sendpipeline +SELECT $1, $2 \bind 'val2' 'val3' \sendpipeline \endpipeline -- Send multiple syncs @@ -30,12 +30,12 @@ SELECT $1, $2 \bind 'val2' 'val3' \g \echo :PIPELINE_COMMAND_COUNT \echo :PIPELINE_SYNC_COUNT \echo :PIPELINE_RESULT_COUNT -SELECT $1 \bind 'val1' \g +SELECT $1 \bind 'val1' \sendpipeline \syncpipeline \syncpipeline -SELECT $1, $2 \bind 'val2' 'val3' \g +SELECT $1, $2 \bind 'val2' 'val3' \sendpipeline \syncpipeline -SELECT $1, $2 \bind 'val4' 'val5' \g +SELECT $1, $2 \bind 'val4' 'val5' \sendpipeline \echo :PIPELINE_COMMAND_COUNT \echo :PIPELINE_SYNC_COUNT \echo :PIPELINE_RESULT_COUNT @@ -44,39 +44,39 @@ SELECT $1, $2 \bind 'val4' 'val5' \g -- \startpipeline should not have any effect if already in a pipeline. \startpipeline \startpipeline -SELECT $1 \bind 'val1' \g +SELECT $1 \bind 'val1' \sendpipeline \endpipeline -- Convert an implicit transaction block to an explicit transaction block. \startpipeline -INSERT INTO psql_pipeline VALUES ($1) \bind 1 \g -BEGIN \bind \g -INSERT INTO psql_pipeline VALUES ($1) \bind 2 \g -ROLLBACK \bind \g +INSERT INTO psql_pipeline VALUES ($1) \bind 1 \sendpipeline +BEGIN \bind \sendpipeline +INSERT INTO psql_pipeline VALUES ($1) \bind 2 \sendpipeline +ROLLBACK \bind \sendpipeline \endpipeline -- Multiple explicit transactions \startpipeline -BEGIN \bind \g -INSERT INTO psql_pipeline VALUES ($1) \bind 1 \g -ROLLBACK \bind \g -BEGIN \bind \g -INSERT INTO psql_pipeline VALUES ($1) \bind 1 \g -COMMIT \bind \g +BEGIN \bind \sendpipeline +INSERT INTO psql_pipeline VALUES ($1) \bind 1 \sendpipeline +ROLLBACK \bind \sendpipeline +BEGIN \bind \sendpipeline +INSERT INTO psql_pipeline VALUES ($1) \bind 1 \sendpipeline +COMMIT \bind \sendpipeline \endpipeline -- COPY FROM STDIN \startpipeline -SELECT $1 \bind 'val1' \g -COPY psql_pipeline FROM STDIN \bind \g +SELECT $1 \bind 'val1' \sendpipeline +COPY psql_pipeline FROM STDIN \bind \sendpipeline \endpipeline 2 test2 \. -- COPY FROM STDIN with \flushrequest + \getresults \startpipeline -SELECT $1 \bind 'val1' \g -COPY psql_pipeline FROM STDIN \bind \g +SELECT $1 \bind 'val1' \sendpipeline +COPY psql_pipeline FROM STDIN \bind \sendpipeline \flushrequest \getresults 3 test3 @@ -85,8 +85,8 @@ COPY psql_pipeline FROM STDIN \bind \g -- COPY FROM STDIN with \syncpipeline + \getresults \startpipeline -SELECT $1 \bind 'val1' \g -COPY psql_pipeline FROM STDIN \bind \g +SELECT $1 \bind 'val1' \sendpipeline +COPY psql_pipeline FROM STDIN \bind \sendpipeline \syncpipeline \getresults 4 test4 @@ -95,22 +95,22 @@ COPY psql_pipeline FROM STDIN \bind \g -- COPY TO STDOUT \startpipeline -SELECT $1 \bind 'val1' \g -copy psql_pipeline TO STDOUT \bind \g +SELECT $1 \bind 'val1' \sendpipeline +copy psql_pipeline TO STDOUT \bind \sendpipeline \endpipeline -- COPY TO STDOUT with \flushrequest + \getresults \startpipeline -SELECT $1 \bind 'val1' \g -copy psql_pipeline TO STDOUT \bind \g +SELECT $1 \bind 'val1' \sendpipeline +copy psql_pipeline TO STDOUT \bind \sendpipeline \flushrequest \getresults \endpipeline -- COPY TO STDOUT with \syncpipeline + \getresults \startpipeline -SELECT $1 \bind 'val1' \g -copy psql_pipeline TO STDOUT \bind \g +SELECT $1 \bind 'val1' \sendpipeline +copy psql_pipeline TO STDOUT \bind \sendpipeline \syncpipeline \getresults \endpipeline @@ -120,22 +120,22 @@ copy psql_pipeline TO STDOUT \bind \g SELECT $1 \parse '' SELECT $1, $2 \parse '' SELECT $2 \parse pipeline_1 -\bind_named '' 1 2 \g -\bind_named pipeline_1 2 \g +\bind_named '' 1 2 \sendpipeline +\bind_named pipeline_1 2 \sendpipeline \endpipeline -- \getresults displays all results preceding a \flushrequest. \startpipeline -SELECT $1 \bind 1 \g -SELECT $1 \bind 2 \g +SELECT $1 \bind 1 \sendpipeline +SELECT $1 \bind 2 \sendpipeline \flushrequest \getresults \endpipeline -- \getresults displays all results preceding a \syncpipeline. \startpipeline -SELECT $1 \bind 1 \g -SELECT $1 \bind 2 \g +SELECT $1 \bind 1 \sendpipeline +SELECT $1 \bind 2 \sendpipeline \syncpipeline \getresults \endpipeline @@ -143,7 +143,7 @@ SELECT $1 \bind 2 \g -- \getresults immediately returns if there is no result to fetch. \startpipeline \getresults -SELECT $1 \bind 2 \g +SELECT $1 \bind 2 \sendpipeline \getresults \flushrequest \endpipeline @@ -151,42 +151,42 @@ SELECT $1 \bind 2 \g -- \getresults only fetches results preceding a \flushrequest. \startpipeline -SELECT $1 \bind 2 \g +SELECT $1 \bind 2 \sendpipeline \flushrequest -SELECT $1 \bind 2 \g +SELECT $1 \bind 2 \sendpipeline \getresults \endpipeline -- \getresults only fetches results preceding a \syncpipeline. \startpipeline -SELECT $1 \bind 2 \g +SELECT $1 \bind 2 \sendpipeline \syncpipeline -SELECT $1 \bind 2 \g +SELECT $1 \bind 2 \sendpipeline \getresults \endpipeline -- Use pipeline with chunked results for both \getresults and \endpipeline. \startpipeline \set FETCH_COUNT 10 -SELECT $1 \bind 2 \g +SELECT $1 \bind 2 \sendpipeline \flushrequest \getresults -SELECT $1 \bind 2 \g +SELECT $1 \bind 2 \sendpipeline \endpipeline \unset FETCH_COUNT -- \getresults with specific number of requested results. \startpipeline -SELECT $1 \bind 1 \g -SELECT $1 \bind 2 \g -SELECT $1 \bind 3 \g +SELECT $1 \bind 1 \sendpipeline +SELECT $1 \bind 2 \sendpipeline +SELECT $1 \bind 3 \sendpipeline \echo :PIPELINE_SYNC_COUNT \syncpipeline \echo :PIPELINE_SYNC_COUNT \echo :PIPELINE_RESULT_COUNT \getresults 1 \echo :PIPELINE_RESULT_COUNT -SELECT $1 \bind 4 \g +SELECT $1 \bind 4 \sendpipeline \getresults 3 \echo :PIPELINE_RESULT_COUNT \endpipeline @@ -195,7 +195,7 @@ SELECT $1 \bind 4 \g \startpipeline \syncpipeline \syncpipeline -SELECT $1 \bind 1 \g +SELECT $1 \bind 1 \sendpipeline \flushrequest \getresults 2 \getresults 1 @@ -203,9 +203,9 @@ SELECT $1 \bind 1 \g -- \getresults 0 should get all the results. \startpipeline -SELECT $1 \bind 1 \g -SELECT $1 \bind 2 \g -SELECT $1 \bind 3 \g +SELECT $1 \bind 1 \sendpipeline +SELECT $1 \bind 2 \sendpipeline +SELECT $1 \bind 3 \sendpipeline \syncpipeline \getresults 0 \endpipeline @@ -221,36 +221,36 @@ SELECT $1 \bind 3 \g -- pipeline usable. \startpipeline SELECT 1; -SELECT $1 \bind 'val1' \g +SELECT $1 \bind 'val1' \sendpipeline \endpipeline -- After an aborted pipeline, commands after a \syncpipeline should be -- displayed. \startpipeline -SELECT $1 \bind \g +SELECT $1 \bind \sendpipeline \syncpipeline -SELECT $1 \bind 1 \g +SELECT $1 \bind 1 \sendpipeline \endpipeline -- For an incorrect number of parameters, the pipeline is aborted and -- the following queries will not be executed. \startpipeline -SELECT \bind 'val1' \g -SELECT $1 \bind 'val1' \g +SELECT \bind 'val1' \sendpipeline +SELECT $1 \bind 'val1' \sendpipeline \endpipeline -- An explicit transaction with an error needs to be rollbacked after -- the pipeline. \startpipeline -BEGIN \bind \g -INSERT INTO psql_pipeline VALUES ($1) \bind 1 \g -ROLLBACK \bind \g +BEGIN \bind \sendpipeline +INSERT INTO psql_pipeline VALUES ($1) \bind 1 \sendpipeline +ROLLBACK \bind \sendpipeline \endpipeline ROLLBACK; -- \watch sends a simple query, something not allowed within a pipeline. \startpipeline -SELECT \bind \g +SELECT \bind \sendpipeline \watch 1 \endpipeline @@ -258,7 +258,7 @@ SELECT \bind \g -- and the pipeline should still be usable. \startpipeline SELECT $1 \bind 1 \gdesc -SELECT $1 \bind 1 \g +SELECT $1 \bind 1 \sendpipeline \endpipeline -- \gset is not allowed in a pipeline, pipeline should still be usable. @@ -267,54 +267,69 @@ SELECT $1 as i, $2 as j \parse '' SELECT $1 as k, $2 as l \parse 'second' \bind_named '' 1 2 \gset \bind_named second 1 2 \gset pref02_ \echo :pref02_i :pref02_j -\bind_named '' 1 2 \g +\bind_named '' 1 2 \sendpipeline \endpipeline --- \gx is not allowed, pipeline should still be usable. +-- \g and \gx are not allowed, pipeline should still be usable. \startpipeline +SELECT $1 \bind 1 \g +SELECT $1 \bind 1 \g (format=unaligned tuples_only=on) SELECT $1 \bind 1 \gx +SELECT $1 \bind 1 \gx (format=unaligned tuples_only=on) \reset -SELECT $1 \bind 1 \g +SELECT $1 \bind 1 \sendpipeline \endpipeline --- \gx warning should be emitted in an aborted pipeline, with +-- \g and \gx warnings should be emitted in an aborted pipeline, with -- pipeline still usable. \startpipeline -SELECT $1 \bind \g +SELECT $1 \bind \sendpipeline \flushrequest \getresults +SELECT $1 \bind 1 \g SELECT $1 \bind 1 \gx \endpipeline +-- \sendpipeline is not allowed outside of a pipeline +\sendpipeline +SELECT $1 \bind 1 \sendpipeline +\reset + +-- \sendpipeline is not allowed if not preceded by \bind or \bind_named +\startpipeline +\sendpipeline +SELECT 1 \sendpipeline +\endpipeline + -- \gexec is not allowed, pipeline should still be usable. \startpipeline SELECT 'INSERT INTO psql_pipeline(a) SELECT generate_series(1, 10)' \parse 'insert_stmt' \bind_named insert_stmt \gexec -\bind_named insert_stmt \g -SELECT COUNT(*) FROM psql_pipeline \bind \g +\bind_named insert_stmt \sendpipeline +SELECT COUNT(*) FROM psql_pipeline \bind \sendpipeline \endpipeline -- After an error, pipeline is aborted and requires \syncpipeline to be -- reusable. \startpipeline -SELECT $1 \bind \g -SELECT $1 \bind 1 \g +SELECT $1 \bind \sendpipeline +SELECT $1 \bind 1 \sendpipeline SELECT $1 \parse a -\bind_named a 1 \g +\bind_named a 1 \sendpipeline \close a \flushrequest \getresults -- Pipeline is aborted. -SELECT $1 \bind 1 \g +SELECT $1 \bind 1 \sendpipeline SELECT $1 \parse a -\bind_named a 1 \g +\bind_named a 1 \sendpipeline \close a -- Sync allows pipeline to recover. \syncpipeline \getresults -SELECT $1 \bind 1 \g +SELECT $1 \bind 1 \sendpipeline SELECT $1 \parse a -\bind_named a 1 \g +\bind_named a 1 \sendpipeline \close a \flushrequest \getresults @@ -322,10 +337,10 @@ SELECT $1 \parse a -- In an aborted pipeline, \getresults 1 aborts commands one at a time. \startpipeline -SELECT $1 \bind \g -SELECT $1 \bind 1 \g +SELECT $1 \bind \sendpipeline +SELECT $1 \bind 1 \sendpipeline SELECT $1 \parse a -\bind_named a 1 \g +\bind_named a 1 \sendpipeline \syncpipeline \getresults 1 \getresults 1 @@ -337,10 +352,10 @@ SELECT $1 \parse a -- Test chunked results with an aborted pipeline. \startpipeline \set FETCH_COUNT 10 -SELECT $1 \bind \g +SELECT $1 \bind \sendpipeline \flushrequest \getresults -SELECT $1 \bind \g +SELECT $1 \bind \sendpipeline \endpipeline \unset FETCH_COUNT @@ -356,7 +371,7 @@ select 1; -- Error messages accumulate and are repeated. \startpipeline -SELECT 1 \bind \g +SELECT 1 \bind \sendpipeline SELECT 1; SELECT 1; \endpipeline @@ -371,66 +386,66 @@ SELECT 1; -- commit the implicit transaction block. The first command after a -- sync will not be seen as belonging to a pipeline. \startpipeline -SET LOCAL statement_timeout='1h' \bind \g -SHOW statement_timeout \bind \g +SET LOCAL statement_timeout='1h' \bind \sendpipeline +SHOW statement_timeout \bind \sendpipeline \syncpipeline -SHOW statement_timeout \bind \g -SET LOCAL statement_timeout='2h' \bind \g -SHOW statement_timeout \bind \g +SHOW statement_timeout \bind \sendpipeline +SET LOCAL statement_timeout='2h' \bind \sendpipeline +SHOW statement_timeout \bind \sendpipeline \endpipeline -- REINDEX CONCURRENTLY fails if not the first command in a pipeline. \startpipeline -SELECT $1 \bind 1 \g -REINDEX TABLE CONCURRENTLY psql_pipeline \bind \g -SELECT $1 \bind 2 \g +SELECT $1 \bind 1 \sendpipeline +REINDEX TABLE CONCURRENTLY psql_pipeline \bind \sendpipeline +SELECT $1 \bind 2 \sendpipeline \endpipeline -- REINDEX CONCURRENTLY works if it is the first command in a pipeline. \startpipeline -REINDEX TABLE CONCURRENTLY psql_pipeline \bind \g -SELECT $1 \bind 2 \g +REINDEX TABLE CONCURRENTLY psql_pipeline \bind \sendpipeline +SELECT $1 \bind 2 \sendpipeline \endpipeline -- Subtransactions are not allowed in a pipeline. \startpipeline -SAVEPOINT a \bind \g -SELECT $1 \bind 1 \g -ROLLBACK TO SAVEPOINT a \bind \g -SELECT $1 \bind 2 \g +SAVEPOINT a \bind \sendpipeline +SELECT $1 \bind 1 \sendpipeline +ROLLBACK TO SAVEPOINT a \bind \sendpipeline +SELECT $1 \bind 2 \sendpipeline \endpipeline -- LOCK fails as the first command in a pipeline, as not seen in an -- implicit transaction block. \startpipeline -LOCK psql_pipeline \bind \g -SELECT $1 \bind 2 \g +LOCK psql_pipeline \bind \sendpipeline +SELECT $1 \bind 2 \sendpipeline \endpipeline -- LOCK succeeds as it is not the first command in a pipeline, -- seen in an implicit transaction block. \startpipeline -SELECT $1 \bind 1 \g -LOCK psql_pipeline \bind \g -SELECT $1 \bind 2 \g +SELECT $1 \bind 1 \sendpipeline +LOCK psql_pipeline \bind \sendpipeline +SELECT $1 \bind 2 \sendpipeline \endpipeline -- VACUUM works as the first command in a pipeline. \startpipeline -VACUUM psql_pipeline \bind \g +VACUUM psql_pipeline \bind \sendpipeline \endpipeline -- VACUUM fails when not the first command in a pipeline. \startpipeline -SELECT 1 \bind \g -VACUUM psql_pipeline \bind \g +SELECT 1 \bind \sendpipeline +VACUUM psql_pipeline \bind \sendpipeline \endpipeline -- VACUUM works after a \syncpipeline. \startpipeline -SELECT 1 \bind \g +SELECT 1 \bind \sendpipeline \syncpipeline -VACUUM psql_pipeline \bind \g +VACUUM psql_pipeline \bind \sendpipeline \endpipeline -- Clean up |