/*
* psql - the PostgreSQL interactive terminal
*
- * Copyright (c) 2000-2008, PostgreSQL Global Development Group
+ * Copyright (c) 2000-2010, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/common.c,v 1.139 2008/05/14 19:10:29 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/common.c,v 1.147 2010/07/28 04:39:14 petere Exp $
*/
#include "postgres_fe.h"
#include "common.h"
while ((notify = PQnotifies(pset.db)))
{
- fprintf(pset.queryFout, _("Asynchronous notification \"%s\" received from server process with PID %d.\n"),
- notify->relname, notify->be_pid);
+ /* for backward compatibility, only show payload if nonempty */
+ if (notify->extra[0])
+ fprintf(pset.queryFout, _("Asynchronous notification \"%s\" with payload \"%s\" received from server process with PID %d.\n"),
+ notify->relname, notify->extra, notify->be_pid);
+ else
+ fprintf(pset.queryFout, _("Asynchronous notification \"%s\" received from server process with PID %d.\n"),
+ notify->relname, notify->be_pid);
fflush(pset.queryFout);
PQfreemem(notify);
}
{
if (on_error_rollback_warning == false && pset.sversion < 80000)
{
- fprintf(stderr, _("The server version (%d) does not support savepoints for ON_ERROR_ROLLBACK.\n"),
- pset.sversion);
+ fprintf(stderr, _("The server (version %d.%d) does not support savepoints for ON_ERROR_ROLLBACK.\n"),
+ pset.sversion / 10000, (pset.sversion / 100) % 100);
on_error_rollback_warning = true;
}
else
/* If we made a temporary savepoint, possibly release/rollback */
if (on_error_rollback_savepoint)
{
- PGresult *svptres;
+ const char *svptcmd;
transaction_status = PQtransactionStatus(pset.db);
- /* We always rollback on an error */
if (transaction_status == PQTRANS_INERROR)
- svptres = PQexec(pset.db, "ROLLBACK TO pg_psql_temporary_savepoint");
- /* If they are no longer in a transaction, then do nothing */
+ {
+ /* We always rollback on an error */
+ svptcmd = "ROLLBACK TO pg_psql_temporary_savepoint";
+ }
else if (transaction_status != PQTRANS_INTRANS)
- svptres = NULL;
+ {
+ /* If they are no longer in a transaction, then do nothing */
+ svptcmd = NULL;
+ }
else
{
/*
(strcmp(PQcmdStatus(results), "SAVEPOINT") == 0 ||
strcmp(PQcmdStatus(results), "RELEASE") == 0 ||
strcmp(PQcmdStatus(results), "ROLLBACK") == 0))
- svptres = NULL;
+ svptcmd = NULL;
else
- svptres = PQexec(pset.db, "RELEASE pg_psql_temporary_savepoint");
+ svptcmd = "RELEASE pg_psql_temporary_savepoint";
}
- if (svptres && PQresultStatus(svptres) != PGRES_COMMAND_OK)
+
+ if (svptcmd)
{
- psql_error("%s", PQerrorMessage(pset.db));
- PQclear(results);
+ PGresult *svptres;
+
+ svptres = PQexec(pset.db, svptcmd);
+ if (PQresultStatus(svptres) != PGRES_COMMAND_OK)
+ {
+ psql_error("%s", PQerrorMessage(pset.db));
+ PQclear(svptres);
+
+ PQclear(results);
+ ResetCancelConn();
+ return false;
+ }
PQclear(svptres);
- ResetCancelConn();
- return false;
}
-
- PQclear(svptres);
}
PQclear(results);
/* Possible microtiming output */
- if (OK && pset.timing && !pset.quiet)
+ if (OK && pset.timing)
printf(_("Time: %.3f ms\n"), elapsed_msec);
/* check for events that may occur during query execution */
char fetch_cmd[64];
instr_time before,
after;
+ int flush_error;
*elapsed_msec = 0;
}
}
+ /* clear any pre-existing error indication on the output stream */
+ clearerr(pset.queryFout);
+
for (;;)
{
if (pset.timing)
printQuery(results, &my_popt, pset.queryFout, pset.logfile);
- /*
- * Make sure to flush the output stream, so intermediate results are
- * visible to the client immediately.
- */
- fflush(pset.queryFout);
+ PQclear(results);
/* after the first result set, disallow header decoration */
my_popt.topt.start_table = false;
my_popt.topt.prior_records += ntuples;
- PQclear(results);
+ /*
+ * Make sure to flush the output stream, so intermediate results are
+ * visible to the client immediately. We check the results because if
+ * the pager dies/exits/etc, there's no sense throwing more data at
+ * it.
+ */
+ flush_error = fflush(pset.queryFout);
- if (ntuples < pset.fetch_count || cancel_pressed)
+ /*
+ * Check if we are at the end, if a cancel was pressed, or if there
+ * were any errors either trying to flush out the results, or more
+ * generally on the output stream at all. If we hit any errors
+ * writing things to the stream, we presume $PAGER has disappeared and
+ * stop bothering to pull down more data.
+ */
+ if (ntuples < pset.fetch_count || cancel_pressed || flush_error ||
+ ferror(pset.queryFout))
break;
}