]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Make error messages more explicit, PQtrace() output more readable.
authorBryan Henderson <bryanh@giraffe.netgate.net>
Tue, 31 Dec 1996 07:29:17 +0000 (07:29 +0000)
committerBryan Henderson <bryanh@giraffe.netgate.net>
Tue, 31 Dec 1996 07:29:17 +0000 (07:29 +0000)
src/interfaces/libpq/fe-exec.c
src/interfaces/libpq/fe-misc.c

index 9e3bc3f5948838d29a2f5d5f07ac785242c91cb6..9f1f64c7265e3e30486e51732fc296519c336e43 100644 (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,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
index 852ceefe9e9223763a5f063b3b7bb4ee8b5df92b..2743cd3ecd6296bfff71afed66d2ab927efe1116 100644 (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);
 }
+
+