/*
* psql - the PostgreSQL interactive terminal
*
- * Copyright (c) 2000-2006, PostgreSQL Global Development Group
+ * Copyright (c) 2000-2010, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/common.c,v 1.131 2006/12/16 00:38:43 adunstan 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"
#include <win32.h>
#endif
+#include "portability/instr_time.h"
+
#include "pqsignal.h"
#include "settings.h"
#include "command.h"
#include "copy.h"
-#include "mb/pg_wchar.h"
#include "mbprint.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 (pset.fetch_count <= 0 || !is_select_command(query))
{
/* Default fetch-it-all-and-print mode */
- TimevalStruct before,
+ instr_time before,
after;
if (pset.timing)
- GETTIMEOFDAY(&before);
+ INSTR_TIME_SET_CURRENT(before);
results = PQexec(pset.db, query);
if (pset.timing)
{
- GETTIMEOFDAY(&after);
- elapsed_msec = DIFF_MSEC(&after, &before);
+ INSTR_TIME_SET_CURRENT(after);
+ INSTR_TIME_SUBTRACT(after, before);
+ elapsed_msec = INSTR_TIME_GET_MILLISEC(after);
}
/* but printing results isn't: */
/* 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);
bool did_pager = false;
int ntuples;
char fetch_cmd[64];
- TimevalStruct before,
+ instr_time before,
after;
+ int flush_error;
*elapsed_msec = 0;
my_popt.topt.prior_records = 0;
if (pset.timing)
- GETTIMEOFDAY(&before);
+ INSTR_TIME_SET_CURRENT(before);
/* if we're not in a transaction, start one */
if (PQtransactionStatus(pset.db) == PQTRANS_IDLE)
if (pset.timing)
{
- GETTIMEOFDAY(&after);
- *elapsed_msec += DIFF_MSEC(&after, &before);
+ INSTR_TIME_SET_CURRENT(after);
+ INSTR_TIME_SUBTRACT(after, before);
+ *elapsed_msec += INSTR_TIME_GET_MILLISEC(after);
}
snprintf(fetch_cmd, sizeof(fetch_cmd),
}
}
+ /* clear any pre-existing error indication on the output stream */
+ clearerr(pset.queryFout);
+
for (;;)
{
if (pset.timing)
- GETTIMEOFDAY(&before);
+ INSTR_TIME_SET_CURRENT(before);
/* get FETCH_COUNT tuples at a time */
results = PQexec(pset.db, fetch_cmd);
if (pset.timing)
{
- GETTIMEOFDAY(&after);
- *elapsed_msec += DIFF_MSEC(&after, &before);
+ INSTR_TIME_SET_CURRENT(after);
+ INSTR_TIME_SUBTRACT(after, before);
+ *elapsed_msec += INSTR_TIME_GET_MILLISEC(after);
}
if (PQresultStatus(results) != PGRES_TUPLES_OK)
printQuery(results, &my_popt, pset.queryFout, pset.logfile);
+ 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;
}
cleanup:
if (pset.timing)
- GETTIMEOFDAY(&before);
+ INSTR_TIME_SET_CURRENT(before);
/*
* We try to close the cursor on either success or failure, but on failure
if (pset.timing)
{
- GETTIMEOFDAY(&after);
- *elapsed_msec += DIFF_MSEC(&after, &before);
+ INSTR_TIME_SET_CURRENT(after);
+ INSTR_TIME_SUBTRACT(after, before);
+ *elapsed_msec += INSTR_TIME_GET_MILLISEC(after);
}
return OK;
if (*(fn + 1) == '\0')
get_home_path(home); /* ~ or ~/ only */
else if ((pw = getpwnam(fn + 1)) != NULL)
- StrNCpy(home, pw->pw_dir, MAXPGPATH); /* ~user */
+ strlcpy(home, pw->pw_dir, sizeof(home)); /* ~user */
*p = oldp;
if (strlen(home) != 0)