diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index 8f926922241e84c98fabc07053f6a51f91b48848..560feffadc988300919c1e05af992660301380ea 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -57,14 +57,13 @@ header file <FileName>libpq-fe.h</FileName> and must link with the
 <synopsis>
 PGconn *PQconnectdb(const char *conninfo)
 </synopsis>
-   This routine opens a new database connection using the parameters
-   taken from the string <literal>conninfo</literal>.  Unlike PQsetdbLogin()
-   below, the parameter set
-   can be extended without changing the function signature, so use
-   of this routine is prefered for application programming.  The passed
-   string can be empty to use all default
-   parameters, or it can contain one or more parameter settings
-   separated by whitespace. 
+   This routine opens a new database connection using the parameters taken
+   from the string <literal>conninfo</literal>.  Unlike PQsetdbLogin() below,
+   the parameter set can be extended without changing the function signature,
+   so use either of this routine or the non-blocking analogues PQconnectStart
+   / PQconnectPoll is prefered for application programming.  The passed string
+   can be empty to use all default parameters, or it can contain one or more
+   parameter settings separated by whitespace.
    </Para>
    <Para>
    Each parameter setting is in the form <literal>keyword = value</literal>.
@@ -80,8 +79,38 @@ PGconn *PQconnectdb(const char *conninfo)
      <term><literal>host</literal></term>
      <ListItem>
      <Para>
-      Host to connect to. If a non-zero-length string is specified, TCP/IP communication is used.
-      Without a host name, libpq will connect using a local Unix domain socket.
+      Name of host to connect to. If a non-zero-length string is specified, TCP/IP
+      communication is used.  Using this parameter causes a hostname look-up.
+      See hostaddr.
+     </Para>
+     </ListItem>
+    </VarListEntry>
+
+    <VarListEntry>
+     <term><literal>hostaddr</literal></term>
+     <ListItem>
+     <Para>
+      IP address of host to connect to. This should be in standard
+      numbers-and-dots form, as used by the BSD functions inet_aton et al. If
+      a non-zero-length string is specified, TCP/IP communication is used.
+     </Para>
+     <Para>
+      Using hostaddr instead of host allows the application to avoid a host
+      name look-up, which may be important in applications with time
+      constraints. However, Kerberos authentication requires the host
+      name. The following therefore applies. If host is specified without
+      hostaddr, a hostname look-up is forced. If hostaddr is specified without
+      host, the value for hostaddr gives the remote address; if Kerberos is
+      used, this causes a reverse name query. If both host and hostaddr are
+      specified, the value for hostaddr gives the remote address; the value
+      for host is ignored, unless Kerberos is used, in which case that value
+      is used for Kerberos authentication. Note that authentication is likely
+      to fail if libpq is passed a host name which is not the name of the
+      machine at hostaddr.
+     </Para>
+     <Para>
+      Without both a host name and host address, libpq will connect using a
+      local Unix domain socket.
      </Para>
      </ListItem>
     </VarListEntry>
@@ -149,6 +178,9 @@ PGconn *PQconnectdb(const char *conninfo)
    The return value is a pointer to an abstract struct
    representing the connection to the backend.
    </Para>
+   <Para>
+    This function is not thread-safe.
+   </Para>
   </ListItem>
 
   <ListItem>
@@ -167,6 +199,9 @@ PGconn *PQsetdbLogin(const char *pghost,
    This is the predecessor of <function>PQconnectdb</function> with a fixed number
    of parameters but the same functionality.   
    </Para>
+   <Para>
+    This function is not thread-safe.
+   </Para>
   </ListItem>
 
   <ListItem>
@@ -185,6 +220,173 @@ PGconn *PQsetdb(char *pghost,
    </Para>
   </ListItem>
 
+ <ListItem>
+  <Para>
+   <Function>PQconnectStart</Function>
+   <Function>PQconnectPoll</Function>
+   Make a connection to the database server in a non-blocking manner.
+<synopsis>
+PGconn *PQconnectStart(const char *conninfo)
+</synopsis>
+<synopsis>
+PostgresPollingStatusType *PQconnectPoll(PQconn *conn)
+</synopsis>
+   These two routines are used to open a connection to a database server such
+   that your application's thread of execution is not blocked on remote I/O
+   whilst doing so.
+  </Para>
+  <Para>
+   The database connection is made using the parameters taken from the string
+   <literal>conninfo</literal>, passed to PQconnectStart. This string is in
+   the same format as described above for PQconnectdb.
+  </Para>
+  <Para>
+   Neither PQconnectStart nor PQconnectPoll will block, as long as a number of
+   restrictions are met:
+   <ItemizedList>
+    <ListItem>
+     <Para>
+      The hostaddr and host parameters are used appropriately to ensure that
+      name and reverse name queries are not made. See the documentation of
+      these parameters under PQconnectdb above for details.
+     </Para>
+    </ListItem>
+
+    <ListItem>
+     <Para>
+      If you call PQtrace, ensure that the stream object into which you trace
+      will not block.
+     </Para>
+    </ListItem>
+
+    <ListItem>
+     <Para>
+      You ensure for yourself that the socket is in the appropriate state
+      before calling PQconnectPoll, as described below.
+     </Para>
+    </ListItem>
+   </ItemizedList>
+  </Para>
+
+  <Para>
+   To begin, call conn=PQconnectStart("&lt;connection_info_string&gt;"). If
+   conn is NULL, then libpq has been unable to allocate a new PGconn
+   structure. Otherwise, a valid PGconn pointer is returned (though not yet
+   representing a valid connection to the database). On return from
+   PQconnectStart, call status=PQstatus(conn). If status equals
+   CONNECTION_BAD, PQconnectStart has failed.
+  </Para>
+  <Para>
+   If PQconnectStart succeeds, the next stage is to poll libpq so that it may
+   proceed with the connection sequence.  Loop thus: Consider a connection
+   'inactive' by default. If PQconnectPoll last returned PGRES_POLLING_ACTIVE,
+   consider it 'active' instead. If PQconnectPoll(conn) last returned
+   PGRES_POLLING_READING, perform a select for reading on PQsocket(conn). If
+   it last returned PGRES_POLLING_WRITING, perform a select for writing on
+   PQsocket(conn). If you have yet to call PQconnectPoll, i.e. after the call
+   to PQconnectStart, behave as if it last returned PGRES_POLLING_WRITING.  If
+   the select shows that the socket is ready, consider it 'active'. If it has
+   been decided that this connection is 'active', call PQconnectPoll(conn)
+   again. If this call returns PGRES_POLLING_FAILED, the connection procedure
+   has failed.  If this call returns PGRES_POLLING_OK, the connection has been
+   successfully made.
+  </Para>
+  <Para>
+    Note that the use of select() to ensure that the socket is ready is merely
+    a (likely) example; those with other facilities available, such as a
+    poll() call, may of course use that instead.
+  </Para>
+  <Para>
+    At any time during connection, the status of the connection may be
+    checked, by calling PQstatus. If this is CONNECTION_BAD, then the
+    connection procedure has failed; if this is CONNECTION_OK, then the
+    connection is ready.  Either of these states should be equally detectable
+    from the return value of PQconnectPoll, as above. Other states may be
+    shown during (and only during) an asynchronous connection procedure. These
+    indicate the current stage of the connection procedure, and may be useful
+    to provide feedback to the user for example. These statuses may include:
+    <ItemizedList>
+     <ListItem>
+      <Para>
+      CONNECTION_STARTED: Waiting for connection to be made.
+      </Para>
+     </ListItem>
+     <ListItem>
+      <Para>
+      CONNECTION_MADE: Connection OK; waiting to send.
+      </Para>
+     </ListItem>
+     <ListItem>
+      <Para>
+      CONNECTION_AWAITING_RESPONSE: Waiting for a response from the backend.
+      </Para>
+     </ListItem>
+     <ListItem>
+      <Para>
+      CONNECTION_AUTH_RESPONSE: Got an authentication response; about to deal
+      with it.
+      </Para>
+     </ListItem>
+     <ListItem>
+      <Para>
+      CONNECTION_ERROR_RESPONSE: Got an error response; about to deal with it.
+      </Para>
+     </ListItem>
+     <ListItem>
+      <Para>
+      CONNECTION_AUTH_OK: Received authentication; waiting for ReadyForQuery etc.
+      </Para>
+     </ListItem>
+     <ListItem>
+      <Para>
+      CONNECTION_SETENV: Negotiating environment.
+      </Para>
+     </ListItem>
+    </ItemizedList>
+
+    Note that, although these constants will remain (in order to maintain
+    compatibility) an application should never rely upon these appearing in a
+    particular order, or at all, or on the status always being one of these
+    documented values. An application may do something like this:
+<ProgramListing>
+    switch(PQstatus(conn))
+    {
+        case CONNECTION_STARTED:
+            feedback = "Connecting...";
+	    break;
+
+        case CONNECTION_MADE:
+            feedback = "Connected to server...";
+            break;
+.
+.
+.
+        default:
+	    feedback = "Connecting...";
+    }
+</ProgramListing>
+  </Para>
+  <Para>
+   Note that if PQconnectStart returns a non-NULL pointer, you must call
+   PQfinish upon that, when you are finished with it, in order to dispose of
+   the structure and any associated memory blocks. This must be done even if a
+   call to PQconnectStart or PQconnectPoll failed.
+  </Para>
+  <Para>
+   PQconnectPoll will currently block if libpq is compiled with USE_SSL
+   defined. This restriction may be removed in the future.
+  </Para>
+  <Para>
+   PQconnectPoll will currently block under Windows, unless libpq is compiled
+   with WIN32_NON_BLOCKING_CONNECTIONS defined. This code has not yet been
+   tested under Windows, and so it is currently off by default. This may be
+   changed in the future.
+  </Para>
+  <Para>
+   These functions are not thread-safe.
+  </Para>
+ </ListItem>
+
   <ListItem>
    <Para>
    <Function>PQconndefaults</Function> Returns the default connection options.
@@ -215,6 +417,9 @@ struct PQconninfoOption
    will depend on environment variables and other context.
    Callers must treat the connection options data as read-only.
    </Para>
+   <Para>
+    This function is not thread-safe.
+   </Para>
   </ListItem>
 
   <ListItem>
@@ -247,6 +452,31 @@ void PQreset(PGconn *conn)
    </Para>
   </ListItem>
 
+  <ListItem>
+   <Para>
+   <Function>PQresetStart</Function>
+   <Function>PQresetPoll</Function>
+   Reset the communication  port  with  the  backend, in a non-blocking manner.
+<synopsis>
+int PQresetStart(PGconn *conn);
+</synopsis>
+<synopsis>
+PostgresPollingStatusType PQresetPoll(PGconn *conn);
+</synopsis>
+    These functions will close the connection to the backend and attempt to
+    reestablish a new connection to the same postmaster, using all the same
+    parameters previously used. This may be useful for error recovery if a
+    working connection is lost. They differ from PQreset (above) in that they
+    act in a non-blocking manner. These functions suffer from the same
+    restrictions as PQconnectStart and PQconnectPoll.
+   </Para>
+   <Para>
+    Call PQresetStart. If it returns 0, the reset has failed. If it returns 1,
+    poll the reset using PQresetPoll in exactly the same way as you would
+    create the connection using PQconnectPoll.
+   </Para>
+  </ListItem>
+
  </ItemizedList>
 </Para>
 
@@ -338,19 +568,25 @@ const char *PQoptions(const PGconn *conn)
 <Para>
 <Function>PQstatus</Function>
          Returns the status of the connection. 
-         The status can be <literal>CONNECTION_OK</literal> or <literal>CONNECTION_BAD</literal>.
 <synopsis>
 ConnStatusType PQstatus(const PGconn *conn)
 </synopsis>
 </Para>
 
 <Para>
-A failed connection attempt is signaled by status <literal>CONNECTION_BAD</literal>.
-Ordinarily, an OK status will remain so until <function>PQfinish</function>, but a
+The status can be one of a number of values. However, only two of these are
+seen outside of an asynchronous connection procedure -
+<literal>CONNECTION_OK</literal> or <literal>CONNECTION_BAD</literal>. A good
+connection to the database has the status CONNECTION_OK. A failed connection
+attempt is signaled by status <literal>CONNECTION_BAD</literal>.  Ordinarily,
+an OK status will remain so until <function>PQfinish</function>, but a
 communications failure might result in the status changing to
-<literal>CONNECTION_BAD</literal> prematurely.  In that case the application could
-try to recover by calling <function>PQreset</function>.
+<literal>CONNECTION_BAD</literal> prematurely.  In that case the application
+could try to recover by calling <function>PQreset</function>.
 </Para>
+<Para>
+See the entry for PQconnectStart and PQconnectPoll with regards to other status codes
+that might be seen.
 </ListItem>
 
 <ListItem>
@@ -385,6 +621,60 @@ server host, not the local host!
 </Para>
 </ListItem>
 
+ <ListItem>
+  <Para>
+   <Function>PQsetenvStart</Function>
+   <Function>PQsetenvPoll</Function>
+   <Function>PQsetenvAbort</Function>
+   Perform an environment negotiation.
+<synopsis>
+PGsetenvHandle *PQsetenvStart(PGconn *conn)
+</synopsis>
+<synopsis>
+PostgresPollingStatusType *PQsetenvPoll(PGsetenvHandle handle)
+</synopsis>
+<synopsis>
+void PQsetenvAbort(PGsetenvHandle handle)
+</synopsis>
+   These two routines can be used to re-perform the environment negotiation
+   that occurs during the opening of a connection to a database server. I have
+   no idea why this might be useful (XXX anyone?) but it might prove useful
+   for users to be able to reconfigure their character encodings on-the-fly,
+   for example.
+  </Para>
+  <Para>
+   These functions will not block, subject to the restrictions applied to
+   PQconnectStart and PQconnectPoll.
+  </Para>
+  <Para>
+   To begin, call handle=PQsetenvStart(conn), where conn is an open connection
+   to the database server. If handle is NULL, then libpq has been unable to
+   allocate a new PGsetenvHandle structure. Otherwise, a valid handle is
+   returned. This handle is intended to be opaque - you may only use it to
+   call other functions in libpq (PQsetenvPoll, for example).
+  </Para>
+  <Para>
+    Poll the procedure using PQsetenvPoll, in exactly the same way as you would
+    create a connection using PQconnectPoll.
+  </Para>
+  <Para>
+    The procedure may be aborted at any time by calling PQsetenvAbort(handle).
+  </Para>
+  <Para>
+   These functions are not thread-safe.
+  </Para>
+ </ListItem>
+
+ <ListItem>
+  <Para>
+   <Function>PQsetenv</Function>
+   Perform an environment negotiation.
+<synopsis>
+int PQsetenv(PGconn *conn)
+</synopsis>
+   This function performs the same duties as PQsetenvStart and PQsetenvPoll, but
+   blocks to do so. It returns 1 on success and 0 on failure.
+  </Para>
 </ItemizedList>
 </Para>
 </Sect1>
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 7e2fb4437975807ccfbc8a5d8321c75a613d1b77..85764b1e9d405d0cbfcea057ddadbc39199163bb 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -7,11 +7,13 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.106 1999/11/11 00:10:13 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.107 1999/11/30 03:08:18 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
 
+#include <sys/types.h>
+#include <sys/socket.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <ctype.h>
@@ -27,6 +29,7 @@
 #include <unistd.h>
 #include <netdb.h>
 #include <netinet/tcp.h>
+#include <arpa/inet.h>
 #endif
 
 #ifndef HAVE_STRDUP
@@ -40,11 +43,37 @@
 #include "mb/pg_wchar.h"
 #endif
 
+/* ----------
+ *     pg_setenv_state
+ * A struct used when polling a setenv request. This is referred to externally
+ * using a PGsetenvHandle.
+ * ----------
+ */
+struct pg_setenv_state
+{
+	enum
+	{
+		SETENV_STATE_OPTION_SEND,    /* About to send an Environment Option */
+		SETENV_STATE_OPTION_WAIT,    /* Waiting for above send to complete  */
+#ifdef MULTIBYTE
+		SETENV_STATE_ENCODINGS_SEND, /* About to send an "encodings" query  */
+		SETENV_STATE_ENCODINGS_WAIT, /* Waiting for query to complete       */
+#endif
+		SETENV_STATE_OK,
+		SETENV_STATE_FAILED
+	} state;
+	PGconn *conn;
+	PGresult *res;
+	struct EnvironmentOptions *eo;
+} ;
+
+static int connectDBStart(PGconn *conn);
+static int connectDBComplete(PGconn *conn);
+
 #ifdef USE_SSL
 static SSL_CTX *SSL_context = NULL;
 #endif
 
-static ConnStatusType connectDB(PGconn *conn);
 static PGconn *makeEmptyPGconn(void);
 static void freePGconn(PGconn *conn);
 static void closePGconn(PGconn *conn);
@@ -53,9 +82,6 @@ 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);
-
 #define NOTIFYLIST_INITIAL_SIZE 10
 #define NOTIFYLIST_GROWBY 10
 
@@ -98,6 +124,9 @@ static PQconninfoOption PQconninfoOptions[] = {
 	{"host", "PGHOST", NULL, NULL,
 	"Database-Host", "", 40},
 
+	{"hostaddr", "PGHOSTADDR", NULL, NULL,
+	 "Database-Host-IPv4-Address", "", 15}, /* Room for abc.def.ghi.jkl */
+
 	{"port", "PGPORT", DEF_PGPORT, NULL,
 	"Database-Port", "", 6},
 
@@ -145,27 +174,86 @@ static struct EnvironmentOptions
 	}
 };
 
+
+/* ----------------
+ *      Connecting to a Database
+ *
+ * There are now four different ways a user of this API can connect to the
+ * database.  Two are not recommended for use in new code, because of their
+ * lack of extensibility with respect to the passing of options to the
+ * backend.  These are PQsetdb and PQsetdbLogin (the former now being a macro
+ * to the latter).
+ *
+ * If it is desired to connect in a synchronous (blocking) manner, use the
+ * function PQconnectdb.
+ *
+ * To connect in an asychronous (non-blocking) manner, use the functions
+ * PQconnectStart, and PQconnectPoll.
+ *
+ * Internally, the static functions connectDBStart, connectDBComplete
+ * are part of the connection procedure.
+ * 
+ * ----------------
+ */
+
 /* ----------------
  *		PQconnectdb
  *
  * establishes a connection to a postgres backend through the postmaster
  * using connection information in a string.
  *
- * The conninfo string is a list of
+ * The conninfo string is a white-separated list of
  *
  *	   option = value
  *
- * definitions. Value might be a single value containing no whitespaces
- * or a single quoted string. If a single quote should appear everywhere
- * in the value, it must be escaped with a backslash like \'
+ * definitions. Value might be a single value containing no whitespaces or
+ * a single quoted string. If a single quote should appear anywhere in
+ * the value, it must be escaped with a backslash like \'
  *
- * Returns a PGconn* which is needed for all subsequent libpq calls
- * if the status field of the connection returned is CONNECTION_BAD,
- * then some fields may be null'ed out instead of having valid values
- * ----------------
- */
+ * Returns a PGconn* which is needed for all subsequent libpq calls, or NULL
+ * if a memory allocation failed.
+ * If the status field of the connection returned is CONNECTION_BAD,
+ * then some fields may be null'ed out instead of having valid values.
+ *
+ * You should call PQfinish (if conn is not NULL) regardless of whether this
+ * call succeeded.
+ *
+ * ---------------- */
+
 PGconn *
 PQconnectdb(const char *conninfo)
+{
+	PGconn *conn = PQconnectStart(conninfo);
+	
+	(void)(!conn || (conn->status == CONNECTION_BAD) ||
+		   !connectDBComplete(conn));
+
+	return conn;
+}
+
+/* ----------------
+ *		PQconnectStart
+ *
+ * Begins the establishment of a connection to a postgres backend through the
+ * postmaster using connection information in a string.
+ *
+ * See comment for PQconnectdb for the definition of the string format.
+ *
+ * Returns a PGconn*.  If NULL is returned, a malloc error has occurred, and
+ * you should not attempt to proceed with this connection.  If the status
+ * field of the connection returned is CONNECTION_BAD, an error has
+ * occurred. In this case you should call PQfinish on the result, (perhaps
+ * inspecting the error message first).  Other fields of the structure may not
+ * be valid if that occurs.  If the status field is not CONNECTION_BAD, then
+ * this stage has succeeded - call PQconnectPoll, using select(2) to see when
+ * this is necessary.
+ *
+ * See PQconnectPoll for more info.
+ *
+ * ---------------- */
+
+PGconn *
+PQconnectStart(const char *conninfo)
 {
 	PGconn	   *conn;
 	char	   *tmp;
@@ -174,6 +262,7 @@ PQconnectdb(const char *conninfo)
 	 * Allocate memory for the conn structure
 	 * ----------
 	 */
+	
 	conn = makeEmptyPGconn();
 	if (conn == NULL)
 		return (PGconn *) NULL;
@@ -188,6 +277,8 @@ PQconnectdb(const char *conninfo)
 		conninfo_free();
 		return conn;
 	}
+	tmp = conninfo_getval("hostaddr");
+	conn->pghostaddr = tmp ? strdup(tmp) : NULL;
 	tmp = conninfo_getval("host");
 	conn->pghost = tmp ? strdup(tmp) : NULL;
 	tmp = conninfo_getval("port");
@@ -213,7 +304,11 @@ PQconnectdb(const char *conninfo)
 	 * Connect to the database
 	 * ----------
 	 */
-	conn->status = connectDB(conn);
+	if (!connectDBStart(conn))
+	{
+	  /* Just in case we failed to set it in connectDBStart */
+		conn->status = CONNECTION_BAD;
+	}
 
 	return conn;
 }
@@ -384,10 +479,14 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, cons
 	}
 
 	if (error)
+	{
 		conn->status = CONNECTION_BAD;
+	}
 	else
-		conn->status = connectDB(conn);
-
+	{
+		(void)(!connectDBStart(conn) || !connectDBComplete(conn));
+	}
+		
 	return conn;
 }
 
@@ -480,7 +579,9 @@ update_db_info(PGconn *conn)
 				if (strcmp(old + offset, "localhost") != 0)
 				{
 					printfPQExpBuffer(&conn->errorMessage,
-									  "connectDB() -- non-tcp access only possible on localhost\n");
+									  "connectDBStart() -- "
+									  "non-tcp access only possible on "
+									  "localhost\n");
 					return 1;
 				}
 			}
@@ -494,24 +595,84 @@ update_db_info(PGconn *conn)
 	return 0;
 }
 
-/*
- * connectDB -
- * make a connection to the backend so it is ready to receive queries.
- * return CONNECTION_OK if successful, CONNECTION_BAD if not.
- *
+
+/* ----------
+ * connectMakeNonblocking -
+ * Make a connection non-blocking.
+ * Returns 1 if successful, 0 if not.
+ * ----------
  */
-static ConnStatusType
-connectDB(PGconn *conn)
+static int
+connectMakeNonblocking(PGconn *conn)
+{
+#ifndef WIN32
+	if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) < 0)
+#else
+	if (ioctlsocket(conn->sock, FIONBIO, &on) != 0)
+#endif
+	{
+		printfPQExpBuffer(&conn->errorMessage,
+						  "connectMakeNonblocking -- fcntl() failed: errno=%d\n%s\n",
+						  errno, strerror(errno));
+		return 0;
+	}
+
+	return 1;
+}
+
+/* ----------
+ * connectNoDelay -
+ * Sets the TCP_NODELAY socket option.
+ * Returns 1 if successful, 0 if not.
+ * ----------
+ */
+static int
+connectNoDelay(PGconn *conn)
+{
+	struct protoent *pe;
+	int			on = 1;
+
+	pe = getprotobyname("TCP");
+	if (pe == NULL)
+	{
+		printfPQExpBuffer(&conn->errorMessage,
+						  "connectNoDelay() -- "
+						  "getprotobyname failed: errno=%d\n%s\n",
+						  errno, strerror(errno));
+		return 0;
+	}
+	if (setsockopt(conn->sock, pe->p_proto, TCP_NODELAY,
+#ifdef WIN32
+				   (char *)
+#endif
+				   &on,
+				   sizeof(on)) < 0)
+	{
+		printfPQExpBuffer(&conn->errorMessage,
+						  "connectNoDelay() -- setsockopt failed: errno=%d\n%s\n",
+						  errno, strerror(errno));
+#ifdef WIN32
+		printf("Winsock error: %i\n", WSAGetLastError());
+#endif
+		return 0;
+	}
+
+	return 1;
+}
+
+
+/* ----------
+ * connectDBStart -
+ * Start to make a connection to the backend so it is ready to receive
+ * queries.
+ * Returns 1 if successful, 0 if not.
+ * ----------
+ */
+static int
+connectDBStart(PGconn *conn)
 {
-	PGresult   *res;
-	struct hostent *hp;
-	StartupPacket sp;
-	AuthRequest areq;
-	SOCKET_SIZE_TYPE laddrlen;
 	int			portno,
 				family;
-	char		beresp;
-	int			on = 1;
 #ifdef USE_SSL
 	StartupPacket           np; /* Used to negotiate SSL connection */
 	char                    SSLok;
@@ -519,92 +680,126 @@ connectDB(PGconn *conn)
 	int                     tried_ssl = 0;      /* Set if SSL negotiation was tried */
 #endif
 
+	if (!conn)
+		return 0;
 	/*
 	 * parse dbName to get all additional info in it, if any
 	 */
 	if (update_db_info(conn) != 0)
 		goto connect_errReturn;
 
+	/* Ensure our buffers are empty */
+	conn->inStart = conn->inCursor = conn->inEnd = 0;
+	conn->outCount = 0;
+
 	/*
-	 * Initialize the startup packet.
+	 * Set up the connection to postmaster/backend.
+	 * Note that this supports IPv4 and UDP only.
 	 */
 
-	MemSet((char *) &sp, 0, sizeof(StartupPacket));
-
-	sp.protoVersion = (ProtocolVersion) htonl(PG_PROTOCOL_LIBPQ);
+	MemSet((char *) &conn->raddr, 0, sizeof(conn->raddr));
 
-	strncpy(sp.user, conn->pguser, SM_USER);
-	strncpy(sp.database, conn->dbName, SM_DATABASE);
-	strncpy(sp.tty, conn->pgtty, SM_TTY);
+	if (conn->pghostaddr != NULL)
+	{
+		/* Using pghostaddr avoids a hostname lookup */
+		/* Note that this supports IPv4 only */
+		struct in_addr addr;
 
-	if (conn->pgoptions)
-		strncpy(sp.options, conn->pgoptions, SM_OPTIONS);
+		if(!inet_aton(conn->pghostaddr, &addr))
+		{
+			printfPQExpBuffer(&conn->errorMessage,
+							  "connectDBStart() -- "
+							  "invalid host address: %s\n", conn->pghostaddr);
+			goto connect_errReturn;
+		}
 
-	/*
-	 * Open a connection to postmaster/backend.
-	 */
+		family = AF_INET;
 
-	if (conn->pghost != NULL)
+		memmove((char *) &(conn->raddr.in.sin_addr),
+				(char *) &addr, sizeof(addr));
+	}
+	else if (conn->pghost != NULL)
 	{
+		/* Using pghost, so we have to look-up the hostname */
+		struct hostent *hp;
+
 		hp = gethostbyname(conn->pghost);
 		if ((hp == NULL) || (hp->h_addrtype != AF_INET))
 		{
 			printfPQExpBuffer(&conn->errorMessage,
-							  "connectDB() --  unknown hostname: %s\n",
+							  "connectDBStart() --  unknown hostname: %s\n",
 							  conn->pghost);
 			goto connect_errReturn;
 		}
 		family = AF_INET;
+
+		memmove((char *) &(conn->raddr.in.sin_addr),
+				(char *) hp->h_addr,
+				hp->h_length);
 	}
 	else
 	{
-		hp = NULL;
+		/* pghostaddr and pghost are NULL, so use UDP */
 		family = AF_UNIX;
 	}
 
-	MemSet((char *) &conn->raddr, 0, sizeof(conn->raddr));
+	/* Set family */
 	conn->raddr.sa.sa_family = family;
 
+	/* Set port number */
 	portno = atoi(conn->pgport);
 	if (family == AF_INET)
 	{
-		memmove((char *) &(conn->raddr.in.sin_addr),
-				(char *) hp->h_addr,
-				hp->h_length);
 		conn->raddr.in.sin_port = htons((unsigned short) (portno));
 		conn->raddr_len = sizeof(struct sockaddr_in);
 	}
 #if !defined(WIN32) && !defined(__CYGWIN32__)
-	else
-		conn->raddr_len = UNIXSOCK_PATH(conn->raddr.un, portno);
+		else
+			conn->raddr_len = UNIXSOCK_PATH(conn->raddr.un, portno);
 #endif
 
 
-	/* Connect to the server  */
+	/* Open a socket */
 	if ((conn->sock = socket(family, SOCK_STREAM, 0)) < 0)
 	{
 		printfPQExpBuffer(&conn->errorMessage,
-						  "connectDB() -- socket() failed: errno=%d\n%s\n",
+						  "connectDBStart() -- "
+						  "socket() failed: errno=%d\n%s\n",
 						  errno, strerror(errno));
 		goto connect_errReturn;
 	}
-	if (connect(conn->sock, &conn->raddr.sa, conn->raddr_len) < 0)
+
+	/* ----------
+	 * Set the right options. Normally, we need nonblocking I/O, and we don't
+	 * want delay of outgoing data for AF_INET sockets.  If we are using SSL,
+	 * then we need the blocking I/O (XXX Can this be fixed?).
+	 * ---------- */
+
+	if (family == AF_INET)
 	{
-		printfPQExpBuffer(&conn->errorMessage,
-						  "connectDB() -- connect() failed: %s\n"
-						  "Is the postmaster running%s at '%s' and accepting connections on %s '%s'?\n",
-						  strerror(errno),
-						  (family == AF_INET) ? " (with -i)" : "",
-						  conn->pghost ? conn->pghost : "localhost",
-						  (family == AF_INET) ? "TCP/IP port" : "Unix socket",
-						  conn->pgport);
-		goto connect_errReturn;
+		if (!connectNoDelay(conn))
+			goto connect_errReturn;
 	}
 
+	/* ----------
+	 * Since I have no idea whether this is a valid thing to do under Windows
+	 * before a connection is made, and since I have no way of testing it, I
+	 * leave the code looking as below.  When someone decides that they want
+	 * non-blocking connections under Windows, they can define
+	 * WIN32_NON_BLOCKING_CONNECTIONS before compilation.  If it works, then
+	 * this code can be cleaned up.
+	 *
+	 *   Ewan Mellor <eem21@cam.ac.uk>.
+	 * ---------- */
+#if (!defined(WIN32) || defined(WIN32_NON_BLOCKING_CONNECTIONS)) && !defined(USE_SSL)
+	if (!connectMakeNonblocking(conn))
+		goto connect_errReturn;
+#endif	
+
+#ifdef USE_SSL
 	/* This needs to be done before we set into nonblocking, since SSL negotiation
 	 * does not like that mode */
 
-#ifdef USE_SSL
 	/* Attempt to negotiate SSL usage */
 	if (allow_ssl_try) {
 	  tried_ssl = 1;
@@ -653,7 +848,7 @@ connectDB(PGconn *conn)
 	      fprintf(conn->Pfdebug, "Backend reports error, attempting fallback to pre-6.6.\n");
 	    close(conn->sock);
 	    allow_ssl_try = 0;
-	    return connectDB(conn);
+	    return connectDBStart(conn);
 	  }
 	  else if (SSLok != 'N') {
 	    strcpy(conn->errorMessage,
@@ -665,242 +860,812 @@ connectDB(PGconn *conn)
 	  allow_ssl_try = 1; /* We'll allow an attempt to use SSL next time */
 #endif
 
-	/*
-	 * Set the right options. We need nonblocking I/O, and we don't want
-	 * delay of outgoing data.
+	/* ----------
+     * Start / make connection.  We are hopefully in non-blocking mode
+	 * now, but it is possible that:
+	 *   1. Older systems will still block on connect, despite the
+	 *      non-blocking flag. (Anyone know if this is true?)
+	 *   2. We are running under Windows, and aren't even trying
+	 *      to be non-blocking (see above).
+	 *   3. We are using SSL.
+	 * Thus, we have make arrangements for all eventualities.
+	 * ----------
 	 */
-
-#ifndef WIN32
-	if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) < 0)
-#else
-	if (ioctlsocket(conn->sock, FIONBIO, &on) != 0)
-#endif
-	{
-		printfPQExpBuffer(&conn->errorMessage,
-						  "connectDB() -- fcntl() failed: errno=%d\n%s\n",
-						  errno, strerror(errno));
-		goto connect_errReturn;
-	}
-
-	if (family == AF_INET)
+	if (connect(conn->sock, &conn->raddr.sa, conn->raddr_len) < 0)
 	{
-		struct protoent *pe;
-
-		pe = getprotobyname("TCP");
-		if (pe == NULL)
+		if (errno == EINPROGRESS)
 		{
-			printfPQExpBuffer(&conn->errorMessage,
-							  "connectDB(): getprotobyname failed\n");
-			goto connect_errReturn;
+			/* This is fine - we're in non-blocking mode, and the
+			 * connection is in progress. */
+			conn->status = CONNECTION_STARTED;
 		}
-		if (setsockopt(conn->sock, pe->p_proto, TCP_NODELAY,
-#ifdef WIN32
-					   (char *)
-#endif
-					   &on,
-					   sizeof(on)) < 0)
+		else
 		{
+			/* Something's gone wrong */
 			printfPQExpBuffer(&conn->errorMessage,
-							  "connectDB() -- setsockopt failed: errno=%d\n%s\n",
-							  errno, strerror(errno));
-#ifdef WIN32
-			printf("Winsock error: %i\n", WSAGetLastError());
-#endif
+							  "connectDBStart() -- connect() failed: %s\n"
+							  "Is the postmaster running%s at '%s' "
+							  "and accepting connections on %s '%s'?\n",
+							  strerror(errno),
+							  (family == AF_INET) ? " (with -i)" : "",
+							  conn->pghost ? conn->pghost : "localhost",
+							  (family == AF_INET) ?
+							  "TCP/IP port" : "Unix socket",
+							  conn->pgport);
 			goto connect_errReturn;
 		}
 	}
-
-	/* Fill in the client address */
-	laddrlen = sizeof(conn->laddr);
-	if (getsockname(conn->sock, &conn->laddr.sa, &laddrlen) < 0)
+	else
 	{
-		printfPQExpBuffer(&conn->errorMessage,
-						  "connectDB() -- getsockname() failed: errno=%d\n%s\n",
-						  errno, strerror(errno));
-		goto connect_errReturn;
+		/* We're connected already */
+		conn->status = CONNECTION_MADE;
 	}
 
-	/* Ensure our buffers are empty */
-	conn->inStart = conn->inCursor = conn->inEnd = 0;
-	conn->outCount = 0;
+	/* This makes the connection non-blocking, for all those cases which forced us
+	   not to do it above. */
+#if (defined(WIN32) && !defined(WIN32_NON_BLOCKING_CONNECTIONS)) || defined(USE_SSL)
+	if (!connectMakeNonblocking(conn))
+		goto connect_errReturn;
+#endif	
 
-	/* Send the startup packet. */
+	return 1;
 
-	if (pqPacketSend(conn, (char *) &sp, sizeof(StartupPacket)) != STATUS_OK)
+connect_errReturn:
+	if (conn->sock >= 0)
 	{
-		printfPQExpBuffer(&conn->errorMessage,
-						  "connectDB() --  couldn't send startup packet: errno=%d\n%s\n",
-						  errno, strerror(errno));
-		goto connect_errReturn;
+#ifdef WIN32
+		closesocket(conn->sock);
+#else
+		close(conn->sock);
+#endif
+		conn->sock = -1;
 	}
+	conn->status = CONNECTION_BAD;
 
-	/*
-	 * Perform the authentication exchange: wait for backend messages and
-	 * respond as necessary. We fall out of this loop when done talking to
-	 * the postmaster.
-	 */
+	return 0;
+}
 
-	for (;;)
-	{
-		/* Wait for some data to arrive (or for the channel to close) */
-		if (pqWait(TRUE, FALSE, conn))
-			goto connect_errReturn;
-		/* Load data, or detect EOF */
-		if (pqReadData(conn) < 0)
-			goto connect_errReturn;
 
-		/*
-		 * Scan the message. If we run out of data, loop around to try
-		 * again.
-		 */
-		conn->inCursor = conn->inStart;
+/* ----------------
+ *		connectDBComplete
+ *
+ * Block and complete a connection.
+ *
+ * Returns 1 on success, 0 on failure.
+ * ----------------
+ */
+static int
+connectDBComplete(PGconn *conn)
+{
+	PostgresPollingStatusType flag;
+	int r = 0, w = 1;
 
-		if (pqGetc(&beresp, conn))
-			continue;			/* no data yet */
+	do
+	{
+		if(pqWait(r, w, conn))
+		{
+			conn->status = CONNECTION_BAD;
+			return 0;
+		}
 
-		/* Handle errors. */
-		if (beresp == 'E')
+	again:
+		switch(flag = PQconnectPoll(conn))
 		{
-			if (pqGets(&conn->errorMessage, conn))
-				continue;
-			goto connect_errReturn;
+			case PGRES_POLLING_ACTIVE:
+				goto again;
+
+			case PGRES_POLLING_OK:
+				break;
+				
+			case PGRES_POLLING_READING:
+				r = 1;
+				w = 0;
+				break;
+
+			case PGRES_POLLING_WRITING:
+				r = 0;
+				w = 1;
+				break;
+
+			default:
+				/* Just in case we failed to set it in PQconnectPoll */
+				conn->status = CONNECTION_BAD;
+				return 0;
 		}
+	} while (flag != PGRES_POLLING_OK);
+	
+	return 1;
+}
+
+
+/* ----------------
+ *		PQconnectPoll
+ *
+ * Poll an asynchronous connection.
+ *
+ * Returns a PostgresPollingStatusType.
+ * Before calling this function, use select(2) to determine when data arrive.
+ * 
+ * You must call PQfinish whether or not this fails.
+ *
+ * This function and PQconnectStart are intended to allow connections to be
+ * made without blocking the execution of your program on remote I/O. However,
+ * there are a number of caveats:
+ *
+ *   o  If you call PQtrace, ensure that the stream object into which you trace
+        will not block.
+ *   o  If you do not supply an IP address for the remote host (i.e. you 
+ *      supply a host name instead) then this function will block on
+ *      gethostbyname.  You will be fine if using UDP (i.e. by supplying
+ *      neither a host name nor a host address).
+ *   o  If your backend wants to use Kerberos authentication then you must
+ *      supply both a host name and a host address, otherwise this function
+ *      may block on gethostname.
+ *   o  This function will block if compiled with USE_SSL.
+ *
+ * ---------------- */
+PostgresPollingStatusType
+PQconnectPoll(PGconn *conn)
+{
+	PGresult   *res;
 
-		/* Otherwise it should be an authentication request. */
-		if (beresp != 'R')
+	if (conn == NULL)
+		return PGRES_POLLING_FAILED;
+
+	/* Get the new data */
+	switch (conn->status)
+	{
+		/* We really shouldn't have been polled in these two cases, but
+		   we can handle it. */
+		case CONNECTION_BAD:
+			return PGRES_POLLING_FAILED;
+		case CONNECTION_OK:
+			return PGRES_POLLING_OK;
+
+		/* These are reading states */
+		case CONNECTION_AWAITING_RESPONSE:
+		case CONNECTION_AUTH_RESPONSE:
+		case CONNECTION_ERROR_RESPONSE:
+		case CONNECTION_AUTH_OK:
 		{
-			printfPQExpBuffer(&conn->errorMessage,
-							  "connectDB() -- expected authentication request\n");
-			goto connect_errReturn;
+			/* Load waiting data */
+			int n = pqReadData(conn);
+				
+			if (n < 0)
+				goto error_return;
+			if (n == 0)
+				return PGRES_POLLING_READING;
+
+			break;
 		}
 
-		/* Get the type of request. */
-		if (pqGetInt((int *) &areq, 4, conn))
-			continue;
+		/* These are writing states, so we just proceed. */
+		case CONNECTION_STARTED:
+		case CONNECTION_MADE:
+		   break;
 
-		/* Get the password salt if there is one. */
-		if (areq == AUTH_REQ_CRYPT)
+		case CONNECTION_SETENV:
+			/* We allow PQsetenvPoll to decide whether to proceed */
+			break;
+
+		default:
+			printfPQExpBuffer(&conn->errorMessage,
+							  "PQconnectPoll() -- unknown connection state - "
+							  "probably indicative of memory corruption!\n");
+			goto error_return;
+	}
+
+
+ keep_going: /* We will come back to here until there is nothing left to
+				parse. */
+	switch(conn->status)
+	{
+		case CONNECTION_STARTED:
 		{
-			if (pqGetnchar(conn->salt, sizeof(conn->salt), conn))
-				continue;
+			SOCKET_SIZE_TYPE laddrlen;
+			int optval;
+			socklen_t optlen = sizeof(int);
+
+			/* Write ready, since we've made it here, so the connection
+			 * has been made. */
+
+			/* Now check (using getsockopt) that there is not an error
+			   state waiting for us on the socket. */
+
+			if (getsockopt(conn->sock, SOL_SOCKET, SO_ERROR,
+						   &optval, &optlen) == -1)
+			{
+				printfPQExpBuffer(&conn->errorMessage,
+								  "PQconnectPoll() -- getsockopt() failed: "
+								  "errno=%d\n%s\n",
+								  errno, strerror(errno));
+				goto error_return;
+			}
+			else if (optval != 0)
+			{
+				printfPQExpBuffer(&conn->errorMessage,
+								  "PQconnectPoll() -- "
+								  "socket has error condition %d: %s.\n",
+								  optval, strerror(optval));
+				goto error_return;
+			}
+
+			/* Fill in the client address */
+			laddrlen = sizeof(conn->laddr);
+			if (getsockname(conn->sock, &conn->laddr.sa, &laddrlen) < 0)
+			{
+				printfPQExpBuffer(&conn->errorMessage,
+								  "PQconnectPoll() -- getsockname() failed: "
+								  "errno=%d\n%s\n",
+								  errno, strerror(errno));
+				goto error_return;
+			}
+
+			conn->status = CONNECTION_MADE;
+			return PGRES_POLLING_WRITING;
 		}
 
-		/* OK, we successfully read the message; mark data consumed */
-		conn->inStart = conn->inCursor;
+		case CONNECTION_MADE:
+		{
+			StartupPacket sp;
+			
+			/*
+			 * Initialize the startup packet.
+			 */
 
-		/* Respond to the request if necessary. */
-		/* fe-auth.c has not been fixed to support PQExpBuffers, so: */
-		if (fe_sendauth(areq, conn, conn->pghost, conn->pgpass,
-						conn->errorMessage.data) != STATUS_OK)
+			MemSet((char *) &sp, 0, sizeof(StartupPacket));
+	
+			sp.protoVersion = (ProtocolVersion) htonl(PG_PROTOCOL_LIBPQ);
+			
+			strncpy(sp.user, conn->pguser, SM_USER);
+			strncpy(sp.database, conn->dbName, SM_DATABASE);
+			strncpy(sp.tty, conn->pgtty, SM_TTY);
+
+			if (conn->pgoptions)
+				strncpy(sp.options, conn->pgoptions, SM_OPTIONS);
+
+			/* Send the startup packet. */
+
+			if (pqPacketSend(conn, (char *) &sp,
+							 sizeof(StartupPacket)) != STATUS_OK)
+			{
+				printfPQExpBuffer(&conn->errorMessage,
+								  "PQconnectPoll() --  "
+								  "couldn't send startup packet: "
+								  "errno=%d\n%s\n",
+								  errno, strerror(errno));
+				goto error_return;
+			}
+
+			conn->status = CONNECTION_AWAITING_RESPONSE;
+			return PGRES_POLLING_READING;
+		}
+
+
+		/*
+		 * Handle the authentication exchange: wait for backend messages
+		 * and respond as necessary.
+		 */
+		case CONNECTION_AWAITING_RESPONSE:
+		{
+			char		beresp;
+
+			/* Scan the message */
+			conn->inCursor = conn->inStart;
+
+			if (pqGetc(&beresp, conn))
+			{
+				/* We'll come back when there are more data */
+				return PGRES_POLLING_READING;
+			}
+
+			/* Handle errors. */
+			if (beresp == 'E')
+			{
+				conn->status = CONNECTION_ERROR_RESPONSE;
+				goto keep_going;
+			}
+
+			/* Otherwise it should be an authentication request. */
+			if (beresp != 'R')
+			{
+				printfPQExpBuffer(&conn->errorMessage,
+							   "PQconnectPoll() -- expected authentication "
+							   "request\n");
+				goto error_return;
+			}
+
+			/* Got an authentication request, so that's OK */
+			conn->status = CONNECTION_AUTH_RESPONSE;
+			goto keep_going;
+		}
+
+		case CONNECTION_AUTH_RESPONSE:
 		{
+			AuthRequest areq;
+			
+			/* Get the type of request. */
+			if (pqGetInt((int *) &areq, 4, conn))
+			{
+				/* We'll come back when there are more data */
+				return PGRES_POLLING_READING;
+			}
+
+			/* Get the password salt if there is one. */
+			if (areq == AUTH_REQ_CRYPT)
+			{
+				if (pqGetnchar(conn->salt, sizeof(conn->salt), conn))
+				{
+					/* We'll come back when there are more data */
+					return PGRES_POLLING_READING;
+				}
+			}
+
+			/* OK, we successfully read the message; mark data consumed */
+			conn->inStart = conn->inCursor;
+
+			/* Respond to the request if necessary. */
+			/* Note that conn->pghost must be non-NULL if we are going
+			 * avoid the Kerberos code doing a hostname look-up. */
+			/* XXX fe-auth.c has not been fixed to support PQExpBuffers, so: */
+			if (fe_sendauth(areq, conn, conn->pghost, conn->pgpass,
+							conn->errorMessage.data) != STATUS_OK)
+			{
+				conn->errorMessage.len = strlen(conn->errorMessage.data);
+				goto error_return;
+			}
 			conn->errorMessage.len = strlen(conn->errorMessage.data);
-			goto connect_errReturn;
+
+			/* This function has a section near the end that looks like it
+			 * should block.  I think that it will be OK though, since the
+			 * socket is non-blocking, and thus the data should get out
+			 * as quickly as possible.                                    */
+			if (pqFlush(conn))
+				goto error_return;
+
+			if (areq == AUTH_REQ_OK)
+			{
+				/* We are done with authentication exchange */
+				conn->status = CONNECTION_AUTH_OK;
+				/* Set asyncStatus so that PQsetResult will think that what
+				 * comes back next is the result of a query.  See below.  */
+				conn->asyncStatus = PGASYNC_BUSY;
+				goto keep_going;
+			}
+
+			conn->status = CONNECTION_AWAITING_RESPONSE;
+			return PGRES_POLLING_READING;
 		}
 
-		if (pqFlush(conn))
-			goto connect_errReturn;
+		case CONNECTION_ERROR_RESPONSE:
+			if (pqGets(&conn->errorMessage, conn))
+			{
+				/* We'll come back when there are more data */
+				return PGRES_POLLING_READING;
+			}
+			goto error_return;
 
-		/* Are we done? */
-		if (areq == AUTH_REQ_OK)
-			break;
-	}
+		case CONNECTION_AUTH_OK:
+		{
+			/* ----------
+			 * Now we expect to hear from the backend. A ReadyForQuery
+			 * message indicates that startup is successful, but we might
+			 * also get an Error message indicating failure. (Notice
+			 * messages indicating nonfatal warnings are also allowed by
+			 * the protocol, as is a BackendKeyData message.) Easiest way
+			 * to handle this is to let PQgetResult() read the messages. We
+			 * just have to fake it out about the state of the connection.
+			 *----------
+			 */
 
-	/*
-	 * Now we expect to hear from the backend. A ReadyForQuery message
-	 * indicates that startup is successful, but we might also get an
-	 * Error message indicating failure. (Notice messages indicating
-	 * nonfatal warnings are also allowed by the protocol, as is a
-	 * BackendKeyData message.) Easiest way to handle this is to let
-	 * PQgetResult() read the messages. We just have to fake it out about
-	 * the state of the connection.
-	 */
+			if (!PQconsumeInput(conn))
+				goto error_return;
 
-	conn->status = CONNECTION_OK;
-	conn->asyncStatus = PGASYNC_BUSY;
-	res = PQgetResult(conn);
-	/* NULL return indicating we have gone to IDLE state is expected */
-	if (res)
-	{
-		if (res->resultStatus != PGRES_FATAL_ERROR)
+			if(PQisBusy(conn))
+				return PGRES_POLLING_READING;
+			
+			res = PQgetResult(conn);
+			/* NULL return indicating we have gone to
+			   IDLE state is expected */
+			if (res)
+			{
+				if (res->resultStatus != PGRES_FATAL_ERROR)
+					printfPQExpBuffer(&conn->errorMessage,
+									  "PQconnectPoll() -- unexpected message "
+									  "during startup\n");
+				PQclear(res);
+				goto error_return;
+			}
+
+			/*
+			 * Post-connection housekeeping. Send environment variables
+			 * to server.
+			 */
+
+			if ((conn->setenv_handle = PQsetenvStart(conn)) == NULL)
+				goto error_return;
+
+			conn->status = CONNECTION_SETENV;
+
+			goto keep_going;
+		}
+
+		case CONNECTION_SETENV:
+			/* We pretend that the connection is OK for the duration of
+			   theses queries. */
+			conn->status = CONNECTION_OK;
+
+			switch(PQsetenvPoll(conn->setenv_handle))
+			{
+				case PGRES_POLLING_OK: /* Success */
+					conn->status = CONNECTION_OK;
+					return PGRES_POLLING_OK;
+
+				case PGRES_POLLING_READING: /* Still going */
+					conn->status = CONNECTION_SETENV;
+					return PGRES_POLLING_READING;
+
+				case PGRES_POLLING_WRITING: /* Still going */
+					conn->status = CONNECTION_SETENV;
+					return PGRES_POLLING_WRITING;
+
+				default:
+					conn->status = CONNECTION_SETENV;
+					goto error_return;
+			}
+			/* Unreachable */
+
+		default:
 			printfPQExpBuffer(&conn->errorMessage,
-							  "connectDB() -- unexpected message during startup\n");
-		PQclear(res);
-		goto connect_errReturn;
+							  "PQconnectPoll() -- unknown connection state - "
+							  "probably indicative of memory corruption!\n",
+							  sizeof(conn->errorMessage));
+			goto error_return;
 	}
 
-	/*
-	 * Post-connection housekeeping. Send environment variables to server
+	/* Unreachable */
+
+error_return:
+	/* ----------
+	 * We used to close the socket at this point, but that makes it awkward
+	 * for those above us if they wish to remove this socket from their
+	 * own records (an fd_set for example).  We'll just have this socket
+	 * closed when PQfinish is called (which is compulsory even after an
+	 * error, since the connection structure must be freed).
+	 * ----------
 	 */
+	return PGRES_POLLING_FAILED;
+}
 
-	PQsetenv(conn);
 
-	return CONNECTION_OK;
+/* ----------------
+ *		PQsetenvStart
+ *
+ * Starts the process of passing the values of a standard set of environment
+ * variables to the backend.
+ *
+ * ---------------- */
+PGsetenvHandle
+PQsetenvStart(PGconn *conn)
+{
+	struct pg_setenv_state *handle;
 
-connect_errReturn:
-	if (conn->sock >= 0)
+	if ((handle = malloc(sizeof(struct pg_setenv_state))) == NULL)
 	{
-#ifdef WIN32
-		closesocket(conn->sock);
-#else
-		close(conn->sock);
-#endif
-		conn->sock = -1;
+		printfPQExpBuffer(&conn->errorMessage,
+						  "PQsetenvStart() -- malloc error - %s\n",
+						  strerror(errno));
+		return NULL;
 	}
-	return CONNECTION_BAD;
 
+	handle->conn = conn;
+	handle->res = NULL;
+	handle->eo = EnvironmentOptions;
+
+#ifdef MULTIBYTE
+	handle->state = SETENV_STATE_ENCODINGS_SEND;
+#else
+	handle->state = SETENV_STATE_OPTION_SEND;
+#endif
+	
+	return handle; /* Note that a struct pg_setenv_state * is the same as a
+					  PGsetenvHandle */
 }
 
-void
-PQsetenv(PGconn *conn)
+/* ----------------
+ *		PQsetenvPoll
+ *
+ * Polls the process of passing the values of a standard set of environment
+ * variables to the backend.
+ *
+ * ---------------- */
+PostgresPollingStatusType
+PQsetenvPoll(PGsetenvHandle handle)
 {
-	struct EnvironmentOptions *eo;
-	char		setQuery[100];	/* note length limits in sprintf's below */
-	const char *val;
-	PGresult   *res;
 #ifdef MULTIBYTE
-	char	   *envname = "PGCLIENTENCODING";
+	const char envname[] = "PGCLIENTENCODING";
+#endif
 
-	/* Set env. variable PGCLIENTENCODING if it's not set already */
-	val = getenv(envname);
-	if (!val || *val == '\0')
+	if (!handle || handle->state == SETENV_STATE_FAILED)
+		return PGRES_POLLING_FAILED;
+
+	/* Check whether there are any data for us */
+	switch (handle->state)
 	{
-		const char *encoding = NULL;
-
-		/* query server encoding */
-		res = PQexec(conn, "select getdatabaseencoding()");
-		if (res && PQresultStatus(res) == PGRES_TUPLES_OK)
-			encoding = PQgetvalue(res, 0, 0);
-		if (!encoding)			/* this should not happen */
-			encoding = pg_encoding_to_char(MULTIBYTE);
-		if (encoding)
+		/* These are reading states */
+#ifdef MULTIBYTE
+		case SETENV_STATE_ENCODINGS_WAIT:
+#endif
+		case SETENV_STATE_OPTION_WAIT:
 		{
-			/* set client encoding via environment variable */
-			char	   *envbuf;
+			/* Load waiting data */
+			int n = pqReadData(handle->conn);
+				
+			if (n < 0)
+				goto error_return;
+			if (n == 0)
+				return PGRES_POLLING_READING;
 
-			envbuf = (char *) malloc(strlen(envname) + strlen(encoding) + 2);
-			sprintf(envbuf, "%s=%s", envname, encoding);
-			putenv(envbuf);
+			break;
 		}
-		PQclear(res);
-	}
+
+		/* These are writing states, so we just proceed. */
+#ifdef MULTIBYTE
+		case SETENV_STATE_ENCODINGS_SEND:
 #endif
+		case SETENV_STATE_OPTION_SEND:
+			break;
+		   
+		default:
+			printfPQExpBuffer(&handle->conn->errorMessage,
+							  "PQsetenvPoll() -- unknown state - "
+							  "probably indicative of memory corruption!\n");
+			goto error_return;
+	}
 
-	for (eo = EnvironmentOptions; eo->envName; eo++)
+
+ keep_going: /* We will come back to here until there is nothing left to
+				parse. */
+	switch(handle->state)
 	{
-		if ((val = getenv(eo->envName)))
+
+#ifdef MULTIBYTE
+		case SETENV_STATE_ENCODINGS_SEND:
 		{
-			if (strcasecmp(val, "default") == 0)
-				sprintf(setQuery, "SET %s = %.60s", eo->pgName, val);
-			else
-				sprintf(setQuery, "SET %s = '%.60s'", eo->pgName, val);
+			const char *env;
+			
+			/* query server encoding */
+			env = getenv(envname);
+			if (!env || *env == '\0')
+			{
+				if (!PQsendQuery(handle->conn,
+								 "select getdatabaseencoding()"))
+					goto error_return;
+
+				handle->state = SETENV_STATE_ENCODINGS_WAIT;
+				return PGRES_POLLING_READING;
+			}
+		}
+
+		case SETENV_STATE_ENCODINGS_WAIT:
+		{
+			const char *encoding = 0;
+
+			if (!PQconsumeInput(handle->conn))
+				goto error_return;
+
+			if (PQisBusy(handle->conn))
+				return PGRES_POLLING_READING;
+			
+			handle->res = PQgetResult(handle->conn);
+
+			if (handle->res)
+			{
+				if (PQresultStatus(handle->res) != PGRES_TUPLES_OK)
+				{
+					PQclear(handle->res);
+					goto error_return;
+				}
+
+				encoding = PQgetvalue(handle->res, 0, 0);
+				if (!encoding)			/* this should not happen */
+					encoding = pg_encoding_to_char(MULTIBYTE);
+
+				if (encoding)
+				{
+					/* set client encoding via environment variable */
+					char	   *envbuf;
+
+					envbuf = (char *) malloc(strlen(envname) + strlen(encoding) + 2);
+					sprintf(envbuf, "%s=%s", envname, encoding);
+					putenv(envbuf);
+				}
+				PQclear(handle->res);
+				/* We have to keep going in order to clear up the query */
+				goto keep_going;
+			}
+
+			/* NULL result indicates that the query is finished */
+
+			/* Move on to setting the environment options */
+			handle->state = SETENV_STATE_OPTION_SEND;
+			goto keep_going;
+		}
+#endif
+
+		case SETENV_STATE_OPTION_SEND:
+		{
+			/* Send an Environment Option */
+			char		setQuery[100];	/* note length limits in sprintf's below */
+
+			if (handle->eo->envName)
+			{
+				const char *val;
+
+				if ((val = getenv(handle->eo->envName)))
+				{
+					if (strcasecmp(val, "default") == 0)
+						sprintf(setQuery, "SET %s = %.60s",
+								handle->eo->pgName, val);
+					else
+						sprintf(setQuery, "SET %s = '%.60s'",
+								handle->eo->pgName, val);
 #ifdef CONNECTDEBUG
-			printf("Use environment variable %s to send %s\n", eo->envName, setQuery);
+					printf("Use environment variable %s to send %s\n",
+						   handle->eo->envName, setQuery);
 #endif
-			res = PQexec(conn, setQuery);
-			PQclear(res);		/* Don't care? */
+					if (!PQsendQuery(handle->conn, setQuery))
+						goto error_return;
+
+					handle->state = SETENV_STATE_OPTION_WAIT;
+				}
+				else
+				{
+					handle->eo++;
+				}
+			}
+			else
+			{
+				/* No option to send, so we are done. */
+				handle->state = SETENV_STATE_OK;
+			}
+
+			goto keep_going;
 		}
+
+		case SETENV_STATE_OPTION_WAIT:
+		{
+			if (!PQconsumeInput(handle->conn))
+				goto error_return;
+
+			if (PQisBusy(handle->conn))
+				return PGRES_POLLING_READING;
+			
+			handle->res = PQgetResult(handle->conn);
+
+			if (handle->res)
+			{
+				if (PQresultStatus(handle->res) != PGRES_COMMAND_OK)
+				{
+					PQclear(handle->res);
+					goto error_return;
+				}
+				/* Don't need the result */
+				PQclear(handle->res);
+				/* We have to keep going in order to clear up the query */
+				goto keep_going;
+			}
+
+			/* NULL result indicates that the query is finished */
+
+			/* Send the next option */
+			handle->eo++;
+			handle->state = SETENV_STATE_OPTION_SEND;
+			goto keep_going;
+		}
+
+		case SETENV_STATE_OK:
+			/* Tidy up */
+			free(handle);
+			return PGRES_POLLING_OK;
+
+		default:
+			printfPQExpBuffer(&handle->conn->errorMessage,
+							  "PQsetenvPoll() -- unknown state - "
+							  "probably indicative of memory corruption!\n");
+			goto error_return;
+	}
+
+	/* Unreachable */
+
+ error_return:
+	handle->state = SETENV_STATE_FAILED; /* This may protect us even if we
+										  * are called after the handle
+										  * has been freed.             */
+	free(handle);
+	return PGRES_POLLING_FAILED;
+}
+
+
+/* ----------------
+ *		PQsetenvAbort
+ *
+ * Aborts the process of passing the values of a standard set of environment
+ * variables to the backend.
+ *
+ * ---------------- */
+void
+PQsetenvAbort(PGsetenvHandle handle)
+{
+	/* We should not have been called in the FAILED state, but we can cope by
+	 * not freeing the handle (it has probably been freed by now anyway). */
+	if (handle->state != SETENV_STATE_FAILED)
+	{
+		handle->state = SETENV_STATE_FAILED;
+		free(handle);
 	}
-}	/* PQsetenv() */
+}
+
+
+/* ----------------
+ *		PQsetenv
+ *
+ * Passes the values of a standard set of environment variables to the
+ * backend.
+ *
+ * Returns 1 on success, 0 on failure.
+ *
+ * This function used to return void.  I don't think that there should be
+ * compatibility problems caused by giving it a return value, especially as
+ * this function has not been documented previously.
+ *
+ * ---------------- */
+int
+PQsetenv(PGconn *conn)
+{
+	PostgresPollingStatusType flag;
+	PGsetenvHandle handle;
+	int r = 0, w = 1;
+	
+	if((handle = PQsetenvStart(conn)) == NULL)
+		return 0;
+
+	do
+	{
+		if(pqWait(r, w, conn))
+		{
+			/* XXX This is not a good sign - perhaps we should mark the
+			   connection as bad here... */
+			return 0;
+		}
+
+	again:
+		switch(flag = PQsetenvPoll(handle))
+		{
+			case PGRES_POLLING_ACTIVE:
+				goto again;
+
+			case PGRES_POLLING_OK:
+				break;
+				
+			case PGRES_POLLING_READING:
+				r = 1;
+				w = 0;
+				break;
+				
+			case PGRES_POLLING_WRITING:
+				r = 0;
+				w = 1;
+				break;
+				
+			default: /* Failed */
+				return 0;
+		}
+	} while (flag != PGRES_POLLING_OK);
+  
+	return 1;
+}
+
 
 /*
  * makeEmptyPGconn
@@ -973,6 +1738,8 @@ freePGconn(PGconn *conn)
 #endif
 	if (conn->pghost)
 		free(conn->pghost);
+	if (conn->pghostaddr)
+		free(conn->pghostaddr);
 	if (conn->pgport)
 		free(conn->pgport);
 	if (conn->pgtty)
@@ -1006,6 +1773,12 @@ freePGconn(PGconn *conn)
 static void
 closePGconn(PGconn *conn)
 {
+	if (conn->status == CONNECTION_SETENV)
+	{
+		/* We have to abort the setenv process as well */
+		PQsetenvAbort(conn->setenv_handle);
+	}
+
 	if (conn->sock >= 0)
 	{
 
@@ -1067,8 +1840,47 @@ PQreset(PGconn *conn)
 	if (conn)
 	{
 		closePGconn(conn);
-		conn->status = connectDB(conn);
+
+		(void)(!connectDBStart(conn) || !connectDBComplete(conn));
 	}
+
+	return;
+}
+
+
+/* PQresetStart :
+   resets the connection to the backend
+   closes the existing connection and makes a new one
+   Returns 1 on success, 0 on failure.
+*/
+int
+PQresetStart(PGconn *conn)
+{
+	if (conn)
+	{
+		closePGconn(conn);
+
+		return connectDBStart(conn);
+	}
+
+	return 1;
+}
+
+
+/* PQresetPoll :
+   resets the connection to the backend
+   closes the existing connection and makes a new one
+*/
+
+PostgresPollingStatusType
+PQresetPoll(PGconn *conn)
+{
+	if (conn)
+	{
+		return PQconnectPoll(conn);
+	}
+
+	return PGRES_POLLING_FAILED;
 }
 
 
diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c
index d29277bf2004276bfaab4b9515848d347b81ed00..89425e0034c40c1d3de798a72b8260fb89c4a6aa 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.32 1999/11/11 00:10:14 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.33 1999/11/30 03:08:19 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -269,29 +269,69 @@ pqPutInt(int value, size_t bytes, PGconn *conn)
 
 /* --------------------------------------------------------------------- */
 /* pqReadReady: is select() saying the file is ready to read?
+ * Returns -1 on failure, 0 if not ready, 1 if ready.
  */
-static int
+int
 pqReadReady(PGconn *conn)
 {
 	fd_set		input_mask;
 	struct timeval timeout;
 
-	if (conn->sock < 0)
-		return 0;
+	if (!conn || conn->sock < 0)
+		return -1;
 
 	FD_ZERO(&input_mask);
 	FD_SET(conn->sock, &input_mask);
 	timeout.tv_sec = 0;
 	timeout.tv_usec = 0;
+ retry:
 	if (select(conn->sock + 1, &input_mask, (fd_set *) NULL, (fd_set *) NULL,
 			   &timeout) < 0)
 	{
+		if (errno == EINTR)
+			/* Interrupted system call - we'll just try again */
+			goto retry;
+
 		printfPQExpBuffer(&conn->errorMessage,
 						  "pqReadReady() -- select() failed: errno=%d\n%s\n",
 						  errno, strerror(errno));
-		return 0;
+		return -1;
+	}
+
+	return FD_ISSET(conn->sock, &input_mask) ? 1 : 0;
+}
+
+/* --------------------------------------------------------------------- */
+/* pqWriteReady: is select() saying the file is ready to write?
+ * Returns -1 on failure, 0 if not ready, 1 if ready.
+ */
+int
+pqWriteReady(PGconn *conn)
+{
+	fd_set		input_mask;
+	struct timeval timeout;
+
+	if (!conn || conn->sock < 0)
+		return -1;
+
+	FD_ZERO(&input_mask);
+	FD_SET(conn->sock, &input_mask);
+	timeout.tv_sec = 0;
+	timeout.tv_usec = 0;
+ retry:
+	if (select(conn->sock + 1, (fd_set *) NULL, &input_mask, (fd_set *) NULL,
+			   &timeout) < 0)
+	{
+		if (errno == EINTR)
+			/* Interrupted system call - we'll just try again */
+			goto retry;
+
+		printfPQExpBuffer(&conn->errorMessage,
+						  "pqWriteReady() -- select() failed: errno=%d\n%s\n",
+						  errno, strerror(errno));
+		return -1;
 	}
-	return FD_ISSET(conn->sock, &input_mask);
+	return FD_ISSET(conn->sock, &input_mask) ? 1 : 0;
 }
 
 /* --------------------------------------------------------------------- */
@@ -418,8 +458,17 @@ tryAgain:
 	 * be taken much, since in normal practice we should not be trying to
 	 * read data unless the file selected for reading already.
 	 */
-	if (!pqReadReady(conn))
-		return 0;				/* definitely no data available */
+	switch (pqReadReady(conn))
+	{
+		case 0:
+			/* definitely no data available */
+			return 0;
+		case 1:
+			/* ready for read */
+			break;
+		default:
+			goto definitelyFailed;
+	}
 
 	/*
 	 * Still not sure that it's EOF, because some data could have just
@@ -570,6 +619,10 @@ pqFlush(PGconn *conn)
 		if (len > 0)
 		{
 			/* We didn't send it all, wait till we can send more */
+
+			/* At first glance this looks as though it should block.  I think
+			 * that it will be OK though, as long as the socket is
+			 * non-blocking. */
 			if (pqWait(FALSE, TRUE, conn))
 				return EOF;
 		}
@@ -599,9 +652,9 @@ pqWait(int forRead, int forWrite, PGconn *conn)
 		return EOF;
 	}
 
-	/* loop in case select returns EINTR */
-	for (;;)
+	if (forRead || forWrite)
 	{
+	retry:
 		FD_ZERO(&input_mask);
 		FD_ZERO(&output_mask);
 		if (forRead)
@@ -612,14 +665,12 @@ pqWait(int forRead, int forWrite, PGconn *conn)
 				   (struct timeval *) NULL) < 0)
 		{
 			if (errno == EINTR)
-				continue;
+				goto retry;
 			printfPQExpBuffer(&conn->errorMessage,
 							  "pqWait() -- select() failed: errno=%d\n%s\n",
 							  errno, strerror(errno));
 			return EOF;
 		}
-		/* On nonerror return, assume we're done */
-		break;
 	}
 
 	return 0;
diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h
index b1c97e046a60ec93439798182fd063bd3a4279d0..5a25c40121f199cc642f52da0d6361a700286bf5 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.52 1999/11/11 00:10:14 momjian Exp $
+ * $Id: libpq-fe.h,v 1.53 1999/11/30 03:08:19 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -29,10 +29,40 @@ extern		"C"
 
 	typedef enum
 	{
+		/* Although you may decide to change this list in some way,
+		   values which become unused should never be removed, nor
+           should constants be redefined - that would break 
+           compatibility with existing code.                           */
 		CONNECTION_OK,
-		CONNECTION_BAD
+		CONNECTION_BAD,
+		/* Non-blocking mode only below here */
+		/* The existence of these should never be relied upon - they
+		   should only be used for user feedback or similar purposes.  */
+		CONNECTION_STARTED,     /* Waiting for connection to be made.  */
+		CONNECTION_MADE,        /* Connection OK; waiting to send.     */
+		CONNECTION_AWAITING_RESPONSE,   /* Waiting for a response
+										   from the backend.           */
+		CONNECTION_AUTH_RESPONSE,       /* Got an authentication
+										   response; about to deal
+										   with it.                    */
+		CONNECTION_ERROR_RESPONSE,      /* Got an error
+										   response; about to deal 
+										   with it.                    */
+		CONNECTION_AUTH_OK,             /* Received authentication;
+										   waiting for ReadyForQuery
+										   etc.                        */
+		CONNECTION_SETENV               /* Negotiating environment.    */
 	} ConnStatusType;
 
+	typedef enum
+	{
+		PGRES_POLLING_FAILED = 0,
+		PGRES_POLLING_READING,     /* These two indicate that one may    */
+		PGRES_POLLING_WRITING,     /* use select before polling again.   */
+		PGRES_POLLING_OK,
+		PGRES_POLLING_ACTIVE       /* Can call poll function immediately.*/
+	} PostgresPollingStatusType;
+
 	typedef enum
 	{
 		PGRES_EMPTY_QUERY = 0,
@@ -67,6 +97,12 @@ extern		"C"
  */
 	typedef struct pg_result PGresult;
 
+/* PGsetenvHandle is an opaque handle which is returned by PQsetenvStart and
+ * which should be passed to PQsetenvPoll or PQsetenvAbort in order to refer
+ * to the particular process being performed.
+ */
+	typedef struct pg_setenv_state *PGsetenvHandle;
+
 /* PGnotify represents the occurrence of a NOTIFY message.
  * Ideally this would be an opaque typedef, but it's so simple that it's
  * unlikely to change.
@@ -152,11 +188,15 @@ extern		"C"
 /* ===	in fe-connect.c === */
 
 	/* make a new client connection to the backend */
+	/* Asynchronous (non-blocking) */
+	extern PGconn *PQconnectStart(const char *conninfo);
+	extern PostgresPollingStatusType PQconnectPoll(PGconn *conn);
+	/* Synchronous (blocking) */
 	extern PGconn *PQconnectdb(const char *conninfo);
 	extern PGconn *PQsetdbLogin(const char *pghost, const char *pgport,
 								const char *pgoptions, const char *pgtty,
-											const char *dbName,
-									 const char *login, const char *pwd);
+								const char *dbName,
+								const char *login, const char *pwd);
 #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)
 
@@ -170,6 +210,10 @@ extern		"C"
 	 * close the current connection and restablish a new one with the same
 	 * parameters
 	 */
+	/* Asynchronous (non-blocking) */
+	extern int PQresetStart(PGconn *conn);
+	extern PostgresPollingStatusType PQresetPoll(PGconn *conn);
+	/* Synchronous (blocking) */
 	extern void PQreset(PGconn *conn);
 
 	/* issue a cancel request */
@@ -195,6 +239,15 @@ extern		"C"
 	/* Override default notice processor */
 	extern PQnoticeProcessor PQsetNoticeProcessor(PGconn *conn, PQnoticeProcessor proc, void *arg);
 
+	/* Passing of environment variables */
+	/* Asynchronous (non-blocking) */
+	extern PGsetenvHandle PQsetenvStart(PGconn *conn);
+	extern PostgresPollingStatusType PQsetenvPoll(PGsetenvHandle handle);
+	extern void PQsetenvAbort(PGsetenvHandle handle);
+
+	/* Synchronous (blocking) */
+	extern int PQsetenv(PGconn *conn);
+
 /* === in fe-exec.c === */
 
 	/* Simple synchronous query */
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 7323e9fe065db71d8f429b29c0706bbfdc444a78..64566d6c743f5273e24f8757c81e79d5a109e532 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -11,7 +11,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: libpq-int.h,v 1.13 1999/11/11 00:10:14 momjian Exp $
+ * $Id: libpq-int.h,v 1.14 1999/11/30 03:08:19 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -168,6 +168,10 @@ struct pg_conn
 	/* Saved values of connection options */
 	char	   *pghost;			/* the machine on which the server is
 								 * running */
+	char	   *pghostaddr;		/* the IPv4 address of the machine on
+								 * which the server is running, in
+								 * IPv4 numbers-and-dots notation. Takes
+								 * precedence over above. */
 	char	   *pgport;			/* the server's communication port */
 	char	   *pgtty;			/* tty on which the backend messages is
 								 * displayed (NOT ACTUALLY USED???) */
@@ -220,6 +224,9 @@ struct pg_conn
 	PGresult   *result;			/* result being constructed */
 	PGresAttValue *curTuple;	/* tuple currently being read */
 
+	/* Handle for setenv request.  Used during connection only. */
+	PGsetenvHandle setenv_handle;
+
 #ifdef USE_SSL
         SSL *ssl;
 #endif
@@ -268,6 +275,8 @@ extern int	pqPutInt(int value, size_t bytes, PGconn *conn);
 extern int	pqReadData(PGconn *conn);
 extern int	pqFlush(PGconn *conn);
 extern int	pqWait(int forRead, int forWrite, PGconn *conn);
+extern int	pqReadReady(PGconn *conn);
+extern int	pqWriteReady(PGconn *conn);
 
 /* bits in a byte */
 #define BYTELEN 8