psql: Add pipeline status to prompt and some state variables
authorMichael Paquier <[email protected]>
Tue, 25 Feb 2025 01:07:24 +0000 (10:07 +0900)
committerMichael Paquier <[email protected]>
Tue, 25 Feb 2025 01:07:24 +0000 (10:07 +0900)
This commit adds %P to psql prompts, able to report the status of a
pipeline depending on PQpipelineStatus(): on, off or abort.

The following variables are added to report the state of an ongoing
pipeline:
- PIPELINE_SYNC_COUNT: reports the number of piped syncs.
- PIPELINE_COMMAND_COUNT: reports the number of piped commands, a
command being either \bind, \bind_named, \close or \parse.
- PIPELINE_RESULT_COUNT: reports the results available to read with
\getresults.

These variables can be used with \echo or in a prompt, using "%:name:"
in PROMPT1, PROMPT2 or PROMPT3.  Some basic regression tests are added
for these.  The suggestion to use variables to show the details about
the status counters comes from me.  The original patch proposed was less
extensible, hardcoding the output in the prompt.

Author: Anthonin Bonnefoy <[email protected]>
Discussion: https://postgr.es/m/CAO6_XqroE7JuMEm1sWz55rp9fAYX2JwmcP_3m_v51vnOFdsLiQ@mail.gmail.com

doc/src/sgml/ref/psql-ref.sgml
src/bin/psql/common.c
src/bin/psql/prompt.c
src/bin/psql/startup.c
src/test/regress/expected/psql_pipeline.out
src/test/regress/sql/psql_pipeline.sql

index 3edbd65e46cf8cdff4d8976d39bf21ebc8bee051..cedccc14129f861bfb67642789e793ea545214b1 100644 (file)
@@ -3728,6 +3728,12 @@ testdb=&gt; <userinput>\setenv LESS -imx4F</userinput>
         generate one result to get.
        </para>
 
+       <para>
+        When pipeline mode is active, a dedicated prompt variable is available
+        to report the pipeline status.
+        See <xref linkend="app-psql-prompting-p-uc"/> for more details
+       </para>
+
        <para>
         Example:
 <programlisting>
@@ -4502,6 +4508,39 @@ bar
         </listitem>
       </varlistentry>
 
+      <varlistentry id="app-psql-variables-pipeline-command-count">
+        <term><varname>PIPELINE_COMMAND_COUNT</varname></term>
+        <listitem>
+        <para>
+        The number of commands generated by <literal>\bind</literal>,
+        <literal>\bind_named</literal>, <literal>\close</literal> or
+        <literal>\parse</literal> queued in an ongoing pipeline.
+        </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry id="app-psql-variables-pipeline-result-count">
+        <term><varname>PIPELINE_RESULT_COUNT</varname></term>
+        <listitem>
+        <para>
+        The number of commands of an ongoing pipeline that were followed
+        by either a <command>\flushrequest</command> or a
+        <command>\syncpipeline</command>, forcing the server to send the
+        results. These results can be retrieved with
+        <command>\getresults</command>.
+        </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry id="app-psql-variables-pipeline-sync-count">
+        <term><varname>PIPELINE_SYNC_COUNT</varname></term>
+        <listitem>
+        <para>
+        The number of sync messages queued in an ongoing pipeline.
+        </para>
+        </listitem>
+      </varlistentry>
+
       <varlistentry id="app-psql-variables-port">
         <term><varname>PORT</varname></term>
         <listitem>
@@ -4901,6 +4940,17 @@ testdb=&gt; <userinput>INSERT INTO my_table VALUES (:'content');</userinput>
         </listitem>
       </varlistentry>
 
+      <varlistentry id="app-psql-prompting-p-uc">
+        <term><literal>%P</literal></term>
+        <listitem>
+        <para>
+        Pipeline status: <literal>off</literal> when not in a pipeline,
+        <literal>on</literal> when in an ongoing pipeline or
+        <literal>abort</literal> when in an aborted pipeline.
+        </para>
+        </listitem>
+      </varlistentry>
+
       <varlistentry id="app-psql-prompting-r">
         <term><literal>%R</literal></term>
         <listitem>
index bc8c40898f7146531deeb670eb6641055d788194..ed340a466f9961275c87af326c0f3199e949c34a 100644 (file)
@@ -524,6 +524,26 @@ SetShellResultVariables(int wait_result)
 }
 
 
+/*
+ * Set special pipeline variables
+ * - PIPELINE_SYNC_COUNT: The number of piped syncs
+ * - PIPELINE_COMMAND_COUNT: The number of piped commands
+ * - PIPELINE_RESULT_COUNT: The number of results available to read
+ */
+static void
+SetPipelineVariables(void)
+{
+   char        buf[32];
+
+   snprintf(buf, sizeof(buf), "%d", pset.piped_syncs);
+   SetVariable(pset.vars, "PIPELINE_SYNC_COUNT", buf);
+   snprintf(buf, sizeof(buf), "%d", pset.piped_commands);
+   SetVariable(pset.vars, "PIPELINE_COMMAND_COUNT", buf);
+   snprintf(buf, sizeof(buf), "%d", pset.available_results);
+   SetVariable(pset.vars, "PIPELINE_RESULT_COUNT", buf);
+}
+
+
 /*
  * ClearOrSaveResult
  *
@@ -1661,6 +1681,8 @@ ExecQueryAndProcessResults(const char *query,
 
        CheckConnection();
 
+       SetPipelineVariables();
+
        return -1;
    }
 
@@ -1669,8 +1691,10 @@ ExecQueryAndProcessResults(const char *query,
    {
        /*
         * We are in a pipeline and have not reached the pipeline end, or
-        * there was no request to read pipeline results, exit.
+        * there was no request to read pipeline results.  Update the psql
+        * variables tracking the pipeline activity and exit.
         */
+       SetPipelineVariables();
        return 1;
    }
 
@@ -2105,6 +2129,7 @@ ExecQueryAndProcessResults(const char *query,
        Assert(pset.available_results == 0);
    }
    Assert(pset.requested_results == 0);
+   SetPipelineVariables();
 
    /* may need this to recover from conn loss during COPY */
    if (!CheckConnection())
index 08a14feb3c3fb0f5ff79c8d9a04890872620950e..3aa7d2d06c80ef27e5496e11b6d39364ec1e37d4 100644 (file)
@@ -31,6 +31,7 @@
  *     sockets, "[local:/dir/name]" if not default
  * %m - like %M, but hostname only (before first dot), or always "[local]"
  * %p - backend pid
+ * %P - pipeline status: on, off or abort
  * %> - database server port number
  * %n - database user name
  * %s - service
@@ -181,6 +182,19 @@ get_prompt(promptStatus_t status, ConditionalStack cstack)
                            snprintf(buf, sizeof(buf), "%d", pid);
                    }
                    break;
+                   /* pipeline status */
+               case 'P':
+                   {
+                       PGpipelineStatus status = PQpipelineStatus(pset.db);
+
+                       if (status == PQ_PIPELINE_ON)
+                           strlcpy(buf, "on", sizeof(buf));
+                       else if (status == PQ_PIPELINE_ABORTED)
+                           strlcpy(buf, "abort", sizeof(buf));
+                       else
+                           strlcpy(buf, "off", sizeof(buf));
+                       break;
+                   }
 
                case '0':
                case '1':
index 703f3f582c173879683387aacfb029356decd79d..5018eedf1e57040595fc6fad40818a7612ea0e68 100644 (file)
@@ -205,6 +205,11 @@ main(int argc, char *argv[])
    SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);
    SetVariableBool(pset.vars, "SHOW_ALL_RESULTS");
 
+   /* Initialize pipeline variables */
+   SetVariable(pset.vars, "PIPELINE_SYNC_COUNT", "0");
+   SetVariable(pset.vars, "PIPELINE_COMMAND_COUNT", "0");
+   SetVariable(pset.vars, "PIPELINE_RESULT_COUNT", "0");
+
    parse_psql_options(argc, argv, &options);
 
    /*
index f4603d2b66ae53a44b4a1a9d8a5aae81e2dee715..3df2415a84031468b4969364bb308084eb58a2fa 100644 (file)
@@ -57,12 +57,24 @@ SELECT $1, $2 \bind 'val2' 'val3' \g
 
 -- Send multiple syncs
 \startpipeline
+\echo :PIPELINE_COMMAND_COUNT
+0
+\echo :PIPELINE_SYNC_COUNT
+0
+\echo :PIPELINE_RESULT_COUNT
+0
 SELECT $1 \bind 'val1' \g
 \syncpipeline
 \syncpipeline
 SELECT $1, $2 \bind 'val2' 'val3' \g
 \syncpipeline
 SELECT $1, $2 \bind 'val4' 'val5' \g
+\echo :PIPELINE_COMMAND_COUNT
+1
+\echo :PIPELINE_SYNC_COUNT
+3
+\echo :PIPELINE_RESULT_COUNT
+2
 \endpipeline
  ?column? 
 ----------
@@ -303,13 +315,21 @@ SELECT $1 \bind 2 \g
 SELECT $1 \bind 1 \g
 SELECT $1 \bind 2 \g
 SELECT $1 \bind 3 \g
+\echo :PIPELINE_SYNC_COUNT
+0
 \syncpipeline
+\echo :PIPELINE_SYNC_COUNT
+1
+\echo :PIPELINE_RESULT_COUNT
+3
 \getresults 1
  ?column? 
 ----------
  1
 (1 row)
 
+\echo :PIPELINE_RESULT_COUNT
+2
 SELECT $1 \bind 4 \g
 \getresults 3
  ?column? 
@@ -322,6 +342,8 @@ SELECT $1 \bind 4 \g
  3
 (1 row)
 
+\echo :PIPELINE_RESULT_COUNT
+0
 \endpipeline
  ?column? 
 ----------
index ec62e6c5f2471626b00c15b28a807e4778be13d1..6517ebb71f8defdf37c8f3491fb74d6da1dcd23e 100644 (file)
@@ -27,12 +27,18 @@ SELECT $1, $2 \bind 'val2' 'val3' \g
 
 -- Send multiple syncs
 \startpipeline
+\echo :PIPELINE_COMMAND_COUNT
+\echo :PIPELINE_SYNC_COUNT
+\echo :PIPELINE_RESULT_COUNT
 SELECT $1 \bind 'val1' \g
 \syncpipeline
 \syncpipeline
 SELECT $1, $2 \bind 'val2' 'val3' \g
 \syncpipeline
 SELECT $1, $2 \bind 'val4' 'val5' \g
+\echo :PIPELINE_COMMAND_COUNT
+\echo :PIPELINE_SYNC_COUNT
+\echo :PIPELINE_RESULT_COUNT
 \endpipeline
 
 -- \startpipeline should not have any effect if already in a pipeline.
@@ -174,10 +180,15 @@ SELECT $1 \bind 2 \g
 SELECT $1 \bind 1 \g
 SELECT $1 \bind 2 \g
 SELECT $1 \bind 3 \g
+\echo :PIPELINE_SYNC_COUNT
 \syncpipeline
+\echo :PIPELINE_SYNC_COUNT
+\echo :PIPELINE_RESULT_COUNT
 \getresults 1
+\echo :PIPELINE_RESULT_COUNT
 SELECT $1 \bind 4 \g
 \getresults 3
+\echo :PIPELINE_RESULT_COUNT
 \endpipeline
 
 -- \syncpipeline count as one command to fetch for \getresults.