*** src/interfaces/libpq/libpq-fe.h.orig	Sat Jul 18 14:34:34 1998
--- src/interfaces/libpq/libpq-fe.h	Sat Aug  8 19:17:03 1998
***************
*** 121,126 ****
--- 121,129 ----
  		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,170 ****
--- 168,177 ----
  		/* 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,305 ****
--- 307,317 ----
  	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,395 ****
--- 402,408 ----
  	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);
  
*** src/interfaces/libpq/fe-auth.c.orig	Sat Aug  1 15:56:30 1998
--- src/interfaces/libpq/fe-auth.c	Sat Aug  8 19:56:36 1998
***************
*** 445,452 ****
  			(void) sprintf(PQerrormsg,
  				  "pg_krb5_sendauth: authentication rejected: \"%*s\"\n",
  						   error->text.length, error->text.data);
- 			fputs(PQerrormsg, stderr);
- 			pqdebug("%s", PQerrormsg);
  		}
  		else
  		{
--- 445,450 ----
*** src/interfaces/libpq/fe-print.c.orig	Sat Aug  1 15:56:30 1998
--- src/interfaces/libpq/fe-print.c	Sat Aug  8 18:48:54 1998
***************
*** 106,111 ****
--- 106,112 ----
  		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,199 ****
  				{
  					usePipe = 1;
  #ifndef WIN32
! 					pqsignal(SIGPIPE, SIG_IGN);
  #endif
  				}
  				else
--- 194,200 ----
  				{
  					usePipe = 1;
  #ifndef WIN32
! 					oldsigpipehandler = pqsignal(SIGPIPE, SIG_IGN);
  #endif
  				}
  				else
***************
*** 309,315 ****
  			_pclose(fout);
  #else
  			pclose(fout);
! 			pqsignal(SIGPIPE, SIG_DFL);
  #endif
  		}
  		if (po->html3 && !po->expanded)
--- 310,316 ----
  			_pclose(fout);
  #else
  			pclose(fout);
! 			pqsignal(SIGPIPE, oldsigpipehandler);
  #endif
  		}
  		if (po->html3 && !po->expanded)
*** src/interfaces/libpq/fe-exec.c.orig	Mon Jul 13 22:41:25 1998
--- src/interfaces/libpq/fe-exec.c	Sat Aug  8 19:57:05 1998
***************
*** 44,49 ****
--- 44,53 ----
  };
  
  
+ #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,203 ****
--- 202,215 ----
  		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,224 ****
  		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;
  	}
  
  	/* Don't try to send if we know there's no live connection. */
--- 217,232 ----
  		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,234 ****
--- 237,250 ----
  		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,311 ****
  		if (pqGetc(&id, conn))
  			return;
  		/*
! 		 * NOTIFY 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
  		{
  			/*
--- 313,331 ----
  		if (pqGetc(&id, conn))
  			return;
  		/*
! 		 * NOTIFY and NOTICE messages can happen in any state besides COPY OUT;
  		 * always process them right away.
  		 */
  		if (id == 'A')
  		{
  			if (getNotify(conn))
  				return;
  		}
+ 		else if (id == 'N')
+ 		{
+ 			if (getNotice(conn))
+ 				return;
+ 		}
  		else
  		{
  			/*
***************
*** 318,326 ****
  			{
  				if (conn->asyncStatus == PGASYNC_IDLE)
  				{
! 					fprintf(stderr,
  							"Backend message type 0x%02x arrived while idle\n",
  							id);
  					/* Discard the unexpected message; good idea?? */
  					conn->inStart = conn->inEnd;
  				}
--- 338,347 ----
  			{
  				if (conn->asyncStatus == PGASYNC_IDLE)
  				{
! 					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,361 ****
  					if (pqGetc(&id, conn))
  						return;
  					if (id != '\0')
! 						fprintf(stderr,
  								"unexpected character %c following 'I'\n", id);
  					if (conn->result == NULL)
  						conn->result = makeEmptyPGresult(conn,
  														 PGRES_EMPTY_QUERY);
--- 375,385 ----
  					if (pqGetc(&id, conn))
  						return;
  					if (id != '\0')
! 					{
! 						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,380 ****
  					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;
--- 395,400 ----
***************
*** 408,415 ****
  					}
  					else
  					{
! 						fprintf(stderr,
  								"Backend sent D message without prior T\n");
  						/* Discard the unexpected message; good idea?? */
  						conn->inStart = conn->inEnd;
  						return;
--- 428,436 ----
  					}
  					else
  					{
! 						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,431 ****
  					}
  					else
  					{
! 						fprintf(stderr,
  								"Backend sent B message without prior T\n");
  						/* Discard the unexpected message; good idea?? */
  						conn->inStart = conn->inEnd;
  						return;
--- 445,453 ----
  					}
  					else
  					{
! 						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,796 ****
  {
  	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);
  	return 0;
  }
  
--- 805,811 ----
  {
  	if (pqGets(conn->errorMessage, ERROR_MSG_LENGTH, conn))
  		return EOF;
! 	DONOTICE(conn, conn->errorMessage);
  	return 0;
  }
  
***************
*** 970,976 ****
  	 * To recover, reset the connection (talk about using a sledgehammer...)
  	 */
  	PQclear(result);
! 	fprintf(stderr, "PQendcopy: resetting connection\n");
  	PQreset(conn);
  
  	return 1;
--- 985,994 ----
  	 * To recover, reset the connection (talk about using a sledgehammer...)
  	 */
  	PQclear(result);
! 
! 	sprintf(conn->errorMessage, "PQendcopy: resetting connection\n");
! 	DONOTICE(conn, conn->errorMessage);
! 
  	PQreset(conn);
  
  	return 1;
***************
*** 1156,1166 ****
  PQresultStatus(PGresult *res)
  {
  	if (!res)
- 	{
- 		fprintf(stderr, "PQresultStatus() -- pointer to PQresult is null\n");
  		return PGRES_NONFATAL_ERROR;
- 	}
- 
  	return res->resultStatus;
  }
  
--- 1174,1180 ----
***************
*** 1168,1177 ****
  PQntuples(PGresult *res)
  {
  	if (!res)
- 	{
- 		fprintf(stderr, "PQntuples() -- pointer to PQresult is null\n");
  		return 0;
- 	}
  	return res->ntups;
  }
  
--- 1182,1188 ----
***************
*** 1179,1210 ****
  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)
  {
  	if (!res)
  	{
! 		fprintf(stderr, "PQfname() -- pointer to PQresult is null\n");
! 		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
--- 1190,1253 ----
  PQnfields(PGresult *res)
  {
  	if (!res)
  		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 (! check_field_number("PQfname", res, field_num))
+ 		return NULL;
  	if (res->attDescs)
  		return res->attDescs[field_num].name;
  	else
***************
*** 1221,1230 ****
  	char	   *field_case;
  
  	if (!res)
- 	{
- 		fprintf(stderr, "PQfnumber() -- pointer to PQresult is null\n");
  		return -1;
- 	}
  
  	if (field_name == NULL ||
  		field_name[0] == '\0' ||
--- 1264,1270 ----
***************
*** 1258,1276 ****
  Oid
  PQftype(PGresult *res, int field_num)
  {
! 	if (!res)
! 	{
! 		fprintf(stderr, "PQftype() -- pointer to PQresult is null\n");
  		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
--- 1298,1305 ----
  Oid
  PQftype(PGresult *res, int field_num)
  {
! 	if (! check_field_number("PQftype", res, field_num))
  		return InvalidOid;
  	if (res->attDescs)
  		return res->attDescs[field_num].typid;
  	else
***************
*** 1280,1298 ****
  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);
  		return 0;
- 	}
  	if (res->attDescs)
  		return res->attDescs[field_num].typlen;
  	else
--- 1309,1316 ----
  short
  PQfsize(PGresult *res, int field_num)
  {
! 	if (! check_field_number("PQfsize", res, field_num))
  		return 0;
  	if (res->attDescs)
  		return res->attDescs[field_num].typlen;
  	else
***************
*** 1302,1320 ****
  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);
  		return 0;
- 	}
  	if (res->attDescs)
  		return res->attDescs[field_num].atttypmod;
  	else
--- 1320,1327 ----
  int
  PQfmod(PGresult *res, int field_num)
  {
! 	if (! check_field_number("PQfmod", res, field_num))
  		return 0;
  	if (res->attDescs)
  		return res->attDescs[field_num].atttypmod;
  	else
***************
*** 1325,1334 ****
  PQcmdStatus(PGresult *res)
  {
  	if (!res)
- 	{
- 		fprintf(stderr, "PQcmdStatus() -- pointer to PQresult is null\n");
  		return NULL;
- 	}
  	return res->cmdStatus;
  }
  
--- 1332,1338 ----
***************
*** 1343,1352 ****
  	static char oidStatus[32] = {0};
  
  	if (!res)
! 	{
! 		fprintf(stderr, "PQoidStatus () -- pointer to PQresult is null\n");
! 		return NULL;
! 	}
  
  	oidStatus[0] = 0;
  
--- 1347,1353 ----
  	static char oidStatus[32] = {0};
  
  	if (!res)
! 		return "";
  
  	oidStatus[0] = 0;
  
***************
*** 1371,1380 ****
  PQcmdTuples(PGresult *res)
  {
  	if (!res)
! 	{
! 		fprintf(stderr, "PQcmdTuples () -- pointer to PQresult is null\n");
! 		return NULL;
! 	}
  
  	if (strncmp(res->cmdStatus, "INSERT", 6) == 0 ||
  		strncmp(res->cmdStatus, "DELETE", 6) == 0 ||
--- 1372,1378 ----
  PQcmdTuples(PGresult *res)
  {
  	if (!res)
! 		return "";
  
  	if (strncmp(res->cmdStatus, "INSERT", 6) == 0 ||
  		strncmp(res->cmdStatus, "DELETE", 6) == 0 ||
***************
*** 1384,1392 ****
  
  		if (*p == 0)
  		{
! 			fprintf(stderr, "PQcmdTuples (%s) -- bad input from server\n",
  					res->cmdStatus);
! 			return NULL;
  		}
  		p++;
  		if (*(res->cmdStatus) != 'I')	/* UPDATE/DELETE */
--- 1382,1392 ----
  
  		if (*p == 0)
  		{
! 			sprintf(res->conn->errorMessage,
! 					"PQcmdTuples (%s) -- bad input from server\n",
  					res->cmdStatus);
! 			DONOTICE(res->conn, res->conn->errorMessage);
! 			return "";
  		}
  		p++;
  		if (*(res->cmdStatus) != 'I')	/* UPDATE/DELETE */
***************
*** 1395,1402 ****
  			p++;				/* INSERT: skip oid */
  		if (*p == 0)
  		{
! 			fprintf(stderr, "PQcmdTuples (INSERT) -- there's no # of tuples\n");
! 			return NULL;
  		}
  		p++;
  		return (p);
--- 1395,1404 ----
  			p++;				/* INSERT: skip oid */
  		if (*p == 0)
  		{
! 			sprintf(res->conn->errorMessage,
! 					"PQcmdTuples (INSERT) -- there's no # of tuples\n");
! 			DONOTICE(res->conn, res->conn->errorMessage);
! 			return "";
  		}
  		p++;
  		return (p);
***************
*** 1417,1444 ****
  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);
  		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;
  }
  
--- 1419,1426 ----
  char *
  PQgetvalue(PGresult *res, int tup_num, int field_num)
  {
! 	if (! check_tuple_field_number("PQgetvalue", res, tup_num, field_num))
  		return NULL;
  	return res->tuples[tup_num][field_num].value;
  }
  
***************
*** 1450,1478 ****
  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);
  		return 0;
- 	}
- 
  	if (res->tuples[tup_num][field_num].len != NULL_LEN)
  		return res->tuples[tup_num][field_num].len;
  	else
--- 1432,1439 ----
  int
  PQgetlength(PGresult *res, int tup_num, int field_num)
  {
! 	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,1512 ****
  int
  PQgetisnull(PGresult *res, int tup_num, int field_num)
  {
! 	if (!res)
! 	{
! 		fprintf(stderr, "PQgetisnull() -- pointer to PQresult is null\n");
  		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
--- 1446,1453 ----
  int
  PQgetisnull(PGresult *res, int tup_num, int field_num)
  {
! 	if (! check_tuple_field_number("PQgetisnull", res, tup_num, field_num))
  		return 1;				/* pretend it is null */
  	if (res->tuples[tup_num][field_num].len == NULL_LEN)
  		return 1;
  	else
*** src/interfaces/libpq/fe-misc.c.orig	Fri Jul  3 00:24:14 1998
--- src/interfaces/libpq/fe-misc.c	Sat Aug  8 19:57:18 1998
***************
*** 50,55 ****
--- 50,59 ----
  #include "postgres.h"
  #include "libpq-fe.h"
  
+ #define DONOTICE(conn,message) \
+ 	((*(conn)->noticeHook) ((conn)->noticeArg, (message)))
+ 
+ 
  /* --------------------------------------------------------------------- */
  /* pqGetc:
     get a character from the connection
***************
*** 218,224 ****
  			*result = (int) ntohl(tmp4);
  			break;
  		default:
! 			fprintf(stderr, "** int size %d not supported\n", bytes);
  			return EOF;
  	}
  
--- 222,230 ----
  			*result = (int) ntohl(tmp4);
  			break;
  		default:
! 			sprintf(conn->errorMessage,
! 					"pqGetInt: int size %d not supported\n", bytes);
! 			DONOTICE(conn, conn->errorMessage);
  			return EOF;
  	}
  
***************
*** 252,258 ****
  				return EOF;
  			break;
  		default:
! 			fprintf(stderr, "** int size %d not supported\n", bytes);
  			return EOF;
  	}
  
--- 258,266 ----
  				return EOF;
  			break;
  		default:
! 			sprintf(conn->errorMessage,
! 					"pqPutInt: int size %d not supported\n", bytes);
! 			DONOTICE(conn, conn->errorMessage);
  			return EOF;
  	}
  
***************
*** 265,271 ****
  /* --------------------------------------------------------------------- */
  /* pqReadReady: is select() saying the file is ready to read?
   */
! static int
  pqReadReady(PGconn *conn)
  {
  	fd_set			input_mask;
--- 273,279 ----
  /* --------------------------------------------------------------------- */
  /* pqReadReady: is select() saying the file is ready to read?
   */
! int
  pqReadReady(PGconn *conn)
  {
  	fd_set			input_mask;
*** src/interfaces/libpq/fe-connect.c.orig	Sat Aug  1 15:56:30 1998
--- src/interfaces/libpq/fe-connect.c	Sat Aug  8 19:56:50 1998
***************
*** 29,35 ****
  #include <ctype.h>
  #include <string.h>
  #include <errno.h>
- #include <signal.h>
  #include <ctype.h>				/* for isspace() */
  
  #include "postgres.h"
--- 29,34 ----
***************
*** 55,60 ****
--- 54,60 ----
  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,191 ****
  	 */
  	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
--- 181,187 ----
***************
*** 297,307 ****
  
  	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')
  	{
--- 293,299 ----
***************
*** 856,861 ****
--- 848,854 ----
  	/* Zero all pointers */
  	MemSet((char *) conn, 0, sizeof(PGconn));
  
+ 	conn->noticeHook = defaultNoticeProcessor;
  	conn->status = CONNECTION_BAD;
  	conn->asyncStatus = PGASYNC_IDLE;
  	conn->notifyList = DLNewList();
***************
*** 925,959 ****
  	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.
  		 */
! #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 */
  	}
  
  	/*
--- 918,937 ----
  	if (conn->sock >= 0)
  	{
  		/*
! 		 * 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.
  		 */
! 		while (pqReadReady(conn)) {
! 			if (pqReadData(conn) < 0)
! 				break;
! 		}
! 		if (conn->sock >= 0) {
! 			/* Should be safe now... */
! 			(void) pqPuts("X", conn);
! 			(void) pqFlush(conn);
! 		}
  	}
  
  	/*
***************
*** 987,995 ****
  void
  PQfinish(PGconn *conn)
  {
! 	if (!conn)
! 		fprintf(stderr, "PQfinish() -- pointer to PGconn is null\n");
! 	else
  	{
  		closePGconn(conn);
  		freePGconn(conn);
--- 965,971 ----
  void
  PQfinish(PGconn *conn)
  {
! 	if (conn)
  	{
  		closePGconn(conn);
  		freePGconn(conn);
***************
*** 1003,1011 ****
  void
  PQreset(PGconn *conn)
  {
! 	if (!conn)
! 		fprintf(stderr, "PQreset() -- pointer to PGconn is null\n");
! 	else
  	{
  		closePGconn(conn);
  		conn->status = connectDB(conn);
--- 979,985 ----
  void
  PQreset(PGconn *conn)
  {
! 	if (conn)
  	{
  		closePGconn(conn);
  		conn->status = connectDB(conn);
***************
*** 1383,1392 ****
  PQdb(PGconn *conn)
  {
  	if (!conn)
- 	{
- 		fprintf(stderr, "PQdb() -- pointer to PGconn is null\n");
  		return (char *) NULL;
- 	}
  	return conn->dbName;
  }
  
--- 1357,1363 ----
***************
*** 1394,1403 ****
  PQuser(PGconn *conn)
  {
  	if (!conn)
- 	{
- 		fprintf(stderr, "PQuser() -- pointer to PGconn is null\n");
  		return (char *) NULL;
- 	}
  	return conn->pguser;
  }
  
--- 1365,1371 ----
***************
*** 1405,1415 ****
  PQhost(PGconn *conn)
  {
  	if (!conn)
- 	{
- 		fprintf(stderr, "PQhost() -- pointer to PGconn is null\n");
  		return (char *) NULL;
- 	}
- 
  	return conn->pghost;
  }
  
--- 1373,1379 ----
***************
*** 1417,1426 ****
  PQoptions(PGconn *conn)
  {
  	if (!conn)
- 	{
- 		fprintf(stderr, "PQoptions() -- pointer to PGconn is null\n");
  		return (char *) NULL;
- 	}
  	return conn->pgoptions;
  }
  
--- 1381,1387 ----
***************
*** 1428,1437 ****
  PQtty(PGconn *conn)
  {
  	if (!conn)
- 	{
- 		fprintf(stderr, "PQtty() -- pointer to PGconn is null\n");
  		return (char *) NULL;
- 	}
  	return conn->pgtty;
  }
  
--- 1389,1395 ----
***************
*** 1439,1448 ****
  PQport(PGconn *conn)
  {
  	if (!conn)
- 	{
- 		fprintf(stderr, "PQport() -- pointer to PGconn is null\n");
  		return (char *) NULL;
- 	}
  	return conn->pgport;
  }
  
--- 1397,1403 ----
***************
*** 1450,1470 ****
  PQstatus(PGconn *conn)
  {
  	if (!conn)
- 	{
- 		fprintf(stderr, "PQstatus() -- pointer to PGconn is null\n");
  		return CONNECTION_BAD;
- 	}
  	return conn->status;
  }
  
  char *
  PQerrorMessage(PGconn *conn)
  {
  	if (!conn)
! 	{
! 		fprintf(stderr, "PQerrorMessage() -- pointer to PGconn is null\n");
! 		return (char *) NULL;
! 	}
  	return conn->errorMessage;
  }
  
--- 1405,1420 ----
  PQstatus(PGconn *conn)
  {
  	if (!conn)
  		return CONNECTION_BAD;
  	return conn->status;
  }
  
  char *
  PQerrorMessage(PGconn *conn)
  {
+ 	static char noConn[] = "PQerrorMessage: conn pointer is NULL\n";
  	if (!conn)
! 		return noConn;
  	return conn->errorMessage;
  }
  
***************
*** 1472,1481 ****
  PQsocket(PGconn *conn)
  {
  	if (!conn)
- 	{
- 		fprintf(stderr, "PQsocket() -- pointer to PGconn is null\n");
  		return -1;
- 	}
  	return conn->sock;
  }
  
--- 1422,1428 ----
***************
*** 1500,1503 ****
--- 1447,1473 ----
  		fflush(conn->Pfdebug);
  		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);
  }
*** src/man/libpq.3.orig	Wed Jul 15 13:34:06 1998
--- src/man/libpq.3	Sat Aug  8 20:10:16 1998
***************
*** 1,7 ****
  .\" This is -*-nroff-*-
  .\" XXX standard disclaimer belongs here....
  .\" $Header: /usr/local/cvsroot/pgsql/src/man/libpq.3,v 1.22 1998/07/15 17:34:06 momjian Exp $
! .TH LIBPQ INTRO 07/08/98 PostgreSQL PostgreSQL
  .SH DESCRIPTION
  Libpq is the programmer's interface to Postgres.  Libpq is a set of
  library routines which allows
--- 1,7 ----
  .\" This is -*-nroff-*-
  .\" XXX standard disclaimer belongs here....
  .\" $Header: /usr/local/cvsroot/pgsql/src/man/libpq.3,v 1.22 1998/07/15 17:34:06 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,828 ****
--- 823,858 ----
  .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
