aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/interfaces/libpq/fe-exec.c300
-rw-r--r--src/interfaces/libpq/fe-misc.c24
2 files changed, 186 insertions, 138 deletions
diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c
index 9e3bc3f5948..9f1f64c7265 100644
--- a/src/interfaces/libpq/fe-exec.c
+++ b/src/interfaces/libpq/fe-exec.c
@@ -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,129 +557,20 @@ 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) {
+ process_response_from_backend(conn->Pfin, conn->Pfout, conn->Pfdebug, conn,
+ &result, conn->errorMessage);
+ return(result);
+}
- /* 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)*/
-}
/*
* PQnotifies
diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c
index 852ceefe9e9..2743cd3ecd6 100644
--- a/src/interfaces/libpq/fe-misc.c
+++ b/src/interfaces/libpq/fe-misc.c
@@ -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);
}
+
+