new-standalone-mode-1.patch

text/x-patch

Filename: new-standalone-mode-1.patch
Type: text/x-patch
Part: 0
Message: Proof of concept: standalone backend with full FE/BE protocol

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: unified
File+
src/backend/libpq/auth.c 0 0
src/backend/libpq/be-secure.c 0 0
src/backend/libpq/pqcomm.c 0 0
src/backend/main/main.c 0 0
src/backend/postmaster/postmaster.c 0 0
src/backend/replication/walsender.c 0 0
src/backend/tcop/postgres.c 0 0
src/include/libpq/libpq-be.h 0 0
src/include/postmaster/postmaster.h 0 0
src/interfaces/libpq/fe-connect.c 0 0
src/interfaces/libpq/fe-exec.c 0 0
src/interfaces/libpq/fe-misc.c 0 0
src/interfaces/libpq/fe-protocol2.c 0 0
src/interfaces/libpq/fe-protocol3.c 0 0
src/interfaces/libpq/fe-secure.c 0 0
src/interfaces/libpq/libpq-int.h 0 0
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index c765454..6e65a9d 100644
*** a/src/backend/libpq/auth.c
--- b/src/backend/libpq/auth.c
*************** ClientAuthentication(Port *port)
*** 313,318 ****
--- 313,321 ----
  {
  	int			status = STATUS_ERROR;
  
+ 	/* Authentication is not supported over pipes */
+ 	Assert(port->rsock == port->wsock);
+ 
  	/*
  	 * Get the authentication method to use for this frontend/database
  	 * combination.  Note: we do not parse the file at this point; this has
*************** pg_krb5_recvauth(Port *port)
*** 820,826 ****
  		return ret;
  
  	retval = krb5_recvauth(pg_krb5_context, &auth_context,
! 						   (krb5_pointer) &port->sock, pg_krb_srvnam,
  						   pg_krb5_server, 0, pg_krb5_keytab, &ticket);
  	if (retval)
  	{
--- 823,829 ----
  		return ret;
  
  	retval = krb5_recvauth(pg_krb5_context, &auth_context,
! 						   (krb5_pointer) &port->rsock, pg_krb_srvnam,
  						   pg_krb5_server, 0, pg_krb5_keytab, &ticket);
  	if (retval)
  	{
*************** auth_peer(hbaPort *port)
*** 1768,1774 ****
  	struct passwd *pass;
  
  	errno = 0;
! 	if (getpeereid(port->sock, &uid, &gid) != 0)
  	{
  		/* Provide special error message if getpeereid is a stub */
  		if (errno == ENOSYS)
--- 1771,1777 ----
  	struct passwd *pass;
  
  	errno = 0;
! 	if (getpeereid(port->rsock, &uid, &gid) != 0)
  	{
  		/* Provide special error message if getpeereid is a stub */
  		if (errno == ENOSYS)
diff --git a/src/backend/libpq/be-secure.c b/src/backend/libpq/be-secure.c
index 0d66dab..0bde205 100644
*** a/src/backend/libpq/be-secure.c
--- b/src/backend/libpq/be-secure.c
*************** rloop:
*** 301,307 ****
  	{
  		prepare_for_client_read();
  
! 		n = recv(port->sock, ptr, len, 0);
  
  		client_read_ended();
  	}
--- 301,307 ----
  	{
  		prepare_for_client_read();
  
! 		n = read(port->rsock, ptr, len);
  
  		client_read_ended();
  	}
*************** wloop:
*** 393,399 ****
  	}
  	else
  #endif
! 		n = send(port->sock, ptr, len, 0);
  
  	return n;
  }
--- 393,399 ----
  	}
  	else
  #endif
! 		n = write(port->wsock, ptr, len);
  
  	return n;
  }
*************** open_server_SSL(Port *port)
*** 876,881 ****
--- 876,882 ----
  
  	Assert(!port->ssl);
  	Assert(!port->peer);
+ 	Assert(port->rsock == port->wsock);
  
  	if (!(port->ssl = SSL_new(SSL_context)))
  	{
*************** open_server_SSL(Port *port)
*** 886,892 ****
  		close_SSL(port);
  		return -1;
  	}
! 	if (!my_SSL_set_fd(port->ssl, port->sock))
  	{
  		ereport(COMMERROR,
  				(errcode(ERRCODE_PROTOCOL_VIOLATION),
--- 887,893 ----
  		close_SSL(port);
  		return -1;
  	}
! 	if (!my_SSL_set_fd(port->ssl, port->rsock))
  	{
  		ereport(COMMERROR,
  				(errcode(ERRCODE_PROTOCOL_VIOLATION),
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
index 5e86987..fa4d322 100644
*** a/src/backend/libpq/pqcomm.c
--- b/src/backend/libpq/pqcomm.c
*************** pq_close(int code, Datum arg)
*** 215,224 ****
  		 * transport layer reports connection closure, and you can be sure the
  		 * backend has exited.
  		 *
! 		 * We do set sock to PGINVALID_SOCKET to prevent any further I/O,
  		 * though.
  		 */
! 		MyProcPort->sock = PGINVALID_SOCKET;
  	}
  }
  
--- 215,225 ----
  		 * transport layer reports connection closure, and you can be sure the
  		 * backend has exited.
  		 *
! 		 * We do set the socket to PGINVALID_SOCKET to prevent any further I/O,
  		 * though.
  		 */
! 		MyProcPort->rsock = PGINVALID_SOCKET;
! 		MyProcPort->wsock = PGINVALID_SOCKET;
  	}
  }
  
*************** Setup_AF_UNIX(char *sock_path)
*** 609,615 ****
  
  /*
   * StreamConnection -- create a new connection with client using
!  *		server port.  Set port->sock to the FD of the new connection.
   *
   * ASSUME: that this doesn't need to be non-blocking because
   *		the Postmaster uses select() to tell when the server master
--- 610,616 ----
  
  /*
   * StreamConnection -- create a new connection with client using
!  *		server port.  Set port->rsock/wsock to the FD of the new connection.
   *
   * ASSUME: that this doesn't need to be non-blocking because
   *		the Postmaster uses select() to tell when the server master
*************** StreamConnection(pgsocket server_fd, Por
*** 622,630 ****
  {
  	/* accept connection and fill in the client (remote) address */
  	port->raddr.salen = sizeof(port->raddr.addr);
! 	if ((port->sock = accept(server_fd,
! 							 (struct sockaddr *) & port->raddr.addr,
! 							 &port->raddr.salen)) < 0)
  	{
  		ereport(LOG,
  				(errcode_for_socket_access(),
--- 623,631 ----
  {
  	/* accept connection and fill in the client (remote) address */
  	port->raddr.salen = sizeof(port->raddr.addr);
! 	if ((port->rsock = accept(server_fd,
! 							  (struct sockaddr *) & port->raddr.addr,
! 							  &port->raddr.salen)) < 0)
  	{
  		ereport(LOG,
  				(errcode_for_socket_access(),
*************** StreamConnection(pgsocket server_fd, Por
*** 641,646 ****
--- 642,650 ----
  		return STATUS_ERROR;
  	}
  
+ 	/* It's a bidirectional socket, so wsock and rsock are equal */
+ 	port->wsock = port->rsock;
+ 
  #ifdef SCO_ACCEPT_BUG
  
  	/*
*************** StreamConnection(pgsocket server_fd, Por
*** 653,659 ****
  
  	/* fill in the server (local) address */
  	port->laddr.salen = sizeof(port->laddr.addr);
! 	if (getsockname(port->sock,
  					(struct sockaddr *) & port->laddr.addr,
  					&port->laddr.salen) < 0)
  	{
--- 657,663 ----
  
  	/* fill in the server (local) address */
  	port->laddr.salen = sizeof(port->laddr.addr);
! 	if (getsockname(port->rsock,
  					(struct sockaddr *) & port->laddr.addr,
  					&port->laddr.salen) < 0)
  	{
*************** StreamConnection(pgsocket server_fd, Por
*** 668,674 ****
  
  #ifdef	TCP_NODELAY
  		on = 1;
! 		if (setsockopt(port->sock, IPPROTO_TCP, TCP_NODELAY,
  					   (char *) &on, sizeof(on)) < 0)
  		{
  			elog(LOG, "setsockopt(TCP_NODELAY) failed: %m");
--- 672,678 ----
  
  #ifdef	TCP_NODELAY
  		on = 1;
! 		if (setsockopt(port->rsock, IPPROTO_TCP, TCP_NODELAY,
  					   (char *) &on, sizeof(on)) < 0)
  		{
  			elog(LOG, "setsockopt(TCP_NODELAY) failed: %m");
*************** StreamConnection(pgsocket server_fd, Por
*** 676,682 ****
  		}
  #endif
  		on = 1;
! 		if (setsockopt(port->sock, SOL_SOCKET, SO_KEEPALIVE,
  					   (char *) &on, sizeof(on)) < 0)
  		{
  			elog(LOG, "setsockopt(SO_KEEPALIVE) failed: %m");
--- 680,686 ----
  		}
  #endif
  		on = 1;
! 		if (setsockopt(port->rsock, SOL_SOCKET, SO_KEEPALIVE,
  					   (char *) &on, sizeof(on)) < 0)
  		{
  			elog(LOG, "setsockopt(SO_KEEPALIVE) failed: %m");
*************** StreamConnection(pgsocket server_fd, Por
*** 690,696 ****
  		 * http://support.microsoft.com/kb/823764/EN-US/
  		 */
  		on = PQ_SEND_BUFFER_SIZE * 4;
! 		if (setsockopt(port->sock, SOL_SOCKET, SO_SNDBUF, (char *) &on,
  					   sizeof(on)) < 0)
  		{
  			elog(LOG, "setsockopt(SO_SNDBUF) failed: %m");
--- 694,700 ----
  		 * http://support.microsoft.com/kb/823764/EN-US/
  		 */
  		on = PQ_SEND_BUFFER_SIZE * 4;
! 		if (setsockopt(port->rsock, SOL_SOCKET, SO_SNDBUF, (char *) &on,
  					   sizeof(on)) < 0)
  		{
  			elog(LOG, "setsockopt(SO_SNDBUF) failed: %m");
*************** TouchSocketFiles(void)
*** 779,784 ****
--- 783,793 ----
   *
   * Sets the socket non-blocking if nonblocking is TRUE, or sets it
   * blocking otherwise.
+  *
+  * When using a pair of pipes for communication, this affects the read side
+  * only; when using a bidirectional socket, it affects both read and write.
+  * We currently have no need for nonblocking write in the pipe case, so it's
+  * not worth rethinking this API (yet).
   * --------------------------------
   */
  static void
*************** pq_set_nonblocking(bool nonblocking)
*** 798,810 ****
  	 */
  	if (nonblocking)
  	{
! 		if (!pg_set_noblock(MyProcPort->sock))
  			ereport(COMMERROR,
  				  (errmsg("could not set socket to non-blocking mode: %m")));
  	}
  	else
  	{
! 		if (!pg_set_block(MyProcPort->sock))
  			ereport(COMMERROR,
  					(errmsg("could not set socket to blocking mode: %m")));
  	}
--- 807,819 ----
  	 */
  	if (nonblocking)
  	{
! 		if (!pg_set_noblock(MyProcPort->rsock))
  			ereport(COMMERROR,
  				  (errmsg("could not set socket to non-blocking mode: %m")));
  	}
  	else
  	{
! 		if (!pg_set_block(MyProcPort->rsock))
  			ereport(COMMERROR,
  					(errmsg("could not set socket to blocking mode: %m")));
  	}
*************** pq_setkeepaliveswin32(Port *port, int id
*** 1481,1487 ****
  	ka.keepalivetime = idle * 1000;
  	ka.keepaliveinterval = interval * 1000;
  
! 	if (WSAIoctl(port->sock,
  				 SIO_KEEPALIVE_VALS,
  				 (LPVOID) &ka,
  				 sizeof(ka),
--- 1490,1496 ----
  	ka.keepalivetime = idle * 1000;
  	ka.keepaliveinterval = interval * 1000;
  
! 	if (WSAIoctl(port->rsock,
  				 SIO_KEEPALIVE_VALS,
  				 (LPVOID) &ka,
  				 sizeof(ka),
*************** pq_getkeepalivesidle(Port *port)
*** 1520,1526 ****
  		ACCEPT_TYPE_ARG3 size = sizeof(port->default_keepalives_idle);
  
  #ifdef TCP_KEEPIDLE
! 		if (getsockopt(port->sock, IPPROTO_TCP, TCP_KEEPIDLE,
  					   (char *) &port->default_keepalives_idle,
  					   &size) < 0)
  		{
--- 1529,1535 ----
  		ACCEPT_TYPE_ARG3 size = sizeof(port->default_keepalives_idle);
  
  #ifdef TCP_KEEPIDLE
! 		if (getsockopt(port->rsock, IPPROTO_TCP, TCP_KEEPIDLE,
  					   (char *) &port->default_keepalives_idle,
  					   &size) < 0)
  		{
*************** pq_getkeepalivesidle(Port *port)
*** 1528,1534 ****
  			port->default_keepalives_idle = -1; /* don't know */
  		}
  #else
! 		if (getsockopt(port->sock, IPPROTO_TCP, TCP_KEEPALIVE,
  					   (char *) &port->default_keepalives_idle,
  					   &size) < 0)
  		{
--- 1537,1543 ----
  			port->default_keepalives_idle = -1; /* don't know */
  		}
  #else
! 		if (getsockopt(port->rsock, IPPROTO_TCP, TCP_KEEPALIVE,
  					   (char *) &port->default_keepalives_idle,
  					   &size) < 0)
  		{
*************** pq_setkeepalivesidle(int idle, Port *por
*** 1574,1587 ****
  		idle = port->default_keepalives_idle;
  
  #ifdef TCP_KEEPIDLE
! 	if (setsockopt(port->sock, IPPROTO_TCP, TCP_KEEPIDLE,
  				   (char *) &idle, sizeof(idle)) < 0)
  	{
  		elog(LOG, "setsockopt(TCP_KEEPIDLE) failed: %m");
  		return STATUS_ERROR;
  	}
  #else
! 	if (setsockopt(port->sock, IPPROTO_TCP, TCP_KEEPALIVE,
  				   (char *) &idle, sizeof(idle)) < 0)
  	{
  		elog(LOG, "setsockopt(TCP_KEEPALIVE) failed: %m");
--- 1583,1596 ----
  		idle = port->default_keepalives_idle;
  
  #ifdef TCP_KEEPIDLE
! 	if (setsockopt(port->rsock, IPPROTO_TCP, TCP_KEEPIDLE,
  				   (char *) &idle, sizeof(idle)) < 0)
  	{
  		elog(LOG, "setsockopt(TCP_KEEPIDLE) failed: %m");
  		return STATUS_ERROR;
  	}
  #else
! 	if (setsockopt(port->rsock, IPPROTO_TCP, TCP_KEEPALIVE,
  				   (char *) &idle, sizeof(idle)) < 0)
  	{
  		elog(LOG, "setsockopt(TCP_KEEPALIVE) failed: %m");
*************** pq_getkeepalivesinterval(Port *port)
*** 1618,1624 ****
  #ifndef WIN32
  		ACCEPT_TYPE_ARG3 size = sizeof(port->default_keepalives_interval);
  
! 		if (getsockopt(port->sock, IPPROTO_TCP, TCP_KEEPINTVL,
  					   (char *) &port->default_keepalives_interval,
  					   &size) < 0)
  		{
--- 1627,1633 ----
  #ifndef WIN32
  		ACCEPT_TYPE_ARG3 size = sizeof(port->default_keepalives_interval);
  
! 		if (getsockopt(port->rsock, IPPROTO_TCP, TCP_KEEPINTVL,
  					   (char *) &port->default_keepalives_interval,
  					   &size) < 0)
  		{
*************** pq_setkeepalivesinterval(int interval, P
*** 1662,1668 ****
  	if (interval == 0)
  		interval = port->default_keepalives_interval;
  
! 	if (setsockopt(port->sock, IPPROTO_TCP, TCP_KEEPINTVL,
  				   (char *) &interval, sizeof(interval)) < 0)
  	{
  		elog(LOG, "setsockopt(TCP_KEEPINTVL) failed: %m");
--- 1671,1677 ----
  	if (interval == 0)
  		interval = port->default_keepalives_interval;
  
! 	if (setsockopt(port->rsock, IPPROTO_TCP, TCP_KEEPINTVL,
  				   (char *) &interval, sizeof(interval)) < 0)
  	{
  		elog(LOG, "setsockopt(TCP_KEEPINTVL) failed: %m");
*************** pq_getkeepalivescount(Port *port)
*** 1698,1704 ****
  	{
  		ACCEPT_TYPE_ARG3 size = sizeof(port->default_keepalives_count);
  
! 		if (getsockopt(port->sock, IPPROTO_TCP, TCP_KEEPCNT,
  					   (char *) &port->default_keepalives_count,
  					   &size) < 0)
  		{
--- 1707,1713 ----
  	{
  		ACCEPT_TYPE_ARG3 size = sizeof(port->default_keepalives_count);
  
! 		if (getsockopt(port->rsock, IPPROTO_TCP, TCP_KEEPCNT,
  					   (char *) &port->default_keepalives_count,
  					   &size) < 0)
  		{
*************** pq_setkeepalivescount(int count, Port *p
*** 1737,1743 ****
  	if (count == 0)
  		count = port->default_keepalives_count;
  
! 	if (setsockopt(port->sock, IPPROTO_TCP, TCP_KEEPCNT,
  				   (char *) &count, sizeof(count)) < 0)
  	{
  		elog(LOG, "setsockopt(TCP_KEEPCNT) failed: %m");
--- 1746,1752 ----
  	if (count == 0)
  		count = port->default_keepalives_count;
  
! 	if (setsockopt(port->rsock, IPPROTO_TCP, TCP_KEEPCNT,
  				   (char *) &count, sizeof(count)) < 0)
  	{
  		elog(LOG, "setsockopt(TCP_KEEPCNT) failed: %m");
diff --git a/src/backend/main/main.c b/src/backend/main/main.c
index 33c5a0a..a301923 100644
*** a/src/backend/main/main.c
--- b/src/backend/main/main.c
*************** main(int argc, char *argv[])
*** 191,196 ****
--- 191,198 ----
  		AuxiliaryProcessMain(argc, argv);		/* does not return */
  	else if (argc > 1 && strcmp(argv[1], "--describe-config") == 0)
  		GucInfoMain();			/* does not return */
+ 	else if (argc > 1 && strcmp(argv[1], "--child") == 0)
+ 		ChildPostgresMain(argc, argv, get_current_username(progname)); /* does not return */
  	else if (argc > 1 && strcmp(argv[1], "--single") == 0)
  		PostgresMain(argc, argv, get_current_username(progname)); /* does not return */
  	else
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 73520a6..2aac9c8 100644
*** a/src/backend/postmaster/postmaster.c
--- b/src/backend/postmaster/postmaster.c
*************** ServerLoop(void)
*** 1430,1436 ****
  						 * We no longer need the open socket or port structure
  						 * in this process
  						 */
! 						StreamClose(port->sock);
  						ConnFree(port);
  					}
  				}
--- 1430,1437 ----
  						 * We no longer need the open socket or port structure
  						 * in this process
  						 */
! 						StreamClose(port->rsock);
! 						/* wsock is same socket, do not close separately */
  						ConnFree(port);
  					}
  				}
*************** ProcessStartupPacket(Port *port, bool SS
*** 1630,1636 ****
  #endif
  
  retry1:
! 		if (send(port->sock, &SSLok, 1, 0) != 1)
  		{
  			if (errno == EINTR)
  				goto retry1;	/* if interrupted, just retry */
--- 1631,1637 ----
  #endif
  
  retry1:
! 		if (send(port->wsock, &SSLok, 1, 0) != 1)
  		{
  			if (errno == EINTR)
  				goto retry1;	/* if interrupted, just retry */
*************** ConnCreate(int serverFd)
*** 1984,1991 ****
  
  	if (StreamConnection(serverFd, port) != STATUS_OK)
  	{
! 		if (port->sock >= 0)
! 			StreamClose(port->sock);
  		ConnFree(port);
  		return NULL;
  	}
--- 1985,1993 ----
  
  	if (StreamConnection(serverFd, port) != STATUS_OK)
  	{
! 		if (port->rsock >= 0)
! 			StreamClose(port->rsock);
! 		/* wsock must be same socket, do not close separately */
  		ConnFree(port);
  		return NULL;
  	}
*************** BackendStartup(Port *port)
*** 3363,3369 ****
  	/* in parent, successful fork */
  	ereport(DEBUG2,
  			(errmsg_internal("forked new backend, pid=%d socket=%d",
! 							 (int) pid, (int) port->sock)));
  
  	/*
  	 * Everything's been successful, it's safe to add this backend to our list
--- 3365,3371 ----
  	/* in parent, successful fork */
  	ereport(DEBUG2,
  			(errmsg_internal("forked new backend, pid=%d socket=%d",
! 							 (int) pid, (int) port->rsock)));
  
  	/*
  	 * Everything's been successful, it's safe to add this backend to our list
*************** report_fork_failure_to_client(Port *port
*** 3401,3413 ****
  			 strerror(errnum));
  
  	/* Set port to non-blocking.  Don't do send() if this fails */
! 	if (!pg_set_noblock(port->sock))
  		return;
  
  	/* We'll retry after EINTR, but ignore all other failures */
  	do
  	{
! 		rc = send(port->sock, buffer, strlen(buffer) + 1, 0);
  	} while (rc < 0 && errno == EINTR);
  }
  
--- 3403,3415 ----
  			 strerror(errnum));
  
  	/* Set port to non-blocking.  Don't do send() if this fails */
! 	if (!pg_set_noblock(port->wsock))
  		return;
  
  	/* We'll retry after EINTR, but ignore all other failures */
  	do
  	{
! 		rc = send(port->wsock, buffer, strlen(buffer) + 1, 0);
  	} while (rc < 0 && errno == EINTR);
  }
  
*************** ExitPostmaster(int status)
*** 4268,4273 ****
--- 4270,4335 ----
  	proc_exit(status);
  }
  
+ 
+ /*
+  * ChildPostgresMain - start a new-style standalone postgres process
+  *
+  * This may not belong here, but it does share a lot of code with ConnCreate
+  * and BackendInitialize.  Basically what it has to do is set up a
+  * MyProcPort structure and then hand off control to PostgresMain.
+  * Beware that not very much stuff is initialized yet.
+  *
+  * In the future it might be interesting to support a "standalone
+  * multiprocess" mode in which we have a postmaster process that doesn't
+  * listen for connections, but does supervise autovacuum, bgwriter, etc
+  * auxiliary processes.  So that's another reason why postmaster.c might be
+  * the right place for this.
+  */
+ void
+ ChildPostgresMain(int argc, char *argv[], const char *username)
+ {
+ 	Port	   *port;
+ 
+ 	if (!(port = (Port *) calloc(1, sizeof(Port))))
+ 		ereport(FATAL,
+ 				(errcode(ERRCODE_OUT_OF_MEMORY),
+ 				 errmsg("out of memory")));
+ 
+ 	/*
+ 	 * GSSAPI specific state struct must exist even though we won't use it
+ 	 */
+ #if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
+ 	port->gss = (pg_gssinfo *) calloc(1, sizeof(pg_gssinfo));
+ 	if (!port->gss)
+ 		ereport(FATAL,
+ 				(errcode(ERRCODE_OUT_OF_MEMORY),
+ 				 errmsg("out of memory")));
+ #endif
+ 
+ 	/* The pipe file descriptors are presumed to be 0,1 */
+ 	port->rsock = 0;
+ 	port->wsock = 1;
+ 
+ 	/* Default assumption about protocol to use */
+ 	FrontendProtocol = port->proto = PG_PROTOCOL_LATEST;
+ 
+ 	/* save process start time */
+ 	port->SessionStartTime = GetCurrentTimestamp();
+ 	MyStartTime = timestamptz_to_time_t(port->SessionStartTime);
+ 
+ 	/* set these to empty in case they are needed */
+ 	port->remote_host = "";
+ 	port->remote_port = "";
+ 
+ 	MyProcPort = port;
+ 
+ 	/* And pass off control to PostgresMain */
+ 	PostgresMain(argc, argv, username);
+ 
+ 	abort();					/* not reached */
+ }
+ 
+ 
  /*
   * sigusr1_handler - handle signal conditions from child processes
   */
*************** save_backend_variables(BackendParameters
*** 4795,4801 ****
  #endif
  {
  	memcpy(&param->port, port, sizeof(Port));
! 	if (!write_inheritable_socket(&param->portsocket, port->sock, childPid))
  		return false;
  
  	strlcpy(param->DataDir, DataDir, MAXPGPATH);
--- 4857,4863 ----
  #endif
  {
  	memcpy(&param->port, port, sizeof(Port));
! 	if (!write_inheritable_socket(&param->portsocket, port->rsock, childPid))
  		return false;
  
  	strlcpy(param->DataDir, DataDir, MAXPGPATH);
*************** static void
*** 5022,5028 ****
  restore_backend_variables(BackendParameters *param, Port *port)
  {
  	memcpy(port, &param->port, sizeof(Port));
! 	read_inheritable_socket(&port->sock, &param->portsocket);
  
  	SetDataDir(param->DataDir);
  
--- 5084,5091 ----
  restore_backend_variables(BackendParameters *param, Port *port)
  {
  	memcpy(port, &param->port, sizeof(Port));
! 	read_inheritable_socket(&port->rsock, &param->portsocket);
! 	port->wsock = port->rsock;
  
  	SetDataDir(param->DataDir);
  
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 38f7a3f..8cda8a3 100644
*** a/src/backend/replication/walsender.c
--- b/src/backend/replication/walsender.c
*************** WalSndLoop(void)
*** 855,861 ****
  
  			/* Sleep until something happens or replication timeout */
  			WaitLatchOrSocket(&MyWalSnd->latch, wakeEvents,
! 							  MyProcPort->sock, sleeptime);
  
  			/*
  			 * Check for replication timeout.  Note we ignore the corner case
--- 855,861 ----
  
  			/* Sleep until something happens or replication timeout */
  			WaitLatchOrSocket(&MyWalSnd->latch, wakeEvents,
! 							  MyProcPort->rsock, sleeptime);
  
  			/*
  			 * Check for replication timeout.  Note we ignore the corner case
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index f1248a8..d589f71 100644
*** a/src/backend/tcop/postgres.c
--- b/src/backend/tcop/postgres.c
*************** process_postgres_switches(int argc, char
*** 3257,3264 ****
  	{
  		gucsource = PGC_S_ARGV; /* switches came from command line */
  
! 		/* Ignore the initial --single argument, if present */
! 		if (argc > 1 && strcmp(argv[1], "--single") == 0)
  		{
  			argv++;
  			argc--;
--- 3257,3266 ----
  	{
  		gucsource = PGC_S_ARGV; /* switches came from command line */
  
! 		/* Ignore the initial --single or --child argument, if present */
! 		if (argc > 1 &&
! 			(strcmp(argv[1], "--single") == 0 ||
! 			 strcmp(argv[1], "--child") == 0))
  		{
  			argv++;
  			argc--;
*************** PostgresMain(int argc, char *argv[], con
*** 3522,3532 ****
  	 * standalone).
  	 */
  	if (!IsUnderPostmaster)
- 	{
  		MyProcPid = getpid();
  
  		MyStartTime = time(NULL);
- 	}
  
  	/*
  	 * Fire up essential subsystems: error and memory management
--- 3524,3533 ----
  	 * standalone).
  	 */
  	if (!IsUnderPostmaster)
  		MyProcPid = getpid();
  
+ 	if (MyProcPort == NULL)
  		MyStartTime = time(NULL);
  
  	/*
  	 * Fire up essential subsystems: error and memory management
*************** PostgresMain(int argc, char *argv[], con
*** 3538,3543 ****
--- 3539,3554 ----
  
  	SetProcessingMode(InitProcessing);
  
+ 	/*
+ 	 * In child-postgres mode, we can now initialize libpq and then enable
+ 	 * reporting of ereport errors to the client.
+ 	 */
+ 	if (!IsUnderPostmaster && MyProcPort != NULL)
+ 	{
+ 		pq_init();					/* initialize libpq to talk to client */
+ 		whereToSendOutput = DestRemote;	/* now safe to ereport to client */
+ 	}
+ 
  	/* Compute paths, if we didn't inherit them from postmaster */
  	if (my_exec_path[0] == '\0')
  	{
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index 4d92c18..3427e71 100644
*** a/src/include/libpq/libpq-be.h
--- b/src/include/libpq/libpq-be.h
*************** typedef struct
*** 99,110 ****
   * still available when a backend is running (see MyProcPort).	The data
   * it points to must also be malloc'd, or else palloc'd in TopMemoryContext,
   * so that it survives into PostgresMain execution!
   */
  
  typedef struct Port
  {
! 	pgsocket	sock;			/* File descriptor */
! 	bool		noblock;		/* is the socket in non-blocking mode? */
  	ProtocolVersion proto;		/* FE/BE protocol version */
  	SockAddr	laddr;			/* local addr (postmaster) */
  	SockAddr	raddr;			/* remote addr (client) */
--- 99,118 ----
   * still available when a backend is running (see MyProcPort).	The data
   * it points to must also be malloc'd, or else palloc'd in TopMemoryContext,
   * so that it survives into PostgresMain execution!
+  *
+  * When using a socket to communicate with the frontend, rsock and wsock are
+  * equal.  When using a pair of pipes, they are not.  Note that SSL, GSS,
+  * etc are not supported in the latter case, since those libraries expect to
+  * work with bidirectional file descriptors.  By convention, we use rsock
+  * when performing an operation that expects a socket; it doesn't really
+  * matter, but let's be consistent.
   */
  
  typedef struct Port
  {
! 	pgsocket	rsock;			/* File descriptor for reading */
! 	pgsocket	wsock;			/* File descriptor for writing */
! 	bool		noblock;		/* is the read socket in non-blocking mode? */
  	ProtocolVersion proto;		/* FE/BE protocol version */
  	SockAddr	laddr;			/* local addr (postmaster) */
  	SockAddr	raddr;			/* remote addr (client) */
*************** typedef struct Port
*** 157,168 ****
  	int			keepalives_interval;
  	int			keepalives_count;
  
- #if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
- 
  	/*
  	 * If GSSAPI is supported, store GSSAPI information. Otherwise, store a
  	 * NULL pointer to make sure offsets in the struct remain the same.
  	 */
  	pg_gssinfo *gss;
  #else
  	void	   *gss;
--- 165,175 ----
  	int			keepalives_interval;
  	int			keepalives_count;
  
  	/*
  	 * If GSSAPI is supported, store GSSAPI information. Otherwise, store a
  	 * NULL pointer to make sure offsets in the struct remain the same.
  	 */
+ #if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
  	pg_gssinfo *gss;
  #else
  	void	   *gss;
diff --git a/src/include/postmaster/postmaster.h b/src/include/postmaster/postmaster.h
index 0fe7ec2..6d4245c 100644
*** a/src/include/postmaster/postmaster.h
--- b/src/include/postmaster/postmaster.h
*************** extern int	postmaster_alive_fds[2];
*** 47,52 ****
--- 47,55 ----
  extern const char *progname;
  
  extern void PostmasterMain(int argc, char *argv[]) __attribute__((noreturn));
+ 
+ extern void ChildPostgresMain(int argc, char *argv[], const char *username) __attribute__((noreturn));
+ 
  extern void ClosePostmasterPorts(bool am_syslogger);
  
  extern int	MaxLivePostmasterChildren(void);
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 3dcd0c3..c226eb8 100644
*** a/src/interfaces/libpq/fe-connect.c
--- b/src/interfaces/libpq/fe-connect.c
***************
*** 17,22 ****
--- 17,23 ----
  
  #include <sys/types.h>
  #include <sys/stat.h>
+ #include <sys/wait.h>
  #include <fcntl.h>
  #include <ctype.h>
  #include <time.h>
*************** static const PQconninfoOption PQconninfo
*** 259,264 ****
--- 260,271 ----
  	{"replication", NULL, NULL, NULL,
  	"Replication", "D", 5},
  
+ 	{"standalone_datadir", NULL, NULL, NULL,
+ 	"Standalone-Data-Directory", "D", 64},
+ 
+ 	{"standalone_backend", NULL, NULL, NULL,
+ 	"Standalone-Backend", "D", 64},
+ 
  	/* Terminating entry --- MUST BE LAST */
  	{NULL, NULL, NULL, NULL,
  	NULL, NULL, 0}
*************** pgthreadlock_t pg_g_threadlock = default
*** 345,350 ****
--- 352,392 ----
  
  
  /*
+  *		pqDropConnection
+  *
+  * Close any physical connection to the server, and reset associated
+  * state inside the connection object.  We don't release state that
+  * would be needed to reconnect, though.
+  */
+ void
+ pqDropConnection(PGconn *conn)
+ {
+ 	/* Drop any SSL state */
+ 	pqsecure_close(conn);
+ 	/* Close the file descriptor(s) proper */
+ 	if (conn->rsock >= 0)
+ 		closesocket(conn->rsock);
+ 	if (conn->rsock != conn->wsock && conn->wsock >= 0)
+ 		closesocket(conn->wsock);
+ 	conn->rsock = conn->wsock = -1;
+ 	/* If we forked a child postgres process, wait for it to exit */
+ 	if (conn->postgres_pid > 0)
+ 	{
+ 		while (waitpid(conn->postgres_pid, NULL, 0) < 0)
+ 		{
+ 			/* If interrupted by signal, keep waiting */
+ 			if (errno != EINTR)
+ 				break;
+ 		}
+ 	}
+ 	conn->postgres_pid = -1;
+ 	/* Discard any unread/unsent data */
+ 	conn->inStart = conn->inCursor = conn->inEnd = 0;
+ 	conn->outCount = 0;
+ }
+ 
+ 
+ /*
   *		Connecting to a Database
   *
   * There are now six different ways a user of this API can connect to the
*************** fillPGconn(PGconn *conn, PQconninfoOptio
*** 621,626 ****
--- 663,672 ----
  	conn->pghost = tmp ? strdup(tmp) : NULL;
  	tmp = conninfo_getval(connOptions, "port");
  	conn->pgport = tmp ? strdup(tmp) : NULL;
+ 	tmp = conninfo_getval(connOptions, "standalone_datadir");
+ 	conn->standalone_datadir = tmp ? strdup(tmp) : NULL;
+ 	tmp = conninfo_getval(connOptions, "standalone_backend");
+ 	conn->standalone_backend = tmp ? strdup(tmp) : NULL;
  	tmp = conninfo_getval(connOptions, "tty");
  	conn->pgtty = tmp ? strdup(tmp) : NULL;
  	tmp = conninfo_getval(connOptions, "options");
*************** connectNoDelay(PGconn *conn)
*** 1003,1009 ****
  #ifdef	TCP_NODELAY
  	int			on = 1;
  
! 	if (setsockopt(conn->sock, IPPROTO_TCP, TCP_NODELAY,
  				   (char *) &on,
  				   sizeof(on)) < 0)
  	{
--- 1049,1055 ----
  #ifdef	TCP_NODELAY
  	int			on = 1;
  
! 	if (setsockopt(conn->rsock, IPPROTO_TCP, TCP_NODELAY,
  				   (char *) &on,
  				   sizeof(on)) < 0)
  	{
*************** setKeepalivesIdle(PGconn *conn)
*** 1149,1155 ****
  		idle = 0;
  
  #ifdef TCP_KEEPIDLE
! 	if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPIDLE,
  				   (char *) &idle, sizeof(idle)) < 0)
  	{
  		char		sebuf[256];
--- 1195,1201 ----
  		idle = 0;
  
  #ifdef TCP_KEEPIDLE
! 	if (setsockopt(conn->rsock, IPPROTO_TCP, TCP_KEEPIDLE,
  				   (char *) &idle, sizeof(idle)) < 0)
  	{
  		char		sebuf[256];
*************** setKeepalivesIdle(PGconn *conn)
*** 1162,1168 ****
  #else
  #ifdef TCP_KEEPALIVE
  	/* Darwin uses TCP_KEEPALIVE rather than TCP_KEEPIDLE */
! 	if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPALIVE,
  				   (char *) &idle, sizeof(idle)) < 0)
  	{
  		char		sebuf[256];
--- 1208,1214 ----
  #else
  #ifdef TCP_KEEPALIVE
  	/* Darwin uses TCP_KEEPALIVE rather than TCP_KEEPIDLE */
! 	if (setsockopt(conn->rsock, IPPROTO_TCP, TCP_KEEPALIVE,
  				   (char *) &idle, sizeof(idle)) < 0)
  	{
  		char		sebuf[256];
*************** setKeepalivesInterval(PGconn *conn)
*** 1194,1200 ****
  		interval = 0;
  
  #ifdef TCP_KEEPINTVL
! 	if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPINTVL,
  				   (char *) &interval, sizeof(interval)) < 0)
  	{
  		char		sebuf[256];
--- 1240,1246 ----
  		interval = 0;
  
  #ifdef TCP_KEEPINTVL
! 	if (setsockopt(conn->rsock, IPPROTO_TCP, TCP_KEEPINTVL,
  				   (char *) &interval, sizeof(interval)) < 0)
  	{
  		char		sebuf[256];
*************** setKeepalivesCount(PGconn *conn)
*** 1226,1232 ****
  		count = 0;
  
  #ifdef TCP_KEEPCNT
! 	if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPCNT,
  				   (char *) &count, sizeof(count)) < 0)
  	{
  		char		sebuf[256];
--- 1272,1278 ----
  		count = 0;
  
  #ifdef TCP_KEEPCNT
! 	if (setsockopt(conn->rsock, IPPROTO_TCP, TCP_KEEPCNT,
  				   (char *) &count, sizeof(count)) < 0)
  	{
  		char		sebuf[256];
*************** setKeepalivesWin32(PGconn *conn)
*** 1268,1274 ****
  	ka.keepalivetime = idle * 1000;
  	ka.keepaliveinterval = interval * 1000;
  
! 	if (WSAIoctl(conn->sock,
  				 SIO_KEEPALIVE_VALS,
  				 (LPVOID) &ka,
  				 sizeof(ka),
--- 1314,1320 ----
  	ka.keepalivetime = idle * 1000;
  	ka.keepaliveinterval = interval * 1000;
  
! 	if (WSAIoctl(conn->rsock,
  				 SIO_KEEPALIVE_VALS,
  				 (LPVOID) &ka,
  				 sizeof(ka),
*************** setKeepalivesWin32(PGconn *conn)
*** 1289,1294 ****
--- 1335,1397 ----
  #endif   /* SIO_KEEPALIVE_VALS */
  #endif   /* WIN32 */
  
+ /*
+  * Fork and exec a command, connecting up pipes to its stdin and stdout.
+  */
+ static pid_t
+ pg_popen2(char **argv, int *infp, int *outfp)
+ {
+ 	pid_t		pid;
+ 	int			p_stdin[2];
+ 	int			p_stdout[2];
+ 
+ 	if (pipe(p_stdin) != 0)
+ 		return -1;
+ 	if (pipe(p_stdout) != 0)
+ 	{
+ 		close(p_stdin[0]);
+ 		close(p_stdin[1]);
+ 		return -1;
+ 	}
+ 
+ 	pid = fork();
+ 
+ 	if (pid < 0)
+ 	{
+ 		/* fork failed */
+ 		close(p_stdin[0]);
+ 		close(p_stdin[1]);
+ 		close(p_stdout[0]);
+ 		close(p_stdout[1]);
+ 		return pid;
+ 	}
+ 	else if (pid == 0)
+ 	{
+ 		/* successful, in child process */
+ 		close(p_stdin[1]);
+ 		close(p_stdout[0]);
+ 		dup2(p_stdin[0], 0);
+ 		close(p_stdin[0]);
+ 		dup2(p_stdout[1], 1);
+ 		close(p_stdout[1]);
+ 
+ 		execv(argv[0], argv);
+ 		perror(argv[0]);
+ 		exit(1);
+ 	}
+ 	else
+ 	{
+ 		/* successful, in parent process */
+ 		close(p_stdin[0]);
+ 		close(p_stdout[1]);
+ 		*infp = p_stdout[0];
+ 		*outfp = p_stdin[1];
+ 	}
+ 
+ 	return pid;
+ }
+ 
+ 
  /* ----------
   * connectDBStart -
   *		Begin the process of making a connection to the backend.
*************** connectDBStart(PGconn *conn)
*** 1317,1322 ****
--- 1420,1474 ----
  	conn->outCount = 0;
  
  	/*
+ 	 * If the standalone_datadir option was specified, ignore any host or
+ 	 * port specifications and just try to fork a standalone backend.
+ 	 */
+ 	if (conn->standalone_datadir && conn->standalone_datadir[0])
+ 	{
+ 		char   *be_argv[10];
+ 
+ 		/*
+ 		 * We set up the backend's command line in execv(3) style, so that
+ 		 * we don't need to cope with shell quoting rules.
+ 		 */
+ 		if (conn->standalone_backend && conn->standalone_backend[0])
+ 			be_argv[0] = conn->standalone_backend;
+ 		else					/* assume we should use hard-wired path */
+ 			be_argv[0] = PGBINDIR "/postgres";
+ 
+ 		be_argv[1] = "--child";
+ 		be_argv[2] = "-D";
+ 		be_argv[3] = conn->standalone_datadir;
+ 		be_argv[4] = (conn->dbName && conn->dbName[0]) ? conn->dbName : NULL;
+ 		be_argv[5] = NULL;
+ 
+ 		conn->postgres_pid = pg_popen2(be_argv, &conn->rsock, &conn->wsock);
+ 		if (conn->postgres_pid < 0)
+ 		{
+ 			char		sebuf[256];
+ 
+ 			appendPQExpBuffer(&conn->errorMessage,
+ 							  libpq_gettext("could not fork standalone backend: %s\n"),
+ 							  pqStrerror(errno, sebuf, sizeof(sebuf)));
+ 			goto connect_errReturn;
+ 		}
+ 
+ 		/*
+ 		 * Go directly to CONNECTION_AUTH_OK state, since the standalone
+ 		 * backend is not going to issue any authentication challenge to us.
+ 		 * We're just waiting for startup to conclude.
+ 		 */
+ #ifdef USE_SSL
+ 		conn->allow_ssl_try = false;
+ #endif
+ 		conn->pversion = PG_PROTOCOL(3, 0);
+ 		conn->status = CONNECTION_AUTH_OK;
+ 		conn->asyncStatus = PGASYNC_BUSY;
+ 
+ 		return 1;
+ 	}
+ 
+ 	/*
  	 * Determine the parameters to pass to pg_getaddrinfo_all.
  	 */
  
*************** connectDBStart(PGconn *conn)
*** 1416,1427 ****
  		return 1;
  
  connect_errReturn:
! 	if (conn->sock >= 0)
! 	{
! 		pqsecure_close(conn);
! 		closesocket(conn->sock);
! 		conn->sock = -1;
! 	}
  	conn->status = CONNECTION_BAD;
  	return 0;
  }
--- 1568,1574 ----
  		return 1;
  
  connect_errReturn:
! 	pqDropConnection(conn);
  	conn->status = CONNECTION_BAD;
  	return 0;
  }
*************** keep_going:						/* We will come back to
*** 1617,1624 ****
  					conn->raddr.salen = addr_cur->ai_addrlen;
  
  					/* Open a socket */
! 					conn->sock = socket(addr_cur->ai_family, SOCK_STREAM, 0);
! 					if (conn->sock < 0)
  					{
  						/*
  						 * ignore socket() failure if we have more addresses
--- 1764,1771 ----
  					conn->raddr.salen = addr_cur->ai_addrlen;
  
  					/* Open a socket */
! 					conn->rsock = socket(addr_cur->ai_family, SOCK_STREAM, 0);
! 					if (conn->rsock < 0)
  					{
  						/*
  						 * ignore socket() failure if we have more addresses
*************** keep_going:						/* We will come back to
*** 1635,1640 ****
--- 1782,1790 ----
  						break;
  					}
  
+ 					/* Socket is bidirectional */
+ 					conn->wsock = conn->rsock;
+ 
  					/*
  					 * Select socket options: no delay of outgoing data for
  					 * TCP sockets, nonblock mode, close-on-exec. Fail if any
*************** keep_going:						/* We will come back to
*** 1644,1674 ****
  					{
  						if (!connectNoDelay(conn))
  						{
! 							closesocket(conn->sock);
! 							conn->sock = -1;
  							conn->addr_cur = addr_cur->ai_next;
  							continue;
  						}
  					}
! 					if (!pg_set_noblock(conn->sock))
  					{
  						appendPQExpBuffer(&conn->errorMessage,
  										  libpq_gettext("could not set socket to non-blocking mode: %s\n"),
  							SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
! 						closesocket(conn->sock);
! 						conn->sock = -1;
  						conn->addr_cur = addr_cur->ai_next;
  						continue;
  					}
  
  #ifdef F_SETFD
! 					if (fcntl(conn->sock, F_SETFD, FD_CLOEXEC) == -1)
  					{
  						appendPQExpBuffer(&conn->errorMessage,
  										  libpq_gettext("could not set socket to close-on-exec mode: %s\n"),
  							SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
! 						closesocket(conn->sock);
! 						conn->sock = -1;
  						conn->addr_cur = addr_cur->ai_next;
  						continue;
  					}
--- 1794,1821 ----
  					{
  						if (!connectNoDelay(conn))
  						{
! 							pqDropConnection(conn);
  							conn->addr_cur = addr_cur->ai_next;
  							continue;
  						}
  					}
! 					if (!pg_set_noblock(conn->rsock))
  					{
  						appendPQExpBuffer(&conn->errorMessage,
  										  libpq_gettext("could not set socket to non-blocking mode: %s\n"),
  							SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
! 						pqDropConnection(conn);
  						conn->addr_cur = addr_cur->ai_next;
  						continue;
  					}
  
  #ifdef F_SETFD
! 					if (fcntl(conn->rsock, F_SETFD, FD_CLOEXEC) == -1)
  					{
  						appendPQExpBuffer(&conn->errorMessage,
  										  libpq_gettext("could not set socket to close-on-exec mode: %s\n"),
  							SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
! 						pqDropConnection(conn);
  						conn->addr_cur = addr_cur->ai_next;
  						continue;
  					}
*************** keep_going:						/* We will come back to
*** 1693,1699 ****
  							/* Do nothing */
  						}
  #ifndef WIN32
! 						else if (setsockopt(conn->sock,
  											SOL_SOCKET, SO_KEEPALIVE,
  											(char *) &on, sizeof(on)) < 0)
  						{
--- 1840,1846 ----
  							/* Do nothing */
  						}
  #ifndef WIN32
! 						else if (setsockopt(conn->rsock,
  											SOL_SOCKET, SO_KEEPALIVE,
  											(char *) &on, sizeof(on)) < 0)
  						{
*************** keep_going:						/* We will come back to
*** 1715,1722 ****
  
  						if (err)
  						{
! 							closesocket(conn->sock);
! 							conn->sock = -1;
  							conn->addr_cur = addr_cur->ai_next;
  							continue;
  						}
--- 1862,1868 ----
  
  						if (err)
  						{
! 							pqDropConnection(conn);
  							conn->addr_cur = addr_cur->ai_next;
  							continue;
  						}
*************** keep_going:						/* We will come back to
*** 1754,1760 ****
  
  #ifdef SO_NOSIGPIPE
  					optval = 1;
! 					if (setsockopt(conn->sock, SOL_SOCKET, SO_NOSIGPIPE,
  								   (char *) &optval, sizeof(optval)) == 0)
  					{
  						conn->sigpipe_so = true;
--- 1900,1906 ----
  
  #ifdef SO_NOSIGPIPE
  					optval = 1;
! 					if (setsockopt(conn->rsock, SOL_SOCKET, SO_NOSIGPIPE,
  								   (char *) &optval, sizeof(optval)) == 0)
  					{
  						conn->sigpipe_so = true;
*************** keep_going:						/* We will come back to
*** 1766,1772 ****
  					 * Start/make connection.  This should not block, since we
  					 * are in nonblock mode.  If it does, well, too bad.
  					 */
! 					if (connect(conn->sock, addr_cur->ai_addr,
  								addr_cur->ai_addrlen) < 0)
  					{
  						if (SOCK_ERRNO == EINPROGRESS ||
--- 1912,1918 ----
  					 * Start/make connection.  This should not block, since we
  					 * are in nonblock mode.  If it does, well, too bad.
  					 */
! 					if (connect(conn->rsock, addr_cur->ai_addr,
  								addr_cur->ai_addrlen) < 0)
  					{
  						if (SOCK_ERRNO == EINPROGRESS ||
*************** keep_going:						/* We will come back to
*** 1802,1812 ****
  					 * failure and keep going if there are more addresses.
  					 */
  					connectFailureMessage(conn, SOCK_ERRNO);
! 					if (conn->sock >= 0)
! 					{
! 						closesocket(conn->sock);
! 						conn->sock = -1;
! 					}
  
  					/*
  					 * Try the next address, if any.
--- 1948,1954 ----
  					 * failure and keep going if there are more addresses.
  					 */
  					connectFailureMessage(conn, SOCK_ERRNO);
! 					pqDropConnection(conn);
  
  					/*
  					 * Try the next address, if any.
*************** keep_going:						/* We will come back to
*** 1835,1841 ****
  				 * state waiting for us on the socket.
  				 */
  
! 				if (getsockopt(conn->sock, SOL_SOCKET, SO_ERROR,
  							   (char *) &optval, &optlen) == -1)
  				{
  					appendPQExpBuffer(&conn->errorMessage,
--- 1977,1983 ----
  				 * state waiting for us on the socket.
  				 */
  
! 				if (getsockopt(conn->rsock, SOL_SOCKET, SO_ERROR,
  							   (char *) &optval, &optlen) == -1)
  				{
  					appendPQExpBuffer(&conn->errorMessage,
*************** keep_going:						/* We will come back to
*** 1851,1856 ****
--- 1993,1999 ----
  					 * error message.
  					 */
  					connectFailureMessage(conn, optval);
+ 					pqDropConnection(conn);
  
  					/*
  					 * If more addresses remain, keep trying, just as in the
*************** keep_going:						/* We will come back to
*** 1858,1868 ****
  					 */
  					if (conn->addr_cur->ai_next != NULL)
  					{
- 						if (conn->sock >= 0)
- 						{
- 							closesocket(conn->sock);
- 							conn->sock = -1;
- 						}
  						conn->addr_cur = conn->addr_cur->ai_next;
  						conn->status = CONNECTION_NEEDED;
  						goto keep_going;
--- 2001,2006 ----
*************** keep_going:						/* We will come back to
*** 1872,1878 ****
  
  				/* Fill in the client address */
  				conn->laddr.salen = sizeof(conn->laddr.addr);
! 				if (getsockname(conn->sock,
  								(struct sockaddr *) & conn->laddr.addr,
  								&conn->laddr.salen) < 0)
  				{
--- 2010,2016 ----
  
  				/* Fill in the client address */
  				conn->laddr.salen = sizeof(conn->laddr.addr);
! 				if (getsockname(conn->rsock,
  								(struct sockaddr *) & conn->laddr.addr,
  								&conn->laddr.salen) < 0)
  				{
*************** keep_going:						/* We will come back to
*** 1910,1916 ****
  					gid_t		gid;
  
  					errno = 0;
! 					if (getpeereid(conn->sock, &uid, &gid) != 0)
  					{
  						/*
  						 * Provide special error message if getpeereid is a
--- 2048,2054 ----
  					gid_t		gid;
  
  					errno = 0;
! 					if (getpeereid(conn->rsock, &uid, &gid) != 0)
  					{
  						/*
  						 * Provide special error message if getpeereid is a
*************** keep_going:						/* We will come back to
*** 2137,2148 ****
  						/* only retry once */
  						conn->allow_ssl_try = false;
  						/* Must drop the old connection */
! 						closesocket(conn->sock);
! 						conn->sock = -1;
  						conn->status = CONNECTION_NEEDED;
- 						/* Discard any unread/unsent data */
- 						conn->inStart = conn->inCursor = conn->inEnd = 0;
- 						conn->outCount = 0;
  						goto keep_going;
  					}
  				}
--- 2275,2282 ----
  						/* only retry once */
  						conn->allow_ssl_try = false;
  						/* Must drop the old connection */
! 						pqDropConnection(conn);
  						conn->status = CONNECTION_NEEDED;
  						goto keep_going;
  					}
  				}
*************** keep_going:						/* We will come back to
*** 2252,2264 ****
  					{
  						conn->pversion = PG_PROTOCOL(2, 0);
  						/* Must drop the old connection */
! 						pqsecure_close(conn);
! 						closesocket(conn->sock);
! 						conn->sock = -1;
  						conn->status = CONNECTION_NEEDED;
- 						/* Discard any unread/unsent data */
- 						conn->inStart = conn->inCursor = conn->inEnd = 0;
- 						conn->outCount = 0;
  						goto keep_going;
  					}
  
--- 2386,2393 ----
  					{
  						conn->pversion = PG_PROTOCOL(2, 0);
  						/* Must drop the old connection */
! 						pqDropConnection(conn);
  						conn->status = CONNECTION_NEEDED;
  						goto keep_going;
  					}
  
*************** keep_going:						/* We will come back to
*** 2323,2334 ****
  						/* only retry once */
  						conn->wait_ssl_try = false;
  						/* Must drop the old connection */
! 						closesocket(conn->sock);
! 						conn->sock = -1;
  						conn->status = CONNECTION_NEEDED;
- 						/* Discard any unread/unsent data */
- 						conn->inStart = conn->inCursor = conn->inEnd = 0;
- 						conn->outCount = 0;
  						goto keep_going;
  					}
  
--- 2452,2459 ----
  						/* only retry once */
  						conn->wait_ssl_try = false;
  						/* Must drop the old connection */
! 						pqDropConnection(conn);
  						conn->status = CONNECTION_NEEDED;
  						goto keep_going;
  					}
  
*************** keep_going:						/* We will come back to
*** 2343,2355 ****
  						/* only retry once */
  						conn->allow_ssl_try = false;
  						/* Must drop the old connection */
! 						pqsecure_close(conn);
! 						closesocket(conn->sock);
! 						conn->sock = -1;
  						conn->status = CONNECTION_NEEDED;
- 						/* Discard any unread/unsent data */
- 						conn->inStart = conn->inCursor = conn->inEnd = 0;
- 						conn->outCount = 0;
  						goto keep_going;
  					}
  #endif
--- 2468,2475 ----
  						/* only retry once */
  						conn->allow_ssl_try = false;
  						/* Must drop the old connection */
! 						pqDropConnection(conn);
  						conn->status = CONNECTION_NEEDED;
  						goto keep_going;
  					}
  #endif
*************** keep_going:						/* We will come back to
*** 2509,2521 ****
  							PQclear(res);
  							conn->send_appname = false;
  							/* Must drop the old connection */
! 							pqsecure_close(conn);
! 							closesocket(conn->sock);
! 							conn->sock = -1;
  							conn->status = CONNECTION_NEEDED;
- 							/* Discard any unread/unsent data */
- 							conn->inStart = conn->inCursor = conn->inEnd = 0;
- 							conn->outCount = 0;
  							goto keep_going;
  						}
  					}
--- 2629,2636 ----
  							PQclear(res);
  							conn->send_appname = false;
  							/* Must drop the old connection */
! 							pqDropConnection(conn);
  							conn->status = CONNECTION_NEEDED;
  							goto keep_going;
  						}
  					}
*************** makeEmptyPGconn(void)
*** 2722,2728 ****
  	conn->client_encoding = PG_SQL_ASCII;
  	conn->std_strings = false;	/* unless server says differently */
  	conn->verbosity = PQERRORS_DEFAULT;
! 	conn->sock = -1;
  	conn->auth_req_received = false;
  	conn->password_needed = false;
  	conn->dot_pgpass_used = false;
--- 2837,2844 ----
  	conn->client_encoding = PG_SQL_ASCII;
  	conn->std_strings = false;	/* unless server says differently */
  	conn->verbosity = PQERRORS_DEFAULT;
! 	conn->rsock = conn->wsock = -1;
! 	conn->postgres_pid = -1;
  	conn->auth_req_received = false;
  	conn->password_needed = false;
  	conn->dot_pgpass_used = false;
*************** freePGconn(PGconn *conn)
*** 2802,2807 ****
--- 2918,2927 ----
  		free(conn->pgport);
  	if (conn->pgunixsocket)
  		free(conn->pgunixsocket);
+ 	if (conn->standalone_datadir)
+ 		free(conn->standalone_datadir);
+ 	if (conn->standalone_backend)
+ 		free(conn->standalone_backend);
  	if (conn->pgtty)
  		free(conn->pgtty);
  	if (conn->connect_timeout)
*************** closePGconn(PGconn *conn)
*** 2887,2893 ****
  	 * Note that the protocol doesn't allow us to send Terminate messages
  	 * during the startup phase.
  	 */
! 	if (conn->sock >= 0 && conn->status == CONNECTION_OK)
  	{
  		/*
  		 * Try to send "close connection" message to backend. Ignore any
--- 3007,3013 ----
  	 * Note that the protocol doesn't allow us to send Terminate messages
  	 * during the startup phase.
  	 */
! 	if (conn->wsock >= 0 && conn->status == CONNECTION_OK)
  	{
  		/*
  		 * Try to send "close connection" message to backend. Ignore any
*************** closePGconn(PGconn *conn)
*** 2909,2920 ****
  	/*
  	 * Close the connection, reset all transient state, flush I/O buffers.
  	 */
! 	if (conn->sock >= 0)
! 	{
! 		pqsecure_close(conn);
! 		closesocket(conn->sock);
! 	}
! 	conn->sock = -1;
  	conn->status = CONNECTION_BAD;		/* Well, not really _bad_ - just
  										 * absent */
  	conn->asyncStatus = PGASYNC_IDLE;
--- 3029,3035 ----
  	/*
  	 * Close the connection, reset all transient state, flush I/O buffers.
  	 */
! 	pqDropConnection(conn);
  	conn->status = CONNECTION_BAD;		/* Well, not really _bad_ - just
  										 * absent */
  	conn->asyncStatus = PGASYNC_IDLE;
*************** closePGconn(PGconn *conn)
*** 2943,2950 ****
  	if (conn->lobjfuncs)
  		free(conn->lobjfuncs);
  	conn->lobjfuncs = NULL;
- 	conn->inStart = conn->inCursor = conn->inEnd = 0;
- 	conn->outCount = 0;
  #ifdef ENABLE_GSS
  	{
  		OM_uint32	min_s;
--- 3058,3063 ----
*************** PQgetCancel(PGconn *conn)
*** 3115,3121 ****
  	if (!conn)
  		return NULL;
  
! 	if (conn->sock < 0)
  		return NULL;
  
  	cancel = malloc(sizeof(PGcancel));
--- 3228,3234 ----
  	if (!conn)
  		return NULL;
  
! 	if (conn->rsock < 0)
  		return NULL;
  
  	cancel = malloc(sizeof(PGcancel));
*************** PQrequestCancel(PGconn *conn)
*** 3296,3302 ****
  	if (!conn)
  		return FALSE;
  
! 	if (conn->sock < 0)
  	{
  		strlcpy(conn->errorMessage.data,
  				"PQrequestCancel() -- connection is not open\n",
--- 3409,3415 ----
  	if (!conn)
  		return FALSE;
  
! 	if (conn->rsock < 0)
  	{
  		strlcpy(conn->errorMessage.data,
  				"PQrequestCancel() -- connection is not open\n",
*************** PQsocket(const PGconn *conn)
*** 5232,5238 ****
  {
  	if (!conn)
  		return -1;
! 	return conn->sock;
  }
  
  int
--- 5345,5351 ----
  {
  	if (!conn)
  		return -1;
! 	return conn->rsock;
  }
  
  int
diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c
index 77124ef..0c81803 100644
*** a/src/interfaces/libpq/fe-exec.c
--- b/src/interfaces/libpq/fe-exec.c
*************** PQfn(PGconn *conn,
*** 2523,2529 ****
  	/* clear the error string */
  	resetPQExpBuffer(&conn->errorMessage);
  
! 	if (conn->sock < 0 || conn->asyncStatus != PGASYNC_IDLE ||
  		conn->result != NULL)
  	{
  		printfPQExpBuffer(&conn->errorMessage,
--- 2523,2529 ----
  	/* clear the error string */
  	resetPQExpBuffer(&conn->errorMessage);
  
! 	if (conn->rsock < 0 || conn->asyncStatus != PGASYNC_IDLE ||
  		conn->result != NULL)
  	{
  		printfPQExpBuffer(&conn->errorMessage,
diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c
index b5e5519..a34d203 100644
*** a/src/interfaces/libpq/fe-misc.c
--- b/src/interfaces/libpq/fe-misc.c
*************** static int	pqPutMsgBytes(const void *buf
*** 64,70 ****
  static int	pqSendSome(PGconn *conn, int len);
  static int pqSocketCheck(PGconn *conn, int forRead, int forWrite,
  			  time_t end_time);
! static int	pqSocketPoll(int sock, int forRead, int forWrite, time_t end_time);
  
  /*
   * PQlibVersion: return the libpq version number
--- 64,72 ----
  static int	pqSendSome(PGconn *conn, int len);
  static int pqSocketCheck(PGconn *conn, int forRead, int forWrite,
  			  time_t end_time);
! static int	pqSocketPoll(int rsock, int wsock, int forRead, int forWrite,
! 			 time_t end_time);
! 
  
  /*
   * PQlibVersion: return the libpq version number
*************** pqReadData(PGconn *conn)
*** 605,611 ****
  	int			someread = 0;
  	int			nread;
  
! 	if (conn->sock < 0)
  	{
  		printfPQExpBuffer(&conn->errorMessage,
  						  libpq_gettext("connection not open\n"));
--- 607,613 ----
  	int			someread = 0;
  	int			nread;
  
! 	if (conn->rsock < 0)
  	{
  		printfPQExpBuffer(&conn->errorMessage,
  						  libpq_gettext("connection not open\n"));
*************** retry4:
*** 780,790 ****
  	 * has been set already.
  	 */
  definitelyFailed:
  	conn->status = CONNECTION_BAD;		/* No more connection to backend */
- 	pqsecure_close(conn);
- 	closesocket(conn->sock);
- 	conn->sock = -1;
- 
  	return -1;
  }
  
--- 782,789 ----
  	 * has been set already.
  	 */
  definitelyFailed:
+ 	pqDropConnection(conn);
  	conn->status = CONNECTION_BAD;		/* No more connection to backend */
  	return -1;
  }
  
*************** pqSendSome(PGconn *conn, int len)
*** 804,810 ****
  	int			remaining = conn->outCount;
  	int			result = 0;
  
! 	if (conn->sock < 0)
  	{
  		printfPQExpBuffer(&conn->errorMessage,
  						  libpq_gettext("connection not open\n"));
--- 803,809 ----
  	int			remaining = conn->outCount;
  	int			result = 0;
  
! 	if (conn->rsock < 0)
  	{
  		printfPQExpBuffer(&conn->errorMessage,
  						  libpq_gettext("connection not open\n"));
*************** pqSocketCheck(PGconn *conn, int forRead,
*** 1013,1019 ****
  
  	if (!conn)
  		return -1;
! 	if (conn->sock < 0)
  	{
  		printfPQExpBuffer(&conn->errorMessage,
  						  libpq_gettext("socket not open\n"));
--- 1012,1018 ----
  
  	if (!conn)
  		return -1;
! 	if (conn->rsock < 0)
  	{
  		printfPQExpBuffer(&conn->errorMessage,
  						  libpq_gettext("socket not open\n"));
*************** pqSocketCheck(PGconn *conn, int forRead,
*** 1031,1037 ****
  
  	/* We will retry as long as we get EINTR */
  	do
! 		result = pqSocketPoll(conn->sock, forRead, forWrite, end_time);
  	while (result < 0 && SOCK_ERRNO == EINTR);
  
  	if (result < 0)
--- 1030,1037 ----
  
  	/* We will retry as long as we get EINTR */
  	do
! 		result = pqSocketPoll(conn->rsock, conn->wsock, forRead, forWrite,
! 							  end_time);
  	while (result < 0 && SOCK_ERRNO == EINTR);
  
  	if (result < 0)
*************** pqSocketCheck(PGconn *conn, int forRead,
*** 1048,1054 ****
  
  
  /*
!  * Check a file descriptor for read and/or write data, possibly waiting.
   * If neither forRead nor forWrite are set, immediately return a timeout
   * condition (without waiting).  Return >0 if condition is met, 0
   * if a timeout occurred, -1 if an error or interrupt occurred.
--- 1048,1054 ----
  
  
  /*
!  * Check file descriptor(s) for read and/or write data, possibly waiting.
   * If neither forRead nor forWrite are set, immediately return a timeout
   * condition (without waiting).  Return >0 if condition is met, 0
   * if a timeout occurred, -1 if an error or interrupt occurred.
*************** pqSocketCheck(PGconn *conn, int forRead,
*** 1057,1080 ****
   * if end_time is 0 (or indeed, any time before now).
   */
  static int
! pqSocketPoll(int sock, int forRead, int forWrite, time_t end_time)
  {
  	/* We use poll(2) if available, otherwise select(2) */
  #ifdef HAVE_POLL
! 	struct pollfd input_fd;
  	int			timeout_ms;
  
  	if (!forRead && !forWrite)
  		return 0;
  
! 	input_fd.fd = sock;
! 	input_fd.events = POLLERR;
! 	input_fd.revents = 0;
! 
! 	if (forRead)
! 		input_fd.events |= POLLIN;
! 	if (forWrite)
! 		input_fd.events |= POLLOUT;
  
  	/* Compute appropriate timeout interval */
  	if (end_time == ((time_t) -1))
--- 1057,1100 ----
   * if end_time is 0 (or indeed, any time before now).
   */
  static int
! pqSocketPoll(int rsock, int wsock, int forRead, int forWrite, time_t end_time)
  {
  	/* We use poll(2) if available, otherwise select(2) */
  #ifdef HAVE_POLL
! 	struct pollfd poll_fds[2];
! 	int			nfds;
  	int			timeout_ms;
  
  	if (!forRead && !forWrite)
  		return 0;
  
! 	if (forRead && forWrite && rsock != wsock)
! 	{
! 		/* need two pollfds; this path is uncommon */
! 		poll_fds[0].fd = rsock;
! 		poll_fds[0].events = POLLIN | POLLERR;
! 		poll_fds[0].revents = 0;
! 		poll_fds[1].fd = wsock;
! 		poll_fds[1].events = POLLOUT | POLLERR;
! 		poll_fds[1].revents = 0;
! 		nfds = 2;
! 	}
! 	else
! 	{
! 		poll_fds[0].events = POLLERR;
! 		poll_fds[0].revents = 0;
! 		if (forRead)
! 		{
! 			poll_fds[0].fd = rsock;
! 			poll_fds[0].events |= POLLIN;
! 		}
! 		if (forWrite)
! 		{
! 			poll_fds[0].fd = wsock;
! 			poll_fds[0].events |= POLLOUT;
! 		}
! 		nfds = 1;
! 	}
  
  	/* Compute appropriate timeout interval */
  	if (end_time == ((time_t) -1))
*************** pqSocketPoll(int sock, int forRead, int
*** 1089,1100 ****
  			timeout_ms = 0;
  	}
  
! 	return poll(&input_fd, 1, timeout_ms);
  #else							/* !HAVE_POLL */
  
  	fd_set		input_mask;
  	fd_set		output_mask;
  	fd_set		except_mask;
  	struct timeval timeout;
  	struct timeval *ptr_timeout;
  
--- 1109,1121 ----
  			timeout_ms = 0;
  	}
  
! 	return poll(poll_fds, nfds, timeout_ms);
  #else							/* !HAVE_POLL */
  
  	fd_set		input_mask;
  	fd_set		output_mask;
  	fd_set		except_mask;
+ 	int			maxfd;
  	struct timeval timeout;
  	struct timeval *ptr_timeout;
  
*************** pqSocketPoll(int sock, int forRead, int
*** 1104,1115 ****
  	FD_ZERO(&input_mask);
  	FD_ZERO(&output_mask);
  	FD_ZERO(&except_mask);
  	if (forRead)
! 		FD_SET(sock, &input_mask);
  
  	if (forWrite)
! 		FD_SET(sock, &output_mask);
! 	FD_SET(sock, &except_mask);
  
  	/* Compute appropriate timeout interval */
  	if (end_time == ((time_t) -1))
--- 1125,1145 ----
  	FD_ZERO(&input_mask);
  	FD_ZERO(&output_mask);
  	FD_ZERO(&except_mask);
+ 	maxfd = -1;
+ 
  	if (forRead)
! 	{
! 		FD_SET(rsock, &input_mask);
! 		FD_SET(rsock, &except_mask);
! 		maxfd = rsock;
! 	}
  
  	if (forWrite)
! 	{
! 		FD_SET(wsock, &output_mask);
! 		FD_SET(wsock, &except_mask);
! 		maxfd = Max(maxfd, wsock);
! 	}
  
  	/* Compute appropriate timeout interval */
  	if (end_time == ((time_t) -1))
*************** pqSocketPoll(int sock, int forRead, int
*** 1126,1132 ****
  		ptr_timeout = &timeout;
  	}
  
! 	return select(sock + 1, &input_mask, &output_mask,
  				  &except_mask, ptr_timeout);
  #endif   /* HAVE_POLL */
  }
--- 1156,1162 ----
  		ptr_timeout = &timeout;
  	}
  
! 	return select(maxfd + 1, &input_mask, &output_mask,
  				  &except_mask, ptr_timeout);
  #endif   /* HAVE_POLL */
  }
diff --git a/src/interfaces/libpq/fe-protocol2.c b/src/interfaces/libpq/fe-protocol2.c
index 1ba5885..16faca9 100644
*** a/src/interfaces/libpq/fe-protocol2.c
--- b/src/interfaces/libpq/fe-protocol2.c
*************** pqGetline2(PGconn *conn, char *s, int ma
*** 1211,1217 ****
  {
  	int			result = 1;		/* return value if buffer overflows */
  
! 	if (conn->sock < 0 ||
  		conn->asyncStatus != PGASYNC_COPY_OUT)
  	{
  		*s = '\0';
--- 1211,1217 ----
  {
  	int			result = 1;		/* return value if buffer overflows */
  
! 	if (conn->rsock < 0 ||
  		conn->asyncStatus != PGASYNC_COPY_OUT)
  	{
  		*s = '\0';
diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c
index d289f82..ab88109 100644
*** a/src/interfaces/libpq/fe-protocol3.c
--- b/src/interfaces/libpq/fe-protocol3.c
*************** handleSyncLoss(PGconn *conn, char id, in
*** 430,438 ****
  	pqSaveErrorResult(conn);
  	conn->asyncStatus = PGASYNC_READY;	/* drop out of GetResult wait loop */
  
! 	pqsecure_close(conn);
! 	closesocket(conn->sock);
! 	conn->sock = -1;
  	conn->status = CONNECTION_BAD;		/* No more connection to backend */
  }
  
--- 430,436 ----
  	pqSaveErrorResult(conn);
  	conn->asyncStatus = PGASYNC_READY;	/* drop out of GetResult wait loop */
  
! 	pqDropConnection(conn);
  	conn->status = CONNECTION_BAD;		/* No more connection to backend */
  }
  
*************** pqGetline3(PGconn *conn, char *s, int ma
*** 1539,1545 ****
  {
  	int			status;
  
! 	if (conn->sock < 0 ||
  		conn->asyncStatus != PGASYNC_COPY_OUT ||
  		conn->copy_is_binary)
  	{
--- 1537,1543 ----
  {
  	int			status;
  
! 	if (conn->rsock < 0 ||
  		conn->asyncStatus != PGASYNC_COPY_OUT ||
  		conn->copy_is_binary)
  	{
diff --git a/src/interfaces/libpq/fe-secure.c b/src/interfaces/libpq/fe-secure.c
index b1ad776..22adf12 100644
*** a/src/interfaces/libpq/fe-secure.c
--- b/src/interfaces/libpq/fe-secure.c
*************** pqsecure_open_client(PGconn *conn)
*** 257,263 ****
  		/* Create a connection-specific SSL object */
  		if (!(conn->ssl = SSL_new(SSL_context)) ||
  			!SSL_set_app_data(conn->ssl, conn) ||
! 			!SSL_set_fd(conn->ssl, conn->sock))
  		{
  			char	   *err = SSLerrmessage();
  
--- 257,263 ----
  		/* Create a connection-specific SSL object */
  		if (!(conn->ssl = SSL_new(SSL_context)) ||
  			!SSL_set_app_data(conn->ssl, conn) ||
! 			!SSL_set_fd(conn->ssl, conn->rsock))
  		{
  			char	   *err = SSLerrmessage();
  
*************** rloop:
*** 418,424 ****
  	else
  #endif   /* USE_SSL */
  	{
! 		n = recv(conn->sock, ptr, len, 0);
  
  		if (n < 0)
  		{
--- 418,424 ----
  	else
  #endif   /* USE_SSL */
  	{
! 		n = read(conn->rsock, ptr, len);
  
  		if (n < 0)
  		{
*************** retry_masked:
*** 588,594 ****
  
  		DISABLE_SIGPIPE(conn, spinfo, return -1);
  
! 		n = send(conn->sock, ptr, len, flags);
  
  		if (n < 0)
  		{
--- 588,597 ----
  
  		DISABLE_SIGPIPE(conn, spinfo, return -1);
  
! 		if (flags)
! 			n = send(conn->wsock, ptr, len, flags);
! 		else
! 			n = write(conn->wsock, ptr, len);
  
  		if (n < 0)
  		{
*************** retry_masked:
*** 600,606 ****
  			 * try the flag again, and retry the send().
  			 */
  #ifdef MSG_NOSIGNAL
! 			if (flags != 0 && result_errno == EINVAL)
  			{
  				conn->sigpipe_flag = false;
  				flags = 0;
--- 603,610 ----
  			 * try the flag again, and retry the send().
  			 */
  #ifdef MSG_NOSIGNAL
! 			if (flags != 0 &&
! 				(result_errno == EINVAL || result_errno == ENOTSOCK))
  			{
  				conn->sigpipe_flag = false;
  				flags = 0;
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 2bac59c..f146bac 100644
*** a/src/interfaces/libpq/libpq-int.h
--- b/src/interfaces/libpq/libpq-int.h
*************** struct pg_conn
*** 303,308 ****
--- 303,310 ----
  	char	   *pgunixsocket;	/* the Unix-domain socket that the server is
  								 * listening on; if NULL, uses a default
  								 * constructed from pgport */
+ 	char	   *standalone_datadir;	/* data directory for standalone backend */
+ 	char	   *standalone_backend;	/* executable for standalone backend */
  	char	   *pgtty;			/* tty on which the backend messages is
  								 * displayed (OBSOLETE, NOT USED) */
  	char	   *connect_timeout;	/* connection timeout (numeric string) */
*************** struct pg_conn
*** 360,367 ****
  	PGnotify   *notifyHead;		/* oldest unreported Notify msg */
  	PGnotify   *notifyTail;		/* newest unreported Notify msg */
  
  	/* Connection data */
- 	int			sock;			/* Unix FD for socket, -1 if not connected */
  	SockAddr	laddr;			/* Local address */
  	SockAddr	raddr;			/* Remote address */
  	ProtocolVersion pversion;	/* FE/BE protocol version in use */
--- 362,383 ----
  	PGnotify   *notifyHead;		/* oldest unreported Notify msg */
  	PGnotify   *notifyTail;		/* newest unreported Notify msg */
  
+ 	/*
+ 	 * File descriptors for the connection to the backend.  Normally we use a
+ 	 * bidirectional socket, so that rsock and wsock are equal.  However, we
+ 	 * can also use a pair of pipes, in which case they're not.  Note that
+ 	 * SSL, GSS, and much of the authentication code only work for the
+ 	 * bidirectional-socket case.  By convention, we use rsock when performing
+ 	 * an operation that expects a socket; it doesn't really matter, but let's
+ 	 * be consistent.
+ 	 */
+ 	int			rsock;			/* read FD, or -1 if not connected */
+ 	int			wsock;			/* write FD, or -1 if not connected */
+ 
+ 	/* If we forked a child postgres process, its PID is kept here */
+ 	pid_t		postgres_pid;	/* PID, or -1 if none */
+ 
  	/* Connection data */
  	SockAddr	laddr;			/* Local address */
  	SockAddr	raddr;			/* Remote address */
  	ProtocolVersion pversion;	/* FE/BE protocol version in use */
*************** extern char *const pgresStatus[];
*** 488,493 ****
--- 504,510 ----
  
  /* === in fe-connect.c === */
  
+ extern void pqDropConnection(PGconn *conn);
  extern int pqPacketSend(PGconn *conn, char pack_type,
  			 const void *buf, size_t buf_len);
  extern bool pqGetHomeDirectory(char *buf, int bufsize);