mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-03-19 20:00:51 +08:00
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
This commit is contained in:
parent
71f35f5916
commit
1eb9fd49d1
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user