From 1eb9fd49d11a2e91e0e9eb465c815958c376937d Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Wed, 19 Feb 2003 03:54:39 +0000 Subject: [PATCH] Here's some changes I made last night to psql's common.c (as found in 7.3.2). It removes some code duplication and #ifdeffing, and some unstructured ugliness such as tacky breaks and an unneeded continue. Breaks up a large function into smaller functions and reduces required nesting levels, and kills a variable or two. Jeroen T. Vermeulen --- src/bin/psql/common.c | 412 +++++++++++++++++++++++------------------- 1 file changed, 230 insertions(+), 182 deletions(-) diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c index ca9b07c8fa..164918ff67 100644 --- a/src/bin/psql/common.c +++ b/src/bin/psql/common.c @@ -3,7 +3,7 @@ * * Copyright 2000 by PostgreSQL Global Development Group * - * $Header: /cvsroot/pgsql/src/bin/psql/common.c,v 1.53 2003/01/07 22:23:17 tgl Exp $ + * $Header: /cvsroot/pgsql/src/bin/psql/common.c,v 1.54 2003/02/19 03:54:39 momjian Exp $ */ #include "postgres_fe.h" #include "common.h" @@ -42,6 +42,26 @@ #include "print.h" #include "mainloop.h" + +/* Workarounds for Windows */ +/* Probably to be moved up the source tree in the future, perhaps to be replaced by + * more specific checks like configure-style HAVE_GETTIMEOFDAY macros. + */ +#ifndef WIN32 + +typedef struct timeval TimevalStruct; +#define GETTIMEOFDAY(T) gettimeofday(T, NULL) +#define DIFF_MSEC(T, U) ((((T)->tv_sec - (U)->tv_sec) * 1000000.0 + (T)->tv_usec - (U)->tv_usec) / 1000.0) + +#else + +typedef struct _timeb TimevalStruct; +#define GETTIMEOFDAY(T) _ftime(&T) +#define DIFF_MSEC(T, U) ((((T)->time - (U)->time) * 1000.0 + (T)->millitm - (U)->millitm)) + +#endif + + extern bool prompt_state; /* @@ -206,6 +226,63 @@ handle_sigint(SIGNAL_ARGS) #endif /* not WIN32 */ + +/* ConnectionUp + * + * Returns whether our backend connection is still there. + */ +static bool +ConnectionUp() +{ + return PQstatus(pset.db) != CONNECTION_BAD; +} + + + +/* CheckConnection + * + * Verify that we still have a good connection to the backend, and if not, + * see if it can be restored. + * + * Returns true if either the connection was still there, or it could be + * restored successfully; false otherwise. If, however, there was no + * connection and the session is non-interactive, this will exit the program + * with a code of EXIT_BADCONN. + */ +static bool +CheckConnection() +{ + bool OK = ConnectionUp(); + if (!OK) + { + if (!pset.cur_cmd_interactive) + { + psql_error("connection to server was lost\n"); + exit(EXIT_BADCONN); + } + + fputs(gettext("The connection to the server was lost. Attempting reset: "), stderr); + PQreset(pset.db); + OK = ConnectionUp(); + if (!OK) + { + fputs(gettext("Failed.\n"), stderr); + PQfinish(pset.db); + pset.db = NULL; + SetVariable(pset.vars, "DBNAME", NULL); + SetVariable(pset.vars, "HOST", NULL); + SetVariable(pset.vars, "PORT", NULL); + SetVariable(pset.vars, "USER", NULL); + SetVariable(pset.vars, "ENCODING", NULL); + } + else + fputs(gettext("Succeeded.\n"), stderr); + } + + return OK; +} + + /* * PSQLexec * @@ -250,19 +327,22 @@ PSQLexec(const char *query, bool ignore_command_ok) cancelConn = pset.db; if (PQsendQuery(pset.db, query)) { - while ((newres = PQgetResult(pset.db)) != NULL) + rstatus = PGRES_EMPTY_QUERY; + + while (((newres = PQgetResult(pset.db)) != NULL) && + (rstatus == PGRES_COPY_IN) && + (rstatus == PGRES_COPY_OUT)) { rstatus = PQresultStatus(newres); if (ignore_command_ok && rstatus == PGRES_COMMAND_OK) { PQclear(newres); - continue; } - PQclear(res); - res = newres; - if (rstatus == PGRES_COPY_IN || - rstatus == PGRES_COPY_OUT) - break; + else + { + PQclear(res); + res = newres; + } } } rstatus = PQresultStatus(res); @@ -277,37 +357,147 @@ PSQLexec(const char *query, bool ignore_command_ok) rstatus == PGRES_COPY_IN || rstatus == PGRES_COPY_OUT)) return res; - else - { - psql_error("%s", PQerrorMessage(pset.db)); - PQclear(res); - if (PQstatus(pset.db) == CONNECTION_BAD) + psql_error("%s", PQerrorMessage(pset.db)); + PQclear(res); + + CheckConnection(); + + return NULL; +} + + + +/* + * PrintNotifications: check for asynchronous notifications, and print them out + * + */ +static void +PrintNotifications(void) +{ + PGnotify *notify; + + while ((notify = PQnotifies(pset.db)) != NULL) + { + fprintf(pset.queryFout, gettext("Asynchronous NOTIFY '%s' from backend with pid %d received.\n"), + notify->relname, notify->be_pid); + free(notify); + fflush(pset.queryFout); + } +} + + +/* + * PrintQueryTuples: assuming query result is OK, print its tuples + * + * Returns true if successful, false otherwise. + */ +static bool +PrintQueryTuples(const PGresult *results) +{ + /* write output to \g argument, if any */ + if (pset.gfname) + { + FILE *queryFout_copy = pset.queryFout; + bool queryFoutPipe_copy = pset.queryFoutPipe; + + pset.queryFout = stdout; /* so it doesn't get + * closed */ + + /* open file/pipe */ + if (!setQFout(pset.gfname)) { - if (!pset.cur_cmd_interactive) - { - psql_error("connection to server was lost\n"); - exit(EXIT_BADCONN); - } - fputs(gettext("The connection to the server was lost. Attempting reset: "), stderr); - PQreset(pset.db); - if (PQstatus(pset.db) == CONNECTION_BAD) - { - fputs(gettext("Failed.\n"), stderr); - PQfinish(pset.db); - pset.db = NULL; - SetVariable(pset.vars, "DBNAME", NULL); - SetVariable(pset.vars, "HOST", NULL); - SetVariable(pset.vars, "PORT", NULL); - SetVariable(pset.vars, "USER", NULL); - SetVariable(pset.vars, "ENCODING", NULL); - } - else - fputs(gettext("Succeeded.\n"), stderr); + pset.queryFout = queryFout_copy; + pset.queryFoutPipe = queryFoutPipe_copy; + return false; } - return NULL; + printQuery(results, &pset.popt, pset.queryFout); + + /* close file/pipe, restore old setting */ + setQFout(NULL); + + pset.queryFout = queryFout_copy; + pset.queryFoutPipe = queryFoutPipe_copy; + + free(pset.gfname); + pset.gfname = NULL; } + else + { + printQuery(results, &pset.popt, pset.queryFout); + } + + return true; +} + + + +/* + * PrintQueryResults: analyze query results and print them out + * + * Note: Utility function for use by SendQuery() only. + * + * Returns true if the query executed successfully, false otherwise. + */ +static bool +PrintQueryResults(PGresult *results, + const TimevalStruct *before, + const TimevalStruct *after) +{ + bool success = false; + + switch (PQresultStatus(results)) + { + case PGRES_TUPLES_OK: + success = PrintQueryTuples(results); + break; + case PGRES_EMPTY_QUERY: + success = true; + break; + case PGRES_COMMAND_OK: + { + char buf[10]; + + success = true; + sprintf(buf, "%u", (unsigned int) PQoidValue(results)); + if (!QUIET()) + fprintf(pset.queryFout, "%s\n", PQcmdStatus(results)); + SetVariable(pset.vars, "LASTOID", buf); + break; + } + case PGRES_COPY_OUT: + success = handleCopyOut(pset.db, pset.queryFout); + break; + + case PGRES_COPY_IN: + if (pset.cur_cmd_interactive && !QUIET()) + puts(gettext("Enter data to be copied followed by a newline.\n" + "End with a backslash and a period on a line by itself.")); + + success = handleCopyIn(pset.db, pset.cur_cmd_source, + pset.cur_cmd_interactive ? get_prompt(PROMPT_COPY) : NULL); + break; + + case PGRES_NONFATAL_ERROR: + case PGRES_FATAL_ERROR: + case PGRES_BAD_RESPONSE: + success = false; + psql_error("%s", PQerrorMessage(pset.db)); + break; + } + + fflush(pset.queryFout); + + if (!CheckConnection()) return false; + + PrintNotifications(); + + /* Possible microtiming output */ + if (pset.timing && success) + printf(gettext("Time: %.2f ms\n"), DIFF_MSEC(after, before)); + + return success; } @@ -327,16 +517,8 @@ PSQLexec(const char *query, bool ignore_command_ok) bool SendQuery(const char *query) { - bool success = false; PGresult *results; - PGnotify *notify; -#ifndef WIN32 - struct timeval before, - after; -#else - struct _timeb before, - after; -#endif + TimevalStruct before, after; if (!pset.db) { @@ -367,19 +549,11 @@ SendQuery(const char *query) cancelConn = pset.db; -#ifndef WIN32 if (pset.timing) - gettimeofday(&before, NULL); + GETTIMEOFDAY(&before); results = PQexec(pset.db, query); if (pset.timing) - gettimeofday(&after, NULL); -#else - if (pset.timing) - _ftime(&before); - results = PQexec(pset.db, query); - if (pset.timing) - _ftime(&after); -#endif + GETTIMEOFDAY(&after); if (PQresultStatus(results) == PGRES_COPY_IN) copy_in_state = true; @@ -390,137 +564,11 @@ SendQuery(const char *query) if (results == NULL) { fputs(PQerrorMessage(pset.db), pset.queryFout); - success = false; - } - else - { - switch (PQresultStatus(results)) - { - case PGRES_TUPLES_OK: - /* write output to \g argument, if any */ - if (pset.gfname) - { - FILE *queryFout_copy = pset.queryFout; - bool queryFoutPipe_copy = pset.queryFoutPipe; - - pset.queryFout = stdout; /* so it doesn't get - * closed */ - - /* open file/pipe */ - if (!setQFout(pset.gfname)) - { - pset.queryFout = queryFout_copy; - pset.queryFoutPipe = queryFoutPipe_copy; - success = false; - break; - } - - printQuery(results, &pset.popt, pset.queryFout); - - /* close file/pipe, restore old setting */ - setQFout(NULL); - - pset.queryFout = queryFout_copy; - pset.queryFoutPipe = queryFoutPipe_copy; - - free(pset.gfname); - pset.gfname = NULL; - - success = true; - } - else - { - printQuery(results, &pset.popt, pset.queryFout); - success = true; - } - break; - case PGRES_EMPTY_QUERY: - success = true; - break; - case PGRES_COMMAND_OK: - { - char buf[10]; - - success = true; - sprintf(buf, "%u", (unsigned int) PQoidValue(results)); - if (!QUIET()) - fprintf(pset.queryFout, "%s\n", PQcmdStatus(results)); - SetVariable(pset.vars, "LASTOID", buf); - break; - } - case PGRES_COPY_OUT: - success = handleCopyOut(pset.db, pset.queryFout); - break; - - case PGRES_COPY_IN: - if (pset.cur_cmd_interactive && !QUIET()) - puts(gettext("Enter data to be copied followed by a newline.\n" - "End with a backslash and a period on a line by itself.")); - - success = handleCopyIn(pset.db, pset.cur_cmd_source, - pset.cur_cmd_interactive ? get_prompt(PROMPT_COPY) : NULL); - break; - - case PGRES_NONFATAL_ERROR: - case PGRES_FATAL_ERROR: - case PGRES_BAD_RESPONSE: - success = false; - psql_error("%s", PQerrorMessage(pset.db)); - break; - } - - fflush(pset.queryFout); - - if (PQstatus(pset.db) == CONNECTION_BAD) - { - if (!pset.cur_cmd_interactive) - { - psql_error("connection to server was lost\n"); - exit(EXIT_BADCONN); - } - fputs(gettext("The connection to the server was lost. Attempting reset: "), stderr); - PQreset(pset.db); - if (PQstatus(pset.db) == CONNECTION_BAD) - { - fputs(gettext("Failed.\n"), stderr); - PQfinish(pset.db); - PQclear(results); - pset.db = NULL; - SetVariable(pset.vars, "DBNAME", NULL); - SetVariable(pset.vars, "HOST", NULL); - SetVariable(pset.vars, "PORT", NULL); - SetVariable(pset.vars, "USER", NULL); - SetVariable(pset.vars, "ENCODING", NULL); - return false; - } - else - fputs(gettext("Succeeded.\n"), stderr); - } - - /* check for asynchronous notification returns */ - while ((notify = PQnotifies(pset.db)) != NULL) - { - fprintf(pset.queryFout, gettext("Asynchronous NOTIFY '%s' from backend with pid %d received.\n"), - notify->relname, notify->be_pid); - free(notify); - fflush(pset.queryFout); - } - - if (results) - PQclear(results); + return false; } - /* Possible microtiming output */ - if (pset.timing && success) -#ifndef WIN32 - printf(gettext("Time: %.2f ms\n"), - ((after.tv_sec - before.tv_sec) * 1000000.0 + after.tv_usec - before.tv_usec) / 1000.0); -#else - printf(gettext("Time: %.2f ms\n"), - ((after.time - before.time) * 1000.0 + after.millitm - before.millitm)); -#endif - - return success; + return PrintQueryResults(results, &before, &after); + PQclear(results); }