diff --git a/contrib/pg_stat_statements/expected/pg_stat_statements.out b/contrib/pg_stat_statements/expected/pg_stat_statements.out
index 674ed270a8f85..fb97f6873700c 100644
--- a/contrib/pg_stat_statements/expected/pg_stat_statements.out
+++ b/contrib/pg_stat_statements/expected/pg_stat_statements.out
@@ -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
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index 67e527124d9f4..bd4f26e6cc877 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -127,11 +127,18 @@ echo '\x \\ SELECT * FROM foo;' | psql
commands included in the string to divide it into multiple
transactions. (See
for more details about how the server handles multi-query strings.)
+ Also, psql only prints the
+ result of the last SQL command in the string.
+ This is different from the behavior when the same string is read from
+ a file or fed to psql's standard input,
+ because then psql sends
+ each SQL command separately.
- If having several commands executed in one transaction is not desired,
- use repeated commands or feed multiple commands to
- psql's standard input,
+ Because of this behavior, putting more than one SQL command in a
+ single string often has unexpected results.
+ It's better to use repeated commands or feed
+ multiple commands to psql's standard input,
either using echo as illustrated above, or
via a shell here-document, for example:
@@ -3525,6 +3532,10 @@ select 1\; select 2\; select 3;
commands included in the string to divide it into multiple
transactions. (See
for more details about how the server handles multi-query strings.)
+ psql prints only the last query result
+ it receives for each request; in this example, although all
+ three SELECTs are indeed executed, psql
+ only prints the 3.
@@ -4111,18 +4122,6 @@ bar
- SHOW_ALL_RESULTS
-
-
- When this variable is set to off, only the last
- result of a combined query (\;) is shown instead of
- all of them. The default is on. The off behavior
- is for compatibility with older versions of psql.
-
-
-
-
-
SHOW_CONTEXT
diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c
index 028a357991fd2..7a95465111ad1 100644
--- a/src/bin/psql/common.c
+++ b/src/bin/psql/common.c
@@ -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 @@ ExecQueryTuples(const PGresult *result)
/*
- * 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,
- ©stream, &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,
- ©_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,
+ ©stream, &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,
+ ©_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),
+ ©_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),
- ©_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 ? ¬es->flip : ¬es->flop, msg);
-}
-
-/*
- * Show notices stored in buffer, which is then reset.
- */
-static void
-ShowNoticeMessage(t_notice_messages *notes)
-{
- PQExpBufferData *current = notes->in_flip ? ¬es->flip : ¬es->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(¬es.flip);
- initPQExpBuffer(¬es.flop);
- PQsetNoticeProcessor(pset.db, AppendNoticeMessage, ¬es);
-
- /* 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(¬es);
- 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(¬es);
-
- 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, ¬es);
- }
-
- /*
- * 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(¬es);
-
- /* 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(¬es.flip);
- termPQExpBuffer(¬es.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 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
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 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
if (started_txn)
{
results = PQexec(pset.db, OK ? "COMMIT" : "ROLLBACK");
- OK &= AcceptResult(results, true) &&
+ OK &= AcceptResult(results) &&
(PQresultStatus(results) == PGRES_COMMAND_OK);
ClearOrSaveResult(results);
}
diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c
index 36501d5e2b99d..8e3bb38ab1e05 100644
--- a/src/bin/psql/help.c
+++ b/src/bin/psql/help.c
@@ -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"
diff --git a/src/bin/psql/settings.h b/src/bin/psql/settings.h
index 62583ad6ca6fc..83f2e6f254edd 100644
--- a/src/bin/psql/settings.h
+++ b/src/bin/psql/settings.h
@@ -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;
diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c
index 17437ce07dd13..110906a4e959b 100644
--- a/src/bin/psql/startup.c
+++ b/src/bin/psql/startup.c
@@ -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);
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index d34271e3b8799..cfd0a840c7ca4 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -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"))
diff --git a/src/test/regress/expected/copyselect.out b/src/test/regress/expected/copyselect.out
index bb9e026f913ae..72865fe1ebeea 100644
--- a/src/test/regress/expected/copyselect.out
+++ b/src/test/regress/expected/copyselect.out
@@ -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
diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out
index 672937b2f8872..49139dd3633bd 100644
--- a/src/test/regress/expected/psql.out
+++ b/src/test/regress/expected/psql.out
@@ -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);
diff --git a/src/test/regress/expected/transactions.out b/src/test/regress/expected/transactions.out
index be1db0d5c0b53..61862d595d1ab 100644
--- a/src/test/regress/expected/transactions.out
+++ b/src/test/regress/expected/transactions.out
@@ -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
diff --git a/src/test/regress/sql/copyselect.sql b/src/test/regress/sql/copyselect.sql
index e32a4f8e38e52..1d98dad3c8c55 100644
--- a/src/test/regress/sql/copyselect.sql
+++ b/src/test/regress/sql/copyselect.sql
@@ -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; -- 0 1
+select 0\; copy test3 from stdin\; copy test3 from stdin\; select 1; -- 1
1
\.
2
diff --git a/src/test/regress/sql/psql.sql b/src/test/regress/sql/psql.sql
index f90a0270fc335..68121d171cd91 100644
--- a/src/test/regress/sql/psql.sql
+++ b/src/test/regress/sql/psql.sql
@@ -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);
diff --git a/src/test/regress/sql/transactions.sql b/src/test/regress/sql/transactions.sql
index 7fc9f094680b4..8886280c0a628 100644
--- a/src/test/regress/sql/transactions.sql
+++ b/src/test/regress/sql/transactions.sql
@@ -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: