diff options
author | Bruce Momjian <bruce@momjian.us> | 1997-09-07 05:04:48 +0000 |
---|---|---|
committer | Bruce Momjian <bruce@momjian.us> | 1997-09-07 05:04:48 +0000 |
commit | 1ccd423235a48739d6f7a4d7889705b5f9ecc69b (patch) | |
tree | 8001c4e839dfad8f29ceda7f8c5f5dbb8759b564 /src/interfaces/libpq/fe-exec.c | |
parent | 8fecd4febf8357f3cc20383ed29ced484877d5ac (diff) | |
download | postgresql-1ccd423235a48739d6f7a4d7889705b5f9ecc69b.tar.gz postgresql-1ccd423235a48739d6f7a4d7889705b5f9ecc69b.zip |
Massive commit to run PGINDENT on all *.c and *.h files.
Diffstat (limited to 'src/interfaces/libpq/fe-exec.c')
-rw-r--r-- | src/interfaces/libpq/fe-exec.c | 3014 |
1 files changed, 1627 insertions, 1387 deletions
diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c index 771e8c66e2b..be8913e7bf7 100644 --- a/src/interfaces/libpq/fe-exec.c +++ b/src/interfaces/libpq/fe-exec.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * fe-exec.c-- - * functions related to sending a query down to the backend + * functions related to sending a query down to the backend * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.35 1997/09/05 00:09:47 momjian Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.36 1997/09/07 05:03:28 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -23,19 +23,22 @@ #include "libpq-fe.h" #include <sys/ioctl.h> #ifndef HAVE_TERMIOS_H -# include <sys/termios.h> +#include <sys/termios.h> #else -# include <termios.h> +#include <termios.h> #endif #ifdef TIOCGWINSZ -struct winsize screen_size; +struct winsize screen_size; + #else -struct winsize { - int ws_row; - int ws_col; -} screen_size; +struct winsize +{ + int ws_row; + int ws_col; +} screen_size; + #endif /* the rows array in a PGresGroup has to grow to accommodate the rows */ @@ -43,325 +46,358 @@ struct winsize { #define TUPARR_GROW_BY 100 /* keep this in same order as ExecStatusType in pgtclCmds.h */ -const char* pgresStatus[] = { - "PGRES_EMPTY_QUERY", - "PGRES_COMMAND_OK", - "PGRES_TUPLES_OK", - "PGRES_BAD_RESPONSE", - "PGRES_NONFATAL_ERROR", - "PGRES_FATAL_ERROR" +const char *pgresStatus[] = { + "PGRES_EMPTY_QUERY", + "PGRES_COMMAND_OK", + "PGRES_TUPLES_OK", + "PGRES_BAD_RESPONSE", + "PGRES_NONFATAL_ERROR", + "PGRES_FATAL_ERROR" }; -static PGresult* makePGresult(PGconn *conn, char *pname); -static void addTuple(PGresult *res, PGresAttValue *tup); -static PGresAttValue* getTuple(PGconn *conn, PGresult *res, int binary); -static PGresult* makeEmptyPGresult(PGconn *conn, ExecStatusType status); -static void fill(int length, int max, char filler, FILE *fp); -static char* do_header(FILE *fout, PQprintOpt *po, const int nFields, - int fieldMax[], char *fieldNames[], unsigned char fieldNotNum[], - const int fs_len, PGresult *res); +static PGresult *makePGresult(PGconn * conn, char *pname); +static void addTuple(PGresult * res, PGresAttValue * tup); +static PGresAttValue *getTuple(PGconn * conn, PGresult * res, int binary); +static PGresult *makeEmptyPGresult(PGconn * conn, ExecStatusType status); +static void fill(int length, int max, char filler, FILE * fp); +static char * +do_header(FILE * fout, PQprintOpt * po, const int nFields, + int fieldMax[], char *fieldNames[], unsigned char fieldNotNum[], + const int fs_len, PGresult * res); /* * PQclear - - * free's the memory associated with a PGresult + * free's the memory associated with a PGresult * */ void -PQclear(PGresult* res) +PQclear(PGresult * res) { - int i,j; - - if (!res) - return; - - /* free all the rows */ - for (i=0;i<res->ntups;i++) { - for (j=0;j<res->numAttributes;j++) { - if (res->tuples[i][j].value) - free(res->tuples[i][j].value); - } - if (res->tuples[i]) free(res->tuples[i]); - } - if (res->tuples) free(res->tuples); - - /* free all the attributes */ - for (i=0;i<res->numAttributes;i++) { - if (res->attDescs[i].name) - free(res->attDescs[i].name); - } - if (res->attDescs) free(res->attDescs); - - /* free the structure itself */ - free(res); + int i, + j; + + if (!res) + return; + + /* free all the rows */ + for (i = 0; i < res->ntups; i++) + { + for (j = 0; j < res->numAttributes; j++) + { + if (res->tuples[i][j].value) + free(res->tuples[i][j].value); + } + if (res->tuples[i]) + free(res->tuples[i]); + } + if (res->tuples) + free(res->tuples); + + /* free all the attributes */ + for (i = 0; i < res->numAttributes; i++) + { + if (res->attDescs[i].name) + free(res->attDescs[i].name); + } + if (res->attDescs) + free(res->attDescs); + + /* free the structure itself */ + free(res); } /* * PGresult - - * returns a newly allocated, initialized PGresult + * returns a newly allocated, initialized PGresult * */ -static PGresult* -makeEmptyPGresult(PGconn *conn, ExecStatusType status) +static PGresult * +makeEmptyPGresult(PGconn * conn, ExecStatusType status) { - PGresult *result; - - result = (PGresult*)malloc(sizeof(PGresult)); - - result->conn = conn; - result->ntups = 0; - result->numAttributes = 0; - result->attDescs = NULL; - result->tuples = NULL; - result->tupArrSize = 0; - result->resultStatus = status; - result->cmdStatus[0] = '\0'; - result->binary = 0; - return result; + PGresult *result; + + result = (PGresult *) malloc(sizeof(PGresult)); + + result->conn = conn; + result->ntups = 0; + result->numAttributes = 0; + result->attDescs = NULL; + result->tuples = NULL; + result->tupArrSize = 0; + result->resultStatus = status; + result->cmdStatus[0] = '\0'; + result->binary = 0; + return result; } /* * getTuple - - * get the next row from the stream + * get the next row from the stream * - * the CALLER is responsible from freeing the PGresAttValue returned + * the CALLER is responsible from freeing the PGresAttValue returned */ -static PGresAttValue* -getTuple(PGconn *conn, PGresult* result, int binary) +static PGresAttValue * +getTuple(PGconn * conn, PGresult * result, int binary) { - char bitmap[MAX_FIELDS]; /* the backend sends us a bitmap of */ - /* which attributes are null */ - int bitmap_index = 0; - int i; - int nbytes; /* the number of bytes in bitmap */ - char bmap; /* One byte of the bitmap */ - int bitcnt = 0; /* number of bits examined in current byte */ - int vlen; /* length of the current field value */ - FILE *pfin = conn->Pfin; - FILE *pfdebug = conn->Pfdebug; - - PGresAttValue* tup; - - int nfields = result->numAttributes; - - result->binary = binary; - - tup = (PGresAttValue*) malloc(nfields * sizeof(PGresAttValue)); - - nbytes = nfields / BYTELEN; - if ( (nfields % BYTELEN) > 0) - nbytes++; - - if (pqGetnchar(bitmap, nbytes, pfin, pfdebug) == 1){ - sprintf(conn->errorMessage, - "Error reading null-values bitmap from row data stream\n"); - return NULL; - } - - bmap = bitmap[bitmap_index]; - - for (i=0;i<nfields;i++) { - if (!(bmap & 0200)) { - /* if the field value is absent, make it '\0' */ - tup[i].value = (char*)malloc(1); - tup[i].value[0] = '\0'; - tup[i].len = NULL_LEN; - } - else { - /* get the value length (the first four bytes are for length) */ - pqGetInt(&vlen, VARHDRSZ, pfin, pfdebug); - if (binary == 0) { - vlen = vlen - VARHDRSZ; - } - if (vlen < 0) - vlen = 0; - tup[i].len = vlen; - tup[i].value = (char*) malloc(vlen + 1); - /* read in the value; */ - if (vlen > 0) - pqGetnchar((char*)(tup[i].value), vlen, pfin, pfdebug); - tup[i].value[vlen] = '\0'; - } - /* get the appropriate bitmap */ - bitcnt++; - if (bitcnt == BYTELEN) { - bitmap_index++; - bmap = bitmap[bitmap_index]; - bitcnt = 0; - } else - bmap <<= 1; - } - - return tup; + char bitmap[MAX_FIELDS]; /* the backend sends us a bitmap + * of */ + + /* which attributes are null */ + int bitmap_index = 0; + int i; + int nbytes; /* the number of bytes in bitmap */ + char bmap; /* One byte of the bitmap */ + int bitcnt = 0; /* number of bits examined in current byte */ + int vlen; /* length of the current field value */ + FILE *pfin = conn->Pfin; + FILE *pfdebug = conn->Pfdebug; + + PGresAttValue *tup; + + int nfields = result->numAttributes; + + result->binary = binary; + + tup = (PGresAttValue *) malloc(nfields * sizeof(PGresAttValue)); + + nbytes = nfields / BYTELEN; + if ((nfields % BYTELEN) > 0) + nbytes++; + + if (pqGetnchar(bitmap, nbytes, pfin, pfdebug) == 1) + { + sprintf(conn->errorMessage, + "Error reading null-values bitmap from row data stream\n"); + return NULL; + } + + bmap = bitmap[bitmap_index]; + + for (i = 0; i < nfields; i++) + { + if (!(bmap & 0200)) + { + /* if the field value is absent, make it '\0' */ + tup[i].value = (char *) malloc(1); + tup[i].value[0] = '\0'; + tup[i].len = NULL_LEN; + } + else + { + /* get the value length (the first four bytes are for length) */ + pqGetInt(&vlen, VARHDRSZ, pfin, pfdebug); + if (binary == 0) + { + vlen = vlen - VARHDRSZ; + } + if (vlen < 0) + vlen = 0; + tup[i].len = vlen; + tup[i].value = (char *) malloc(vlen + 1); + /* read in the value; */ + if (vlen > 0) + pqGetnchar((char *) (tup[i].value), vlen, pfin, pfdebug); + tup[i].value[vlen] = '\0'; + } + /* get the appropriate bitmap */ + bitcnt++; + if (bitcnt == BYTELEN) + { + bitmap_index++; + bmap = bitmap[bitmap_index]; + bitcnt = 0; + } + else + bmap <<= 1; + } + + return tup; } /* * addTuple - * add a row to the PGresult structure, growing it if necessary - * to accommodate + * add a row to the PGresult structure, growing it if necessary + * to accommodate * */ -static void -addTuple(PGresult* res, PGresAttValue* tup) +static void +addTuple(PGresult * res, PGresAttValue * tup) { - if (res->ntups == res->tupArrSize) { - /* grow the array */ - res->tupArrSize += TUPARR_GROW_BY; - - if (res->ntups == 0) - res->tuples = (PGresAttValue**) - malloc(res->tupArrSize * sizeof(PGresAttValue*)); - else - /* we can use realloc because shallow copying of the structure is okay */ - res->tuples = (PGresAttValue**) - realloc(res->tuples, res->tupArrSize * sizeof(PGresAttValue*)); - } - - res->tuples[res->ntups] = tup; - res->ntups++; + if (res->ntups == res->tupArrSize) + { + /* grow the array */ + res->tupArrSize += TUPARR_GROW_BY; + + if (res->ntups == 0) + res->tuples = (PGresAttValue **) + malloc(res->tupArrSize * sizeof(PGresAttValue *)); + else + + /* + * we can use realloc because shallow copying of the structure + * is okay + */ + res->tuples = (PGresAttValue **) + realloc(res->tuples, res->tupArrSize * sizeof(PGresAttValue *)); + } + + res->tuples[res->ntups] = tup; + res->ntups++; } /* * PGresult - * fill out the PGresult structure with result rows from the backend - * this is called after query has been successfully run and we have - * a portal name + * fill out the PGresult structure with result rows from the backend + * this is called after query has been successfully run and we have + * a portal name * - * ASSUMPTION: we assume only *1* row group is returned from the backend + * ASSUMPTION: we assume only *1* row group is returned from the backend * - * the CALLER is reponsible for free'ing the new PGresult allocated here + * the CALLER is reponsible for free'ing the new PGresult allocated here * */ -static PGresult* -makePGresult(PGconn* conn, char* pname) +static PGresult * +makePGresult(PGconn * conn, char *pname) { - PGresult* result; - int id; - int nfields; - int i; - int done = 0; - - PGresAttValue* newTup; - - FILE* pfin = conn->Pfin; - FILE* pfdebug = conn->Pfdebug; - - result = makeEmptyPGresult(conn, PGRES_TUPLES_OK); - - /* makePGresult() should only be called when the */ - /* id of the stream is 'T' to start with */ - - /* the next two bytes are the number of fields */ - if (pqGetInt(&nfields, 2, pfin, pfdebug) == 1) { - sprintf(conn->errorMessage, - "could not get the number of fields from the 'T' message\n"); - goto makePGresult_badResponse_return; - } - else - result->numAttributes = nfields; - - /* allocate space for the attribute descriptors */ - if (nfields > 0) { - result->attDescs = (PGresAttDesc*) malloc(nfields * sizeof(PGresAttDesc)); - } - - /* get type info */ - for (i=0;i<nfields;i++) { - char typName[MAX_MESSAGE_LEN]; - int adtid; - int adtsize; - - if ( pqGets(typName, MAX_MESSAGE_LEN, pfin, pfdebug) || - pqGetInt(&adtid, 4, pfin, pfdebug) || - pqGetInt(&adtsize, 2, pfin, pfdebug)) { - sprintf(conn->errorMessage, - "error reading type information from the 'T' message\n"); - goto makePGresult_badResponse_return; - } - result->attDescs[i].name = malloc(strlen(typName)+1); - strcpy(result->attDescs[i].name,typName); - result->attDescs[i].adtid = adtid; - result->attDescs[i].adtsize = adtsize; /* casting from int to int2 here */ - } - - id = pqGetc(pfin,pfdebug); - - /* process the data stream until we're finished */ - while(!done) { - switch (id) { - case 'T': /* a new row group */ - sprintf(conn->errorMessage, - "makePGresult() -- " - "is not equipped to handle multiple row groups.\n"); - goto makePGresult_badResponse_return; - case 'B': /* a row in binary format */ - case 'D': /* a row in ASCII format */ - newTup = getTuple(conn, result, (id == 'B')); - if (newTup == NULL) - goto makePGresult_badResponse_return; - addTuple(result,newTup); - break; - case 'C': /* end of portal row stream */ - { - char command[MAX_MESSAGE_LEN]; - pqGets(command,MAX_MESSAGE_LEN, pfin, pfdebug); /* read command tag */ - done = 1; - } - break; - case 'E': /* errors */ - if (pqGets(conn->errorMessage, ERROR_MSG_LENGTH, pfin, pfdebug) == 1) { - sprintf(conn->errorMessage, - "Error return detected from backend, " - "but error message cannot be read"); - } - result->resultStatus = PGRES_FATAL_ERROR; - return result; - break; - case 'N': /* notices from the backend */ - if (pqGets(conn->errorMessage, ERROR_MSG_LENGTH, pfin, pfdebug) == 1) { - sprintf(conn->errorMessage, - "Notice return detected from backend, " - "but error message cannot be read"); - } else - /* XXXX send Notices to stderr for now */ - fprintf(stderr, "%s\n", conn->errorMessage); - break; - default: /* uh-oh - this should never happen but frequently does when the - backend dumps core */ - sprintf(conn->errorMessage, - "FATAL: unrecognized data from the backend. " - "It probably dumped core.\n"); - fprintf(stderr, conn->errorMessage); - result->resultStatus = PGRES_FATAL_ERROR; - return result; - break; - } - if (!done) - id = getc(pfin); - } /* while (1) */ - - result->resultStatus = PGRES_TUPLES_OK; - return result; + PGresult *result; + int id; + int nfields; + int i; + int done = 0; + + PGresAttValue *newTup; + + FILE *pfin = conn->Pfin; + FILE *pfdebug = conn->Pfdebug; + + result = makeEmptyPGresult(conn, PGRES_TUPLES_OK); + + /* makePGresult() should only be called when the */ + /* id of the stream is 'T' to start with */ + + /* the next two bytes are the number of fields */ + if (pqGetInt(&nfields, 2, pfin, pfdebug) == 1) + { + sprintf(conn->errorMessage, + "could not get the number of fields from the 'T' message\n"); + goto makePGresult_badResponse_return; + } + else + result->numAttributes = nfields; + + /* allocate space for the attribute descriptors */ + if (nfields > 0) + { + result->attDescs = (PGresAttDesc *) malloc(nfields * sizeof(PGresAttDesc)); + } + + /* get type info */ + for (i = 0; i < nfields; i++) + { + char typName[MAX_MESSAGE_LEN]; + int adtid; + int adtsize; + + if (pqGets(typName, MAX_MESSAGE_LEN, pfin, pfdebug) || + pqGetInt(&adtid, 4, pfin, pfdebug) || + pqGetInt(&adtsize, 2, pfin, pfdebug)) + { + sprintf(conn->errorMessage, + "error reading type information from the 'T' message\n"); + goto makePGresult_badResponse_return; + } + result->attDescs[i].name = malloc(strlen(typName) + 1); + strcpy(result->attDescs[i].name, typName); + result->attDescs[i].adtid = adtid; + result->attDescs[i].adtsize = adtsize; /* casting from int to + * int2 here */ + } + + id = pqGetc(pfin, pfdebug); + + /* process the data stream until we're finished */ + while (!done) + { + switch (id) + { + case 'T': /* a new row group */ + sprintf(conn->errorMessage, + "makePGresult() -- " + "is not equipped to handle multiple row groups.\n"); + goto makePGresult_badResponse_return; + case 'B': /* a row in binary format */ + case 'D': /* a row in ASCII format */ + newTup = getTuple(conn, result, (id == 'B')); + if (newTup == NULL) + goto makePGresult_badResponse_return; + addTuple(result, newTup); + break; + case 'C': /* end of portal row stream */ + { + char command[MAX_MESSAGE_LEN]; + + pqGets(command, MAX_MESSAGE_LEN, pfin, pfdebug); /* read command tag */ + done = 1; + } + break; + case 'E': /* errors */ + if (pqGets(conn->errorMessage, ERROR_MSG_LENGTH, pfin, pfdebug) == 1) + { + sprintf(conn->errorMessage, + "Error return detected from backend, " + "but error message cannot be read"); + } + result->resultStatus = PGRES_FATAL_ERROR; + return result; + break; + case 'N': /* notices from the backend */ + if (pqGets(conn->errorMessage, ERROR_MSG_LENGTH, pfin, pfdebug) == 1) + { + sprintf(conn->errorMessage, + "Notice return detected from backend, " + "but error message cannot be read"); + } + else + /* XXXX send Notices to stderr for now */ + fprintf(stderr, "%s\n", conn->errorMessage); + break; + default: /* uh-oh this should never happen but + * frequently does when the backend dumps + * core */ + sprintf(conn->errorMessage, + "FATAL: unrecognized data from the backend. " + "It probably dumped core.\n"); + fprintf(stderr, conn->errorMessage); + result->resultStatus = PGRES_FATAL_ERROR; + return result; + break; + } + if (!done) + id = getc(pfin); + } /* while (1) */ + + result->resultStatus = PGRES_TUPLES_OK; + return result; makePGresult_badResponse_return: - result->resultStatus = PGRES_BAD_RESPONSE; - return result; + result->resultStatus = PGRES_BAD_RESPONSE; + return result; } /* - * Assuming that we just sent a query to the backend, read the backend's + * 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 @@ -370,450 +406,522 @@ makePGresult_badResponse_return: */ static void -process_response_from_backend(FILE *pfin, FILE *pfout, FILE *pfdebug, - PGconn *conn, - PGresult **result_p, char * const reason) { - - int 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. - */ - int errors; - /* If an error is received, we must still drain out the empty - queries sent. So we need another flag. - */ - 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 */ - errors = 0; /* No errors received 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; - errors++; - if (emptiesSent == 0) { - 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 - */ - if (!errors) { - *result_p = makeEmptyPGresult(conn,PGRES_COMMAND_OK); - strncpy((*result_p)->cmdStatus, cmdStatus, CMDSTATUS_LEN-1); - } else { - *result_p = (PGresult*)NULL; - } - done = true; - } - } - else { - if (!errors) { - *result_p = makeEmptyPGresult(conn, PGRES_EMPTY_QUERY); - } else { - *result_p = (PGresult*)NULL; - } - 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 */ +process_response_from_backend(FILE * pfin, FILE * pfout, FILE * pfdebug, + PGconn * conn, + PGresult ** result_p, char *const reason) +{ + + int 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. + */ + int errors; + + /* + * If an error is received, we must still drain out the empty queries + * sent. So we need another flag. + */ + 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 */ + errors = 0; /* No errors received 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; + errors++; + if (emptiesSent == 0) + { + 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 + */ + if (!errors) + { + *result_p = makeEmptyPGresult(conn, PGRES_COMMAND_OK); + strncpy((*result_p)->cmdStatus, cmdStatus, CMDSTATUS_LEN - 1); + } + else + { + *result_p = (PGresult *) NULL; + } + done = true; + } + } + else + { + if (!errors) + { + *result_p = makeEmptyPGresult(conn, PGRES_EMPTY_QUERY); + } + else + { + *result_p = (PGresult *) NULL; + } + 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 - * send a query to the backend and package up the result in a Pgresult + * send a query to the backend and package up the result in a Pgresult * - * if the query failed, return NULL, conn->errorMessage is set to + * if the query failed, return NULL, conn->errorMessage is set to * a relevant message - * if query is successful, a new PGresult is returned + * if query is successful, a new PGresult is returned * the use is responsible for freeing that structure when done with it * */ -PGresult* -PQexec(PGconn* conn, const char* query) +PGresult * +PQexec(PGconn * conn, const char *query) { - PGresult *result; - char buffer[MAX_MESSAGE_LEN]; - - if (!conn) return NULL; - if (!query) { - sprintf(conn->errorMessage, "PQexec() -- query pointer is null."); - return NULL; - } - - /*clear the error string */ - conn->errorMessage[0] = '\0'; - - /* check to see if the query string is too long */ - if (strlen(query) > MAX_MESSAGE_LEN) { - sprintf(conn->errorMessage, "PQexec() -- query is too long. " - "Maximum length is %d\n", MAX_MESSAGE_LEN -2 ); - return NULL; - } - - /* Don't try to send if we know there's no live connection. */ - if (conn->status != CONNECTION_OK) { - sprintf(conn->errorMessage, "PQexec() -- There is no connection " - "to the backend.\n"); - return NULL; - } - - /* the frontend-backend protocol uses 'Q' to designate queries */ - sprintf(buffer,"Q%s",query); - - /* send the query to the backend; */ - 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)); - return NULL; - } - - process_response_from_backend(conn->Pfin, conn->Pfout, conn->Pfdebug, conn, - &result, conn->errorMessage); - return(result); + PGresult *result; + char buffer[MAX_MESSAGE_LEN]; + + if (!conn) + return NULL; + if (!query) + { + sprintf(conn->errorMessage, "PQexec() -- query pointer is null."); + return NULL; + } + + /* clear the error string */ + conn->errorMessage[0] = '\0'; + + /* check to see if the query string is too long */ + if (strlen(query) > MAX_MESSAGE_LEN) + { + sprintf(conn->errorMessage, "PQexec() -- query is too long. " + "Maximum length is %d\n", MAX_MESSAGE_LEN - 2); + return NULL; + } + + /* Don't try to send if we know there's no live connection. */ + if (conn->status != CONNECTION_OK) + { + sprintf(conn->errorMessage, "PQexec() -- There is no connection " + "to the backend.\n"); + return NULL; + } + + /* the frontend-backend protocol uses 'Q' to designate queries */ + sprintf(buffer, "Q%s", query); + + /* send the query to the backend; */ + 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)); + return NULL; + } + + 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 + * returns a PGnotify* structure of the latest async notification * that has not yet been handled * - * returns NULL, if there is currently + * returns NULL, if there is currently * no unhandled async notification from the backend * * the CALLER is responsible for FREE'ing the structure returned */ -PGnotify* -PQnotifies(PGconn *conn) +PGnotify * +PQnotifies(PGconn * conn) { - Dlelem *e; - - if (!conn) return NULL; - - if (conn->status != CONNECTION_OK) - return NULL; - /* RemHead returns NULL if list is empy */ - e = DLRemHead(conn->notifyList); - if (e) - return (PGnotify*)DLE_VAL(e); - else - return NULL; + Dlelem *e; + + if (!conn) + return NULL; + + if (conn->status != CONNECTION_OK) + return NULL; + /* RemHead returns NULL if list is empy */ + e = DLRemHead(conn->notifyList); + if (e) + return (PGnotify *) DLE_VAL(e); + else + return NULL; } /* * PQgetline - gets a newline-terminated string from the backend. - * + * * Chiefly here so that applications can use "COPY <rel> to stdout" - * and read the output string. Returns a null-terminated string in s. + * and read the output string. Returns a null-terminated string in s. * * PQgetline reads up to maxlen-1 characters (like fgets(3)) but strips * the terminating \n (like gets(3)). * * RETURNS: - * EOF if it is detected or invalid arguments are given - * 0 if EOL is reached (i.e., \n has been read) - * (this is required for backward-compatibility -- this - * routine used to always return EOF or 0, assuming that - * the line ended within maxlen bytes.) - * 1 in other cases + * EOF if it is detected or invalid arguments are given + * 0 if EOL is reached (i.e., \n has been read) + * (this is required for backward-compatibility -- this + * routine used to always return EOF or 0, assuming that + * the line ended within maxlen bytes.) + * 1 in other cases */ int -PQgetline(PGconn *conn, char *s, int maxlen) +PQgetline(PGconn * conn, char *s, int maxlen) { - int c = '\0'; - - if (!conn) return EOF; - - if (!conn->Pfin || !s || maxlen <= 1) - return(EOF); - - for (; maxlen > 1 && - (c = pqGetc(conn->Pfin, conn->Pfdebug)) != '\n' && - c != EOF; - --maxlen) { - *s++ = c; - } - *s = '\0'; - - if (c == EOF) { - return(EOF); /* error -- reached EOF before \n */ - } else if (c == '\n') { - return(0); /* done with this line */ - } - return(1); /* returning a full buffer */ + int c = '\0'; + + if (!conn) + return EOF; + + if (!conn->Pfin || !s || maxlen <= 1) + return (EOF); + + for (; maxlen > 1 && + (c = pqGetc(conn->Pfin, conn->Pfdebug)) != '\n' && + c != EOF; + --maxlen) + { + *s++ = c; + } + *s = '\0'; + + if (c == EOF) + { + return (EOF); /* error -- reached EOF before \n */ + } + else if (c == '\n') + { + return (0); /* done with this line */ + } + return (1); /* returning a full buffer */ } /* * PQputline -- sends a string to the backend. - * + * * Chiefly here so that applications can use "COPY <rel> from stdin". * */ void -PQputline(PGconn *conn, const char *s) +PQputline(PGconn * conn, const char *s) { - if (conn && (conn->Pfout)) { - (void) fputs(s, conn->Pfout); - fflush(conn->Pfout); - } + if (conn && (conn->Pfout)) + { + (void) fputs(s, conn->Pfout); + fflush(conn->Pfout); + } } /* * PQendcopy - * called while waiting for the backend to respond with success/failure - * to a "copy". + * called while waiting for the backend to respond with success/failure + * to a "copy". * * RETURNS: - * 0 on success - * 1 on failure + * 0 on success + * 1 on failure */ int -PQendcopy(PGconn *conn) +PQendcopy(PGconn * conn) { - FILE *pfin, *pfdebug; - bool valid = true; - - if (!conn) return (int)NULL; - - pfin = conn->Pfin; - pfdebug = conn->Pfdebug; - - if ( pqGetc(pfin,pfdebug) == 'C') - { - char command[MAX_MESSAGE_LEN]; - pqGets(command,MAX_MESSAGE_LEN, pfin, pfdebug); /* read command tag */ - } - else valid = false; - - if ( valid ) - return (0); - else { - sprintf(conn->errorMessage, - "Error return detected from backend, " - "but attempt to read the message failed."); - fprintf(stderr,"resetting connection\n"); - PQreset(conn); - return(1); - } + FILE *pfin, + *pfdebug; + bool valid = true; + + if (!conn) + return (int) NULL; + + pfin = conn->Pfin; + pfdebug = conn->Pfdebug; + + if (pqGetc(pfin, pfdebug) == 'C') + { + char command[MAX_MESSAGE_LEN]; + + pqGets(command, MAX_MESSAGE_LEN, pfin, pfdebug); /* read command tag */ + } + else + valid = false; + + if (valid) + return (0); + else + { + sprintf(conn->errorMessage, + "Error return detected from backend, " + "but attempt to read the message failed."); + fprintf(stderr, "resetting connection\n"); + PQreset(conn); + return (1); + } } /* simply send out max-length number of filler characters to fp */ static void -fill (int length, int max, char filler, FILE *fp) +fill(int length, int max, char filler, FILE * fp) { - int count; - char filltmp[2]; - - filltmp[0] = filler; - filltmp[1] = 0; - count = max - length; - while (count-- >= 0) - { - fprintf(fp, "%s", filltmp); - } - } + int count; + char filltmp[2]; + + filltmp[0] = filler; + filltmp[1] = 0; + count = max - length; + while (count-- >= 0) + { + fprintf(fp, "%s", filltmp); + } +} /* * PQdisplayTuples() * kept for backward compatibility */ void -PQdisplayTuples(PGresult *res, - FILE *fp, /* where to send the output */ - int fillAlign, /* pad the fields with spaces */ - const char *fieldSep, /* field separator */ - int printHeader, /* display headers? */ - int quiet - ) +PQdisplayTuples(PGresult * res, + FILE * fp, /* where to send the output */ + int fillAlign, /* pad the fields with spaces */ + const char *fieldSep, /* field separator */ + int printHeader,/* display headers? */ + int quiet +) { #define DEFAULT_FIELD_SEP " " - int i, j; - int nFields; - int nTuples; - int fLength[MAX_FIELDS]; - - if (fieldSep == NULL) - fieldSep = DEFAULT_FIELD_SEP; - - /* Get some useful info about the results */ - nFields = PQnfields(res); - nTuples = PQntuples(res); - - if (fp == NULL) - fp = stdout; - - /* Zero the initial field lengths */ - for (j=0 ; j < nFields; j++) { - fLength[j] = strlen(PQfname(res,j)); - } - /* Find the max length of each field in the result */ - /* will be somewhat time consuming for very large results */ - if (fillAlign) { - for (i=0; i < nTuples; i++) { - for (j=0 ; j < nFields; j++) { - if (PQgetlength(res,i,j) > fLength[j]) - fLength[j] = PQgetlength(res,i,j); - } - } - } - - if (printHeader) { - /* first, print out the attribute names */ - for (i=0; i < nFields; i++) { - fputs(PQfname(res,i), fp); - if (fillAlign) - fill (strlen (PQfname(res,i)), fLength[i], ' ', fp); - fputs(fieldSep,fp); - } - fprintf(fp, "\n"); - - /* Underline the attribute names */ - for (i=0; i < nFields; i++) { - if (fillAlign) - fill (0, fLength[i], '-', fp); - fputs(fieldSep,fp); - } - fprintf(fp, "\n"); - } - - /* next, print out the instances */ - for (i=0; i < nTuples; i++) { - for (j=0 ; j < nFields; j++) { - fprintf(fp, "%s", PQgetvalue(res,i,j)); - if (fillAlign) - fill (strlen (PQgetvalue(res,i,j)), fLength[j], ' ', fp); - fputs(fieldSep,fp); - } - fprintf(fp, "\n"); - } - - if (!quiet) - fprintf (fp, "\nQuery returned %d row%s.\n",PQntuples(res), - (PQntuples(res) == 1) ? "" : "s"); - - fflush(fp); + int i, + j; + int nFields; + int nTuples; + int fLength[MAX_FIELDS]; + + if (fieldSep == NULL) + fieldSep = DEFAULT_FIELD_SEP; + + /* Get some useful info about the results */ + nFields = PQnfields(res); + nTuples = PQntuples(res); + + if (fp == NULL) + fp = stdout; + + /* Zero the initial field lengths */ + for (j = 0; j < nFields; j++) + { + fLength[j] = strlen(PQfname(res, j)); + } + /* Find the max length of each field in the result */ + /* will be somewhat time consuming for very large results */ + if (fillAlign) + { + for (i = 0; i < nTuples; i++) + { + for (j = 0; j < nFields; j++) + { + if (PQgetlength(res, i, j) > fLength[j]) + fLength[j] = PQgetlength(res, i, j); + } + } + } + + if (printHeader) + { + /* first, print out the attribute names */ + for (i = 0; i < nFields; i++) + { + fputs(PQfname(res, i), fp); + if (fillAlign) + fill(strlen(PQfname(res, i)), fLength[i], ' ', fp); + fputs(fieldSep, fp); + } + fprintf(fp, "\n"); + + /* Underline the attribute names */ + for (i = 0; i < nFields; i++) + { + if (fillAlign) + fill(0, fLength[i], '-', fp); + fputs(fieldSep, fp); + } + fprintf(fp, "\n"); + } + + /* next, print out the instances */ + for (i = 0; i < nTuples; i++) + { + for (j = 0; j < nFields; j++) + { + fprintf(fp, "%s", PQgetvalue(res, i, j)); + if (fillAlign) + fill(strlen(PQgetvalue(res, i, j)), fLength[j], ' ', fp); + fputs(fieldSep, fp); + } + fprintf(fp, "\n"); + } + + if (!quiet) + fprintf(fp, "\nQuery returned %d row%s.\n", PQntuples(res), + (PQntuples(res) == 1) ? "" : "s"); + + fflush(fp); } @@ -825,260 +933,311 @@ PQdisplayTuples(PGresult *res, * */ void -PQprintTuples(PGresult *res, - FILE* fout, /* output stream */ - int PrintAttNames,/* print attribute names or not*/ - int TerseOutput, /* delimiter bars or not?*/ - int colWidth /* width of column, if 0, use variable width */ - ) +PQprintTuples(PGresult * res, + FILE * fout, /* output stream */ + int PrintAttNames,/* print attribute names or not */ + int TerseOutput, /* delimiter bars or not? */ + int colWidth /* width of column, if 0, use variable + * width */ +) { - int nFields; - int nTups; - int i,j; - char formatString[80]; - - char *tborder = NULL; - - nFields = PQnfields(res); - nTups = PQntuples(res); - - if (colWidth > 0) { - sprintf(formatString,"%%s %%-%ds",colWidth); - } else - sprintf(formatString,"%%s %%s"); - - if ( nFields > 0 ) { /* only print rows with at least 1 field. */ - - if (!TerseOutput) - { - int width; - width = nFields * 14; - tborder = malloc (width+1); - for (i = 0; i <= width; i++) - tborder[i] = '-'; - tborder[i] = '\0'; - fprintf(fout,"%s\n",tborder); - } - - for (i=0; i < nFields; i++) { - if (PrintAttNames) { - fprintf(fout,formatString, - TerseOutput ? "" : "|", - PQfname(res, i)); - } - } - - if (PrintAttNames) { - if (TerseOutput) - fprintf(fout,"\n"); - else - fprintf(fout, "|\n%s\n",tborder); - } - - for (i = 0; i < nTups; i++) { - for (j = 0; j < nFields; j++) { - char *pval = PQgetvalue(res,i,j); - fprintf(fout, formatString, - TerseOutput ? "" : "|", - pval ? pval : ""); - } - if (TerseOutput) - fprintf(fout,"\n"); - else - fprintf(fout, "|\n%s\n",tborder); - } - } + int nFields; + int nTups; + int i, + j; + char formatString[80]; + + char *tborder = NULL; + + nFields = PQnfields(res); + nTups = PQntuples(res); + + if (colWidth > 0) + { + sprintf(formatString, "%%s %%-%ds", colWidth); + } + else + sprintf(formatString, "%%s %%s"); + + if (nFields > 0) + { /* only print rows with at least 1 field. */ + + if (!TerseOutput) + { + int width; + + width = nFields * 14; + tborder = malloc(width + 1); + for (i = 0; i <= width; i++) + tborder[i] = '-'; + tborder[i] = '\0'; + fprintf(fout, "%s\n", tborder); + } + + for (i = 0; i < nFields; i++) + { + if (PrintAttNames) + { + fprintf(fout, formatString, + TerseOutput ? "" : "|", + PQfname(res, i)); + } + } + + if (PrintAttNames) + { + if (TerseOutput) + fprintf(fout, "\n"); + else + fprintf(fout, "|\n%s\n", tborder); + } + + for (i = 0; i < nTups; i++) + { + for (j = 0; j < nFields; j++) + { + char *pval = PQgetvalue(res, i, j); + + fprintf(fout, formatString, + TerseOutput ? "" : "|", + pval ? pval : ""); + } + if (TerseOutput) + fprintf(fout, "\n"); + else + fprintf(fout, "|\n%s\n", tborder); + } + } } static void -do_field(PQprintOpt *po, PGresult *res, - const int i, const int j, char *buf, const int fs_len, - char *fields[], - const int nFields, char *fieldNames[], - unsigned char fieldNotNum[], int fieldMax[], - const int fieldMaxLen, FILE *fout - ) { - - char *pval, *p, *o; - int plen; - bool skipit; - - plen=PQgetlength(res,i,j); - pval=PQgetvalue(res,i,j); - - if (plen < 1 || !pval || !*pval) { - if (po->align || po->expanded) skipit = true; - else { - skipit = false; - goto efield; - } - } else skipit = false; - - if (!skipit) { - for (p=pval, o=buf; *p; *(o++)=*(p++)) { - if ((fs_len==1 && (*p==*(po->fieldSep))) || *p=='\\' || *p=='\n') - *(o++)='\\'; - if (po->align && (*pval=='E' || *pval=='e' || - !((*p>='0' && *p<='9') || - *p=='.' || - *p=='E' || - *p=='e' || - *p==' ' || - *p=='-'))) - fieldNotNum[j]=1; - } - *o='\0'; - if (!po->expanded && (po->align || po->html3)) { - int n=strlen(buf); - if (n>fieldMax[j]) - fieldMax[j]=n; - if (!(fields[i*nFields+j]=(char *)malloc(n+1))) { - perror("malloc"); - exit(1); - } - strcpy(fields[i*nFields+j], buf); - } else { - if (po->expanded) { - if (po->html3) - fprintf(fout, - "<tr><td align=left><b>%s</b></td>" - "<td align=%s>%s</td></tr>\n", - fieldNames[j], - fieldNotNum[j] ? "left": "right", - buf); - else { - if (po->align) - fprintf(fout, - "%-*s%s %s\n", - fieldMaxLen-fs_len, fieldNames[j], po->fieldSep, - buf); - else - fprintf(fout, "%s%s%s\n", fieldNames[j], po->fieldSep, buf); - } - } else { - if (!po->html3) { - fputs(buf, fout); - efield: - if ((j+1)<nFields) - fputs(po->fieldSep, fout); - else - fputc('\n', fout); - } - } - } - } +do_field(PQprintOpt * po, PGresult * res, + const int i, const int j, char *buf, const int fs_len, + char *fields[], + const int nFields, char *fieldNames[], + unsigned char fieldNotNum[], int fieldMax[], + const int fieldMaxLen, FILE * fout +) +{ + + char *pval, + *p, + *o; + int plen; + bool skipit; + + plen = PQgetlength(res, i, j); + pval = PQgetvalue(res, i, j); + + if (plen < 1 || !pval || !*pval) + { + if (po->align || po->expanded) + skipit = true; + else + { + skipit = false; + goto efield; + } + } + else + skipit = false; + + if (!skipit) + { + for (p = pval, o = buf; *p; *(o++) = *(p++)) + { + if ((fs_len == 1 && (*p == *(po->fieldSep))) || *p == '\\' || *p == '\n') + *(o++) = '\\'; + if (po->align && (*pval == 'E' || *pval == 'e' || + !((*p >= '0' && *p <= '9') || + *p == '.' || + *p == 'E' || + *p == 'e' || + *p == ' ' || + *p == '-'))) + fieldNotNum[j] = 1; + } + *o = '\0'; + if (!po->expanded && (po->align || po->html3)) + { + int n = strlen(buf); + + if (n > fieldMax[j]) + fieldMax[j] = n; + if (!(fields[i * nFields + j] = (char *) malloc(n + 1))) + { + perror("malloc"); + exit(1); + } + strcpy(fields[i * nFields + j], buf); + } + else + { + if (po->expanded) + { + if (po->html3) + fprintf(fout, + "<tr><td align=left><b>%s</b></td>" + "<td align=%s>%s</td></tr>\n", + fieldNames[j], + fieldNotNum[j] ? "left" : "right", + buf); + else + { + if (po->align) + fprintf(fout, + "%-*s%s %s\n", + fieldMaxLen - fs_len, fieldNames[j], po->fieldSep, + buf); + else + fprintf(fout, "%s%s%s\n", fieldNames[j], po->fieldSep, buf); + } + } + else + { + if (!po->html3) + { + fputs(buf, fout); + efield: + if ((j + 1) < nFields) + fputs(po->fieldSep, fout); + else + fputc('\n', fout); + } + } + } + } } -static char* -do_header(FILE *fout, PQprintOpt *po, const int nFields, int fieldMax[], - char *fieldNames[], unsigned char fieldNotNum[], - const int fs_len, PGresult *res) { - - int j; /* for loop index */ - char *border=NULL; - - if (po->html3) - fputs("<tr>", fout); - else { - int j; /* for loop index */ - int tot=0; - int n=0; - char *p=NULL; - for (; n < nFields; n++) - tot+=fieldMax[n]+fs_len+(po->standard? 2: 0); - if (po->standard) - tot+=fs_len*2+2; - border=malloc(tot+1); - if (!border) { - perror("malloc"); - exit(1); - } - p=border; - if (po->standard) { - char *fs=po->fieldSep; - while (*fs++) - *p++='+'; - } - for (j=0; j < nFields; j++) { - int len; - for (len=fieldMax[j] + (po->standard? 2:0) ; len--; *p++='-'); - if (po->standard || (j+1)<nFields) { - char *fs=po->fieldSep; - while (*fs++) - *p++='+'; - } - } - *p='\0'; - if (po->standard) - fprintf(fout, "%s\n", border); - } - if (po->standard) - fputs(po->fieldSep, fout); - for (j=0; j < nFields; j++) { - char *s=PQfname(res, j); - if (po->html3) { - fprintf(fout, "<th align=%s>%s</th>", - fieldNotNum[j]? "left": "right", fieldNames[j]); - } else { - int n=strlen(s); - if (n>fieldMax[j]) - fieldMax[j]=n; - if (po->standard) - fprintf(fout, - fieldNotNum[j] ? " %-*s ": " %*s ", - fieldMax[j], s); - else - fprintf(fout, fieldNotNum[j] ? "%-*s": "%*s", fieldMax[j], s); - if (po->standard || (j+1)<nFields) - fputs(po->fieldSep, fout); - } - } - if (po->html3) - fputs("</tr>\n", fout); - else - fprintf(fout, "\n%s\n", border); - return border; +static char * +do_header(FILE * fout, PQprintOpt * po, const int nFields, int fieldMax[], + char *fieldNames[], unsigned char fieldNotNum[], + const int fs_len, PGresult * res) +{ + + int j; /* for loop index */ + char *border = NULL; + + if (po->html3) + fputs("<tr>", fout); + else + { + int j; /* for loop index */ + int tot = 0; + int n = 0; + char *p = NULL; + + for (; n < nFields; n++) + tot += fieldMax[n] + fs_len + (po->standard ? 2 : 0); + if (po->standard) + tot += fs_len * 2 + 2; + border = malloc(tot + 1); + if (!border) + { + perror("malloc"); + exit(1); + } + p = border; + if (po->standard) + { + char *fs = po->fieldSep; + + while (*fs++) + *p++ = '+'; + } + for (j = 0; j < nFields; j++) + { + int len; + + for (len = fieldMax[j] + (po->standard ? 2 : 0); len--; *p++ = '-'); + if (po->standard || (j + 1) < nFields) + { + char *fs = po->fieldSep; + + while (*fs++) + *p++ = '+'; + } + } + *p = '\0'; + if (po->standard) + fprintf(fout, "%s\n", border); + } + if (po->standard) + fputs(po->fieldSep, fout); + for (j = 0; j < nFields; j++) + { + char *s = PQfname(res, j); + + if (po->html3) + { + fprintf(fout, "<th align=%s>%s</th>", + fieldNotNum[j] ? "left" : "right", fieldNames[j]); + } + else + { + int n = strlen(s); + + if (n > fieldMax[j]) + fieldMax[j] = n; + if (po->standard) + fprintf(fout, + fieldNotNum[j] ? " %-*s " : " %*s ", + fieldMax[j], s); + else + fprintf(fout, fieldNotNum[j] ? "%-*s" : "%*s", fieldMax[j], s); + if (po->standard || (j + 1) < nFields) + fputs(po->fieldSep, fout); + } + } + if (po->html3) + fputs("</tr>\n", fout); + else + fprintf(fout, "\n%s\n", border); + return border; } static void -output_row(FILE *fout, PQprintOpt *po, const int nFields, char *fields[], - unsigned char fieldNotNum[], int fieldMax[], char *border, - const int row_index) { - - int field_index; /* for loop index */ - - if (po->html3) - fputs("<tr>", fout); - else if (po->standard) - fputs(po->fieldSep, fout); - for (field_index = 0; field_index < nFields; field_index++) { - char *p=fields[row_index*nFields+field_index]; - if (po->html3) - fprintf(fout, "<td align=%s>%s</td>", - fieldNotNum[field_index]? "left": "right", p? p: ""); - else { - fprintf(fout, - fieldNotNum[field_index] ? - (po->standard ? " %-*s ": "%-*s") : - (po->standard ? " %*s ": "%*s"), - fieldMax[field_index], - p ? p: ""); - if (po->standard || field_index+1 < nFields) - fputs(po->fieldSep, fout); - } - if (p) - free(p); - } - if (po->html3) - fputs("</tr>", fout); - else - if (po->standard) - fprintf(fout, "\n%s", border); - fputc('\n', fout); +output_row(FILE * fout, PQprintOpt * po, const int nFields, char *fields[], + unsigned char fieldNotNum[], int fieldMax[], char *border, + const int row_index) +{ + + int field_index;/* for loop index */ + + if (po->html3) + fputs("<tr>", fout); + else if (po->standard) + fputs(po->fieldSep, fout); + for (field_index = 0; field_index < nFields; field_index++) + { + char *p = fields[row_index * nFields + field_index]; + + if (po->html3) + fprintf(fout, "<td align=%s>%s</td>", + fieldNotNum[field_index] ? "left" : "right", p ? p : ""); + else + { + fprintf(fout, + fieldNotNum[field_index] ? + (po->standard ? " %-*s " : "%-*s") : + (po->standard ? " %*s " : "%*s"), + fieldMax[field_index], + p ? p : ""); + if (po->standard || field_index + 1 < nFields) + fputs(po->fieldSep, fout); + } + if (p) + free(p); + } + if (po->html3) + fputs("</tr>", fout); + else if (po->standard) + fprintf(fout, "\n%s", border); + fputc('\n', fout); } @@ -1097,591 +1256,672 @@ output_row(FILE *fout, PQprintOpt *po, const int nFields, char *fields[], */ void -PQprint(FILE *fout, - PGresult *res, - PQprintOpt *po - ) +PQprint(FILE * fout, + PGresult * res, + PQprintOpt * po +) { - int nFields; - - nFields = PQnfields(res); - - if ( nFields > 0 ) { /* only print rows with at least 1 field. */ - int i,j; - int nTups; - int *fieldMax=NULL; /* in case we don't use them */ - unsigned char *fieldNotNum=NULL; - char *border=NULL; - char **fields=NULL; - char **fieldNames; - int fieldMaxLen=0; - int numFieldName; - int fs_len=strlen(po->fieldSep); - int total_line_length = 0; - int usePipe = 0; - char *pagerenv; - char buf[8192*2+1]; - - nTups = PQntuples(res); - if (!(fieldNames=(char **)calloc(nFields, sizeof (char *)))) { - perror("calloc"); - exit(1); - } - if (!(fieldNotNum=(unsigned char *)calloc(nFields, 1))) { - perror("calloc"); - exit(1); - } - if (!(fieldMax=(int *)calloc(nFields, sizeof(int)))) { - perror("calloc"); - exit(1); - } - for (numFieldName=0; - po->fieldName && po->fieldName[numFieldName]; - numFieldName++) - ; - for (j=0; j < nFields; j++) { - int len; - char *s = - (j<numFieldName && po->fieldName[j][0])? - po->fieldName[j]: PQfname(res, j); - fieldNames[j]=s; - len=s ? strlen(s): 0; - fieldMax[j] = len; - len+=fs_len; - if (len>fieldMaxLen) - fieldMaxLen=len; - total_line_length += len; - } - - total_line_length += nFields * strlen(po->fieldSep) + 1; - - if (fout == NULL) - fout = stdout; - if (po->pager && fout == stdout && - isatty(fileno(stdin)) && - isatty(fileno(stdout))) { - /* try to pipe to the pager program if possible */ + int nFields; + + nFields = PQnfields(res); + + if (nFields > 0) + { /* only print rows with at least 1 field. */ + int i, + j; + int nTups; + int *fieldMax = NULL; /* in case we don't use + * them */ + unsigned char *fieldNotNum = NULL; + char *border = NULL; + char **fields = NULL; + char **fieldNames; + int fieldMaxLen = 0; + int numFieldName; + int fs_len = strlen(po->fieldSep); + int total_line_length = 0; + int usePipe = 0; + char *pagerenv; + char buf[8192 * 2 + 1]; + + nTups = PQntuples(res); + if (!(fieldNames = (char **) calloc(nFields, sizeof(char *)))) + { + perror("calloc"); + exit(1); + } + if (!(fieldNotNum = (unsigned char *) calloc(nFields, 1))) + { + perror("calloc"); + exit(1); + } + if (!(fieldMax = (int *) calloc(nFields, sizeof(int)))) + { + perror("calloc"); + exit(1); + } + for (numFieldName = 0; + po->fieldName && po->fieldName[numFieldName]; + numFieldName++) + ; + for (j = 0; j < nFields; j++) + { + int len; + char *s = + (j < numFieldName && po->fieldName[j][0]) ? + po->fieldName[j] : PQfname(res, j); + + fieldNames[j] = s; + len = s ? strlen(s) : 0; + fieldMax[j] = len; + len += fs_len; + if (len > fieldMaxLen) + fieldMaxLen = len; + total_line_length += len; + } + + total_line_length += nFields * strlen(po->fieldSep) + 1; + + if (fout == NULL) + fout = stdout; + if (po->pager && fout == stdout && + isatty(fileno(stdin)) && + isatty(fileno(stdout))) + { + /* try to pipe to the pager program if possible */ #ifdef TIOCGWINSZ - if (ioctl(fileno(stdout),TIOCGWINSZ,&screen_size) == -1 || - screen_size.ws_col == 0 || - screen_size.ws_row == 0) { + if (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) == -1 || + screen_size.ws_col == 0 || + screen_size.ws_row == 0) + { #endif - screen_size.ws_row = 24; - screen_size.ws_col = 80; + screen_size.ws_row = 24; + screen_size.ws_col = 80; #ifdef TIOCGWINSZ - } + } #endif - pagerenv=getenv("PAGER"); - if (pagerenv != NULL && - pagerenv[0] != '\0' && - !po->html3 && - ((po->expanded && - nTups * (nFields+1) >= screen_size.ws_row) || - (!po->expanded && - nTups * (total_line_length / screen_size.ws_col + 1) * - ( 1 + (po->standard != 0)) >= - screen_size.ws_row - - (po->header != 0) * - (total_line_length / screen_size.ws_col + 1) * 2 - - (po->header != 0) *2 /* row count and newline */ - ))) { - fout = popen(pagerenv, "w"); - if (fout) { - usePipe = 1; - pqsignal(SIGPIPE, SIG_IGN); - } else - fout = stdout; - } - } - - if (!po->expanded && (po->align || po->html3)) { - if (!(fields=(char **)calloc(nFields*(nTups+1), sizeof(char *)))) { - perror("calloc"); - exit(1); - } - } else - if (po->header && !po->html3) { - if (po->expanded) { - if (po->align) - fprintf(fout, "%-*s%s Value\n", - fieldMaxLen-fs_len, "Field", po->fieldSep); - else - fprintf(fout, "%s%sValue\n", "Field", po->fieldSep); - } else { - int len=0; - for (j=0; j < nFields; j++) { - char *s=fieldNames[j]; - fputs(s, fout); - len+=strlen(s)+fs_len; - if ((j+1)<nFields) - fputs(po->fieldSep, fout); - } - fputc('\n', fout); - for (len-=fs_len; len--; fputc('-', fout)); - fputc('\n', fout); - } - } - if (po->expanded && po->html3) { - if (po->caption) - fprintf(fout, "<centre><h2>%s</h2></centre>\n", po->caption); - else - fprintf(fout, - "<centre><h2>" - "Query retrieved %d rows * %d fields" - "</h2></centre>\n", - nTups, nFields); - } - for (i = 0; i < nTups; i++) { - if (po->expanded) { - if (po->html3) - fprintf(fout, - "<table %s><caption align=high>%d</caption>\n", - po->tableOpt? po->tableOpt: "", i); - else - fprintf(fout, "-- RECORD %d --\n", i); - } - for (j = 0; j < nFields; j++) - do_field(po, res, i, j, buf, fs_len, fields, nFields, - fieldNames, fieldNotNum, - fieldMax, fieldMaxLen, fout); - if (po->html3 && po->expanded) - fputs("</table>\n", fout); - } - if (!po->expanded && (po->align || po->html3)) { - if (po->html3) { - if (po->header) { - if (po->caption) - fprintf(fout, - "<table %s><caption align=high>%s</caption>\n", - po->tableOpt? po->tableOpt: "", - po->caption); - else - fprintf(fout, - "<table %s><caption align=high>" - "Retrieved %d rows * %d fields" - "</caption>\n", - po->tableOpt? po->tableOpt: "", nTups, nFields); - } else - fprintf(fout, "<table %s>", po->tableOpt? po->tableOpt: ""); - } - if (po->header) - border = do_header(fout, po, nFields, fieldMax, fieldNames, - fieldNotNum, fs_len, res); - for (i = 0; i < nTups; i++) - output_row(fout, po, nFields, fields, - fieldNotNum, fieldMax, border, i); - free(fields); - if (border) - free(border); - } - if (po->header && !po->html3) - fprintf (fout, "(%d row%s)\n\n",PQntuples(res), - (PQntuples(res) == 1) ? "" : "s"); - free(fieldMax); - free(fieldNotNum); - free(fieldNames); - if (usePipe) { - pclose(fout); - pqsignal(SIGPIPE, SIG_DFL); - } - if (po->html3 && !po->expanded) - fputs("</table>\n", fout); - } + pagerenv = getenv("PAGER"); + if (pagerenv != NULL && + pagerenv[0] != '\0' && + !po->html3 && + ((po->expanded && + nTups * (nFields + 1) >= screen_size.ws_row) || + (!po->expanded && + nTups * (total_line_length / screen_size.ws_col + 1) * + (1 + (po->standard != 0)) >= + screen_size.ws_row - + (po->header != 0) * + (total_line_length / screen_size.ws_col + 1) * 2 + - (po->header != 0) * 2 /* row count and newline */ + ))) + { + fout = popen(pagerenv, "w"); + if (fout) + { + usePipe = 1; + pqsignal(SIGPIPE, SIG_IGN); + } + else + fout = stdout; + } + } + + if (!po->expanded && (po->align || po->html3)) + { + if (!(fields = (char **) calloc(nFields * (nTups + 1), sizeof(char *)))) + { + perror("calloc"); + exit(1); + } + } + else if (po->header && !po->html3) + { + if (po->expanded) + { + if (po->align) + fprintf(fout, "%-*s%s Value\n", + fieldMaxLen - fs_len, "Field", po->fieldSep); + else + fprintf(fout, "%s%sValue\n", "Field", po->fieldSep); + } + else + { + int len = 0; + + for (j = 0; j < nFields; j++) + { + char *s = fieldNames[j]; + + fputs(s, fout); + len += strlen(s) + fs_len; + if ((j + 1) < nFields) + fputs(po->fieldSep, fout); + } + fputc('\n', fout); + for (len -= fs_len; len--; fputc('-', fout)); + fputc('\n', fout); + } + } + if (po->expanded && po->html3) + { + if (po->caption) + fprintf(fout, "<centre><h2>%s</h2></centre>\n", po->caption); + else + fprintf(fout, + "<centre><h2>" + "Query retrieved %d rows * %d fields" + "</h2></centre>\n", + nTups, nFields); + } + for (i = 0; i < nTups; i++) + { + if (po->expanded) + { + if (po->html3) + fprintf(fout, + "<table %s><caption align=high>%d</caption>\n", + po->tableOpt ? po->tableOpt : "", i); + else + fprintf(fout, "-- RECORD %d --\n", i); + } + for (j = 0; j < nFields; j++) + do_field(po, res, i, j, buf, fs_len, fields, nFields, + fieldNames, fieldNotNum, + fieldMax, fieldMaxLen, fout); + if (po->html3 && po->expanded) + fputs("</table>\n", fout); + } + if (!po->expanded && (po->align || po->html3)) + { + if (po->html3) + { + if (po->header) + { + if (po->caption) + fprintf(fout, + "<table %s><caption align=high>%s</caption>\n", + po->tableOpt ? po->tableOpt : "", + po->caption); + else + fprintf(fout, + "<table %s><caption align=high>" + "Retrieved %d rows * %d fields" + "</caption>\n", + po->tableOpt ? po->tableOpt : "", nTups, nFields); + } + else + fprintf(fout, "<table %s>", po->tableOpt ? po->tableOpt : ""); + } + if (po->header) + border = do_header(fout, po, nFields, fieldMax, fieldNames, + fieldNotNum, fs_len, res); + for (i = 0; i < nTups; i++) + output_row(fout, po, nFields, fields, + fieldNotNum, fieldMax, border, i); + free(fields); + if (border) + free(border); + } + if (po->header && !po->html3) + fprintf(fout, "(%d row%s)\n\n", PQntuples(res), + (PQntuples(res) == 1) ? "" : "s"); + free(fieldMax); + free(fieldNotNum); + free(fieldNames); + if (usePipe) + { + pclose(fout); + pqsignal(SIGPIPE, SIG_DFL); + } + if (po->html3 && !po->expanded) + fputs("</table>\n", fout); + } } /* ---------------- - * PQfn - Send a function call to the POSTGRES backend. + * PQfn - Send a function call to the POSTGRES backend. * - * conn : backend connection - * fnid : function id - * result_buf : pointer to result buffer (&int if integer) - * result_len : length of return value. - * actual_result_len: actual length returned. (differs from result_len - * for varlena structures.) - * result_type : If the result is an integer, this must be 1, - * otherwise this should be 0 - * args : pointer to a NULL terminated arg array. - * (length, if integer, and result-pointer) - * nargs : # of arguments in args array. + * conn : backend connection + * fnid : function id + * result_buf : pointer to result buffer (&int if integer) + * result_len : length of return value. + * actual_result_len: actual length returned. (differs from result_len + * for varlena structures.) + * result_type : If the result is an integer, this must be 1, + * otherwise this should be 0 + * args : pointer to a NULL terminated arg array. + * (length, if integer, and result-pointer) + * nargs : # of arguments in args array. * * RETURNS - * NULL on failure. PQerrormsg will be set. - * "G" if there is a return value. - * "V" if there is no return value. + * NULL on failure. PQerrormsg will be set. + * "G" if there is a return value. + * "V" if there is no return value. * ---------------- */ -PGresult* -PQfn(PGconn *conn, - int fnid, - int *result_buf, - int *actual_result_len, - int result_is_int, - PQArgBlock *args, - int nargs) +PGresult * +PQfn(PGconn * conn, + int fnid, + int *result_buf, + int *actual_result_len, + int result_is_int, + PQArgBlock * args, + int nargs) { - FILE *pfin, *pfout, *pfdebug; - int id; - int i; - - if (!conn) return NULL; - - pfin = conn->Pfin; - pfout = conn->Pfout; - pfdebug = conn->Pfdebug; - - /* clear the error string */ - conn->errorMessage[0] = '\0'; - - pqPuts("F ",pfout,pfdebug); /* function */ - pqPutInt(fnid, 4, pfout, pfdebug); /* function id */ - pqPutInt(nargs, 4, pfout, pfdebug); /* # of args */ - - for (i = 0; i < nargs; ++i) { /* len.int4 + contents */ - pqPutInt(args[i].len, 4, pfout, pfdebug); - if (args[i].isint) { - pqPutInt(args[i].u.integer, 4, pfout, pfdebug); - } else { - pqPutnchar((char *)args[i].u.ptr, args[i].len, pfout, pfdebug); - } - } - pqFlush(pfout, pfdebug); - - id = pqGetc(pfin, pfdebug); - if (id != 'V') { - if (id == 'E') { - pqGets(conn->errorMessage,ERROR_MSG_LENGTH,pfin,pfdebug); - } else - sprintf(conn->errorMessage, - "PQfn: expected a 'V' from the backend. Got '%c' instead", - id); - return makeEmptyPGresult(conn,PGRES_FATAL_ERROR); - } - - id = pqGetc(pfin, pfdebug); - for (;;) { - int c; - switch (id) { - case 'G': /* function returned properly */ - pqGetInt(actual_result_len,4,pfin,pfdebug); - if (result_is_int) { - pqGetInt(result_buf,4,pfin,pfdebug); - } else { - pqGetnchar((char *) result_buf, *actual_result_len, - pfin, pfdebug); - } - c = pqGetc(pfin, pfdebug); /* get the last '0'*/ - return makeEmptyPGresult(conn,PGRES_COMMAND_OK); - case 'E': - sprintf(conn->errorMessage, - "PQfn: returned an error"); - return makeEmptyPGresult(conn,PGRES_FATAL_ERROR); - case 'N': - /* print notice and go back to processing return values */ - if (pqGets(conn->errorMessage, ERROR_MSG_LENGTH, pfin, pfdebug) - == 1) { - sprintf(conn->errorMessage, - "Notice return detected from backend, but message " - "cannot be read"); - } else - fprintf(stderr, "%s\n", conn->errorMessage); - /* keep iterating */ - break; - case '0': /* no return value */ - return makeEmptyPGresult(conn,PGRES_COMMAND_OK); - default: - /* The backend violates the protocol. */ - sprintf(conn->errorMessage, - "FATAL: PQfn: protocol error: id=%x\n", id); - return makeEmptyPGresult(conn,PGRES_FATAL_ERROR); - } - } + FILE *pfin, + *pfout, + *pfdebug; + int id; + int i; + + if (!conn) + return NULL; + + pfin = conn->Pfin; + pfout = conn->Pfout; + pfdebug = conn->Pfdebug; + + /* clear the error string */ + conn->errorMessage[0] = '\0'; + + pqPuts("F ", pfout, pfdebug); /* function */ + pqPutInt(fnid, 4, pfout, pfdebug); /* function id */ + pqPutInt(nargs, 4, pfout, pfdebug); /* # of args */ + + for (i = 0; i < nargs; ++i) + { /* len.int4 + contents */ + pqPutInt(args[i].len, 4, pfout, pfdebug); + if (args[i].isint) + { + pqPutInt(args[i].u.integer, 4, pfout, pfdebug); + } + else + { + pqPutnchar((char *) args[i].u.ptr, args[i].len, pfout, pfdebug); + } + } + pqFlush(pfout, pfdebug); + + id = pqGetc(pfin, pfdebug); + if (id != 'V') + { + if (id == 'E') + { + pqGets(conn->errorMessage, ERROR_MSG_LENGTH, pfin, pfdebug); + } + else + sprintf(conn->errorMessage, + "PQfn: expected a 'V' from the backend. Got '%c' instead", + id); + return makeEmptyPGresult(conn, PGRES_FATAL_ERROR); + } + + id = pqGetc(pfin, pfdebug); + for (;;) + { + int c; + + switch (id) + { + case 'G': /* function returned properly */ + pqGetInt(actual_result_len, 4, pfin, pfdebug); + if (result_is_int) + { + pqGetInt(result_buf, 4, pfin, pfdebug); + } + else + { + pqGetnchar((char *) result_buf, *actual_result_len, + pfin, pfdebug); + } + c = pqGetc(pfin, pfdebug); /* get the last '0' */ + return makeEmptyPGresult(conn, PGRES_COMMAND_OK); + case 'E': + sprintf(conn->errorMessage, + "PQfn: returned an error"); + return makeEmptyPGresult(conn, PGRES_FATAL_ERROR); + case 'N': + /* print notice and go back to processing return values */ + if (pqGets(conn->errorMessage, ERROR_MSG_LENGTH, pfin, pfdebug) + == 1) + { + sprintf(conn->errorMessage, + "Notice return detected from backend, but message " + "cannot be read"); + } + else + fprintf(stderr, "%s\n", conn->errorMessage); + /* keep iterating */ + break; + case '0': /* no return value */ + return makeEmptyPGresult(conn, PGRES_COMMAND_OK); + default: + /* The backend violates the protocol. */ + sprintf(conn->errorMessage, + "FATAL: PQfn: protocol error: id=%x\n", id); + return makeEmptyPGresult(conn, PGRES_FATAL_ERROR); + } + } } /* ====== accessor funcs for PGresult ======== */ -ExecStatusType -PQresultStatus(PGresult* res) -{ - if (!res) { - fprintf(stderr, "PQresultStatus() -- pointer to PQresult is null"); - return PGRES_NONFATAL_ERROR; - } +ExecStatusType +PQresultStatus(PGresult * res) +{ + if (!res) + { + fprintf(stderr, "PQresultStatus() -- pointer to PQresult is null"); + return PGRES_NONFATAL_ERROR; + } - return res->resultStatus; + return res->resultStatus; } -int -PQntuples(PGresult *res) +int +PQntuples(PGresult * res) { - if (!res) { - fprintf(stderr, "PQntuples() -- pointer to PQresult is null"); - return (int)NULL; - } - return res->ntups; + if (!res) + { + fprintf(stderr, "PQntuples() -- pointer to PQresult is null"); + return (int) NULL; + } + return res->ntups; } int -PQnfields(PGresult *res) +PQnfields(PGresult * res) { - if (!res) { - fprintf(stderr, "PQnfields() -- pointer to PQresult is null"); - return (int)NULL; - } - return res->numAttributes; + if (!res) + { + fprintf(stderr, "PQnfields() -- pointer to PQresult is null"); + return (int) NULL; + } + return res->numAttributes; } /* returns NULL if the field_num is invalid */ -char* -PQfname(PGresult *res, int field_num) +char * +PQfname(PGresult * res, int field_num) { - if (!res) { - fprintf(stderr, "PQfname() -- pointer to PQresult is null"); - return NULL; - } - - if (field_num > (res->numAttributes - 1)) { - fprintf(stderr, - "PQfname: ERROR! name of field %d(of %d) is not available", - field_num, res->numAttributes -1); - return NULL; - } - if (res->attDescs) { - return res->attDescs[field_num].name; - } else - return NULL; + if (!res) + { + fprintf(stderr, "PQfname() -- pointer to PQresult is null"); + return NULL; + } + + if (field_num > (res->numAttributes - 1)) + { + fprintf(stderr, + "PQfname: ERROR! name of field %d(of %d) is not available", + field_num, res->numAttributes - 1); + return NULL; + } + if (res->attDescs) + { + return res->attDescs[field_num].name; + } + else + return NULL; } /* returns -1 on a bad field name */ int -PQfnumber(PGresult *res, const char* field_name) +PQfnumber(PGresult * res, const char *field_name) { - int i; + int i; - if (!res) { - fprintf(stderr, "PQfnumber() -- pointer to PQresult is null"); - return -1; - } + if (!res) + { + fprintf(stderr, "PQfnumber() -- pointer to PQresult is null"); + return -1; + } - if (field_name == NULL || - field_name[0] == '\0' || - res->attDescs == NULL) - return -1; + if (field_name == NULL || + field_name[0] == '\0' || + res->attDescs == NULL) + return -1; - for (i=0;i<res->numAttributes;i++) { - if ( strcasecmp(field_name, res->attDescs[i].name) == 0 ) - return i; - } - return -1; + for (i = 0; i < res->numAttributes; i++) + { + if (strcasecmp(field_name, res->attDescs[i].name) == 0) + return i; + } + return -1; } Oid -PQftype(PGresult *res, int field_num) +PQftype(PGresult * res, int field_num) { - if (!res) { - fprintf(stderr, "PQftype() -- pointer to PQresult is null"); - return InvalidOid; - } - - if (field_num > (res->numAttributes - 1)) { - fprintf(stderr, - "PQftype: ERROR! type of field %d(of %d) is not available", - field_num, res->numAttributes -1); - } - if (res->attDescs) { - return res->attDescs[field_num].adtid; - } else - return InvalidOid; + if (!res) + { + fprintf(stderr, "PQftype() -- pointer to PQresult is null"); + return InvalidOid; + } + + if (field_num > (res->numAttributes - 1)) + { + fprintf(stderr, + "PQftype: ERROR! type of field %d(of %d) is not available", + field_num, res->numAttributes - 1); + } + if (res->attDescs) + { + return res->attDescs[field_num].adtid; + } + else + return InvalidOid; } int2 -PQfsize(PGresult *res, int field_num) +PQfsize(PGresult * res, int field_num) { - if (!res) { - fprintf(stderr, "PQfsize() -- pointer to PQresult is null"); - return (int2)NULL; - } - - if (field_num > (res->numAttributes - 1)) { - fprintf(stderr, - "PQfsize: ERROR! size of field %d(of %d) is not available", - field_num, res->numAttributes -1); - } - if (res->attDescs) { - return res->attDescs[field_num].adtsize; - } else - return 0; + if (!res) + { + fprintf(stderr, "PQfsize() -- pointer to PQresult is null"); + return (int2) NULL; + } + + if (field_num > (res->numAttributes - 1)) + { + fprintf(stderr, + "PQfsize: ERROR! size of field %d(of %d) is not available", + field_num, res->numAttributes - 1); + } + if (res->attDescs) + { + return res->attDescs[field_num].adtsize; + } + else + return 0; } -char* PQcmdStatus(PGresult *res) { - if (!res) { - fprintf(stderr, "PQcmdStatus() -- pointer to PQresult is null"); - return NULL; - } - return res->cmdStatus; +char * +PQcmdStatus(PGresult * res) +{ + if (!res) + { + fprintf(stderr, "PQcmdStatus() -- pointer to PQresult is null"); + return NULL; + } + return res->cmdStatus; } /* PQoidStatus - - if the last command was an INSERT, return the oid string - if not, return "" + if the last command was an INSERT, return the oid string + if not, return "" */ -static char oidStatus[32] = {0}; -const char* PQoidStatus (PGresult *res) +static char oidStatus[32] = {0}; +const char * +PQoidStatus(PGresult * res) { - if (!res) - { - fprintf (stderr, "PQoidStatus () -- pointer to PQresult is null"); - return NULL; - } - - oidStatus[0] = 0; - if ( !res->cmdStatus ) - return oidStatus; - - if ( strncmp (res->cmdStatus, "INSERT", 6) == 0 ) - { - char *p = res->cmdStatus + 7; - char *e; - - for (e = p; *e != ' ' && *e; ) e++; - sprintf (oidStatus, "%.*s", e - p, p); - } - return oidStatus; + if (!res) + { + fprintf(stderr, "PQoidStatus () -- pointer to PQresult is null"); + return NULL; + } + + oidStatus[0] = 0; + if (!res->cmdStatus) + return oidStatus; + + if (strncmp(res->cmdStatus, "INSERT", 6) == 0) + { + char *p = res->cmdStatus + 7; + char *e; + + for (e = p; *e != ' ' && *e;) + e++; + sprintf(oidStatus, "%.*s", e - p, p); + } + return oidStatus; } /* PQcmdTuples - - if the last command was an INSERT/UPDATE/DELETE, return number - of inserted/affected tuples, if not, return "" + if the last command was an INSERT/UPDATE/DELETE, return number + of inserted/affected tuples, if not, return "" */ -const char* PQcmdTuples (PGresult *res) +const char * +PQcmdTuples(PGresult * res) { - if (!res) - { - fprintf (stderr, "PQcmdTuples () -- pointer to PQresult is null"); - return NULL; - } - - if ( !res->cmdStatus ) - return ""; - - if ( strncmp (res->cmdStatus, "INSERT", 6) == 0 || - strncmp (res->cmdStatus, "DELETE", 6) == 0 || - strncmp (res->cmdStatus, "UPDATE", 6) == 0 ) - { - char *p = res->cmdStatus + 6; - - if ( *p == 0 ) - { - fprintf (stderr, "PQcmdTuples (%s) -- short input from server", - res->cmdStatus); - return NULL; - } - p++; - if ( *(res->cmdStatus) != 'I' ) /* UPDATE/DELETE */ - return (p); - while ( *p != ' ' && *p ) p++; /* INSERT: skip oid */ - if ( *p == 0 ) - { - fprintf (stderr, "PQcmdTuples (INSERT) -- there's no # of tuples"); - return NULL; - } - p++; - return (p); - } - return ""; + if (!res) + { + fprintf(stderr, "PQcmdTuples () -- pointer to PQresult is null"); + return NULL; + } + + if (!res->cmdStatus) + return ""; + + if (strncmp(res->cmdStatus, "INSERT", 6) == 0 || + strncmp(res->cmdStatus, "DELETE", 6) == 0 || + strncmp(res->cmdStatus, "UPDATE", 6) == 0) + { + char *p = res->cmdStatus + 6; + + if (*p == 0) + { + fprintf(stderr, "PQcmdTuples (%s) -- short input from server", + res->cmdStatus); + return NULL; + } + p++; + if (*(res->cmdStatus) != 'I') /* UPDATE/DELETE */ + return (p); + while (*p != ' ' && *p) + p++; /* INSERT: skip oid */ + if (*p == 0) + { + fprintf(stderr, "PQcmdTuples (INSERT) -- there's no # of tuples"); + return NULL; + } + p++; + return (p); + } + return ""; } /* PQgetvalue: - return the value of field 'field_num' of row 'tup_num' + return the value of field 'field_num' of row 'tup_num' - If res is binary, then the value returned is NOT a null-terminated - ASCII string, but the binary representation in the server's native - format. + If res is binary, then the value returned is NOT a null-terminated + ASCII string, but the binary representation in the server's native + format. - if res is not binary, a null-terminated ASCII string is returned. + if res is not binary, a null-terminated ASCII string is returned. */ -char* -PQgetvalue(PGresult *res, int tup_num, int field_num) +char * +PQgetvalue(PGresult * res, int tup_num, int field_num) { - if (!res) { - fprintf(stderr, "PQgetvalue: pointer to PQresult is null\n"); - return NULL; - } else if (tup_num > (res->ntups - 1)) { - fprintf(stderr, - "PQgetvalue: There is no row %d in the query results. " - "The highest numbered row is %d.\n", - tup_num, res->ntups - 1); - return NULL; - } else if (field_num > (res->numAttributes - 1)) { - fprintf(stderr, - "PQgetvalue: There is no field %d in the query results. " - "The highest numbered field is %d.\n", - field_num, res->numAttributes - 1); - return NULL; - } - - return res->tuples[tup_num][field_num].value; + if (!res) + { + fprintf(stderr, "PQgetvalue: pointer to PQresult is null\n"); + return NULL; + } + else if (tup_num > (res->ntups - 1)) + { + fprintf(stderr, + "PQgetvalue: There is no row %d in the query results. " + "The highest numbered row is %d.\n", + tup_num, res->ntups - 1); + return NULL; + } + else if (field_num > (res->numAttributes - 1)) + { + fprintf(stderr, + "PQgetvalue: There is no field %d in the query results. " + "The highest numbered field is %d.\n", + field_num, res->numAttributes - 1); + return NULL; + } + + return res->tuples[tup_num][field_num].value; } /* PQgetlength: - returns the length of a field value in bytes. If res is binary, - i.e. a result of a binary portal, then the length returned does - NOT include the size field of the varlena. + returns the length of a field value in bytes. If res is binary, + i.e. a result of a binary portal, then the length returned does + NOT include the size field of the varlena. */ int -PQgetlength(PGresult *res, int tup_num, int field_num) +PQgetlength(PGresult * res, int tup_num, int field_num) { - if (!res) { - fprintf(stderr, "PQgetlength() -- pointer to PQresult is null"); - return (int)NULL; - } - - if (tup_num > (res->ntups - 1 )|| - field_num > (res->numAttributes - 1)) { - fprintf(stderr, - "PQgetlength: ERROR! field %d(of %d) of row %d(of %d) " - "is not available", - field_num, res->numAttributes - 1, tup_num, res->ntups); - } - - if (res->tuples[tup_num][field_num].len != NULL_LEN) - return res->tuples[tup_num][field_num].len; - else - return 0; - } + if (!res) + { + fprintf(stderr, "PQgetlength() -- pointer to PQresult is null"); + return (int) NULL; + } + + if (tup_num > (res->ntups - 1) || + field_num > (res->numAttributes - 1)) + { + fprintf(stderr, + "PQgetlength: ERROR! field %d(of %d) of row %d(of %d) " + "is not available", + field_num, res->numAttributes - 1, tup_num, res->ntups); + } + + if (res->tuples[tup_num][field_num].len != NULL_LEN) + return res->tuples[tup_num][field_num].len; + else + return 0; +} /* PQgetisnull: - returns the null status of a field value. + returns the null status of a field value. */ int -PQgetisnull(PGresult *res, int tup_num, int field_num) +PQgetisnull(PGresult * res, int tup_num, int field_num) { - if (!res) { - fprintf(stderr, "PQgetisnull() -- pointer to PQresult is null"); - return (int)NULL; - } - - if (tup_num > (res->ntups - 1 )|| - field_num > (res->numAttributes - 1)) { - fprintf(stderr, - "PQgetisnull: ERROR! field %d(of %d) of row %d(of %d) " - "is not available", - field_num, res->numAttributes - 1, tup_num, res->ntups); - } - - if (res->tuples[tup_num][field_num].len == NULL_LEN) - return 1; - else - return 0; + if (!res) + { + fprintf(stderr, "PQgetisnull() -- pointer to PQresult is null"); + return (int) NULL; + } + + if (tup_num > (res->ntups - 1) || + field_num > (res->numAttributes - 1)) + { + fprintf(stderr, + "PQgetisnull: ERROR! field %d(of %d) of row %d(of %d) " + "is not available", + field_num, res->numAttributes - 1, tup_num, res->ntups); + } + + if (res->tuples[tup_num][field_num].len == NULL_LEN) + return 1; + else + return 0; } |