X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=src%2Fbin%2Fpsql%2Fcommon.c;h=ed929372420fba4c9bf9077cec112f103b15971c;hb=4ff9c8dd48b265d925be8bf90ac65c34a249c7b5;hp=76e0c0e6b890282fedd552b92c72c90f044ff693;hpb=7bdc55cc7113137c5f597a33db9dc240b1bd47da;p=postgresql diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c index 76e0c0e6b8..ed92937242 100644 --- a/src/bin/psql/common.c +++ b/src/bin/psql/common.c @@ -1,9 +1,9 @@ /* * 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" @@ -17,12 +17,13 @@ #include #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" @@ -554,8 +555,13 @@ PrintNotifications(void) 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); } @@ -823,8 +829,8 @@ SendQuery(const char *query) { 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 @@ -845,11 +851,11 @@ SendQuery(const char *query) 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); @@ -859,8 +865,9 @@ SendQuery(const char *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: */ @@ -878,16 +885,20 @@ SendQuery(const char *query) /* 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 { /* @@ -899,20 +910,27 @@ SendQuery(const char *query) (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); @@ -962,8 +980,9 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec) bool did_pager = false; int ntuples; char fetch_cmd[64]; - TimevalStruct before, + instr_time before, after; + int flush_error; *elapsed_msec = 0; @@ -973,7 +992,7 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec) 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) @@ -1002,8 +1021,9 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec) 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), @@ -1026,18 +1046,22 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec) } } + /* 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) @@ -1076,13 +1100,29 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec) 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; } @@ -1107,7 +1147,7 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec) 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 @@ -1132,8 +1172,9 @@ cleanup: 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; @@ -1497,7 +1538,7 @@ expand_tilde(char **filename) 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)