Proof of concept: standalone backend with full FE/BE protocol - Mailing list pgsql-hackers

From Tom Lane
Subject Proof of concept: standalone backend with full FE/BE protocol
Date
Msg-id 12511.1346631791@sss.pgh.pa.us
Whole thread Raw
Responses Re: Proof of concept: standalone backend with full FE/BE protocol  (Heikki Linnakangas <hlinnaka@iki.fi>)
Re: Proof of concept: standalone backend with full FE/BE protocol  (Amit Kapila <amit.kapila@huawei.com>)
Re: Proof of concept: standalone backend with full FE/BE protocol  (Josh Berkus <josh@agliodbs.com>)
Re: Proof of concept: standalone backend with full FE/BE protocol  (Jim Nasby <jim@nasby.net>)
Re: Proof of concept: standalone backend with full FE/BE protocol  (Gurjeet Singh <singh.gurjeet@gmail.com>)
List pgsql-hackers
Attached is a proof-of-concept patch for talking to a standalone backend
using libpq and a pair of pipes.  It works, to the extent that psql and
pg_dump can run without any postmaster present:

$ psql regression
psql: could not connect to server: No such file or directory
        Is the server running locally and accepting
        connections on Unix domain socket "/tmp/.s.PGSQL.5432"?
$ psql "standalone_datadir = $PGDATA dbname = regression"
psql (9.3devel)
Type "help" for help.

regression=> \d
                    List of relations
 Schema |            Name             |   Type   | Owner
--------+-----------------------------+----------+-------
 public | a                           | table    | tgl
 public | a_star                      | table    | tgl
 public | abstime_tbl                 | table    | tgl
 public | aggtest                     | table    | tgl
 public | array_index_op_test         | table    | tgl
...

but there's quite a bit of work to do yet before this could be a
committable patch.  Some notes:

1. As you can see above, the feature is triggered by specifying the new
connection option "standalone_datadir", whose value must be the location
of the data directory.  I also invented an option "standalone_backend",
which can be set to specify which postgres executable to launch.  If the
latter isn't specified, libpq defaults to trying the installation PGBINDIR
that was selected by configure.  (I don't think it can use the relative
path tricks we use in pg_ctl and elsewhere, since there's no good reason
to assume that it's running in a Postgres-supplied program.)  I'm not
particularly wedded to these names or the syntax, but I think this is the
basic functionality we'd need.

2. As far as the backend is concerned, use of FE/BE protocol rather than
traditional standalone mode is triggered by writing "--child" instead of
"--single" as the first argument on the postgres command line.  (I'm not
wedded to that name either ... anybody have a better idea?)

3. The bulk of the changes have to do with the fact that we need to keep
track of two file descriptors not one.  This was a bit tedious, but fairly
straightforward --- though I was surprised to find that send() and recv()
don't work on pipes, at least not on Linux.  You have to use read() and
write() instead.

4. As coded, the backend assumes the incoming pipe is on its FD 0 and the
outgoing pipe is on its FD 1.  This made the command line simple but I'm
having second thoughts about it: if anything inside the backend tries to
read stdin or write stdout, unpleasant things will happen.  It might be
better to not reassign the pipe FD numbers.  In that case we'd have to
pass them on the command line, so that the syntax would be something
like "postgres --child 4,5 -D pgdata ...".

5. The fork/exec code is pretty primitive with respect to error handling.
I didn't put much time into it since I'm afraid we may need to refactor
it entirely before a Windows equivalent can be written.  (And I need
somebody to write/test the Windows equivalent - any volunteers?)

6. I didn't bother with passing anything except -D and the database name
to the standalone backend.  Probably we'd like to be able to pass other
command-line switches too.  Again, it's not clear that it's worth doing
much here until we have equivalent Windows code available.

7. I haven't tried to make pg_upgrade use this yet.

8. PQcancel needs some work - it can't do what it does now, but it could
do kill(conn->postgres_pid, SIGINT) instead.  At least in Unix.  I have no
idea what we'd do in Windows.  This doesn't matter for pg_upgrade of
course, but it'd be important for manual use of this mode.


Although the immediate use of this would be for pg_upgrade, I think that
people would soon drop the traditional --single mode and do anything they
need to do in standalone mode using this method, since psql is so vastly
more user-friendly than a --single backend.

In the longer run, this could provide a substitute for the "embedded
database" mode that we keep saying we're not going to implement.  That is,
applications could fire up a standalone backend as a child process and not
need a postmaster anywhere, which would be a lot more convenient for an
app that wants a private database and doesn't want to involve its users in
managing a Postgres server.  However, there are some additional things
we'd need to think about before advertising it as a fit solution for that.
Notably, while the lack of any background processes is just what you want
for pg_upgrade and disaster recovery, an ordinary application is probably
going to want to rely on autovacuum; and we need bgwriter and other
background processes for best performance.  So I'm speculating about
having a postmaster process that isn't listening on any ports, but is
managing background processes in addition to a single child backend.
That's for another day though.

Comments?  Anyone want to have a go at fixing this for Windows?

            regards, tom lane

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(¶m->port, port, sizeof(Port));
!     if (!write_inheritable_socket(¶m->portsocket, port->sock, childPid))
          return false;

      strlcpy(param->DataDir, DataDir, MAXPGPATH);
--- 4857,4863 ----
  #endif
  {
      memcpy(¶m->port, port, sizeof(Port));
!     if (!write_inheritable_socket(¶m->portsocket, port->rsock, childPid))
          return false;

      strlcpy(param->DataDir, DataDir, MAXPGPATH);
*************** static void
*** 5022,5028 ****
  restore_backend_variables(BackendParameters *param, Port *port)
  {
      memcpy(port, ¶m->port, sizeof(Port));
!     read_inheritable_socket(&port->sock, ¶m->portsocket);

      SetDataDir(param->DataDir);

--- 5084,5091 ----
  restore_backend_variables(BackendParameters *param, Port *port)
  {
      memcpy(port, ¶m->port, sizeof(Port));
!     read_inheritable_socket(&port->rsock, ¶m->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);

pgsql-hackers by date:

Previous
From: Jeff Janes
Date:
Subject: Re: PATCH: pgbench - aggregation of info written into log
Next
From: Andrew Dunstan
Date:
Subject: pg_upgrade bugs