diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c
index 430a8c37894cfe0b080f33bd17fe358ac239208a..8d96a1af8cce7053533be4e6bcf906051b16a212 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 1e306ee7dd2965287681fafde01367f80634d31e..cc8af6d6acfb824058884fd64cc21fd29ff32ded 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 <ctype.h>
 #include <string.h>
 #include <errno.h>
-#include <signal.h>
 #include <ctype.h>				/* 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 63bc1a078be276f5920536eec2beadfb7007fd36..8979018314407e71b37d625568a29ad95c036154 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,20 +217,16 @@ PQsendQuery(PGconn *conn, const char *query)
 		return 0;
 	}
 
-	/* clear the error string */
-	conn->errorMessage[0] = '\0';
-
-	/* initialize async result-accumulation state */
-	conn->result = NULL;
-	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;
+	/* 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. */
@@ -229,6 +237,14 @@ PQsendQuery(PGconn *conn, const char *query)
 		return 0;
 	}
 
+	/* clear the error string */
+	conn->errorMessage[0] = '\0';
+
+	/* initialize async result-accumulation state */
+	conn->result = NULL;
+	conn->curTuple = NULL;
+	conn->asyncErrorMessage[0] = '\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;
 }
 
 /*
-   returns NULL if the field_num is invalid
-*/
-char *
-PQfname(PGresult *res, int field_num)
+ * 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)
 	{
-		fprintf(stderr, "PQfname() -- pointer to PQresult is null\n");
-		return NULL;
+		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)
 	{
-		fprintf(stderr,
-				"PQfname: ERROR! field number %d is out of range 0..%d\n",
-				field_num, res->numAttributes - 1);
-		return NULL;
+		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 (! check_field_number("PQfname", res, field_num))
+		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");
-		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);
+	if (! check_field_number("PQfsize", res, field_num))
 		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");
-		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);
+	if (! check_field_number("PQfmod", res, field_num))
 		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");
-		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);
+	if (! check_tuple_field_number("PQgetvalue", res, tup_num, field_num))
 		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");
-		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);
+	if (! check_tuple_field_number("PQgetlength", res, tup_num, field_num))
 		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 52bf28b6123cedee49aa17ae35a4772489457022..512633ca0fc815d6e2298ef725e00b7891c508c5 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 4d6688e63a2aca17357459f98965599ec4299123..f60231be699f2caa3a7fd66f8696a56feed4f6b6 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 d0265762e13b4aa1b2f33a331229960301905089..7e6660c83dbd23ff6a64d7fc9cbc8c7208c6e3c4 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 d26799e83880d284cf50ab241af01afcefa644a6..3b332075fccc412b17ebded9a74b594133891ccc 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