*** postgresql-7.3.2.orig/src/bin/psql/common.c 2003-02-13 02:14:25.000000000 +0100 --- postgresql-7.3.2/src/bin/psql/common.c 2003-02-13 03:15:46.000000000 +0100 *************** *** 42,47 **** --- 42,67 ---- #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,211 **** --- 226,288 ---- #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,268 **** cancelConn = pset.db; if (PQsendQuery(pset.db, query)) { ! while ((newres = PQgetResult(pset.db)) != NULL) { 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; } } rstatus = PQresultStatus(res); --- 327,348 ---- cancelConn = pset.db; if (PQsendQuery(pset.db, query)) { ! 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); } ! else ! { ! PQclear(res); ! res = newres; ! } } } rstatus = PQresultStatus(res); *************** *** 277,313 **** 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) { ! 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); ! } ! return NULL; } } --- 357,503 ---- rstatus == PGRES_COPY_IN || rstatus == PGRES_COPY_OUT)) return res; ! ! 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)) { ! pset.queryFout = queryFout_copy; ! pset.queryFoutPipe = queryFoutPipe_copy; ! return false; ! } ! ! 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,342 **** bool SendQuery(const char *query) { - bool success = false; PGresult *results; ! PGnotify *notify; ! #ifndef WIN32 ! struct timeval before, ! after; ! #else ! struct _timeb before, ! after; ! #endif if (!pset.db) { --- 517,524 ---- bool SendQuery(const char *query) { PGresult *results; ! TimevalStruct before, after; if (!pset.db) { *************** *** 367,385 **** cancelConn = pset.db; - #ifndef WIN32 if (pset.timing) ! gettimeofday(&before, NULL); 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 if (PQresultStatus(results) == PGRES_COPY_IN) copy_in_state = true; --- 549,559 ---- cancelConn = pset.db; if (pset.timing) ! GETTIMEOFDAY(&before); results = PQexec(pset.db, query); if (pset.timing) ! GETTIMEOFDAY(&after); if (PQresultStatus(results) == PGRES_COPY_IN) copy_in_state = true; *************** *** 390,526 **** 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); } ! /* 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; } --- 564,574 ---- if (results == NULL) { fputs(PQerrorMessage(pset.db), pset.queryFout); ! return false; } ! return PrintQueryResults(results, &before, &after); ! PQclear(results); }