]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Revert "psql: Show all query results by default"
authorPeter Eisentraut <peter@eisentraut.org>
Thu, 15 Apr 2021 17:41:42 +0000 (19:41 +0200)
committerPeter Eisentraut <peter@eisentraut.org>
Thu, 15 Apr 2021 17:42:55 +0000 (19:42 +0200)
This reverts commit 3a5130672296ed4e682403a77a9a3ad3d21cef75.

Per discussion, this patch had too many issues to resolve at this
point of the development cycle.  We'll try again in the future.

Discussion: https://www.postgresql.org/message-id/flat/alpine.DEB.2.21.1904132231510.8961@lancre

13 files changed:
contrib/pg_stat_statements/expected/pg_stat_statements.out
doc/src/sgml/ref/psql-ref.sgml
src/bin/psql/common.c
src/bin/psql/help.c
src/bin/psql/settings.h
src/bin/psql/startup.c
src/bin/psql/tab-complete.c
src/test/regress/expected/copyselect.out
src/test/regress/expected/psql.out
src/test/regress/expected/transactions.out
src/test/regress/sql/copyselect.sql
src/test/regress/sql/psql.sql
src/test/regress/sql/transactions.sql

index 674ed270a8f85aab650fcde41a0cfab779200588..fb97f6873700cb3424df72a3b2e4d707f68bd623 100644 (file)
@@ -50,28 +50,8 @@ BEGIN \;
 SELECT 2.0 AS "float" \;
 SELECT 'world' AS "text" \;
 COMMIT;
- float 
--------
-   2.0
-(1 row)
-
- text  
--------
- world
-(1 row)
-
 -- compound with empty statements and spurious leading spacing
 \;\;   SELECT 3 + 3 \;\;\;   SELECT ' ' || ' !' \;\;   SELECT 1 + 4 \;;
- ?column? 
-----------
-        6
-(1 row)
-
- ?column? 
-----------
-   !
-(1 row)
-
  ?column? 
 ----------
         5
@@ -81,11 +61,6 @@ COMMIT;
 SELECT 1 + 1 + 1 AS "add" \gset
 SELECT :add + 1 + 1 AS "add" \;
 SELECT :add + 1 + 1 AS "add" \gset
- add 
------
-   5
-(1 row)
-
 -- set operator
 SELECT 1 AS i UNION SELECT 2 ORDER BY i;
  i 
index 67e527124d9f4e0422cfb4944fda610ecb30740c..bd4f26e6cc877c245eba971746701a019e075cfe 100644 (file)
@@ -127,11 +127,18 @@ echo '\x \\ SELECT * FROM foo;' | psql
        commands included in the string to divide it into multiple
        transactions.  (See <xref linkend="protocol-flow-multi-statement"/>
        for more details about how the server handles multi-query strings.)
+       Also, <application>psql</application> only prints the
+       result of the last <acronym>SQL</acronym> command in the string.
+       This is different from the behavior when the same string is read from
+       a file or fed to <application>psql</application>'s standard input,
+       because then <application>psql</application> sends
+       each <acronym>SQL</acronym> command separately.
       </para>
       <para>
-       If having several commands executed in one transaction is not desired, 
-       use repeated <option>-c</option> commands or feed multiple commands to
-       <application>psql</application>'s standard input,
+       Because of this behavior, putting more than one SQL command in a
+       single <option>-c</option> string often has unexpected results.
+       It's better to use repeated <option>-c</option> commands or feed
+       multiple commands to <application>psql</application>'s standard input,
        either using <application>echo</application> as illustrated above, or
        via a shell here-document, for example:
 <programlisting>
@@ -3525,6 +3532,10 @@ select 1\; select 2\; select 3;
         commands included in the string to divide it into multiple
         transactions.  (See <xref linkend="protocol-flow-multi-statement"/>
         for more details about how the server handles multi-query strings.)
+        <application>psql</application> prints only the last query result
+        it receives for each request; in this example, although all
+        three <command>SELECT</command>s are indeed executed, <application>psql</application>
+        only prints the <literal>3</literal>.
         </para>
         </listitem>
       </varlistentry>
@@ -4111,18 +4122,6 @@ bar
       </varlistentry>
 
       <varlistentry>
-        <term><varname>SHOW_ALL_RESULTS</varname></term>
-        <listitem>
-        <para>
-        When this variable is set to <literal>off</literal>, only the last
-        result of a combined query (<literal>\;</literal>) is shown instead of
-        all of them.  The default is <literal>on</literal>.  The off behavior
-        is for compatibility with older versions of psql.
-        </para>
-        </listitem>
-      </varlistentry>
-
-       <varlistentry>
         <term><varname>SHOW_CONTEXT</varname></term>
         <listitem>
         <para>
index 028a357991fd2d0d18bb7a43d57f186b7f4e5330..7a95465111ad1f1e3485350f680053ecb28df820 100644 (file)
@@ -33,7 +33,6 @@ static bool DescribeQuery(const char *query, double *elapsed_msec);
 static bool ExecQueryUsingCursor(const char *query, double *elapsed_msec);
 static bool command_no_begin(const char *query);
 static bool is_select_command(const char *query);
-static int SendQueryAndProcessResults(const char *query, double *pelapsed_msec, bool is_watch);
 
 
 /*
@@ -354,7 +353,7 @@ CheckConnection(void)
  * Returns true for valid result, false for error state.
  */
 static bool
-AcceptResult(const PGresult *result, bool show_error)
+AcceptResult(const PGresult *result)
 {
        bool            OK;
 
@@ -385,7 +384,7 @@ AcceptResult(const PGresult *result, bool show_error)
                                break;
                }
 
-       if (!OK && show_error)
+       if (!OK)
        {
                const char *error = PQerrorMessage(pset.db);
 
@@ -473,18 +472,6 @@ ClearOrSaveResult(PGresult *result)
        }
 }
 
-/*
- * Consume all results
- */
-static void
-ClearOrSaveAllResults()
-{
-       PGresult        *result;
-
-       while ((result = PQgetResult(pset.db)) != NULL)
-               ClearOrSaveResult(result);
-}
-
 
 /*
  * Print microtiming output.  Always print raw milliseconds; if the interval
@@ -585,7 +572,7 @@ PSQLexec(const char *query)
 
        ResetCancelConn();
 
-       if (!AcceptResult(res, true))
+       if (!AcceptResult(res))
        {
                ClearOrSaveResult(res);
                res = NULL;
@@ -607,8 +594,10 @@ PSQLexec(const char *query)
 int
 PSQLexecWatch(const char *query, const printQueryOpt *opt)
 {
+       PGresult   *res;
        double          elapsed_msec = 0;
-       int                     res;
+       instr_time      before;
+       instr_time      after;
 
        if (!pset.db)
        {
@@ -617,16 +606,75 @@ PSQLexecWatch(const char *query, const printQueryOpt *opt)
        }
 
        SetCancelConn(pset.db);
-       res = SendQueryAndProcessResults(query, &elapsed_msec, true);
+
+       if (pset.timing)
+               INSTR_TIME_SET_CURRENT(before);
+
+       res = PQexec(pset.db, query);
+
        ResetCancelConn();
 
+       if (!AcceptResult(res))
+       {
+               ClearOrSaveResult(res);
+               return 0;
+       }
+
+       if (pset.timing)
+       {
+               INSTR_TIME_SET_CURRENT(after);
+               INSTR_TIME_SUBTRACT(after, before);
+               elapsed_msec = INSTR_TIME_GET_MILLISEC(after);
+       }
+
+       /*
+        * If SIGINT is sent while the query is processing, the interrupt will be
+        * consumed.  The user's intention, though, is to cancel the entire watch
+        * process, so detect a sent cancellation request and exit in this case.
+        */
+       if (cancel_pressed)
+       {
+               PQclear(res);
+               return 0;
+       }
+
+       switch (PQresultStatus(res))
+       {
+               case PGRES_TUPLES_OK:
+                       printQuery(res, opt, pset.queryFout, false, pset.logfile);
+                       break;
+
+               case PGRES_COMMAND_OK:
+                       fprintf(pset.queryFout, "%s\n%s\n\n", opt->title, PQcmdStatus(res));
+                       break;
+
+               case PGRES_EMPTY_QUERY:
+                       pg_log_error("\\watch cannot be used with an empty query");
+                       PQclear(res);
+                       return -1;
+
+               case PGRES_COPY_OUT:
+               case PGRES_COPY_IN:
+               case PGRES_COPY_BOTH:
+                       pg_log_error("\\watch cannot be used with COPY");
+                       PQclear(res);
+                       return -1;
+
+               default:
+                       pg_log_error("unexpected result status for \\watch");
+                       PQclear(res);
+                       return -1;
+       }
+
+       PQclear(res);
+
        fflush(pset.queryFout);
 
        /* Possible microtiming output */
        if (pset.timing)
                PrintTiming(elapsed_msec);
 
-       return res;
+       return 1;
 }
 
 
@@ -839,114 +887,197 @@ loop_exit:
 
 
 /*
- * Marshal the COPY data.  Either subroutine will get the
- * connection out of its COPY state, then call PQresultStatus()
- * once and report any error. Return whether all was ok.
+ * ProcessResult: utility function for use by SendQuery() only
+ *
+ * When our command string contained a COPY FROM STDIN or COPY TO STDOUT,
+ * PQexec() has stopped at the PGresult associated with the first such
+ * command.  In that event, we'll marshal data for the COPY and then cycle
+ * through any subsequent PGresult objects.
  *
- * For COPY OUT, direct the output to pset.copyStream if it's set,
- * otherwise to pset.gfname if it's set, otherwise to queryFout.
- * For COPY IN, use pset.copyStream as data source if it's set,
- * otherwise cur_cmd_source.
+ * When the command string contained no such COPY command, this function
+ * degenerates to an AcceptResult() call.
  *
- * Update result if further processing is necessary, or NULL otherwise.
- * Return a result when queryFout can safely output a result status:
- * on COPY IN, or on COPY OUT if written to something other than pset.queryFout.
- * Returning NULL prevents the command status from being printed, which
- * we want if the status line doesn't get taken as part of the COPY data.
+ * Changes its argument to point to the last PGresult of the command string,
+ * or NULL if that result was for a COPY TO STDOUT.  (Returning NULL prevents
+ * the command status from being printed, which we want in that case so that
+ * the status line doesn't get taken as part of the COPY data.)
+ *
+ * Returns true on complete success, false otherwise.  Possible failure modes
+ * include purely client-side problems; check the transaction status for the
+ * server-side opinion.
  */
 static bool
-HandleCopyResult(PGresult **result)
+ProcessResult(PGresult **results)
 {
-       bool            success;
-       FILE       *copystream;
-       PGresult   *copy_result;
-       ExecStatusType result_status = PQresultStatus(*result);
-
-       Assert(result_status == PGRES_COPY_OUT ||
-                  result_status == PGRES_COPY_IN);
-
-       SetCancelConn(pset.db);
+       bool            success = true;
+       bool            first_cycle = true;
 
-       if (result_status == PGRES_COPY_OUT)
+       for (;;)
        {
-               bool            need_close = false;
-               bool            is_pipe = false;
+               ExecStatusType result_status;
+               bool            is_copy;
+               PGresult   *next_result;
 
-               if (pset.copyStream)
-               {
-                       /* invoked by \copy */
-                       copystream = pset.copyStream;
-               }
-               else if (pset.gfname)
+               if (!AcceptResult(*results))
                {
-                       /* invoked by \g */
-                       if (openQueryOutputFile(pset.gfname,
-                                                                       &copystream, &is_pipe))
-                       {
-                               need_close = true;
-                               if (is_pipe)
-                                       disable_sigpipe_trap();
-                       }
-                       else
-                               copystream = NULL;      /* discard COPY data entirely */
+                       /*
+                        * Failure at this point is always a server-side failure or a
+                        * failure to submit the command string.  Either way, we're
+                        * finished with this command string.
+                        */
+                       success = false;
+                       break;
                }
-               else
+
+               result_status = PQresultStatus(*results);
+               switch (result_status)
                {
-                       /* fall back to the generic query output stream */
-                       copystream = pset.queryFout;
-               }
+                       case PGRES_EMPTY_QUERY:
+                       case PGRES_COMMAND_OK:
+                       case PGRES_TUPLES_OK:
+                               is_copy = false;
+                               break;
 
-               success = handleCopyOut(pset.db,
-                                                               copystream,
-                                                               &copy_result)
-                       && (copystream != NULL);
+                       case PGRES_COPY_OUT:
+                       case PGRES_COPY_IN:
+                               is_copy = true;
+                               break;
 
-               /*
-                * Suppress status printing if the report would go to the same
-                * place as the COPY data just went.  Note this doesn't
-                * prevent error reporting, since handleCopyOut did that.
-                */
-               if (copystream == pset.queryFout)
-               {
-                       PQclear(copy_result);
-                       copy_result = NULL;
+                       default:
+                               /* AcceptResult() should have caught anything else. */
+                               is_copy = false;
+                               pg_log_error("unexpected PQresultStatus: %d", result_status);
+                               break;
                }
 
-               if (need_close)
+               if (is_copy)
                {
-                       /* close \g argument file/pipe */
-                       if (is_pipe)
+                       /*
+                        * Marshal the COPY data.  Either subroutine will get the
+                        * connection out of its COPY state, then call PQresultStatus()
+                        * once and report any error.
+                        *
+                        * For COPY OUT, direct the output to pset.copyStream if it's set,
+                        * otherwise to pset.gfname if it's set, otherwise to queryFout.
+                        * For COPY IN, use pset.copyStream as data source if it's set,
+                        * otherwise cur_cmd_source.
+                        */
+                       FILE       *copystream;
+                       PGresult   *copy_result;
+
+                       SetCancelConn(pset.db);
+                       if (result_status == PGRES_COPY_OUT)
                        {
-                               pclose(copystream);
-                               restore_sigpipe_trap();
+                               bool            need_close = false;
+                               bool            is_pipe = false;
+
+                               if (pset.copyStream)
+                               {
+                                       /* invoked by \copy */
+                                       copystream = pset.copyStream;
+                               }
+                               else if (pset.gfname)
+                               {
+                                       /* invoked by \g */
+                                       if (openQueryOutputFile(pset.gfname,
+                                                                                       &copystream, &is_pipe))
+                                       {
+                                               need_close = true;
+                                               if (is_pipe)
+                                                       disable_sigpipe_trap();
+                                       }
+                                       else
+                                               copystream = NULL;      /* discard COPY data entirely */
+                               }
+                               else
+                               {
+                                       /* fall back to the generic query output stream */
+                                       copystream = pset.queryFout;
+                               }
+
+                               success = handleCopyOut(pset.db,
+                                                                               copystream,
+                                                                               &copy_result)
+                                       && success
+                                       && (copystream != NULL);
+
+                               /*
+                                * Suppress status printing if the report would go to the same
+                                * place as the COPY data just went.  Note this doesn't
+                                * prevent error reporting, since handleCopyOut did that.
+                                */
+                               if (copystream == pset.queryFout)
+                               {
+                                       PQclear(copy_result);
+                                       copy_result = NULL;
+                               }
+
+                               if (need_close)
+                               {
+                                       /* close \g argument file/pipe */
+                                       if (is_pipe)
+                                       {
+                                               pclose(copystream);
+                                               restore_sigpipe_trap();
+                                       }
+                                       else
+                                       {
+                                               fclose(copystream);
+                                       }
+                               }
                        }
                        else
                        {
-                               fclose(copystream);
+                               /* COPY IN */
+                               copystream = pset.copyStream ? pset.copyStream : pset.cur_cmd_source;
+                               success = handleCopyIn(pset.db,
+                                                                          copystream,
+                                                                          PQbinaryTuples(*results),
+                                                                          &copy_result) && success;
                        }
+                       ResetCancelConn();
+
+                       /*
+                        * Replace the PGRES_COPY_OUT/IN result with COPY command's exit
+                        * status, or with NULL if we want to suppress printing anything.
+                        */
+                       PQclear(*results);
+                       *results = copy_result;
                }
-       }
-       else
-       {
-               /* COPY IN */
-               copystream = pset.copyStream ? pset.copyStream : pset.cur_cmd_source;
-               success = handleCopyIn(pset.db,
-                                                          copystream,
-                                                          PQbinaryTuples(*result),
-                                                          &copy_result);
+               else if (first_cycle)
+               {
+                       /* fast path: no COPY commands; PQexec visited all results */
+                       break;
+               }
+
+               /*
+                * Check PQgetResult() again.  In the typical case of a single-command
+                * string, it will return NULL.  Otherwise, we'll have other results
+                * to process that may include other COPYs.  We keep the last result.
+                */
+               next_result = PQgetResult(pset.db);
+               if (!next_result)
+                       break;
+
+               PQclear(*results);
+               *results = next_result;
+               first_cycle = false;
        }
 
-       ResetCancelConn();
-       PQclear(*result);
-       *result = copy_result;
+       SetResultVariables(*results, success);
+
+       /* may need this to recover from conn loss during COPY */
+       if (!first_cycle && !CheckConnection())
+               return false;
 
        return success;
 }
 
+
 /*
  * PrintQueryStatus: report command status as required
  *
- * Note: Utility function for use by HandleQueryResult() only.
+ * Note: Utility function for use by PrintQueryResults() only.
  */
 static void
 PrintQueryStatus(PGresult *results)
@@ -974,50 +1105,43 @@ PrintQueryStatus(PGresult *results)
 
 
 /*
- * HandleQueryResult: print out, store or execute one query result
- * as required.
+ * PrintQueryResults: print out (or store or execute) query results as required
+ *
+ * Note: Utility function for use by SendQuery() only.
  *
  * Returns true if the query executed successfully, false otherwise.
  */
 static bool
-HandleQueryResult(PGresult *result, bool last)
+PrintQueryResults(PGresult *results)
 {
        bool            success;
        const char *cmdstatus;
 
-       if (result == NULL)
+       if (!results)
                return false;
 
-       switch (PQresultStatus(result))
+       switch (PQresultStatus(results))
        {
                case PGRES_TUPLES_OK:
                        /* store or execute or print the data ... */
-                       if (last && pset.gset_prefix)
-                               success = StoreQueryTuple(result);
-                       else if (last && pset.gexec_flag)
-                               success = ExecQueryTuples(result);
-                       else if (last && pset.crosstab_flag)
-                               success = PrintResultsInCrosstab(result);
-                       else if (last || pset.show_all_results)
-                               success = PrintQueryTuples(result);
+                       if (pset.gset_prefix)
+                               success = StoreQueryTuple(results);
+                       else if (pset.gexec_flag)
+                               success = ExecQueryTuples(results);
+                       else if (pset.crosstab_flag)
+                               success = PrintResultsInCrosstab(results);
                        else
-                               success = true;
-
+                               success = PrintQueryTuples(results);
                        /* if it's INSERT/UPDATE/DELETE RETURNING, also print status */
-                       if (last || pset.show_all_results)
-                       {
-                               cmdstatus = PQcmdStatus(result);
-                               if (strncmp(cmdstatus, "INSERT", 6) == 0 ||
-                                       strncmp(cmdstatus, "UPDATE", 6) == 0 ||
-                                       strncmp(cmdstatus, "DELETE", 6) == 0)
-                                       PrintQueryStatus(result);
-                       }
-
+                       cmdstatus = PQcmdStatus(results);
+                       if (strncmp(cmdstatus, "INSERT", 6) == 0 ||
+                               strncmp(cmdstatus, "UPDATE", 6) == 0 ||
+                               strncmp(cmdstatus, "DELETE", 6) == 0)
+                               PrintQueryStatus(results);
                        break;
 
                case PGRES_COMMAND_OK:
-                       if (last || pset.show_all_results)
-                               PrintQueryStatus(result);
+                       PrintQueryStatus(results);
                        success = true;
                        break;
 
@@ -1027,7 +1151,7 @@ HandleQueryResult(PGresult *result, bool last)
 
                case PGRES_COPY_OUT:
                case PGRES_COPY_IN:
-                       /* nothing to do here: already processed */
+                       /* nothing to do here */
                        success = true;
                        break;
 
@@ -1040,7 +1164,7 @@ HandleQueryResult(PGresult *result, bool last)
                default:
                        success = false;
                        pg_log_error("unexpected PQresultStatus: %d",
-                                                PQresultStatus(result));
+                                                PQresultStatus(results));
                        break;
        }
 
@@ -1049,217 +1173,6 @@ HandleQueryResult(PGresult *result, bool last)
        return success;
 }
 
-/*
- * Data structure and functions to record notices while they are
- * emitted, so that they can be shown later.
- *
- * We need to know which result is last, which requires to extract
- * one result in advance, hence two buffers are needed.
- */
-typedef struct {
-       bool                    in_flip;
-       PQExpBufferData flip;
-       PQExpBufferData flop;
-} t_notice_messages;
-
-/*
- * Store notices in appropriate buffer, for later display.
- */
-static void
-AppendNoticeMessage(void *arg, const char *msg)
-{
-       t_notice_messages *notes = (t_notice_messages*) arg;
-       appendPQExpBufferStr(notes->in_flip ? &notes->flip : &notes->flop, msg);
-}
-
-/*
- * Show notices stored in buffer, which is then reset.
- */
-static void
-ShowNoticeMessage(t_notice_messages *notes)
-{
-       PQExpBufferData *current = notes->in_flip ? &notes->flip : &notes->flop;
-       if (current->data != NULL && *current->data != '\0')
-               pg_log_info("%s", current->data);
-       resetPQExpBuffer(current);
-}
-
-/*
- * SendQueryAndProcessResults: utility function for use by SendQuery()
- * and PSQLexecWatch().
- *
- * Sends query and cycles through PGresult objects.
- *
- * When not under \watch and if our command string contained a COPY FROM STDIN
- * or COPY TO STDOUT, the PGresult associated with these commands must be
- * processed by providing an input or output stream.  In that event, we'll
- * marshal data for the COPY.
- *
- * For other commands, the results are processed normally, depending on their
- * status.
- *
- * Returns 1 on complete success, 0 on interrupt and -1 or errors.  Possible
- * failure modes include purely client-side problems; check the transaction
- * status for the server-side opinion.
- *
- * Note that on a combined query, failure does not mean that nothing was
- * committed.
- */
-static int
-SendQueryAndProcessResults(const char *query, double *pelapsed_msec, bool is_watch)
-{
-       bool                            success;
-       instr_time                      before;
-       PGresult                   *result;
-       t_notice_messages       notes;
-
-       if (pset.timing)
-               INSTR_TIME_SET_CURRENT(before);
-
-       success = PQsendQuery(pset.db, query);
-       ResetCancelConn();
-
-       if (!success)
-       {
-               const char *error = PQerrorMessage(pset.db);
-
-               if (strlen(error))
-                       pg_log_info("%s", error);
-
-               CheckConnection();
-
-               return -1;
-       }
-
-       /*
-        * If SIGINT is sent while the query is processing, the interrupt will be
-        * consumed.  The user's intention, though, is to cancel the entire watch
-        * process, so detect a sent cancellation request and exit in this case.
-        */
-       if (is_watch && cancel_pressed)
-       {
-               ClearOrSaveAllResults();
-               return 0;
-       }
-
-       /* intercept notices */
-       notes.in_flip = true;
-       initPQExpBuffer(&notes.flip);
-       initPQExpBuffer(&notes.flop);
-       PQsetNoticeProcessor(pset.db, AppendNoticeMessage, &notes);
-
-       /* first result */
-       result = PQgetResult(pset.db);
-
-       while (result != NULL)
-       {
-               ExecStatusType result_status;
-               PGresult   *next_result;
-               bool            last;
-
-               if (!AcceptResult(result, false))
-               {
-                       /*
-                        * Some error occured, either a server-side failure or
-                        * a failure to submit the command string.  Record that.
-                        */
-                       const char *error = PQerrorMessage(pset.db);
-
-                       ShowNoticeMessage(&notes);
-                       if (strlen(error))
-                               pg_log_info("%s", error);
-                       CheckConnection();
-                       if (!is_watch)
-                               SetResultVariables(result, false);
-                       ClearOrSaveResult(result);
-                       success = false;
-
-                       /* and switch to next result */
-                       result = PQgetResult(pset.db);
-                       continue;
-               }
-
-               /* must handle COPY before changing the current result */
-               result_status = PQresultStatus(result);
-               Assert(result_status != PGRES_COPY_BOTH);
-               if (result_status == PGRES_COPY_IN ||
-                       result_status == PGRES_COPY_OUT)
-               {
-                       ShowNoticeMessage(&notes);
-
-                       if (is_watch)
-                       {
-                               ClearOrSaveAllResults();
-                               pg_log_error("\\watch cannot be used with COPY");
-                               return -1;
-                       }
-
-                       /* use normal notice processor during COPY */
-                       PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL);
-
-                       success &= HandleCopyResult(&result);
-
-                       PQsetNoticeProcessor(pset.db, AppendNoticeMessage, &notes);
-               }
-
-               /*
-                * Check PQgetResult() again.  In the typical case of a single-command
-                * string, it will return NULL.  Otherwise, we'll have other results
-                * to process.
-                */
-               notes.in_flip = !notes.in_flip;
-               next_result = PQgetResult(pset.db);
-               notes.in_flip = !notes.in_flip;
-               last = (next_result == NULL);
-
-               /*
-                * Get timing measure before printing the last result.
-                *
-                * It will include the display of previous results, if any.
-                * This cannot be helped because the server goes on processing
-                * further queries anyway while the previous ones are being displayed.
-                * The parallel execution of the client display hides the server time
-                * when it is shorter.
-                *
-                * With combined queries, timing must be understood as an upper bound
-                * of the time spent processing them.
-                */
-               if (last && pset.timing)
-               {
-                       instr_time      now;
-                       INSTR_TIME_SET_CURRENT(now);
-                       INSTR_TIME_SUBTRACT(now, before);
-                       *pelapsed_msec = INSTR_TIME_GET_MILLISEC(now);
-               }
-
-               /* notices already shown above for copy */
-               ShowNoticeMessage(&notes);
-
-               /* this may or may not print something depending on settings */
-               if (result != NULL)
-                       success &= HandleQueryResult(result, last);
-
-               /* set variables on last result if all went well */
-               if (!is_watch && last && success)
-                       SetResultVariables(result, true);
-
-               ClearOrSaveResult(result);
-               notes.in_flip = !notes.in_flip;
-               result = next_result;
-       }
-
-       /* reset notice hook */
-       PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL);
-       termPQExpBuffer(&notes.flip);
-       termPQExpBuffer(&notes.flop);
-
-       /* may need this to recover from conn loss during COPY */
-       if (!CheckConnection())
-               return -1;
-
-       return success ? 1 : -1;
-}
-
 
 /*
  * SendQuery: send the query string to the backend
@@ -1381,9 +1294,28 @@ SendQuery(const char *query)
                         pset.crosstab_flag || !is_select_command(query))
        {
                /* Default fetch-it-all-and-print mode */
-               int res = SendQueryAndProcessResults(query, &elapsed_msec, false);
-               OK = (res >= 0);
-               results = NULL;
+               instr_time      before,
+                                       after;
+
+               if (pset.timing)
+                       INSTR_TIME_SET_CURRENT(before);
+
+               results = PQexec(pset.db, query);
+
+               /* these operations are included in the timing result: */
+               ResetCancelConn();
+               OK = ProcessResult(&results);
+
+               if (pset.timing)
+               {
+                       INSTR_TIME_SET_CURRENT(after);
+                       INSTR_TIME_SUBTRACT(after, before);
+                       elapsed_msec = INSTR_TIME_GET_MILLISEC(after);
+               }
+
+               /* but printing results isn't: */
+               if (OK && results)
+                       OK = PrintQueryResults(results);
        }
        else
        {
@@ -1565,7 +1497,7 @@ DescribeQuery(const char *query, double *elapsed_msec)
        PQclear(results);
 
        results = PQdescribePrepared(pset.db, "");
-       OK = AcceptResult(results, true) &&
+       OK = AcceptResult(results) &&
                (PQresultStatus(results) == PGRES_COMMAND_OK);
        if (OK && results)
        {
@@ -1613,7 +1545,7 @@ DescribeQuery(const char *query, double *elapsed_msec)
                        PQclear(results);
 
                        results = PQexec(pset.db, buf.data);
-                       OK = AcceptResult(results, true);
+                       OK = AcceptResult(results);
 
                        if (pset.timing)
                        {
@@ -1623,7 +1555,7 @@ DescribeQuery(const char *query, double *elapsed_msec)
                        }
 
                        if (OK && results)
-                               OK = HandleQueryResult(results, true);
+                               OK = PrintQueryResults(results);
 
                        termPQExpBuffer(&buf);
                }
@@ -1682,7 +1614,7 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
        if (PQtransactionStatus(pset.db) == PQTRANS_IDLE)
        {
                results = PQexec(pset.db, "BEGIN");
-               OK = AcceptResult(results, true) &&
+               OK = AcceptResult(results) &&
                        (PQresultStatus(results) == PGRES_COMMAND_OK);
                ClearOrSaveResult(results);
                if (!OK)
@@ -1696,7 +1628,7 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
                                          query);
 
        results = PQexec(pset.db, buf.data);
-       OK = AcceptResult(results, true) &&
+       OK = AcceptResult(results) &&
                (PQresultStatus(results) == PGRES_COMMAND_OK);
        if (!OK)
                SetResultVariables(results, OK);
@@ -1769,7 +1701,7 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
                                is_pager = false;
                        }
 
-                       OK = AcceptResult(results, true);
+                       OK = AcceptResult(results);
                        Assert(!OK);
                        SetResultVariables(results, OK);
                        ClearOrSaveResult(results);
@@ -1878,7 +1810,7 @@ cleanup:
        results = PQexec(pset.db, "CLOSE _psql_cursor");
        if (OK)
        {
-               OK = AcceptResult(results, true) &&
+               OK = AcceptResult(results) &&
                        (PQresultStatus(results) == PGRES_COMMAND_OK);
                ClearOrSaveResult(results);
        }
@@ -1888,7 +1820,7 @@ cleanup:
        if (started_txn)
        {
                results = PQexec(pset.db, OK ? "COMMIT" : "ROLLBACK");
-               OK &= AcceptResult(results, true) &&
+               OK &= AcceptResult(results) &&
                        (PQresultStatus(results) == PGRES_COMMAND_OK);
                ClearOrSaveResult(results);
        }
index 36501d5e2b99d589e81fd3ba78f7d5b4fdd60914..8e3bb38ab1e050bc903e061df892ada7a0ffd5ce 100644 (file)
@@ -411,8 +411,6 @@ helpVariables(unsigned short int pager)
        fprintf(output, _("  SERVER_VERSION_NAME\n"
                                          "  SERVER_VERSION_NUM\n"
                                          "    server's version (in short string or numeric format)\n"));
-       fprintf(output, _("  SHOW_ALL_RESULTS\n"
-                                         "    show all results of a combined query (\\;) instead of only the last\n"));
        fprintf(output, _("  SHOW_CONTEXT\n"
                                          "    controls display of message context fields [never, errors, always]\n"));
        fprintf(output, _("  SINGLELINE\n"
index 62583ad6ca6fc7ba46e7341684e406989b1dda90..83f2e6f254edd030ef7949df44eb031ff769fbc7 100644 (file)
@@ -148,7 +148,6 @@ typedef struct _psqlSettings
        const char *prompt2;
        const char *prompt3;
        PGVerbosity verbosity;          /* current error verbosity level */
-       bool            show_all_results;
        PGContextVisibility show_context;       /* current context display level */
 } PsqlSettings;
 
index 17437ce07dd13e227493c083e8a8cc4854b89148..110906a4e959b46d4540f6c78580bdde77d3e950 100644 (file)
@@ -196,7 +196,6 @@ main(int argc, char *argv[])
        SetVariable(pset.vars, "PROMPT1", DEFAULT_PROMPT1);
        SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2);
        SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);
-       SetVariableBool(pset.vars, "SHOW_ALL_RESULTS");
 
        parse_psql_options(argc, argv, &options);
 
@@ -1131,12 +1130,6 @@ verbosity_hook(const char *newval)
        return true;
 }
 
-static bool
-show_all_results_hook(const char *newval)
-{
-       return ParseVariableBool(newval, "SHOW_ALL_RESULTS", &pset.show_all_results);
-}
-
 static char *
 show_context_substitute_hook(char *newval)
 {
@@ -1238,9 +1231,6 @@ EstablishVariableSpace(void)
        SetVariableHooks(pset.vars, "VERBOSITY",
                                         verbosity_substitute_hook,
                                         verbosity_hook);
-       SetVariableHooks(pset.vars, "SHOW_ALL_RESULTS",
-                                        bool_substitute_hook,
-                                        show_all_results_hook);
        SetVariableHooks(pset.vars, "SHOW_CONTEXT",
                                         show_context_substitute_hook,
                                         show_context_hook);
index d34271e3b87991e167dcbb28eeb19e8f00eebe2b..cfd0a840c7ca46970adb034f9380f7d729ae20ee 100644 (file)
@@ -4139,7 +4139,7 @@ psql_completion(const char *text, int start, int end)
                matches = complete_from_variables(text, "", "", false);
        else if (TailMatchesCS("\\set", MatchAny))
        {
-               if (TailMatchesCS("AUTOCOMMIT|ON_ERROR_STOP|QUIET|SHOW_ALL_RESULTS|"
+               if (TailMatchesCS("AUTOCOMMIT|ON_ERROR_STOP|QUIET|"
                                                  "SINGLELINE|SINGLESTEP"))
                        COMPLETE_WITH_CS("on", "off");
                else if (TailMatchesCS("COMP_KEYWORD_CASE"))
index bb9e026f913aed4963f8d42ab289eaab0a73918e..72865fe1ebeeac818eea2457828b3e24fb73668f 100644 (file)
@@ -126,7 +126,7 @@ copy (select 1) to stdout\; select 1/0;     -- row, then error
 ERROR:  division by zero
 select 1/0\; copy (select 1) to stdout; -- error only
 ERROR:  division by zero
-copy (select 1) to stdout\; copy (select 2) to stdout\; select 3\; select 4; -- 1 2 3 4
+copy (select 1) to stdout\; copy (select 2) to stdout\; select 0\; select 3; -- 1 2 3
 1
 2
  ?column? 
@@ -134,18 +134,8 @@ copy (select 1) to stdout\; copy (select 2) to stdout\; select 3\; select 4; --
         3
 (1 row)
 
- ?column? 
-----------
-        4
-(1 row)
-
 create table test3 (c int);
-select 0\; copy test3 from stdin\; copy test3 from stdin\; select 1; -- 0 1
- ?column? 
-----------
-        0
-(1 row)
-
+select 0\; copy test3 from stdin\; copy test3 from stdin\; select 1; -- 1
  ?column? 
 ----------
         1
index 672937b2f88727e6446048d78f7d055ef2350dea..49139dd3633bdda985640b8306a9c3238344867b 100644 (file)
@@ -5179,96 +5179,3 @@ List of access methods
  pg_catalog | &&   | anyarray      | anyarray       | boolean     | overlaps
 (1 row)
 
---
--- combined queries
---
-CREATE FUNCTION warn(msg TEXT) RETURNS BOOLEAN LANGUAGE plpgsql
-AS $$
-  BEGIN RAISE NOTICE 'warn %', msg ; RETURN TRUE ; END
-$$;
--- show both
-SELECT 1 AS one \; SELECT warn('1.5') \; SELECT 2 AS two ;
- one 
------
-   1
-(1 row)
-
-NOTICE:  warn 1.5
-CONTEXT:  PL/pgSQL function warn(text) line 2 at RAISE
- warn 
-------
- t
-(1 row)
-
- two 
------
-   2
-(1 row)
-
--- \gset applies to last query only
-SELECT 3 AS three \; SELECT warn('3.5') \; SELECT 4 AS four \gset
- three 
--------
-     3
-(1 row)
-
-NOTICE:  warn 3.5
-CONTEXT:  PL/pgSQL function warn(text) line 2 at RAISE
- warn 
-------
- t
-(1 row)
-
-\echo :three :four
-:three 4
--- syntax error stops all processing
-SELECT 5 \; SELECT 6 + \; SELECT warn('6.5') \; SELECT 7 ;
-ERROR:  syntax error at or near ";"
-LINE 1: SELECT 5 ; SELECT 6 + ; SELECT warn('6.5') ; SELECT 7 ;
-                              ^
--- with aborted transaction, stop on first error
-BEGIN \; SELECT 8 AS eight \; SELECT 9/0 AS nine \; ROLLBACK \; SELECT 10 AS ten ;
- eight 
--------
-     8
-(1 row)
-
-ERROR:  division by zero
--- close previously aborted transaction
-ROLLBACK;
--- misc SQL commands
--- (non SELECT output is sent to stderr, thus is not shown in expected results)
-SELECT 'ok' AS "begin" \;
-CREATE TABLE psql_comics(s TEXT) \;
-INSERT INTO psql_comics VALUES ('Calvin'), ('hobbes') \;
-COPY psql_comics FROM STDIN \;
-UPDATE psql_comics SET s = 'Hobbes' WHERE s = 'hobbes' \;
-DELETE FROM psql_comics WHERE s = 'Moe' \;
-COPY psql_comics TO STDOUT \;
-TRUNCATE psql_comics \;
-DROP TABLE psql_comics \;
-SELECT 'ok' AS "done" ;
- begin 
--------
- ok
-(1 row)
-
-Calvin
-Susie
-Hobbes
- done 
-------
- ok
-(1 row)
-
-\set SHOW_ALL_RESULTS off
-SELECT 1 AS one \; SELECT warn('1.5') \; SELECT 2 AS two ;
-NOTICE:  warn 1.5
-CONTEXT:  PL/pgSQL function warn(text) line 2 at RAISE
- two 
------
-   2
-(1 row)
-
-\set SHOW_ALL_RESULTS on
-DROP FUNCTION warn(TEXT);
index be1db0d5c0b5318ca88d4790ae64ac4ca67f0d12..61862d595d1abec90127bb56a4ff17f2581c750c 100644 (file)
@@ -900,18 +900,8 @@ DROP TABLE abc;
 -- tests rely on the fact that psql will not break SQL commands apart at a
 -- backslash-quoted semicolon, but will send them as one Query.
 create temp table i_table (f1 int);
--- psql will show all results of a multi-statement Query
+-- psql will show only the last result in a multi-statement Query
 SELECT 1\; SELECT 2\; SELECT 3;
- ?column? 
-----------
-        1
-(1 row)
-
- ?column? 
-----------
-        2
-(1 row)
-
  ?column? 
 ----------
         3
@@ -926,12 +916,6 @@ insert into i_table values(1)\; select * from i_table;
 
 -- 1/0 error will cause rolling back the whole implicit transaction
 insert into i_table values(2)\; select * from i_table\; select 1/0;
- f1 
-----
-  1
-  2
-(2 rows)
-
 ERROR:  division by zero
 select * from i_table;
  f1 
@@ -951,18 +935,8 @@ WARNING:  there is no transaction in progress
 -- begin converts implicit transaction into a regular one that
 -- can extend past the end of the Query
 select 1\; begin\; insert into i_table values(5);
- ?column? 
-----------
-        1
-(1 row)
-
 commit;
 select 1\; begin\; insert into i_table values(6);
- ?column? 
-----------
-        1
-(1 row)
-
 rollback;
 -- commit in implicit-transaction state commits but issues a warning.
 insert into i_table values(7)\; commit\; insert into i_table values(8)\; select 1/0;
@@ -989,52 +963,22 @@ rollback;  -- we are not in a transaction at this point
 WARNING:  there is no transaction in progress
 -- implicit transaction block is still a transaction block, for e.g. VACUUM
 SELECT 1\; VACUUM;
- ?column? 
-----------
-        1
-(1 row)
-
 ERROR:  VACUUM cannot run inside a transaction block
 SELECT 1\; COMMIT\; VACUUM;
 WARNING:  there is no transaction in progress
- ?column? 
-----------
-        1
-(1 row)
-
 ERROR:  VACUUM cannot run inside a transaction block
 -- we disallow savepoint-related commands in implicit-transaction state
 SELECT 1\; SAVEPOINT sp;
- ?column? 
-----------
-        1
-(1 row)
-
 ERROR:  SAVEPOINT can only be used in transaction blocks
 SELECT 1\; COMMIT\; SAVEPOINT sp;
 WARNING:  there is no transaction in progress
- ?column? 
-----------
-        1
-(1 row)
-
 ERROR:  SAVEPOINT can only be used in transaction blocks
 ROLLBACK TO SAVEPOINT sp\; SELECT 2;
 ERROR:  ROLLBACK TO SAVEPOINT can only be used in transaction blocks
 SELECT 2\; RELEASE SAVEPOINT sp\; SELECT 3;
- ?column? 
-----------
-        2
-(1 row)
-
 ERROR:  RELEASE SAVEPOINT can only be used in transaction blocks
 -- but this is OK, because the BEGIN converts it to a regular xact
 SELECT 1\; BEGIN\; SAVEPOINT sp\; ROLLBACK TO SAVEPOINT sp\; COMMIT;
- ?column? 
-----------
-        1
-(1 row)
-
 -- Tests for AND CHAIN in implicit transaction blocks
 SET TRANSACTION READ ONLY\; COMMIT AND CHAIN;  -- error
 ERROR:  COMMIT AND CHAIN can only be used in transaction blocks
index e32a4f8e38e52e6bb67e20cd0991a18a49cc8634..1d98dad3c8c55517d241c147f6baa4cbd9e31e38 100644 (file)
@@ -84,10 +84,10 @@ drop table test1;
 -- psql handling of COPY in multi-command strings
 copy (select 1) to stdout\; select 1/0;        -- row, then error
 select 1/0\; copy (select 1) to stdout; -- error only
-copy (select 1) to stdout\; copy (select 2) to stdout\; select 3\; select 4; -- 1 2 3 4
+copy (select 1) to stdout\; copy (select 2) to stdout\; select 0\; select 3; -- 1 2 3
 
 create table test3 (c int);
-select 0\; copy test3 from stdin\; copy test3 from stdin\; select 1; -- 1
+select 0\; copy test3 from stdin\; copy test3 from stdin\; select 1; -- 1
 1
 \.
 2
index f90a0270fc335922d0a7f84ffa5f07d9aec72bfd..68121d171cd91e18f6d078ed479d89f4b4c2e16a 100644 (file)
@@ -1241,41 +1241,3 @@ drop role regress_partitioning_role;
 \dfa bit* small*
 \do - pg_catalog.int4
 \do && anyarray *
-
---
--- combined queries
---
-CREATE FUNCTION warn(msg TEXT) RETURNS BOOLEAN LANGUAGE plpgsql
-AS $$
-  BEGIN RAISE NOTICE 'warn %', msg ; RETURN TRUE ; END
-$$;
--- show both
-SELECT 1 AS one \; SELECT warn('1.5') \; SELECT 2 AS two ;
--- \gset applies to last query only
-SELECT 3 AS three \; SELECT warn('3.5') \; SELECT 4 AS four \gset
-\echo :three :four
--- syntax error stops all processing
-SELECT 5 \; SELECT 6 + \; SELECT warn('6.5') \; SELECT 7 ;
--- with aborted transaction, stop on first error
-BEGIN \; SELECT 8 AS eight \; SELECT 9/0 AS nine \; ROLLBACK \; SELECT 10 AS ten ;
--- close previously aborted transaction
-ROLLBACK;
--- misc SQL commands
--- (non SELECT output is sent to stderr, thus is not shown in expected results)
-SELECT 'ok' AS "begin" \;
-CREATE TABLE psql_comics(s TEXT) \;
-INSERT INTO psql_comics VALUES ('Calvin'), ('hobbes') \;
-COPY psql_comics FROM STDIN \;
-UPDATE psql_comics SET s = 'Hobbes' WHERE s = 'hobbes' \;
-DELETE FROM psql_comics WHERE s = 'Moe' \;
-COPY psql_comics TO STDOUT \;
-TRUNCATE psql_comics \;
-DROP TABLE psql_comics \;
-SELECT 'ok' AS "done" ;
-Moe
-Susie
-\.
-\set SHOW_ALL_RESULTS off
-SELECT 1 AS one \; SELECT warn('1.5') \; SELECT 2 AS two ;
-\set SHOW_ALL_RESULTS on
-DROP FUNCTION warn(TEXT);
index 7fc9f094680b454e0d32ff69e9790089f66db2a7..8886280c0a628faa1afff0a95cc7920f5eea8911 100644 (file)
@@ -504,7 +504,7 @@ DROP TABLE abc;
 
 create temp table i_table (f1 int);
 
--- psql will show all results of a multi-statement Query
+-- psql will show only the last result in a multi-statement Query
 SELECT 1\; SELECT 2\; SELECT 3;
 
 -- this implicitly commits: