Make error messages more explicit, PQtrace() output more readable.

This commit is contained in:
Bryan Henderson 1996-12-31 07:29:17 +00:00
parent e2da92f1c3
commit 8fb0ac8898
2 changed files with 187 additions and 139 deletions

View File

@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.25 1996/12/28 01:57:13 momjian Exp $
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.26 1996/12/31 07:29:15 bryanh Exp $
*
*-------------------------------------------------------------------------
*/
@ -348,6 +348,170 @@ makePGresult_badResponse_return:
}
/*
* Assuming that we just sent a query to the backend, read the backend's
* response from stream <pfin> and respond accordingly.
*
* If <pfdebug> is non-null, write to that stream whatever we receive
* (it's a debugging trace).
*
* Return as <result> a pointer to a proper final PGresult structure,
* newly allocated, for the query based on the response we get. If the
* response we get indicates that the query didn't execute, return a
* null pointer and don't allocate any space, but also place a text
* string explaining the problem at <*reason>.
*/
static void
process_response_from_backend(FILE *pfin, FILE *pfout, FILE *pfdebug,
PGconn *conn,
PGresult **result_p, char * const reason) {
char id;
/* The protocol character received from the backend. The protocol
character is the first character in the backend's response to our
query. It defines the nature of the response.
*/
PGnotify *newNotify;
bool done;
/* We're all done with the query and ready to return the result. */
int emptiesSent;
/* Number of empty queries we have sent in order to flush out multiple
responses, less the number of corresponding responses we have
received.
*/
char cmdStatus[MAX_MESSAGE_LEN];
char pname[MAX_MESSAGE_LEN]; /* portal name */
/* loop because multiple messages, especially NOTICES,
can come back from the backend. NOTICES are output directly to stderr
*/
emptiesSent = 0; /* No empty queries sent yet */
pname[0] = '\0';
done = false; /* initial value */
while (!done) {
/* read the result id */
id = pqGetc(pfin, pfdebug);
if (id == EOF) {
/* hmm, no response from the backend-end, that's bad */
(void) sprintf(reason,
"PQexec() -- Request was sent to backend, but backend "
"closed the channel before "
"responding. This probably means the backend "
"terminated abnormally before or while processing "
"the request.\n");
conn->status = CONNECTION_BAD; /* No more connection to backend */
*result_p = (PGresult*)NULL;
done = true;
} else {
switch (id) {
case 'A':
newNotify = (PGnotify*)malloc(sizeof(PGnotify));
pqGetInt(&(newNotify->be_pid), 4, pfin, pfdebug);
pqGets(newNotify->relname, NAMEDATALEN, pfin, pfdebug);
DLAddTail(conn->notifyList, DLNewElem(newNotify));
/* async messages are piggy'ed back on other messages,
so we stay in the while loop for other messages */
break;
case 'C': /* portal query command, no rows returned */
if (pqGets(cmdStatus, MAX_MESSAGE_LEN, pfin, pfdebug) == 1) {
sprintf(reason,
"PQexec() -- query command completed, "
"but return message from backend cannot be read.");
*result_p = (PGresult*)NULL;
done = true;
} else {
/*
// since backend may produce more than one result for some
// commands need to poll until clear
// send an empty query down, and keep reading out of the pipe
// until an 'I' is received.
*/
pqPuts("Q ", pfout, pfdebug); /* send an empty query */
/*
* Increment a flag and process messages in the usual way because
* there may be async notifications pending. DZ - 31-8-1996
*/
emptiesSent++;
}
break;
case 'E': /* error return */
if (pqGets(conn->errorMessage, ERROR_MSG_LENGTH, pfin, pfdebug) == 1) {
(void) sprintf(reason,
"PQexec() -- error return detected from backend, "
"but attempt to read the error message failed.");
}
*result_p = (PGresult*)NULL;
done = true;
break;
case 'I': { /* empty query */
/* read and throw away the closing '\0' */
int c;
if ((c = pqGetc(pfin,pfdebug)) != '\0') {
fprintf(stderr,"error!, unexpected character %c following 'I'\n", c);
}
if (emptiesSent) {
if (--emptiesSent == 0) { /* is this the last one? */
/*
* If this is the result of a portal query command set the
* command status and message accordingly. DZ - 31-8-1996
*/
*result_p = makeEmptyPGresult(conn,PGRES_COMMAND_OK);
strncpy((*result_p)->cmdStatus, cmdStatus, CMDSTATUS_LEN-1);
done = true;
}
}
else {
*result_p = makeEmptyPGresult(conn, PGRES_EMPTY_QUERY);
done = true;
}
}
break;
case 'N': /* notices from the backend */
if (pqGets(reason, ERROR_MSG_LENGTH, pfin, pfdebug) == 1) {
sprintf(reason,
"PQexec() -- Notice detected from backend, "
"but attempt to read the notice failed.");
*result_p = (PGresult*)NULL;
done = true;
} else
/* Should we really be doing this? These notices are not important
enough for us to presume to put them on stderr. Maybe the caller
should decide whether to put them on stderr or not. BJH 96.12.27
*/
fprintf(stderr,"%s", reason);
break;
case 'P': /* synchronous (normal) portal */
pqGets(pname, MAX_MESSAGE_LEN, pfin, pfdebug); /* read in portal name*/
break;
case 'T': /* actual row results: */
*result_p = makePGresult(conn, pname);
done = true;
break;
case 'D': /* copy command began successfully */
*result_p = makeEmptyPGresult(conn, PGRES_COPY_IN);
done = true;
break;
case 'B': /* copy command began successfully */
*result_p = makeEmptyPGresult(conn, PGRES_COPY_OUT);
done = true;
break;
default:
sprintf(reason,
"unknown protocol character '%c' read from backend. "
"(The protocol character is the first character the "
"backend sends in response to a query it receives).\n",
id);
*result_p = (PGresult*)NULL;
done = true;
} /* switch on protocol character */
} /* if character was received */
} /* while not done */
}
/*
* PQexec
@ -364,16 +528,7 @@ PGresult*
PQexec(PGconn* conn, const char* query)
{
PGresult *result;
int id;
char buffer[MAX_MESSAGE_LEN];
char cmdStatus[MAX_MESSAGE_LEN];
char pname[MAX_MESSAGE_LEN]; /* portal name */
PGnotify *newNotify;
FILE *pfin, *pfout, *pfdebug;
static int emptiesPending = 0;
bool emptySent = false;
pname[0]='\0';
if (!conn) return NULL;
if (!query) {
@ -381,10 +536,6 @@ PQexec(PGconn* conn, const char* query)
return NULL;
}
pfin = conn->Pfin;
pfout = conn->Pfout;
pfdebug = conn->Pfdebug;
/*clear the error string */
conn->errorMessage[0] = '\0';
@ -406,130 +557,21 @@ PQexec(PGconn* conn, const char* query)
sprintf(buffer,"Q%s",query);
/* send the query to the backend; */
if (pqPuts(buffer,pfout, pfdebug) == 1) {
if (pqPuts(buffer, conn->Pfout, conn->Pfdebug) == 1) {
(void) sprintf(conn->errorMessage,
"PQexec() -- while sending query: %s\n"
"-- fprintf to Pfout failed: errno=%d\n%s\n",
query, errno,strerror(errno));
query, errno, strerror(errno));
return NULL;
}
/* loop forever because multiple messages, especially NOTICES,
can come back from the backend
NOTICES are output directly to stderr
*/
while (1) {
/* read the result id */
id = pqGetc(pfin,pfdebug);
if (id == EOF) {
/* hmm, no response from the backend-end, that's bad */
(void) sprintf(conn->errorMessage,
"PQexec() -- Request was sent to backend, but backend "
"closed the channel before "
"responding. This probably means the backend "
"terminated abnormally before or while processing "
"the request.\n");
conn->status = CONNECTION_BAD; /* No more connection to backend */
return (PGresult*)NULL;
}
switch (id) {
case 'A':
newNotify = (PGnotify*)malloc(sizeof(PGnotify));
pqGetInt(&(newNotify->be_pid), 4, pfin, pfdebug);
pqGets(newNotify->relname, NAMEDATALEN, pfin, pfdebug);
DLAddTail(conn->notifyList, DLNewElem(newNotify));
/* async messages are piggy'ed back on other messages,
so we stay in the while loop for other messages */
break;
case 'C': /* portal query command, no rows returned */
if (pqGets(cmdStatus, MAX_MESSAGE_LEN, pfin, pfdebug) == 1) {
sprintf(conn->errorMessage,
"PQexec() -- query command completed, "
"but return message from backend cannot be read.");
return (PGresult*)NULL;
}
else {
/*
// since backend may produce more than one result for some commands
// need to poll until clear
// send an empty query down, and keep reading out of the pipe
// until an 'I' is received.
*/
pqPuts("Q",pfout,pfdebug); /* send an empty query */
/*
* Increment a flag and process messages in the usual way because
* there may be async notifications pending. DZ - 31-8-1996
*/
emptiesPending++;
emptySent = true;
}
break;
case 'E': /* error return */
if (pqGets(conn->errorMessage, ERROR_MSG_LENGTH, pfin, pfdebug) == 1) {
(void) sprintf(conn->errorMessage,
"PQexec() -- error return detected from backend, "
"but attempt to read the error message failed.");
}
return (PGresult*)NULL;
break;
case 'I': /* empty query */
/* read the throw away the closing '\0' */
{
int c;
if ((c = pqGetc(pfin,pfdebug)) != '\0') {
fprintf(stderr,"error!, unexpected character %c following 'I'\n", c);
}
if (emptiesPending) {
if (--emptiesPending == 0 && emptySent) { /* is this the last one? */
/*
* If this is the result of a portal query command set the
* command status and message accordingly. DZ - 31-8-1996
*/
result = makeEmptyPGresult(conn,PGRES_COMMAND_OK);
strncpy(result->cmdStatus,cmdStatus, CMDSTATUS_LEN-1);
return result;
}
}
else {
result = makeEmptyPGresult(conn, PGRES_EMPTY_QUERY);
return result;
}
}
break;
case 'N': /* notices from the backend */
if (pqGets(conn->errorMessage, ERROR_MSG_LENGTH, pfin, pfdebug) == 1) {
sprintf(conn->errorMessage,
"PQexec() -- Notice detected from backend, "
"but attempt to read the notice failed.");
return (PGresult*)NULL;
}
else
fprintf(stderr,"%s", conn->errorMessage);
break;
case 'P': /* synchronous (normal) portal */
pqGets(pname,MAX_MESSAGE_LEN,pfin, pfdebug); /* read in portal name*/
break;
case 'T': /* actual row results: */
return makePGresult(conn, pname);
break;
case 'D': /* copy command began successfully */
return makeEmptyPGresult(conn,PGRES_COPY_IN);
break;
case 'B': /* copy command began successfully */
return makeEmptyPGresult(conn,PGRES_COPY_OUT);
break;
default:
sprintf(conn->errorMessage,
"unknown protocol character %c read from backend\n",
id);
return (PGresult*)NULL;
} /* switch */
} /* while (1)*/
process_response_from_backend(conn->Pfin, conn->Pfout, conn->Pfdebug, conn,
&result, conn->errorMessage);
return(result);
}
/*
* PQnotifies
* returns a PGnotify* structure of the latest async notification

View File

@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.3 1996/11/03 07:14:32 scrappy Exp $
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.4 1996/12/31 07:29:17 bryanh Exp $
*
*-------------------------------------------------------------------------
*/
@ -35,7 +35,7 @@ pqGetc(FILE* fin, FILE* debug)
c = getc(fin);
if (debug && c != EOF)
putc(c,debug);
fprintf(debug, "From backend> %c\n", c);
return c;
}
@ -52,6 +52,7 @@ pqPutnchar(const char* s, int len, FILE *f, FILE *debug)
if (f == NULL)
return 1;
if (debug) fputs("To backend>", debug);
while (len--) {
status = fputc(*s,f);
if (debug)
@ -60,6 +61,7 @@ pqPutnchar(const char* s, int len, FILE *f, FILE *debug)
if (status == EOF)
return 1;
}
if (debug) fputc('\n', debug);
return 0;
}
@ -79,7 +81,7 @@ pqGetnchar(char* s, int len, FILE *f, FILE *debug)
*s = '\0';
if (debug) {
fputs(s,debug);
fprintf(debug, "From backend> %s\n", s);
}
return 0;
}
@ -100,7 +102,7 @@ pqGets(char* s, int len, FILE *f, FILE *debug)
*s = '\0';
if (debug) {
fputs(s,debug);
fprintf(debug, "From backend> %s\n", s);
}
return 0;
}
@ -114,22 +116,24 @@ pqGets(char* s, int len, FILE *f, FILE *debug)
returns 0 if successful, 1 otherwise
*/
int
pqPutInt(int i, int bytes, FILE* f, FILE *debug)
pqPutInt(const int integer, int bytes, FILE* f, FILE *debug)
{
int i;
int status;
i = integer;
if (bytes > 4)
bytes = 4;
while (bytes--) {
status = fputc(i & 0xff, f);
if (debug)
fputc(i & 0xff, debug);
i >>= 8;
if (status == EOF) {
return 1;
}
}
if (debug) fprintf(debug, "To backend (#)> %d\n", integer);
return 0;
}
@ -163,7 +167,7 @@ pqGetInt(int* result, int bytes, FILE* f, FILE *debug)
*result = n;
if (debug)
fprintf(debug,"%d",*result);
fprintf(debug,"From backend (#)> %d\n",*result);
return 0;
}
@ -181,7 +185,7 @@ pqPuts(const char* s, FILE *f, FILE *debug)
fflush(f);
if (debug) {
fputs(s,debug);
fprintf(debug, "To backend> %s\n", s);
}
return 0;
}
@ -195,3 +199,5 @@ pqFlush(FILE *f, FILE *debug)
if (debug)
fflush(debug);
}