diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c index 430a8c3789..8d96a1af8c 100644 --- a/src/interfaces/libpq/fe-auth.c +++ b/src/interfaces/libpq/fe-auth.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.20 1998/07/20 16:57:13 momjian Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.21 1998/08/09 02:59:25 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -445,8 +445,6 @@ pg_krb5_sendauth(const char *PQerrormsg, int sock, (void) sprintf(PQerrormsg, "pg_krb5_sendauth: authentication rejected: \"%*s\"\n", error->text.length, error->text.data); - fputs(PQerrormsg, stderr); - pqdebug("%s", PQerrormsg); } else { diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 1e306ee7dd..cc8af6d6ac 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.77 1998/07/26 04:31:36 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.78 1998/08/09 02:59:26 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -29,7 +29,6 @@ #include #include #include -#include #include /* for isspace() */ #include "postgres.h" @@ -55,6 +54,7 @@ static void closePGconn(PGconn *conn); static int conninfo_parse(const char *conninfo, char *errorMessage); static char *conninfo_getval(char *keyword); static void conninfo_free(void); +static void defaultNoticeProcessor(void * arg, const char * message); /* XXX Why is this not static? */ void PQsetenv(PGconn *conn); @@ -181,11 +181,7 @@ PQconnectdb(const char *conninfo) */ conn = makeEmptyPGconn(); if (conn == NULL) - { - fprintf(stderr, - "FATAL: PQconnectdb() -- unable to allocate memory for a PGconn"); return (PGconn *) NULL; - } /* ---------- * Parse the conninfo string and save settings in conn structure @@ -297,11 +293,7 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, cons conn = makeEmptyPGconn(); if (conn == NULL) - { - fprintf(stderr, - "FATAL: PQsetdbLogin() -- unable to allocate memory for a PGconn"); return (PGconn *) NULL; - } if ((pghost == NULL) || pghost[0] == '\0') { @@ -856,6 +848,7 @@ makeEmptyPGconn(void) /* Zero all pointers */ MemSet((char *) conn, 0, sizeof(PGconn)); + conn->noticeHook = defaultNoticeProcessor; conn->status = CONNECTION_BAD; conn->asyncStatus = PGASYNC_IDLE; conn->notifyList = DLNewList(); @@ -925,35 +918,20 @@ closePGconn(PGconn *conn) if (conn->sock >= 0) { /* - * Try to send close message. - * If connection is already gone, that's cool. No reason for kernel - * to kill us when we try to write to it. So ignore SIGPIPE signals. + * Try to send "close connection" message to backend. + * BUT: backend might have already closed connection. + * To avoid being killed by SIGPIPE, we need to detect this before + * writing. Check for "read ready" condition which indicates EOF. */ -#ifndef WIN32 -#if defined(USE_POSIX_SIGNALS) - struct sigaction ignore_action; - struct sigaction oldaction; - - ignore_action.sa_handler = SIG_IGN; - sigemptyset(&ignore_action.sa_mask); - ignore_action.sa_flags = 0; - sigaction(SIGPIPE, (struct sigaction *) & ignore_action, &oldaction); - - (void) pqPuts("X", conn); - (void) pqFlush(conn); - - sigaction(SIGPIPE, &oldaction, NULL); -#else - void (*oldsignal)(int); - - oldsignal = signal(SIGPIPE, SIG_IGN); - - (void) pqPuts("X", conn); - (void) pqFlush(conn); - - signal(SIGPIPE, oldsignal); -#endif -#endif /* Win32 uses no signals at all */ + while (pqReadReady(conn)) { + if (pqReadData(conn) < 0) + break; + } + if (conn->sock >= 0) { + /* Should be safe now... */ + (void) pqPuts("X", conn); + (void) pqFlush(conn); + } } /* @@ -987,9 +965,7 @@ closePGconn(PGconn *conn) void PQfinish(PGconn *conn) { - if (!conn) - fprintf(stderr, "PQfinish() -- pointer to PGconn is null\n"); - else + if (conn) { closePGconn(conn); freePGconn(conn); @@ -1003,9 +979,7 @@ PQfinish(PGconn *conn) void PQreset(PGconn *conn) { - if (!conn) - fprintf(stderr, "PQreset() -- pointer to PGconn is null\n"); - else + if (conn) { closePGconn(conn); conn->status = connectDB(conn); @@ -1383,10 +1357,7 @@ char * PQdb(PGconn *conn) { if (!conn) - { - fprintf(stderr, "PQdb() -- pointer to PGconn is null\n"); return (char *) NULL; - } return conn->dbName; } @@ -1394,10 +1365,7 @@ char * PQuser(PGconn *conn) { if (!conn) - { - fprintf(stderr, "PQuser() -- pointer to PGconn is null\n"); return (char *) NULL; - } return conn->pguser; } @@ -1405,11 +1373,7 @@ char * PQhost(PGconn *conn) { if (!conn) - { - fprintf(stderr, "PQhost() -- pointer to PGconn is null\n"); return (char *) NULL; - } - return conn->pghost; } @@ -1417,10 +1381,7 @@ char * PQoptions(PGconn *conn) { if (!conn) - { - fprintf(stderr, "PQoptions() -- pointer to PGconn is null\n"); return (char *) NULL; - } return conn->pgoptions; } @@ -1428,10 +1389,7 @@ char * PQtty(PGconn *conn) { if (!conn) - { - fprintf(stderr, "PQtty() -- pointer to PGconn is null\n"); return (char *) NULL; - } return conn->pgtty; } @@ -1439,10 +1397,7 @@ char * PQport(PGconn *conn) { if (!conn) - { - fprintf(stderr, "PQport() -- pointer to PGconn is null\n"); return (char *) NULL; - } return conn->pgport; } @@ -1450,21 +1405,16 @@ ConnStatusType PQstatus(PGconn *conn) { if (!conn) - { - fprintf(stderr, "PQstatus() -- pointer to PGconn is null\n"); return CONNECTION_BAD; - } return conn->status; } char * PQerrorMessage(PGconn *conn) { + static char noConn[] = "PQerrorMessage: conn pointer is NULL\n"; if (!conn) - { - fprintf(stderr, "PQerrorMessage() -- pointer to PGconn is null\n"); - return (char *) NULL; - } + return noConn; return conn->errorMessage; } @@ -1472,10 +1422,7 @@ int PQsocket(PGconn *conn) { if (!conn) - { - fprintf(stderr, "PQsocket() -- pointer to PGconn is null\n"); return -1; - } return conn->sock; } @@ -1501,3 +1448,26 @@ PQuntrace(PGconn *conn) conn->Pfdebug = NULL; } } + +void +PQsetNoticeProcessor (PGconn *conn, PQnoticeProcessor proc, void *arg) +{ + if (conn == NULL) + return; + conn->noticeHook = proc; + conn->noticeArg = arg; +} + +/* + * The default notice/error message processor just prints the + * message on stderr. Applications can override this if they + * want the messages to go elsewhere (a window, for example). + * Note that simply discarding notices is probably a bad idea. + */ + +static void +defaultNoticeProcessor(void * arg, const char * message) +{ + /* Note: we expect the supplied string to end with a newline already. */ + fprintf(stderr, "%s", message); +} diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c index 63bc1a078b..8979018314 100644 --- a/src/interfaces/libpq/fe-exec.c +++ b/src/interfaces/libpq/fe-exec.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.60 1998/07/14 02:41:25 momjian Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.61 1998/08/09 02:59:27 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -44,6 +44,10 @@ const char *pgresStatus[] = { }; +#define DONOTICE(conn,message) \ + ((*(conn)->noticeHook) ((conn)->noticeArg, (message))) + + static PGresult *makeEmptyPGresult(PGconn *conn, ExecStatusType status); static void freeTuple(PGresAttValue *tuple, int numAttributes); static void addTuple(PGresult *res, PGresAttValue *tup); @@ -198,6 +202,14 @@ PQsendQuery(PGconn *conn, const char *query) sprintf(conn->errorMessage, "PQsendQuery() -- query pointer is null."); return 0; } + /* check to see if the query string is too long */ + if (strlen(query) > MAX_MESSAGE_LEN-2) + { + sprintf(conn->errorMessage, "PQsendQuery() -- query is too long. " + "Maximum length is %d\n", MAX_MESSAGE_LEN - 2); + return 0; + } + if (conn->asyncStatus != PGASYNC_IDLE) { sprintf(conn->errorMessage, @@ -205,6 +217,26 @@ PQsendQuery(PGconn *conn, const char *query) return 0; } + /* Check for pending input (asynchronous Notice or Notify messages); + * also detect the case that the backend just closed the connection. + * Note: we have to loop if the first call to pqReadData successfully + * reads some data, since in that case pqReadData won't notice whether + * the connection is now closed. + */ + while (pqReadReady(conn)) { + if (pqReadData(conn) < 0) + return 0; /* errorMessage already set */ + parseInput(conn); /* deal with Notice or Notify, if any */ + } + + /* Don't try to send if we know there's no live connection. */ + if (conn->status != CONNECTION_OK) + { + sprintf(conn->errorMessage, "PQsendQuery() -- There is no connection " + "to the backend.\n"); + return 0; + } + /* clear the error string */ conn->errorMessage[0] = '\0'; @@ -213,22 +245,6 @@ PQsendQuery(PGconn *conn, const char *query) conn->curTuple = NULL; conn->asyncErrorMessage[0] = '\0'; - /* check to see if the query string is too long */ - if (strlen(query) > MAX_MESSAGE_LEN-2) - { - sprintf(conn->errorMessage, "PQsendQuery() -- query is too long. " - "Maximum length is %d\n", MAX_MESSAGE_LEN - 2); - return 0; - } - - /* Don't try to send if we know there's no live connection. */ - if (conn->status != CONNECTION_OK) - { - sprintf(conn->errorMessage, "PQsendQuery() -- There is no connection " - "to the backend.\n"); - return 0; - } - /* send the query to the backend; */ /* the frontend-backend protocol uses 'Q' to designate queries */ if (pqPutnchar("Q", 1, conn)) @@ -297,15 +313,19 @@ parseInput(PGconn *conn) if (pqGetc(&id, conn)) return; /* - * NOTIFY messages can happen in any state besides COPY OUT; + * NOTIFY and NOTICE messages can happen in any state besides COPY OUT; * always process them right away. */ if (id == 'A') { - /* Notify responses can happen at any time */ if (getNotify(conn)) return; } + else if (id == 'N') + { + if (getNotice(conn)) + return; + } else { /* @@ -318,9 +338,10 @@ parseInput(PGconn *conn) { if (conn->asyncStatus == PGASYNC_IDLE) { - fprintf(stderr, + sprintf(conn->errorMessage, "Backend message type 0x%02x arrived while idle\n", id); + DONOTICE(conn, conn->errorMessage); /* Discard the unexpected message; good idea?? */ conn->inStart = conn->inEnd; } @@ -354,8 +375,11 @@ parseInput(PGconn *conn) if (pqGetc(&id, conn)) return; if (id != '\0') - fprintf(stderr, + { + sprintf(conn->errorMessage, "unexpected character %c following 'I'\n", id); + DONOTICE(conn, conn->errorMessage); + } if (conn->result == NULL) conn->result = makeEmptyPGresult(conn, PGRES_EMPTY_QUERY); @@ -371,10 +395,6 @@ parseInput(PGconn *conn) if (pqGetInt(&(conn->be_key), 4, conn)) return; break; - case 'N': /* notices from the backend */ - if (getNotice(conn)) - return; - break; case 'P': /* synchronous (normal) portal */ if (pqGets(conn->errorMessage, ERROR_MSG_LENGTH, conn)) return; @@ -408,8 +428,9 @@ parseInput(PGconn *conn) } else { - fprintf(stderr, + sprintf(conn->errorMessage, "Backend sent D message without prior T\n"); + DONOTICE(conn, conn->errorMessage); /* Discard the unexpected message; good idea?? */ conn->inStart = conn->inEnd; return; @@ -424,8 +445,9 @@ parseInput(PGconn *conn) } else { - fprintf(stderr, + sprintf(conn->errorMessage, "Backend sent B message without prior T\n"); + DONOTICE(conn, conn->errorMessage); /* Discard the unexpected message; good idea?? */ conn->inStart = conn->inEnd; return; @@ -783,14 +805,7 @@ getNotice(PGconn *conn) { if (pqGets(conn->errorMessage, ERROR_MSG_LENGTH, conn)) return EOF; - /* - * 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", conn->errorMessage); + DONOTICE(conn, conn->errorMessage); return 0; } @@ -970,7 +985,10 @@ PQendcopy(PGconn *conn) * To recover, reset the connection (talk about using a sledgehammer...) */ PQclear(result); - fprintf(stderr, "PQendcopy: resetting connection\n"); + + sprintf(conn->errorMessage, "PQendcopy: resetting connection\n"); + DONOTICE(conn, conn->errorMessage); + PQreset(conn); return 1; @@ -1156,11 +1174,7 @@ ExecStatusType PQresultStatus(PGresult *res) { if (!res) - { - fprintf(stderr, "PQresultStatus() -- pointer to PQresult is null\n"); return PGRES_NONFATAL_ERROR; - } - return res->resultStatus; } @@ -1168,10 +1182,7 @@ int PQntuples(PGresult *res) { if (!res) - { - fprintf(stderr, "PQntuples() -- pointer to PQresult is null\n"); return 0; - } return res->ntups; } @@ -1179,32 +1190,64 @@ int PQnfields(PGresult *res) { if (!res) - { - fprintf(stderr, "PQnfields() -- pointer to PQresult is null\n"); return 0; - } return res->numAttributes; } +/* + * Helper routines to range-check field numbers and tuple numbers. + * Return TRUE if OK, FALSE if not + */ + +static int +check_field_number(const char *routineName, PGresult *res, int field_num) +{ + if (!res) + return FALSE; /* no way to display error message... */ + if (field_num < 0 || field_num >= res->numAttributes) + { + sprintf(res->conn->errorMessage, + "%s: ERROR! field number %d is out of range 0..%d\n", + routineName, field_num, res->numAttributes - 1); + DONOTICE(res->conn, res->conn->errorMessage); + return FALSE; + } + return TRUE; +} + +static int +check_tuple_field_number(const char *routineName, PGresult *res, + int tup_num, int field_num) +{ + if (!res) + return FALSE; /* no way to display error message... */ + if (tup_num < 0 || tup_num >= res->ntups) + { + sprintf(res->conn->errorMessage, + "%s: ERROR! tuple number %d is out of range 0..%d\n", + routineName, tup_num, res->ntups - 1); + DONOTICE(res->conn, res->conn->errorMessage); + return FALSE; + } + if (field_num < 0 || field_num >= res->numAttributes) + { + sprintf(res->conn->errorMessage, + "%s: ERROR! field number %d is out of range 0..%d\n", + routineName, field_num, res->numAttributes - 1); + DONOTICE(res->conn, res->conn->errorMessage); + return FALSE; + } + return TRUE; +} + /* returns NULL if the field_num is invalid */ char * PQfname(PGresult *res, int field_num) { - if (!res) - { - fprintf(stderr, "PQfname() -- pointer to PQresult is null\n"); + if (! check_field_number("PQfname", res, field_num)) return NULL; - } - - if (field_num < 0 || field_num >= res->numAttributes) - { - fprintf(stderr, - "PQfname: ERROR! field number %d is out of range 0..%d\n", - field_num, res->numAttributes - 1); - return NULL; - } if (res->attDescs) return res->attDescs[field_num].name; else @@ -1221,10 +1264,7 @@ PQfnumber(PGresult *res, const char *field_name) char *field_case; if (!res) - { - fprintf(stderr, "PQfnumber() -- pointer to PQresult is null\n"); return -1; - } if (field_name == NULL || field_name[0] == '\0' || @@ -1258,19 +1298,8 @@ PQfnumber(PGresult *res, const char *field_name) Oid PQftype(PGresult *res, int field_num) { - if (!res) - { - fprintf(stderr, "PQftype() -- pointer to PQresult is null\n"); + if (! check_field_number("PQftype", res, field_num)) return InvalidOid; - } - - if (field_num < 0 || field_num >= res->numAttributes) - { - fprintf(stderr, - "PQftype: ERROR! field number %d is out of range 0..%d\n", - field_num, res->numAttributes - 1); - return InvalidOid; - } if (res->attDescs) return res->attDescs[field_num].typid; else @@ -1280,19 +1309,8 @@ PQftype(PGresult *res, int field_num) short PQfsize(PGresult *res, int field_num) { - if (!res) - { - fprintf(stderr, "PQfsize() -- pointer to PQresult is null\n"); + if (! check_field_number("PQfsize", res, field_num)) return 0; - } - - if (field_num < 0 || field_num >= res->numAttributes) - { - fprintf(stderr, - "PQfsize: ERROR! field number %d is out of range 0..%d\n", - field_num, res->numAttributes - 1); - return 0; - } if (res->attDescs) return res->attDescs[field_num].typlen; else @@ -1302,19 +1320,8 @@ PQfsize(PGresult *res, int field_num) int PQfmod(PGresult *res, int field_num) { - if (!res) - { - fprintf(stderr, "PQfmod() -- pointer to PQresult is null\n"); + if (! check_field_number("PQfmod", res, field_num)) return 0; - } - - if (field_num < 0 || field_num >= res->numAttributes) - { - fprintf(stderr, - "PQfmod: ERROR! field number %d is out of range 0..%d\n", - field_num, res->numAttributes - 1); - return 0; - } if (res->attDescs) return res->attDescs[field_num].atttypmod; else @@ -1325,10 +1332,7 @@ char * PQcmdStatus(PGresult *res) { if (!res) - { - fprintf(stderr, "PQcmdStatus() -- pointer to PQresult is null\n"); return NULL; - } return res->cmdStatus; } @@ -1343,10 +1347,7 @@ PQoidStatus(PGresult *res) static char oidStatus[32] = {0}; if (!res) - { - fprintf(stderr, "PQoidStatus () -- pointer to PQresult is null\n"); - return NULL; - } + return ""; oidStatus[0] = 0; @@ -1371,10 +1372,7 @@ const char * PQcmdTuples(PGresult *res) { if (!res) - { - fprintf(stderr, "PQcmdTuples () -- pointer to PQresult is null\n"); - return NULL; - } + return ""; if (strncmp(res->cmdStatus, "INSERT", 6) == 0 || strncmp(res->cmdStatus, "DELETE", 6) == 0 || @@ -1384,9 +1382,11 @@ PQcmdTuples(PGresult *res) if (*p == 0) { - fprintf(stderr, "PQcmdTuples (%s) -- bad input from server\n", + sprintf(res->conn->errorMessage, + "PQcmdTuples (%s) -- bad input from server\n", res->cmdStatus); - return NULL; + DONOTICE(res->conn, res->conn->errorMessage); + return ""; } p++; if (*(res->cmdStatus) != 'I') /* UPDATE/DELETE */ @@ -1395,8 +1395,10 @@ PQcmdTuples(PGresult *res) p++; /* INSERT: skip oid */ if (*p == 0) { - fprintf(stderr, "PQcmdTuples (INSERT) -- there's no # of tuples\n"); - return NULL; + sprintf(res->conn->errorMessage, + "PQcmdTuples (INSERT) -- there's no # of tuples\n"); + DONOTICE(res->conn, res->conn->errorMessage); + return ""; } p++; return (p); @@ -1417,28 +1419,8 @@ PQcmdTuples(PGresult *res) char * PQgetvalue(PGresult *res, int tup_num, int field_num) { - if (!res) - { - fprintf(stderr, "PQgetvalue: pointer to PQresult is null\n"); + if (! check_tuple_field_number("PQgetvalue", res, tup_num, field_num)) return NULL; - } - if (tup_num < 0 || tup_num >= res->ntups) - { - 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; - } - if (field_num < 0 || field_num >= res->numAttributes) - { - 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; } @@ -1450,29 +1432,8 @@ PQgetvalue(PGresult *res, int tup_num, int field_num) int PQgetlength(PGresult *res, int tup_num, int field_num) { - if (!res) - { - fprintf(stderr, "PQgetlength() -- pointer to PQresult is null\n"); + if (! check_tuple_field_number("PQgetlength", res, tup_num, field_num)) return 0; - } - - if (tup_num < 0 || tup_num >= res->ntups) - { - fprintf(stderr, - "PQgetlength: There is no row %d in the query results. " - "The highest numbered row is %d.\n", - tup_num, res->ntups - 1); - return 0; - } - if (field_num < 0 || field_num >= res->numAttributes) - { - fprintf(stderr, - "PQgetlength: There is no field %d in the query results. " - "The highest numbered field is %d.\n", - field_num, res->numAttributes - 1); - return 0; - } - if (res->tuples[tup_num][field_num].len != NULL_LEN) return res->tuples[tup_num][field_num].len; else @@ -1485,28 +1446,8 @@ PQgetlength(PGresult *res, int tup_num, int field_num) int PQgetisnull(PGresult *res, int tup_num, int field_num) { - if (!res) - { - fprintf(stderr, "PQgetisnull() -- pointer to PQresult is null\n"); + if (! check_tuple_field_number("PQgetisnull", res, tup_num, field_num)) return 1; /* pretend it is null */ - } - if (tup_num < 0 || tup_num >= res->ntups) - { - fprintf(stderr, - "PQgetisnull: There is no row %d in the query results. " - "The highest numbered row is %d.\n", - tup_num, res->ntups - 1); - return 1; /* pretend it is null */ - } - if (field_num < 0 || field_num >= res->numAttributes) - { - fprintf(stderr, - "PQgetisnull: There is no field %d in the query results. " - "The highest numbered field is %d.\n", - field_num, res->numAttributes - 1); - return 1; /* pretend it is null */ - } - if (res->tuples[tup_num][field_num].len == NULL_LEN) return 1; else diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c index 52bf28b612..512633ca0f 100644 --- a/src/interfaces/libpq/fe-misc.c +++ b/src/interfaces/libpq/fe-misc.c @@ -24,7 +24,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.16 1998/07/03 04:24:14 momjian Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.17 1998/08/09 02:59:29 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -50,6 +50,10 @@ #include "postgres.h" #include "libpq-fe.h" +#define DONOTICE(conn,message) \ + ((*(conn)->noticeHook) ((conn)->noticeArg, (message))) + + /* --------------------------------------------------------------------- */ /* pqGetc: get a character from the connection @@ -218,7 +222,9 @@ pqGetInt(int *result, int bytes, PGconn *conn) *result = (int) ntohl(tmp4); break; default: - fprintf(stderr, "** int size %d not supported\n", bytes); + sprintf(conn->errorMessage, + "pqGetInt: int size %d not supported\n", bytes); + DONOTICE(conn, conn->errorMessage); return EOF; } @@ -252,7 +258,9 @@ pqPutInt(int value, int bytes, PGconn *conn) return EOF; break; default: - fprintf(stderr, "** int size %d not supported\n", bytes); + sprintf(conn->errorMessage, + "pqPutInt: int size %d not supported\n", bytes); + DONOTICE(conn, conn->errorMessage); return EOF; } @@ -265,7 +273,7 @@ pqPutInt(int value, int bytes, PGconn *conn) /* --------------------------------------------------------------------- */ /* pqReadReady: is select() saying the file is ready to read? */ -static int +int pqReadReady(PGconn *conn) { fd_set input_mask; diff --git a/src/interfaces/libpq/fe-print.c b/src/interfaces/libpq/fe-print.c index 4d6688e63a..f60231be69 100644 --- a/src/interfaces/libpq/fe-print.c +++ b/src/interfaces/libpq/fe-print.c @@ -9,7 +9,7 @@ * didn't really belong there. * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-print.c,v 1.8 1998/07/26 04:31:36 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-print.c,v 1.9 1998/08/09 02:59:30 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -106,6 +106,7 @@ PQprint(FILE *fout, int fs_len = strlen(po->fieldSep); int total_line_length = 0; int usePipe = 0; + pqsigfunc oldsigpipehandler = NULL; char *pagerenv; char buf[8192 * 2 + 1]; @@ -193,7 +194,7 @@ PQprint(FILE *fout, { usePipe = 1; #ifndef WIN32 - pqsignal(SIGPIPE, SIG_IGN); + oldsigpipehandler = pqsignal(SIGPIPE, SIG_IGN); #endif } else @@ -309,7 +310,7 @@ PQprint(FILE *fout, _pclose(fout); #else pclose(fout); - pqsignal(SIGPIPE, SIG_DFL); + pqsignal(SIGPIPE, oldsigpipehandler); #endif } if (po->html3 && !po->expanded) diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h index d0265762e1..7e6660c83d 100644 --- a/src/interfaces/libpq/libpq-fe.h +++ b/src/interfaces/libpq/libpq-fe.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: libpq-fe.h,v 1.36 1998/07/18 18:34:34 momjian Exp $ + * $Id: libpq-fe.h,v 1.37 1998/08/09 02:59:31 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -121,6 +121,9 @@ extern "C" int be_pid; /* process id of backend */ } PGnotify; +/* PQnoticeProcessor is a typedef for a callback function type */ + typedef void (*PQnoticeProcessor) (void * arg, const char * message); + /* PGAsyncStatusType is private to libpq, really shouldn't be seen by users */ typedef enum { @@ -165,6 +168,10 @@ extern "C" /* Optional file to write trace info to */ FILE *Pfdebug; + /* Callback procedure for notice/error message processing */ + PQnoticeProcessor noticeHook; + void *noticeArg; + /* Status indicators */ ConnStatusType status; PGAsyncStatusType asyncStatus; @@ -300,6 +307,11 @@ extern "C" extern void PQtrace(PGconn *conn, FILE *debug_port); extern void PQuntrace(PGconn *conn); + /* Override default notice processor */ + extern void PQsetNoticeProcessor (PGconn *conn, + PQnoticeProcessor proc, + void *arg); + /* === in fe-exec.c === */ /* Simple synchronous query */ extern PGresult *PQexec(PGconn *conn, const char *query); @@ -390,6 +402,7 @@ extern "C" extern int pqGetInt(int *result, int bytes, PGconn *conn); extern int pqPutInt(int value, int bytes, PGconn *conn); extern int pqReadData(PGconn *conn); + extern int pqReadReady(PGconn *conn); extern int pqFlush(PGconn *conn); extern int pqWait(int forRead, int forWrite, PGconn *conn); diff --git a/src/man/libpq.3 b/src/man/libpq.3 index d26799e838..3b332075fc 100644 --- a/src/man/libpq.3 +++ b/src/man/libpq.3 @@ -1,7 +1,7 @@ .\" This is -*-nroff-*- .\" XXX standard disclaimer belongs here.... -.\" $Header: /cvsroot/pgsql/src/man/Attic/libpq.3,v 1.22 1998/07/15 17:34:06 momjian Exp $ -.TH LIBPQ INTRO 07/08/98 PostgreSQL PostgreSQL +.\" $Header: /cvsroot/pgsql/src/man/Attic/libpq.3,v 1.23 1998/08/09 02:59:33 momjian Exp $ +.TH LIBPQ INTRO 08/08/98 PostgreSQL PostgreSQL .SH DESCRIPTION Libpq is the programmer's interface to Postgres. Libpq is a set of library routines which allows @@ -823,6 +823,36 @@ Disable tracing started by .nf void PQuntrace(PGconn *conn) .fi + +.PP +.SH "LIBPQ Control Functions" +.PP +.B PQsetNoticeProcessor +.IP +Control reporting of notice and warning messages generated by libpq. +.nf +void PQsetNoticeProcessor (PGconn * conn, + void (*noticeProcessor) (void * arg, const char * message), + void * arg) +.fi +By default, libpq prints "notice" messages from the backend on stderr, +as well as a few error messages that it generates by itself. +This behavior can be overridden by supplying a callback function that +does something else with the messages. The callback function is passed +the text of the error message (which includes a trailing newline), plus +a void pointer that is the same one passed to PQsetNoticeProcessor. +(This pointer can be used to access application-specific state if needed.) +The default notice processor is simply +.nf +static void +defaultNoticeProcessor(void * arg, const char * message) +{ + fprintf(stderr, "%s", message); +} +.fi +To use a special notice processor, call PQsetNoticeProcessor just after +any creation of a new PGconn object. + .PP .SH "User Authentication Functions" .PP