diff --git a/src/interfaces/libpgtcl/pgtclCmds.c b/src/interfaces/libpgtcl/pgtclCmds.c
index 9ed84c11d60675ca38e10fdf6efd132414000d55..10aa2f01bc080f59e6c6f462e7723c0be5c3a48f 100644
--- a/src/interfaces/libpgtcl/pgtclCmds.c
+++ b/src/interfaces/libpgtcl/pgtclCmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclCmds.c,v 1.47 2000/02/27 07:44:22 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclCmds.c,v 1.48 2000/03/11 03:08:35 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -237,25 +237,32 @@ tcl_value(char *value)
 int
 Pg_conndefaults(ClientData cData, Tcl_Interp *interp, int argc, char **argv)
 {
+	PQconninfoOption *options = PQconndefaults();
 	PQconninfoOption *option;
 	Tcl_DString result;
 	char		ibuf[32];
 
-	Tcl_DStringInit(&result);
-	for (option = PQconndefaults(); option->keyword != NULL; option++)
+	if (options)
 	{
-		char	   *val = option->val ? option->val : "";
+		Tcl_DStringInit(&result);
 
-		sprintf(ibuf, "%d", option->dispsize);
-		Tcl_DStringStartSublist(&result);
-		Tcl_DStringAppendElement(&result, option->keyword);
-		Tcl_DStringAppendElement(&result, option->label);
-		Tcl_DStringAppendElement(&result, option->dispchar);
-		Tcl_DStringAppendElement(&result, ibuf);
-		Tcl_DStringAppendElement(&result, val);
-		Tcl_DStringEndSublist(&result);
+		for (option = options; option->keyword != NULL; option++)
+		{
+			char	   *val = option->val ? option->val : "";
+
+			sprintf(ibuf, "%d", option->dispsize);
+			Tcl_DStringStartSublist(&result);
+			Tcl_DStringAppendElement(&result, option->keyword);
+			Tcl_DStringAppendElement(&result, option->label);
+			Tcl_DStringAppendElement(&result, option->dispchar);
+			Tcl_DStringAppendElement(&result, ibuf);
+			Tcl_DStringAppendElement(&result, val);
+			Tcl_DStringEndSublist(&result);
+		}
+		Tcl_DStringResult(interp, &result);
+
+		PQconninfoFree(options);
 	}
-	Tcl_DStringResult(interp, &result);
 
 	return TCL_OK;
 }
diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c
index 7a3bff45e9211e1febdf6c97568a3cda0a0b5d49..fe870963df4e3d3acc9e43d5c115a68996a7cf35 100644
--- a/src/interfaces/libpq/fe-auth.c
+++ b/src/interfaces/libpq/fe-auth.c
@@ -10,7 +10,7 @@
  * exceed INITIAL_EXPBUFFER_SIZE (currently 256 bytes).
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.37 2000/02/07 23:10:08 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.38 2000/03/11 03:08:36 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -75,7 +75,7 @@ struct authsvc
  * allowed.  Unauthenticated connections are disallowed unless there
  * isn't any authentication system.
  */
-static struct authsvc authsvcs[] = {
+static const struct authsvc authsvcs[] = {
 #ifdef KRB4
 	{"krb4", STARTUP_KRB4_MSG, 1},
 	{"kerberos", STARTUP_KRB4_MSG, 1},
@@ -94,7 +94,7 @@ static struct authsvc authsvcs[] = {
 	{"password", STARTUP_PASSWORD_MSG, 0}
 };
 
-static int	n_authsvcs = sizeof(authsvcs) / sizeof(struct authsvc);
+static const int	n_authsvcs = sizeof(authsvcs) / sizeof(struct authsvc);
 
 #ifdef KRB4
 /*----------------------------------------------------------------
@@ -549,7 +549,14 @@ fe_sendauth(AuthRequest areq, PGconn *conn, const char *hostname,
  *
  * Set/return the authentication service currently selected for use by the
  * frontend. (You can only use one in the frontend, obviously.)
+ *
+ * NB: This is not thread-safe if different threads try to select different
+ * authentication services!  It's OK for fe_getauthsvc to select the default,
+ * since that will be the same for all threads, but direct application use
+ * of fe_setauthsvc is not thread-safe.  However, use of fe_setauthsvc is
+ * deprecated anyway...
  */
+
 static int	pg_authsvc = -1;
 
 void
@@ -558,7 +565,7 @@ fe_setauthsvc(const char *name, char *PQerrormsg)
 	int			i;
 
 	for (i = 0; i < n_authsvcs; ++i)
-		if (!strcmp(name, authsvcs[i].name))
+		if (strcmp(name, authsvcs[i].name) == 0)
 		{
 			pg_authsvc = i;
 			break;
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 4f94b7b0a1da06760c46aa296e57a1396c107a54..81973e34f63050b3c809af7027b2f5e11ed2e711 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.122 2000/02/24 15:53:12 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.123 2000/03/11 03:08:36 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -76,35 +76,25 @@ struct pg_setenv_state
 	} state;
 	PGconn *conn;
 	PGresult *res;
-	struct EnvironmentOptions *eo;
+	const struct EnvironmentOptions *eo;
 } ;
 
-static int connectDBStart(PGconn *conn);
-static int connectDBComplete(PGconn *conn);
-
 #ifdef USE_SSL
 static SSL_CTX *SSL_context = NULL;
 #endif
 
-static PGconn *makeEmptyPGconn(void);
-static void freePGconn(PGconn *conn);
-static void closePGconn(PGconn *conn);
-static int	conninfo_parse(const char *conninfo, PQExpBuffer errorMessage);
-static char *conninfo_getval(char *keyword);
-static void conninfo_free(void);
-static void defaultNoticeProcessor(void *arg, const char *message);
-
 #define NOTIFYLIST_INITIAL_SIZE 10
 #define NOTIFYLIST_GROWBY 10
 
 
 /* ----------
  * Definition of the conninfo parameters and their fallback resources.
+ *
  * If Environment-Var and Compiled-in are specified as NULL, no
  * fallback is available. If after all no value can be determined
  * for an option, an error is returned.
  *
- * The values for dbname and user are treated special in conninfo_parse.
+ * The values for dbname and user are treated specially in conninfo_parse.
  * If the Compiled-in resource is specified as a NULL value, the
  * user is determined by fe_getauthname() and for dbname the user
  * name is copied.
@@ -112,23 +102,30 @@ static void defaultNoticeProcessor(void *arg, const char *message);
  * The Label and Disp-Char entries are provided for applications that
  * want to use PQconndefaults() to create a generic database connection
  * dialog. Disp-Char is defined as follows:
- *	   ""		Normal input field
+ *		""		Normal input field
+ *		"*"		Password field - hide value
+ *		"D"		Debug option - don't show by default
+ *
+ * PQconninfoOptions[] is a constant static array that we use to initialize
+ * a dynamically allocated working copy.  All the "val" fields in
+ * PQconninfoOptions[] *must* be NULL.  In a working copy, non-null "val"
+ * fields point to malloc'd strings that should be freed when the working
+ * array is freed (see PQconninfoFree).
  * ----------
  */
-static PQconninfoOption PQconninfoOptions[] = {
-/* ----------------------------------------------------------------- */
-/*	  Option-name		Environment-Var Compiled-in		Current value	*/
-/*						Label							Disp-Char		*/
-/* ----------------- --------------- --------------- --------------- */
-	/* "authtype" is ignored as it is no longer used. */
+static const PQconninfoOption PQconninfoOptions[] = {
+	/* "authtype" is no longer used, so mark it "don't show".  We keep it
+	 * in the array so as not to reject conninfo strings from old apps that
+	 * might still try to set it.
+	 */
 	{"authtype", "PGAUTHTYPE", DefaultAuthtype, NULL,
-	"Database-Authtype", "", 20},
+	"Database-Authtype", "D", 20},
 
 	{"user", "PGUSER", NULL, NULL,
 	"Database-User", "", 20},
 
 	{"password", "PGPASSWORD", DefaultPassword, NULL,
-	"Database-Password", "", 20},
+	"Database-Password", "*", 20},
 
 	{"dbname", "PGDATABASE", NULL, NULL,
 	"Database-Name", "", 20},
@@ -147,12 +144,13 @@ static PQconninfoOption PQconninfoOptions[] = {
 
 	{"options", "PGOPTIONS", DefaultOption, NULL,
 	"Backend-Debug-Options", "D", 40},
-/* ----------------- --------------- --------------- --------------- */
+
+	/* Terminating entry --- MUST BE LAST */
 	{NULL, NULL, NULL, NULL,
 	NULL, NULL, 0}
 };
 
-static struct EnvironmentOptions
+static const struct EnvironmentOptions
 {
 	const char *envName,
 			   *pgName;
@@ -181,6 +179,18 @@ static struct EnvironmentOptions
 };
 
 
+static int connectDBStart(PGconn *conn);
+static int connectDBComplete(PGconn *conn);
+static PGconn *makeEmptyPGconn(void);
+static void freePGconn(PGconn *conn);
+static void closePGconn(PGconn *conn);
+static PQconninfoOption *conninfo_parse(const char *conninfo,
+										PQExpBuffer errorMessage);
+static char *conninfo_getval(PQconninfoOption *connOptions,
+							 const char *keyword);
+static void defaultNoticeProcessor(void *arg, const char *message);
+
+
 /* ----------------
  *      Connecting to a Database
  *
@@ -262,6 +272,7 @@ PGconn *
 PQconnectStart(const char *conninfo)
 {
 	PGconn	   *conn;
+	PQconninfoOption *connOptions;
 	char	   *tmp;
 
 	/* ----------
@@ -274,37 +285,42 @@ PQconnectStart(const char *conninfo)
 		return (PGconn *) NULL;
 
 	/* ----------
-	 * Parse the conninfo string and save settings in conn structure
+	 * Parse the conninfo string
 	 * ----------
 	 */
-	if (conninfo_parse(conninfo, &conn->errorMessage) < 0)
+	connOptions = conninfo_parse(conninfo, &conn->errorMessage);
+	if (connOptions == NULL)
 	{
 		conn->status = CONNECTION_BAD;
-		conninfo_free();
+		/* errorMessage is already set */
 		return conn;
 	}
-	tmp = conninfo_getval("hostaddr");
+
+	/*
+	 * Move option values into conn structure
+	 */
+	tmp = conninfo_getval(connOptions, "hostaddr");
 	conn->pghostaddr = tmp ? strdup(tmp) : NULL;
-	tmp = conninfo_getval("host");
+	tmp = conninfo_getval(connOptions, "host");
 	conn->pghost = tmp ? strdup(tmp) : NULL;
-	tmp = conninfo_getval("port");
+	tmp = conninfo_getval(connOptions, "port");
 	conn->pgport = tmp ? strdup(tmp) : NULL;
-	tmp = conninfo_getval("tty");
+	tmp = conninfo_getval(connOptions, "tty");
 	conn->pgtty = tmp ? strdup(tmp) : NULL;
-	tmp = conninfo_getval("options");
+	tmp = conninfo_getval(connOptions, "options");
 	conn->pgoptions = tmp ? strdup(tmp) : NULL;
-	tmp = conninfo_getval("dbname");
+	tmp = conninfo_getval(connOptions, "dbname");
 	conn->dbName = tmp ? strdup(tmp) : NULL;
-	tmp = conninfo_getval("user");
+	tmp = conninfo_getval(connOptions, "user");
 	conn->pguser = tmp ? strdup(tmp) : NULL;
-	tmp = conninfo_getval("password");
+	tmp = conninfo_getval(connOptions, "password");
 	conn->pgpass = tmp ? strdup(tmp) : NULL;
 
 	/* ----------
-	 * Free the connection info - all is in conn now
+	 * Free the option info - all is in conn now
 	 * ----------
 	 */
-	conninfo_free();
+	PQconninfoFree(connOptions);
 
 	/* ----------
 	 * Connect to the database
@@ -323,20 +339,28 @@ PQconnectStart(const char *conninfo)
  *		PQconndefaults
  *
  * Parse an empty string like PQconnectdb() would do and return the
- * address of the connection options structure. Using this function
- * an application might determine all possible options and their
- * current default values.
+ * working connection options array.
+ *
+ * Using this function, an application may determine all possible options
+ * and their current default values.
+ *
+ * NOTE: as of PostgreSQL 7.0, the returned array is dynamically allocated
+ * and should be freed when no longer needed via PQconninfoFree().  (In prior
+ * versions, the returned array was static, but that's not thread-safe.)
+ * Pre-7.0 applications that use this function will see a small memory leak
+ * until they are updated to call PQconninfoFree.
  * ----------------
  */
 PQconninfoOption *
 PQconndefaults(void)
 {
 	PQExpBufferData  errorBuf;
+	PQconninfoOption *connOptions;
 
 	initPQExpBuffer(&errorBuf);
-	conninfo_parse("", &errorBuf);
+	connOptions = conninfo_parse("", &errorBuf);
 	termPQExpBuffer(&errorBuf);
-	return PQconninfoOptions;
+	return connOptions;
 }
 
 /* ----------------
@@ -565,7 +589,7 @@ update_db_info(PGconn *conn)
 				{
 					printfPQExpBuffer(&conn->errorMessage,
 									  "connectDBStart() -- "
-									  "non-tcp access only possible on "
+									  "non-TCP access only possible on "
 									  "localhost\n");
 					return 1;
 				}
@@ -2037,9 +2061,13 @@ pqPacketSend(PGconn *conn, const char *buf, size_t len)
 
 /* ----------------
  * Conninfo parser routine
+ *
+ * If successful, a malloc'd PQconninfoOption array is returned.
+ * If not successful, NULL is returned and an error message is
+ * left in errorMessage.
  * ----------------
  */
-static int
+static PQconninfoOption *
 conninfo_parse(const char *conninfo, PQExpBuffer errorMessage)
 {
 	char	   *pname;
@@ -2048,16 +2076,27 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage)
 	char	   *tmp;
 	char	   *cp;
 	char	   *cp2;
+	PQconninfoOption *options;
 	PQconninfoOption *option;
 	char		errortmp[INITIAL_EXPBUFFER_SIZE];
 
-	conninfo_free();
+	/* Make a working copy of PQconninfoOptions */
+	options = malloc(sizeof(PQconninfoOptions));
+	if (options == NULL)
+	{
+		printfPQExpBuffer(errorMessage,
+		  "FATAL: cannot allocate memory for copy of PQconninfoOptions\n");
+		return NULL;
+	}
+	memcpy(options, PQconninfoOptions, sizeof(PQconninfoOptions));
 
+	/* Need a modifiable copy of the input string */
 	if ((buf = strdup(conninfo)) == NULL)
 	{
 		printfPQExpBuffer(errorMessage,
 		  "FATAL: cannot allocate memory for copy of conninfo string\n");
-		return -1;
+		PQconninfoFree(options);
+		return NULL;
 	}
 	cp = buf;
 
@@ -2094,10 +2133,11 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage)
 		if (*cp != '=')
 		{
 			printfPQExpBuffer(errorMessage,
-				"ERROR: PQconnectdb() - Missing '=' after '%s' in conninfo\n",
+							  "ERROR: Missing '=' after '%s' in conninfo\n",
 							  pname);
+			PQconninfoFree(options);
 			free(buf);
-			return -1;
+			return NULL;
 		}
 		*cp++ = '\0';
 
@@ -2109,6 +2149,7 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage)
 			cp++;
 		}
 
+		/* Get the parameter value */
 		pval = cp;
 
 		if (*cp != '\'')
@@ -2142,8 +2183,9 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage)
 				{
 					printfPQExpBuffer(errorMessage,
 							"ERROR: PQconnectdb() - unterminated quoted string in conninfo\n");
+					PQconninfoFree(options);
 					free(buf);
-					return -1;
+					return NULL;
 				}
 				if (*cp == '\\')
 				{
@@ -2167,27 +2209,31 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage)
 		 * for the param record.
 		 * ----------
 		 */
-		for (option = PQconninfoOptions; option->keyword != NULL; option++)
+		for (option = options; option->keyword != NULL; option++)
 		{
-			if (!strcmp(option->keyword, pname))
+			if (strcmp(option->keyword, pname) == 0)
 				break;
 		}
 		if (option->keyword == NULL)
 		{
 			printfPQExpBuffer(errorMessage,
-							  "ERROR: PQconnectdb() - unknown option '%s'\n",
+							  "ERROR: Unknown conninfo option '%s'\n",
 							  pname);
+			PQconninfoFree(options);
 			free(buf);
-			return -1;
+			return NULL;
 		}
 
 		/* ----------
 		 * Store the value
 		 * ----------
 		 */
+		if (option->val)
+			free(option->val);
 		option->val = strdup(pval);
 	}
 
+	/* Done with the modifiable input string */
 	free(buf);
 
 	/* ----------
@@ -2195,7 +2241,7 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage)
 	 * in the conninfo string.
 	 * ----------
 	 */
-	for (option = PQconninfoOptions; option->keyword != NULL; option++)
+	for (option = options; option->keyword != NULL; option++)
 	{
 		if (option->val != NULL)
 			continue;			/* Value was in conninfo */
@@ -2228,7 +2274,7 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage)
 		 * Special handling for user
 		 * ----------
 		 */
-		if (!strcmp(option->keyword, "user"))
+		if (strcmp(option->keyword, "user") == 0)
 		{
 			option->val = fe_getauthname(errortmp);
 			/* note any error message is thrown away */
@@ -2239,27 +2285,28 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage)
 		 * Special handling for dbname
 		 * ----------
 		 */
-		if (!strcmp(option->keyword, "dbname"))
+		if (strcmp(option->keyword, "dbname") == 0)
 		{
-			tmp = conninfo_getval("user");
+			tmp = conninfo_getval(options, "user");
 			if (tmp)
 				option->val = strdup(tmp);
 			continue;
 		}
 	}
 
-	return 0;
+	return options;
 }
 
 
 static char *
-conninfo_getval(char *keyword)
+conninfo_getval(PQconninfoOption *connOptions,
+				const char *keyword)
 {
 	PQconninfoOption *option;
 
-	for (option = PQconninfoOptions; option->keyword != NULL; option++)
+	for (option = connOptions; option->keyword != NULL; option++)
 	{
-		if (!strcmp(option->keyword, keyword))
+		if (strcmp(option->keyword, keyword) == 0)
 			return option->val;
 	}
 
@@ -2267,19 +2314,20 @@ conninfo_getval(char *keyword)
 }
 
 
-static void
-conninfo_free()
+void
+PQconninfoFree(PQconninfoOption *connOptions)
 {
 	PQconninfoOption *option;
 
-	for (option = PQconninfoOptions; option->keyword != NULL; option++)
+	if (connOptions == NULL)
+		return;
+
+	for (option = connOptions; option->keyword != NULL; option++)
 	{
 		if (option->val != NULL)
-		{
 			free(option->val);
-			option->val = NULL;
-		}
 	}
+	free(connOptions);
 }
 
 /* =========== accessor functions for PGconn ========= */
@@ -2350,10 +2398,9 @@ PQstatus(const PGconn *conn)
 char *
 PQerrorMessage(const PGconn *conn)
 {
-	static char noConn[] = "PQerrorMessage: conn pointer is NULL\n";
-
 	if (!conn)
-		return noConn;
+		return "PQerrorMessage: conn pointer is NULL\n";
+
 	return conn->errorMessage.data;
 }
 
@@ -2452,13 +2499,15 @@ PQnoticeProcessor
 PQsetNoticeProcessor(PGconn *conn, PQnoticeProcessor proc, void *arg)
 {
 	PQnoticeProcessor old;
+
 	if (conn == NULL)
 		return NULL;
 
 	old = conn->noticeHook;
-	if (proc) {
-	conn->noticeHook = proc;
-	conn->noticeArg = arg;
+	if (proc)
+	{
+		conn->noticeHook = proc;
+		conn->noticeArg = arg;
 	}
 	return old;
 }
diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c
index 7be05bd525a0c68b2ac1be0d8ed8de9e1cbb2ed2..5d614ebe375c8d29adf17c527545dd500b93b20d 100644
--- a/src/interfaces/libpq/fe-exec.c
+++ b/src/interfaces/libpq/fe-exec.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.91 2000/02/24 04:50:51 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.92 2000/03/11 03:08:36 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -39,6 +39,7 @@ char * const pgresStatus[] = {
 };
 
 
+/* Note: DONOTICE macro will work if applied to either PGconn or PGresult */
 #define DONOTICE(conn,message) \
 	((*(conn)->noticeHook) ((conn)->noticeArg, (message)))
 
@@ -135,7 +136,7 @@ PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status)
 
 	result = (PGresult *) malloc(sizeof(PGresult));
 
-	result->conn = conn;		/* might be NULL */
+	result->xconn = conn;		/* might be NULL */
 	result->ntups = 0;
 	result->numAttributes = 0;
 	result->attDescs = NULL;
@@ -150,8 +151,11 @@ PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status)
 	result->curOffset = 0;
 	result->spaceLeft = 0;
 
-	if (conn)					/* consider copying conn's errorMessage */
+	if (conn)
 	{
+		result->noticeHook = conn->noticeHook;
+		result->noticeArg = conn->noticeArg;
+		/* consider copying conn's errorMessage */
 		switch (status)
 		{
 			case PGRES_EMPTY_QUERY:
@@ -166,6 +170,12 @@ PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status)
 				break;
 		}
 	}
+	else
+	{
+		result->noticeHook = NULL;
+		result->noticeArg = NULL;
+	}
+
 	return result;
 }
 
@@ -1833,12 +1843,12 @@ check_field_number(const char *routineName, const PGresult *res, int field_num)
 		return FALSE;			/* no way to display error message... */
 	if (field_num < 0 || field_num >= res->numAttributes)
 	{
-		if (res->conn)
+		if (res->noticeHook)
 		{
 			sprintf(noticeBuf,
 					"%s: ERROR! field number %d is out of range 0..%d\n",
 					routineName, field_num, res->numAttributes - 1);
-			DONOTICE(res->conn, noticeBuf);
+			DONOTICE(res, noticeBuf);
 		}
 		return FALSE;
 	}
@@ -1855,23 +1865,23 @@ check_tuple_field_number(const char *routineName, const PGresult *res,
 		return FALSE;			/* no way to display error message... */
 	if (tup_num < 0 || tup_num >= res->ntups)
 	{
-		if (res->conn)
+		if (res->noticeHook)
 		{
 			sprintf(noticeBuf,
 					"%s: ERROR! tuple number %d is out of range 0..%d\n",
 					routineName, tup_num, res->ntups - 1);
-			DONOTICE(res->conn, noticeBuf);
+			DONOTICE(res, noticeBuf);
 		}
 		return FALSE;
 	}
 	if (field_num < 0 || field_num >= res->numAttributes)
 	{
-		if (res->conn)
+		if (res->noticeHook)
 		{
 			sprintf(noticeBuf,
 					"%s: ERROR! field number %d is out of range 0..%d\n",
 					routineName, field_num, res->numAttributes - 1);
-			DONOTICE(res->conn, noticeBuf);
+			DONOTICE(res, noticeBuf);
 		}
 		return FALSE;
 	}
@@ -1982,11 +1992,11 @@ PQcmdStatus(PGresult *res)
 char *
 PQoidStatus(const PGresult *res)
 {
-        /* 
-         * This must be enough to hold the result. Don't laugh, this is
-         * better than what this function used to do.
-         */
-        static char buf[24];
+	/* 
+	 * This must be enough to hold the result. Don't laugh, this is
+	 * better than what this function used to do.
+	 */
+	static char buf[24];
 
 	size_t len;
 
@@ -1995,7 +2005,7 @@ PQoidStatus(const PGresult *res)
 
 	len = strspn(res->cmdStatus + 7, "0123456789");
 	if (len > 23)
-	        len = 23;
+		len = 23;
 	strncpy(buf, res->cmdStatus + 7, len);
 	buf[23] = '\0';
 
@@ -2046,12 +2056,12 @@ PQcmdTuples(PGresult *res)
 
 		if (*p == 0)
 		{
-			if (res->conn)
+			if (res->noticeHook)
 			{
 				sprintf(noticeBuf,
 						"PQcmdTuples (%s) -- bad input from server\n",
 						res->cmdStatus);
-				DONOTICE(res->conn, noticeBuf);
+				DONOTICE(res, noticeBuf);
 			}
 			return "";
 		}
@@ -2062,11 +2072,11 @@ PQcmdTuples(PGresult *res)
 			p++;				/* INSERT: skip oid */
 		if (*p == 0)
 		{
-			if (res->conn)
+			if (res->noticeHook)
 			{
 				sprintf(noticeBuf,
 					 "PQcmdTuples (INSERT) -- there's no # of tuples\n");
-				DONOTICE(res->conn, noticeBuf);
+				DONOTICE(res, noticeBuf);
 			}
 			return "";
 		}
diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h
index 66437a903fd000852ab12e671b68717b0df0c0fa..fcd8e7819e7e964193f443373db224b16549a9f4 100644
--- a/src/interfaces/libpq/libpq-fe.h
+++ b/src/interfaces/libpq/libpq-fe.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: libpq-fe.h,v 1.60 2000/02/07 23:10:11 petere Exp $
+ * $Id: libpq-fe.h,v 1.61 2000/03/11 03:08:37 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -130,6 +130,10 @@ extern		"C"
 
 /* ----------------
  * Structure for the conninfo parameter definitions returned by PQconndefaults
+ *
+ * All fields except "val" point at static strings which must not be altered.
+ * "val" is either NULL or a malloc'd current-value string.  PQconninfoFree()
+ * will release both the val strings and the PQconninfoOption array itself.
  * ----------------
  */
 	typedef struct _PQconninfoOption
@@ -137,14 +141,14 @@ extern		"C"
 		char	   *keyword;	/* The keyword of the option			*/
 		char	   *envvar;		/* Fallback environment variable name	*/
 		char	   *compiled;	/* Fallback compiled in default value	*/
-		char	   *val;		/* Options value						*/
+		char	   *val;		/* Option's current value, or NULL		*/
 		char	   *label;		/* Label for field in connect dialog	*/
-		char	   *dispchar;	/* Character to display for this field	*/
-		/* in a connect dialog. Values are:		*/
-		/* ""	Display entered value as is  */
-		/* "*"	Password field - hide value  */
-		/* "D"	Debug options - don't 	 */
-		/* create a field by default	*/
+		char	   *dispchar;	/* Character to display for this field
+								 * in a connect dialog. Values are:
+								 * ""	Display entered value as is
+								 * "*"	Password field - hide value
+								 * "D"	Debug option - don't show by default
+								 */
 		int			dispsize;	/* Field size in characters for dialog	*/
 	} PQconninfoOption;
 
@@ -183,11 +187,14 @@ extern		"C"
 #define PQsetdb(M_PGHOST,M_PGPORT,M_PGOPT,M_PGTTY,M_DBNAME)  \
 	PQsetdbLogin(M_PGHOST, M_PGPORT, M_PGOPT, M_PGTTY, M_DBNAME, NULL, NULL)
 
+	/* close the current connection and free the PGconn data structure */
+	extern void PQfinish(PGconn *conn);
+
 	/* get info about connection options known to PQconnectdb */
 	extern PQconninfoOption *PQconndefaults(void);
 
-	/* close the current connection and free the PGconn data structure */
-	extern void PQfinish(PGconn *conn);
+	/* free the data structure returned by PQconndefaults() */
+	extern void PQconninfoFree(PQconninfoOption *connOptions);
 
 	/*
 	 * close the current connection and restablish a new one with the same
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 16555d98852e275d30cc8076e7a00481fe60db54..92bd9cfba83607704f5c6a4741e9626bd6c57350 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -12,7 +12,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: libpq-int.h,v 1.19 2000/02/07 23:10:11 petere Exp $
+ * $Id: libpq-int.h,v 1.20 2000/03/11 03:08:37 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -121,7 +121,21 @@ struct pg_result
 												 * last query */
 	int			binary;			/* binary tuple values if binary == 1,
 								 * otherwise ASCII */
-	PGconn	   *conn;			/* connection we did the query on, if any */
+	/*
+	 * The conn link in PGresult is no longer used by any libpq code.
+	 * It should be removed entirely, because it could be a dangling link
+	 * (the application could keep the PGresult around longer than it keeps
+	 * the PGconn!)  But there may be apps out there that depend on it,
+	 * so we will leave it here at least for a release or so.
+	 */
+	PGconn	   *xconn;			/* connection we did the query on, if any */
+
+	/* Callback procedure for notice/error message processing
+	 * (copied from originating PGconn).
+	 */
+	PQnoticeProcessor noticeHook;
+	void	   *noticeArg;
+
 	char	   *errMsg;			/* error message, or NULL if no error */
 
 	/* All NULL attributes in the query result point to this null string */
diff --git a/src/interfaces/libpq/libpqdll.def b/src/interfaces/libpq/libpqdll.def
index 4c8e0e54a1495cd82a2c3f3ec941cde476af806c..32b0fa6ec3a770a3ace315263a7a056612ed7ca0 100644
--- a/src/interfaces/libpq/libpqdll.def
+++ b/src/interfaces/libpq/libpqdll.def
@@ -78,3 +78,4 @@ EXPORTS
 	appendPQExpBufferStr	@ 75
 	destroyPQExpBuffer	@ 76
 	createPQExpBuffer	@ 77
+	PQconninfoFree		@ 78
diff --git a/src/interfaces/perl5/Pg.xs b/src/interfaces/perl5/Pg.xs
index 2c884c9c033ed5d5c1a84abc526d2d36327a3475..cd8e5fe6818dcb5d96c906f23b11288cee04d293 100644
--- a/src/interfaces/perl5/Pg.xs
+++ b/src/interfaces/perl5/Pg.xs
@@ -1,6 +1,6 @@
 /*-------------------------------------------------------
  *
- * $Id: Pg.xs,v 1.13 1999/10/13 02:26:37 momjian Exp $ with patch for NULs
+ * $Id: Pg.xs,v 1.14 2000/03/11 03:08:37 tgl Exp $ with patch for NULs
  *
  * Copyright (c) 1997, 1998  Edmund Mergl
  *
@@ -247,17 +247,18 @@ PQsetdb(pghost, pgport, pgoptions, pgtty, dbname)
 HV *
 PQconndefaults()
 	CODE:
-		PQconninfoOption *infoOption;
+		PQconninfoOption *infoOptions;
 		RETVAL = newHV();
-                if (infoOption = PQconndefaults()) {
-			while (infoOption->keyword != NULL) {
-				if (infoOption->val != NULL) {
-					hv_store(RETVAL, infoOption->keyword, strlen(infoOption->keyword), newSVpv(infoOption->val, 0), 0);
+		if (infoOptions = PQconndefaults()) {
+			PQconninfoOption *option;
+			for (option = infoOptions; option->keyword != NULL; option++) {
+				if (option->val != NULL) {
+					hv_store(RETVAL, option->keyword, strlen(option->keyword), newSVpv(option->val, 0), 0);
 				} else {
-					hv_store(RETVAL, infoOption->keyword, strlen(infoOption->keyword), newSVpv("", 0), 0);
+					hv_store(RETVAL, option->keyword, strlen(option->keyword), newSVpv("", 0), 0);
 				}
-				infoOption++;
 			}
+			PQconninfoFree(infoOptions);
 		}
 	OUTPUT:
 		RETVAL
@@ -774,17 +775,18 @@ setdb(pghost, pgport, pgoptions, pgtty, dbname)
 HV *
 conndefaults()
 	CODE:
-		PQconninfoOption *infoOption;
+		PQconninfoOption *infoOptions;
 		RETVAL = newHV();
-                if (infoOption = PQconndefaults()) {
-			while (infoOption->keyword != NULL) {
-				if (infoOption->val != NULL) {
-					hv_store(RETVAL, infoOption->keyword, strlen(infoOption->keyword), newSVpv(infoOption->val, 0), 0);
+		if (infoOptions = PQconndefaults()) {
+			PQconninfoOption *option;
+			for (option = infoOptions; option->keyword != NULL; option++) {
+				if (option->val != NULL) {
+					hv_store(RETVAL, option->keyword, strlen(option->keyword), newSVpv(option->val, 0), 0);
 				} else {
-					hv_store(RETVAL, infoOption->keyword, strlen(infoOption->keyword), newSVpv("", 0), 0);
+					hv_store(RETVAL, option->keyword, strlen(option->keyword), newSVpv("", 0), 0);
 				}
-				infoOption++;
 			}
+			PQconninfoFree(infoOptions);
 		}
 	OUTPUT:
 		RETVAL