PostgreSQL virtual hosting support - Mailing list pgsql-patches

From David J. MacKenzie
Subject PostgreSQL virtual hosting support
Date
Msg-id 14693.65154.459852.118103@air.web.us.uu.net
Whole thread Raw
Responses Re: PostgreSQL virtual hosting support  (Bruce Momjian <pgman@candle.pha.pa.us>)
Re: PostgreSQL virtual hosting support  (Bruce Momjian <pgman@candle.pha.pa.us>)
List pgsql-patches
Your name        :    David MacKenzie
Your email address    :    djm@web.us.uu.net


System Configuration
---------------------
  Architecture (example: Intel Pentium)      : Intel x86

  Operating System (example: Linux 2.0.26 ELF)     : BSD/OS 4.0.1

  PostgreSQL version (example: PostgreSQL-7.0):   PostgreSQL-7.0.2

  Compiler used (example:  gcc 2.8.0)        : gcc version 2.7.2.1


Please enter a FULL description of your problem:
------------------------------------------------

UUNET is looking into offering PostgreSQL as a part of a managed web
hosting product, on both shared and dedicated machines.  We currently
offer Oracle and MySQL, and it would be a nice middle-ground.
However, as shipped, PostgreSQL lacks the following features we need
that MySQL has:

1. The ability to listen only on a particular IP address.  Each
   hosting customer has their own IP address, on which all of their
   servers (http, ftp, real media, etc.) run.
2. The ability to place the Unix-domain socket in a mode 700 directory.
   This allows us to automatically create an empty database, with an
   empty DBA password, for new or upgrading customers without having
   to interactively set a DBA password and communicate it to (or from)
   the customer.  This in turn cuts down our install and upgrade times.
3. The ability to connect to the Unix-domain socket from within a
   change-rooted environment.  We run CGI programs chrooted to the
   user's home directory, which is another reason why we need to be
   able to specify where the Unix-domain socket is, instead of /tmp.
4. The ability to, if run as root, open a pid file in /var/run as
   root, and then setuid to the desired user.  (mysqld -u can almost
   do this; I had to patch it, too).

The patch below fixes problem 1-3.  I plan to address #4, also, but
haven't done so yet.  These diffs are big enough that they should give
the PG development team something to think about in the meantime :-)
Also, I'm about to leave for 2 weeks' vacation, so I thought I'd get
out what I have, which works (for the problems it tackles), now.

With these changes, we can set up and run PostgreSQL with scripts the
same way we can with apache or proftpd or mysql.

In summary, this patch makes the following enhancements:

1. Adds an environment variable PGUNIXSOCKET, analogous to MYSQL_UNIX_PORT,
   and command line options -k --unix-socket to the relevant programs.
2. Adds a -h option to postmaster to set the hostname or IP address to
   listen on instead of the default INADDR_ANY.
3. Extends some library interfaces to support the above.
4. Fixes a few memory leaks in PQconnectdb().

The default behavior is unchanged from stock 7.0.2; if you don't use
any of these new features, they don't change the operation.

Index: doc/src/sgml/layout.sgml
*** doc/src/sgml/layout.sgml    2000/06/30 21:15:36    1.1
--- doc/src/sgml/layout.sgml    2000/07/02 03:56:05    1.2
***************
*** 55,61 ****
  For example, if the database server machine is a remote machine, you
  will need to set the <envar>PGHOST</envar> environment variable to the name
  of the database server machine.   The  environment  variable
! <envar>PGPORT</envar> may also have to be set.  The bottom line is this: if
  you try to start an application  program  and  it  complains
  that it cannot connect to the <Application>postmaster</Application>,
  you must go back and make sure that your
--- 55,62 ----
  For example, if the database server machine is a remote machine, you
  will need to set the <envar>PGHOST</envar> environment variable to the name
  of the database server machine.   The  environment  variable
! <envar>PGPORT</envar> or <envar>PGUNIXSOCKET</envar> may also have to be set.
! The bottom line is this: if
  you try to start an application  program  and  it  complains
  that it cannot connect to the <Application>postmaster</Application>,
  you must go back and make sure that your
Index: doc/src/sgml/libpq++.sgml
*** doc/src/sgml/libpq++.sgml    2000/06/30 21:15:36    1.1
--- doc/src/sgml/libpq++.sgml    2000/07/02 03:56:05    1.2
***************
*** 93,98 ****
--- 93,105 ----
        </listitem>
        <listitem>
         <para>
+     <envar>PGUNIXSOCKET</envar>  sets the full Unix domain socket
+     file name for communicating with the <productname>Postgres</productname>
+     backend.
+        </para>
+       </listitem>
+       <listitem>
+        <para>
      <envar>PGDATABASE</envar>  sets the default
      <productname>Postgres</productname> database name.
         </para>
Index: doc/src/sgml/libpq.sgml
*** doc/src/sgml/libpq.sgml    2000/06/30 21:15:36    1.1
--- doc/src/sgml/libpq.sgml    2000/07/02 03:56:05    1.2
***************
*** 134,139 ****
--- 134,148 ----
      </varlistentry>

      <varlistentry>
+      <term><literal>unixsocket</literal></term>
+      <listitem>
+      <para>
+       Full path to Unix-domain socket file to connect to at the server host.
+      </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
       <term><literal>dbname</literal></term>
       <listitem>
       <para>
***************
*** 545,550 ****
--- 554,569 ----

  <listitem>
  <para>
+ <function>PQunixsocket</function>
+          Returns the name of the Unix-domain socket of the connection.
+ <synopsis>
+ char *PQunixsocket(const PGconn *conn)
+ </synopsis>
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
  <function>PQtty</function>
           Returns the debug tty of the connection.
  <synopsis>
***************
*** 1772,1777 ****
--- 1791,1803 ----
  <envar>PGHOST</envar> sets the default server name.
  If a non-zero-length string is specified, TCP/IP communication is used.
  Without a host name, libpq will connect using a local Unix domain socket.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <envar>PGPORT</envar>  sets the default port or local Unix domain socket
+ file extension for communicating with the <productname>Postgres</productname>
+ backend.
  </para>
  </listitem>
  <listitem>
Index: doc/src/sgml/start.sgml
*** doc/src/sgml/start.sgml    2000/06/30 21:15:37    1.1
--- doc/src/sgml/start.sgml    2000/07/02 03:56:05    1.2
***************
*** 110,117 ****
      will need to set the <acronym>PGHOST</acronym> environment
      variable to the name
      of the database server machine.   The  environment  variable
!     <acronym>PGPORT</acronym> may also have to be set.  The bottom
!     line is this: if
      you try to start an application  program  and  it  complains
      that it cannot connect to the <application>postmaster</application>,
      you should immediately consult your site administrator to make
--- 110,117 ----
      will need to set the <acronym>PGHOST</acronym> environment
      variable to the name
      of the database server machine.   The  environment  variable
!     <acronym>PGPORT</acronym> or <acronym>PGUNIXSOCKET</acronym> may also have to be set.
!     The bottom line is this: if
      you try to start an application  program  and  it  complains
      that it cannot connect to the <application>postmaster</application>,
      you should immediately consult your site administrator to make
Index: doc/src/sgml/ref/createdb.sgml
*** doc/src/sgml/ref/createdb.sgml    2000/06/30 21:15:37    1.1
--- doc/src/sgml/ref/createdb.sgml    2000/07/04 04:46:45    1.2
***************
*** 58,63 ****
--- 58,75 ----
        </listitem>
       </varlistentry>

+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+
       <varlistentry>
        <term>-U, --username <replaceable class="parameter">username</replaceable></term>
        <listitem>
Index: doc/src/sgml/ref/createlang.sgml
*** doc/src/sgml/ref/createlang.sgml    2000/06/30 21:15:37    1.1
--- doc/src/sgml/ref/createlang.sgml    2000/07/04 04:46:45    1.2
***************
*** 96,101 ****
--- 96,113 ----
        </listitem>
       </varlistentry>

+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+
       <varlistentry>
        <term>-U, --username <replaceable class="parameter">username</replaceable></term>
        <listitem>
Index: doc/src/sgml/ref/createuser.sgml
*** doc/src/sgml/ref/createuser.sgml    2000/06/30 21:15:37    1.1
--- doc/src/sgml/ref/createuser.sgml    2000/07/04 04:46:45    1.2
***************
*** 59,64 ****
--- 59,76 ----
        </listitem>
       </varlistentry>

+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+
       <varlistentry>
        <term>-e, --echo</term>
        <listitem>
Index: doc/src/sgml/ref/dropdb.sgml
*** doc/src/sgml/ref/dropdb.sgml    2000/06/30 21:15:38    1.1
--- doc/src/sgml/ref/dropdb.sgml    2000/07/04 04:46:45    1.2
***************
*** 58,63 ****
--- 58,75 ----
        </listitem>
       </varlistentry>

+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+
       <varlistentry>
        <term>-U, --username <replaceable class="parameter">username</replaceable></term>
        <listitem>
Index: doc/src/sgml/ref/droplang.sgml
*** doc/src/sgml/ref/droplang.sgml    2000/06/30 21:15:38    1.1
--- doc/src/sgml/ref/droplang.sgml    2000/07/04 04:46:45    1.2
***************
*** 96,101 ****
--- 96,113 ----
        </listitem>
       </varlistentry>

+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+
       <varlistentry>
        <term>-U, --username <replaceable class="parameter">username</replaceable></term>
        <listitem>
Index: doc/src/sgml/ref/dropuser.sgml
*** doc/src/sgml/ref/dropuser.sgml    2000/06/30 21:15:38    1.1
--- doc/src/sgml/ref/dropuser.sgml    2000/07/04 04:46:45    1.2
***************
*** 58,63 ****
--- 58,75 ----
        </listitem>
       </varlistentry>

+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+
       <varlistentry>
        <term>-e, --echo</term>
        <listitem>
Index: doc/src/sgml/ref/pg_dump.sgml
*** doc/src/sgml/ref/pg_dump.sgml    2000/06/30 21:15:38    1.1
--- doc/src/sgml/ref/pg_dump.sgml    2000/07/01 18:41:22    1.2
***************
*** 24,30 ****
    </refsynopsisdivinfo>
    <synopsis>
  pg_dump [ <replaceable class="parameter">dbname</replaceable> ]
! pg_dump [ -h <replaceable class="parameter">host</replaceable> ] [ -p <replaceable
class="parameter">port</replaceable>] 
      [ -t <replaceable class="parameter">table</replaceable> ]
      [ -a ] [ -c ] [ -d ] [ -D ] [ -i ] [ -n ] [ -N ]
      [ -o ] [ -s ] [ -u ] [ -v ] [ -x ]
--- 24,32 ----
    </refsynopsisdivinfo>
    <synopsis>
  pg_dump [ <replaceable class="parameter">dbname</replaceable> ]
! pg_dump [ -h <replaceable class="parameter">host</replaceable> ]
!     [ -k <replaceable class="parameter">path</replaceable> ]
!     [ -p <replaceable class="parameter">port</replaceable> ]
      [ -t <replaceable class="parameter">table</replaceable> ]
      [ -a ] [ -c ] [ -d ] [ -D ] [ -i ] [ -n ] [ -N ]
      [ -o ] [ -s ] [ -u ] [ -v ] [ -x ]
***************
*** 200,205 ****
--- 202,222 ----
      <application>postmaster</application>
      is running.  Defaults to using a local Unix domain socket
      rather than an IP connection..
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>-k <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+        <para>
+     Specifies the local Unix domain socket file path
+     on which the <application>postmaster</application>
+     is listening for connections.
+         Without this option, the socket path name defaults to
+         the value of the <envar>PGUNIXSOCKET</envar> environment
+     variable (if set), otherwise it is constructed
+         from the port number.
         </para>
        </listitem>
       </varlistentry>
Index: doc/src/sgml/ref/pg_dumpall.sgml
*** doc/src/sgml/ref/pg_dumpall.sgml    2000/06/30 21:15:38    1.1
--- doc/src/sgml/ref/pg_dumpall.sgml    2000/07/01 18:41:22    1.2
***************
*** 24,30 ****
    </refsynopsisdivinfo>
    <synopsis>
  pg_dumpall
! pg_dumpall [ -h <replaceable class="parameter">host</replaceable> ] [ -p <replaceable
class="parameter">port</replaceable>] [ -a ] [ -d ] [ -D ] [ -O ] [ -s ] [ -u ] [ -v ] [ -x ] 
    </synopsis>

    <refsect2 id="R2-APP-PG-DUMPALL-1">
--- 24,33 ----
    </refsynopsisdivinfo>
    <synopsis>
  pg_dumpall
! pg_dumpall [ -h <replaceable class="parameter">host</replaceable> ]
!      [ -k <replaceable class="parameter">path</replaceable> ]
!      [ -p <replaceable class="parameter">port</replaceable> ]
!      [ -a ] [ -d ] [ -D ] [ -O ] [ -s ] [ -u ] [ -v ] [ -x ]
    </synopsis>

    <refsect2 id="R2-APP-PG-DUMPALL-1">
***************
*** 137,142 ****
--- 140,160 ----
      <application>postmaster</application>
      is running.  Defaults to using a local Unix domain socket
      rather than an IP connection..
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term>-k <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+        <para>
+     Specifies the local Unix domain socket file path
+     on which the <application>postmaster</application>
+     is listening for connections.
+         Without this option, the socket path name defaults to
+         the value of the <envar>PGUNIXSOCKET</envar> environment
+     variable (if set), otherwise it is constructed
+         from the port number.
         </para>
        </listitem>
       </varlistentry>
Index: doc/src/sgml/ref/postmaster.sgml
*** doc/src/sgml/ref/postmaster.sgml    2000/06/30 21:15:38    1.1
--- doc/src/sgml/ref/postmaster.sgml    2000/07/06 07:48:31    1.7
***************
*** 24,30 ****
    </refsynopsisdivinfo>
    <synopsis>
  postmaster [ -B <replaceable class="parameter">nBuffers</replaceable> ] [ -D <replaceable
class="parameter">DataDir</replaceable>] [ -N <replaceable class="parameter">maxBackends</replaceable> ] [ -S ] 
!     [ -d <replaceable class="parameter">DebugLevel</replaceable> ] [ -i ] [ -l ]
      [ -o <replaceable class="parameter">BackendOptions</replaceable> ] [ -p <replaceable
class="parameter">port</replaceable>] [ -n | -s ] 
    </synopsis>

--- 24,32 ----
    </refsynopsisdivinfo>
    <synopsis>
  postmaster [ -B <replaceable class="parameter">nBuffers</replaceable> ] [ -D <replaceable
class="parameter">DataDir</replaceable>] [ -N <replaceable class="parameter">maxBackends</replaceable> ] [ -S ] 
!     [ -d <replaceable class="parameter">DebugLevel</replaceable> ]
!     [ -h <replaceable class="parameter">hostname</replaceable> ] [ -i ]
!     [ -k <replaceable class="parameter">path</replaceable> ] [ -l ]
      [ -o <replaceable class="parameter">BackendOptions</replaceable> ] [ -p <replaceable
class="parameter">port</replaceable>] [ -n | -s ] 
    </synopsis>

***************
*** 124,129 ****
--- 126,161 ----
       </varlistentry>

       <varlistentry>
+       <term>-h <replaceable class="parameter">hostName</replaceable></term>
+       <listitem>
+        <para>
+     Specifies the TCP/IP hostname or address
+     on which the <application>postmaster</application>
+     is to listen for connections from frontend applications.  Defaults to
+     the value of the
+     <envar>PGHOST</envar>
+     environment variable, or if <envar>PGHOST</envar>
+     is not set, then defaults to "all", meaning listen on all configured addresses
+     (including localhost).
+        </para>
+        <para>
+     If you use a hostname or address other than "all", do not try to run
+     multiple instances of <application>postmaster</application> on the
+     same IP address but different ports.  Doing so will result in them
+     attempting (incorrectly) to use the same shared memory segments.
+     Also, if you use a hostname other than "all", all of the host's IP addresses
+     on which <application>postmaster</application> instances are
+     listening must be distinct in the two last octets.
+        </para>
+        <para>
+     If you do use "all" (the default), then each instance must listen on a
+     different port (via -p or <envar>PGPORT</envar>).  And, of course, do
+     not try to use both approaches on one host.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
        <term>-i</term>
        <listitem>
         <para>
***************
*** 135,140 ****
--- 167,201 ----
       </varlistentry>

       <varlistentry>
+       <term>-k <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+        <para>
+     Specifies the local Unix domain socket path name
+     on which the <application>postmaster</application>
+     is to listen for connections from frontend applications.  Defaults to
+     the value of the
+     <envar>PGUNIXSOCKET</envar>
+     environment variable, or if <envar>PGUNIXSOCKET</envar>
+     is not set, then defaults to a file in <filename>/tmp</filename>
+     constructed from the port number.
+        </para>
+        <para>
+         You can use this option to put the Unix-domain socket in a
+         directory that is private to one or more users using Unix
+     directory permissions.  This is necessary for securely
+     creating databases automatically on shared machines.
+         In that situation, also disallow all TCP/IP connections
+     initially in <filename>pg_hba.conf</filename>.
+     If you specify a socket path other than the
+     default then all frontend applications (including
+     <application>psql</application>) must specify the same
+     socket path using either command-line options or
+     <envar>PGUNIXSOCKET</envar>.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
        <term>-l</term>
        <listitem>
         <para>
Index: doc/src/sgml/ref/psql-ref.sgml
*** doc/src/sgml/ref/psql-ref.sgml    2000/06/30 21:15:38    1.1
--- doc/src/sgml/ref/psql-ref.sgml    2000/07/02 03:56:05    1.3
***************
*** 1329,1334 ****
--- 1329,1347 ----


      <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+
+
+     <varlistentry>
        <term>-H, --html</term>
        <listitem>
        <para>
Index: doc/src/sgml/ref/vacuumdb.sgml
*** doc/src/sgml/ref/vacuumdb.sgml    2000/06/30 21:15:38    1.1
--- doc/src/sgml/ref/vacuumdb.sgml    2000/07/04 04:46:45    1.2
***************
*** 24,30 ****
    </refsynopsisdivinfo>
    <synopsis>
  vacuumdb [ <replaceable class="parameter">options</replaceable> ] [ --analyze | -z ]
!     [ --alldb | -a ] [ --verbose | -v ]
      [ --table '<replaceable class="parameter">table</replaceable> [ ( <replaceable
class="parameter">column</replaceable>[,...] ) ]' ] [ [-d] <replaceable class="parameter">dbname</replaceable> ] 
    </synopsis>

--- 24,30 ----
    </refsynopsisdivinfo>
    <synopsis>
  vacuumdb [ <replaceable class="parameter">options</replaceable> ] [ --analyze | -z ]
!     [ --all | -a ] [ --verbose | -v ]
      [ --table '<replaceable class="parameter">table</replaceable> [ ( <replaceable
class="parameter">column</replaceable>[,...] ) ]' ] [ [-d] <replaceable class="parameter">dbname</replaceable> ] 
    </synopsis>

***************
*** 128,133 ****
--- 128,145 ----
         </para>
        </listitem>
       </varlistentry>
+
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>

       <varlistentry>
        <term>-U <replaceable class="parameter">username</replaceable></term>
Index: src/backend/libpq/pqcomm.c
*** src/backend/libpq/pqcomm.c    2000/06/30 21:15:40    1.1
--- src/backend/libpq/pqcomm.c    2000/07/01 18:50:46    1.3
***************
*** 42,47 ****
--- 42,48 ----
   *        StreamConnection    - Create new connection with client
   *        StreamClose            - Close a client/backend connection
   *        pq_getport        - return the PGPORT setting
+  *        pq_getunixsocket    - return the PGUNIXSOCKET setting
   *        pq_init            - initialize libpq at backend startup
   *        pq_close        - shutdown libpq at backend exit
   *
***************
*** 134,139 ****
--- 135,151 ----
  }

  /* --------------------------------
+  *        pq_getunixsocket - return the PGUNIXSOCKET setting.
+  *        If NULL, default to computing it based on the port.
+  * --------------------------------
+  */
+ char *
+ pq_getunixsocket(void)
+ {
+     return getenv("PGUNIXSOCKET");
+ }
+
+ /* --------------------------------
   *        pq_close - shutdown libpq at backend exit
   *
   * Note: in a standalone backend MyProcPort will be null,
***************
*** 177,189 ****
  /*
   * StreamServerPort -- open a sock stream "listening" port.
   *
!  * This initializes the Postmaster's connection-accepting port.
   *
   * RETURNS: STATUS_OK or STATUS_ERROR
   */

  int
! StreamServerPort(char *hostName, unsigned short portName, int *fdP)
  {
      SockAddr    saddr;
      int            fd,
--- 189,205 ----
  /*
   * StreamServerPort -- open a sock stream "listening" port.
   *
!  * This initializes the Postmaster's connection-accepting port fdP.
!  * If hostName is "any", listen on all configured IP addresses.
!  * If hostName is NULL, listen on a Unix-domain socket instead of TCP;
!  * if unixSocketName is NULL, a default path (constructed in UNIX_SOCK_PATH
!  * in include/libpq/pqcomm.h) based on portName is used.
   *
   * RETURNS: STATUS_OK or STATUS_ERROR
   */

  int
! StreamServerPort(char *hostName, unsigned short portNumber, char *unixSocketName, int *fdP)
  {
      SockAddr    saddr;
      int            fd,
***************
*** 227,233 ****
      saddr.sa.sa_family = family;
      if (family == AF_UNIX)
      {
!         len = UNIXSOCK_PATH(saddr.un, portName);
          strcpy(sock_path, saddr.un.sun_path);

          /*
--- 243,250 ----
      saddr.sa.sa_family = family;
      if (family == AF_UNIX)
      {
!         UNIXSOCK_PATH(saddr.un, portNumber, unixSocketName);
!         len = UNIXSOCK_LEN(saddr.un);
          strcpy(sock_path, saddr.un.sun_path);

          /*
***************
*** 259,267 ****
      }
      else
      {
!         saddr.in.sin_addr.s_addr = htonl(INADDR_ANY);
!         saddr.in.sin_port = htons(portName);
!         len = sizeof(struct sockaddr_in);
      }
      err = bind(fd, &saddr.sa, len);
      if (err < 0)
--- 276,305 ----
      }
      else
      {
!       /* TCP/IP socket */
!       if (!strcmp(hostName, "all")) /* like for databases in pg_hba.conf.  */
!         saddr.in.sin_addr.s_addr = htonl(INADDR_ANY);
!       else
!         {
!           struct hostent *hp;
!
!           hp = gethostbyname(hostName);
!           if ((hp == NULL) || (hp->h_addrtype != AF_INET))
!         {
!           snprintf(PQerrormsg, PQERRORMSG_LENGTH,
!                "FATAL: StreamServerPort: gethostbyname(%s) failed: %s\n",
!                hostName, hstrerror(h_errno));
!           fputs(PQerrormsg, stderr);
!           pqdebug("%s", PQerrormsg);
!           return STATUS_ERROR;
!         }
!           memmove((char *) &(saddr.in.sin_addr),
!               (char *) hp->h_addr,
!               hp->h_length);
!         }
!
!       saddr.in.sin_port = htons(portNumber);
!       len = sizeof(struct sockaddr_in);
      }
      err = bind(fd, &saddr.sa, len);
      if (err < 0)
Index: src/backend/postmaster/postmaster.c
*** src/backend/postmaster/postmaster.c    2000/06/30 21:15:42    1.1
--- src/backend/postmaster/postmaster.c    2000/07/06 07:38:21    1.5
***************
*** 136,143 ****
  /* list of ports associated with still open, but incomplete connections */
  static Dllist *PortList;

! static unsigned short PostPortName = 0;

   /*
    * This is a boolean indicating that there is at least one backend that
    * is accessing the current shared memory and semaphores. Between the
--- 136,150 ----
  /* list of ports associated with still open, but incomplete connections */
  static Dllist *PortList;

! /* Hostname of interface to listen on, or 'any'. */
! static char *HostName = NULL;

+ /* TCP/IP port number to listen on.  Also used to default the Unix-domain socket name.  */
+ static unsigned short PostPortNumber = 0;
+
+ /* Override of the default Unix-domain socket name to listen on, if non-NULL.  */
+ static char *UnixSocketName = NULL;
+
   /*
    * This is a boolean indicating that there is at least one backend that
    * is accessing the current shared memory and semaphores. Between the
***************
*** 274,280 ****
  static void SignalChildren(SIGNAL_ARGS);
  static int    CountChildren(void);
  static int
! SetOptsFile(char *progname, int port, char *datadir,
              int assert, int nbuf, char *execfile,
              int debuglvl, int netserver,
  #ifdef USE_SSL
--- 281,287 ----
  static void SignalChildren(SIGNAL_ARGS);
  static int    CountChildren(void);
  static int
! SetOptsFile(char *progname, char *hostname, int port, char *unixsocket, char *datadir,
              int assert, int nbuf, char *execfile,
              int debuglvl, int netserver,
  #ifdef USE_SSL
***************
*** 370,380 ****
  {
      extern int    NBuffers;        /* from buffer/bufmgr.c */
      int            opt;
-     char       *hostName;
      int            status;
      int            silentflag = 0;
      bool        DataDirOK;        /* We have a usable PGDATA value */
-     char        hostbuf[MAXHOSTNAMELEN];
      int            nonblank_argc;
      char        original_extraoptions[MAXPGPATH];

--- 377,385 ----
***************
*** 431,449 ****
       */
      umask((mode_t) 0077);

-     if (!(hostName = getenv("PGHOST")))
-     {
-         if (gethostname(hostbuf, MAXHOSTNAMELEN) < 0)
-             strcpy(hostbuf, "localhost");
-         hostName = hostbuf;
-     }
-
      MyProcPid = getpid();
      DataDir = getenv("PGDATA"); /* default value */

      opterr = 0;
      IgnoreSystemIndexes(false);
!     while ((opt = getopt(nonblank_argc, argv, "A:a:B:b:D:d:ilm:MN:no:p:Ss")) != EOF)
      {
          switch (opt)
          {
--- 436,447 ----
       */
      umask((mode_t) 0077);

      MyProcPid = getpid();
      DataDir = getenv("PGDATA"); /* default value */

      opterr = 0;
      IgnoreSystemIndexes(false);
!     while ((opt = getopt(nonblank_argc, argv, "A:a:B:b:D:d:h:ik:lm:MN:no:p:Ss")) != EOF)
      {
          switch (opt)
          {
***************
*** 498,506 ****
--- 496,511 ----
                  DebugLvl = atoi(optarg);
                  pg_options[TRACE_VERBOSE] = DebugLvl;
                  break;
+             case 'h':
+                 HostName = optarg;
+                 break;
              case 'i':
                  NetServer = true;
                  break;
+             case 'k':
+                 /* Set PGUNIXSOCKET by hand. */
+                 UnixSocketName = optarg;
+                 break;
  #ifdef USE_SSL
              case 'l':
                  SecureNetServer = true;
***************
*** 545,551 ****
                  break;
              case 'p':
                  /* Set PGPORT by hand. */
!                 PostPortName = (unsigned short) atoi(optarg);
                  break;
              case 'S':

--- 550,556 ----
                  break;
              case 'p':
                  /* Set PGPORT by hand. */
!                 PostPortNumber = (unsigned short) atoi(optarg);
                  break;
              case 'S':

***************
*** 577,584 ****
      /*
       * Select default values for switches where needed
       */
!     if (PostPortName == 0)
!         PostPortName = (unsigned short) pq_getport();

      /*
       * Check for invalid combinations of switches
--- 582,603 ----
      /*
       * Select default values for switches where needed
       */
!     if (HostName == NULL)
!     {
!         if (!(HostName = getenv("PGHOST")))
!         {
!             HostName = "any";
!         }
!     }
!     else if (!NetServer)
!     {
!         fprintf(stderr, "%s: -h requires -i.\n", progname);
!         exit(1);
!     }
!     if (PostPortNumber == 0)
!         PostPortNumber = (unsigned short) pq_getport();
!     if (UnixSocketName == NULL)
!         UnixSocketName = pq_getunixsocket();

      /*
       * Check for invalid combinations of switches
***************
*** 622,628 ****

      if (NetServer)
      {
!         status = StreamServerPort(hostName, PostPortName, &ServerSock_INET);
          if (status != STATUS_OK)
          {
              fprintf(stderr, "%s: cannot create INET stream port\n",
--- 641,647 ----

      if (NetServer)
      {
!         status = StreamServerPort(HostName, PostPortNumber, NULL, &ServerSock_INET);
          if (status != STATUS_OK)
          {
              fprintf(stderr, "%s: cannot create INET stream port\n",
***************
*** 632,638 ****
      }

  #if !defined(__CYGWIN32__) && !defined(__QNX__)
!     status = StreamServerPort(NULL, PostPortName, &ServerSock_UNIX);
      if (status != STATUS_OK)
      {
          fprintf(stderr, "%s: cannot create UNIX stream port\n",
--- 651,657 ----
      }

  #if !defined(__CYGWIN32__) && !defined(__QNX__)
!     status = StreamServerPort(NULL, PostPortNumber, UnixSocketName, &ServerSock_UNIX);
      if (status != STATUS_OK)
      {
          fprintf(stderr, "%s: cannot create UNIX stream port\n",
***************
*** 642,648 ****
  #endif
      /* set up shared memory and semaphores */
      EnableMemoryContext(TRUE);
!     reset_shared(PostPortName);

      /*
       * Initialize the list of active backends.    This list is only used for
--- 661,667 ----
  #endif
      /* set up shared memory and semaphores */
      EnableMemoryContext(TRUE);
!     reset_shared(PostPortNumber);

      /*
       * Initialize the list of active backends.    This list is only used for
***************
*** 664,670 ****
          {
              if (SetOptsFile(
                              progname,    /* postmaster executable file */
!                             PostPortName,        /* port number */
                              DataDir,    /* PGDATA */
                              assert_enabled,        /* whether -A is specified
                                                   * or not */
--- 683,691 ----
          {
              if (SetOptsFile(
                              progname,    /* postmaster executable file */
!                             HostName, /* IP address to bind to */
!                             PostPortNumber,        /* port number */
!                             UnixSocketName,    /* PGUNIXSOCKET */
                              DataDir,    /* PGDATA */
                              assert_enabled,        /* whether -A is specified
                                                   * or not */
***************
*** 753,759 ****
          {
              if (SetOptsFile(
                              progname,    /* postmaster executable file */
!                             PostPortName,        /* port number */
                              DataDir,    /* PGDATA */
                              assert_enabled,        /* whether -A is specified
                                                   * or not */
--- 774,782 ----
          {
              if (SetOptsFile(
                              progname,    /* postmaster executable file */
!                             HostName, /* IP address to bind to */
!                             PostPortNumber,        /* port number */
!                             UnixSocketName,    /* PGUNIXSOCKET */
                              DataDir,    /* PGDATA */
                              assert_enabled,        /* whether -A is specified
                                                   * or not */
***************
*** 837,843 ****
--- 860,868 ----
      fprintf(stderr, "\t-a system\tuse this authentication system\n");
      fprintf(stderr, "\t-b backend\tuse a specific backend server executable\n");
      fprintf(stderr, "\t-d [1-5]\tset debugging level\n");
+     fprintf(stderr, "\t-h hostname\tspecify hostname or IP address or 'any' for postmaster to listen on (also use
-i)\n");
      fprintf(stderr, "\t-i \t\tlisten on TCP/IP sockets as well as Unix domain socket\n");
+     fprintf(stderr, "\t-k path\tspecify Unix-domain socket name for postmaster to listen on\n");
  #ifdef USE_SSL
      fprintf(stderr, " \t-l \t\tfor TCP/IP sockets, listen only on SSL connections\n");
  #endif
***************
*** 1318,1328 ****
--- 1343,1417 ----
  }

  /*
+  * get_host_port -- return a pseudo port number (16 bits)
+  * derived from the primary IP address of HostName.
+  */
+ static unsigned short
+ get_host_port(void)
+ {
+     static unsigned short hostPort = 0;
+
+     if (hostPort == 0)
+     {
+         SockAddr    saddr;
+         struct hostent *hp;
+
+         hp = gethostbyname(HostName);
+         if ((hp == NULL) || (hp->h_addrtype != AF_INET))
+         {
+             char msg[1024];
+             snprintf(msg, sizeof(msg),
+                  "FATAL: get_host_port: gethostbyname(%s) failed: %s\n",
+                  HostName, hstrerror(h_errno));
+             fputs(msg, stderr);
+             pqdebug("%s", msg);
+             exit(1);
+         }
+         memmove((char *) &(saddr.in.sin_addr),
+             (char *) hp->h_addr,
+             hp->h_length);
+         hostPort = ntohl(saddr.in.sin_addr.s_addr) & 0xFFFF;
+     }
+
+     return hostPort;
+ }
+
+ /*
   * reset_shared -- reset shared memory and semaphores
   */
  static void
  reset_shared(unsigned short port)
  {
+     /*
+      * A typical ipc_key is 5432001, which is port 5432, sequence
+      * number 0, and 01 as the index in IPCKeyGetBufferMemoryKey().
+      * The 32-bit INT_MAX is 2147483 6 47.
+      *
+      * The default algorithm for calculating the IPC keys assumes that all
+      * instances of postmaster on a given host are listening on different
+      * ports.  In order to work (prevent shared memory collisions) if you
+      * run multiple PostgreSQL instances on the same port and different IP
+      * addresses on a host, we change the algorithm if you give postmaster
+      * the -h option, or set PGHOST, to a value other than the internal
+      * default of "any".
+      *
+      * If HostName is not "any", then we generate the IPC keys using the
+      * last two octets of the IP address instead of the port number.
+      * This algorithm assumes that no one will run multiple PostgreSQL
+      * instances on one host using two IP addresses that have the same two
+      * last octets in different class C networks.  If anyone does, it
+      * would be rare.
+      *
+      * So, if you use -h or PGHOST, don't try to run two instances of
+      * PostgreSQL on the same IP address but different ports.  If you
+      * don't use them, then you must use different ports (via -p or
+      * PGPORT).  And, of course, don't try to use both approaches on one
+      * host.
+      */
+
+     if (strcmp(HostName, "any"))
+         port = get_host_port();
+
      ipc_key = port * 1000 + shmem_seq * 100;
      CreateSharedMemoryAndSemaphores(ipc_key, MaxBackends);
      shmem_seq += 1;
***************
*** 1540,1546 ****
                  ctime(&tnow));
          fflush(stderr);
          shmem_exit(0);
!         reset_shared(PostPortName);
          StartupPID = StartupDataBase();
          return;
      }
--- 1629,1635 ----
                  ctime(&tnow));
          fflush(stderr);
          shmem_exit(0);
!         reset_shared(PostPortNumber);
          StartupPID = StartupDataBase();
          return;
      }
***************
*** 1720,1726 ****
       * Set up the necessary environment variables for the backend This
       * should really be some sort of message....
       */
!     sprintf(envEntry[0], "POSTPORT=%d", PostPortName);
      putenv(envEntry[0]);
      sprintf(envEntry[1], "POSTID=%d", NextBackendTag);
      putenv(envEntry[1]);
--- 1809,1815 ----
       * Set up the necessary environment variables for the backend This
       * should really be some sort of message....
       */
!     sprintf(envEntry[0], "POSTPORT=%d", PostPortNumber);
      putenv(envEntry[0]);
      sprintf(envEntry[1], "POSTID=%d", NextBackendTag);
      putenv(envEntry[1]);
***************
*** 2174,2180 ****
      for (i = 0; i < 4; ++i)
          MemSet(ssEntry[i], 0, 2 * ARGV_SIZE);

!     sprintf(ssEntry[0], "POSTPORT=%d", PostPortName);
      putenv(ssEntry[0]);
      sprintf(ssEntry[1], "POSTID=%d", NextBackendTag);
      putenv(ssEntry[1]);
--- 2263,2269 ----
      for (i = 0; i < 4; ++i)
          MemSet(ssEntry[i], 0, 2 * ARGV_SIZE);

!     sprintf(ssEntry[0], "POSTPORT=%d", PostPortNumber);
      putenv(ssEntry[0]);
      sprintf(ssEntry[1], "POSTID=%d", NextBackendTag);
      putenv(ssEntry[1]);
***************
*** 2254,2260 ****
   * Create the opts file
   */
  static int
! SetOptsFile(char *progname, int port, char *datadir,
              int assert, int nbuf, char *execfile,
              int debuglvl, int netserver,
  #ifdef USE_SSL
--- 2343,2349 ----
   * Create the opts file
   */
  static int
! SetOptsFile(char *progname, char *hostname, int port, char *unixsocket, char *datadir,
              int assert, int nbuf, char *execfile,
              int debuglvl, int netserver,
  #ifdef USE_SSL
***************
*** 2279,2284 ****
--- 2368,2383 ----
          return (-1);
      }
      snprintf(opts, sizeof(opts), "%s\n-p %d\n-D %s\n", progname, port, datadir);
+     if (netserver)
+     {
+         sprintf(buf, "-h %s\n", hostname);
+         strcat(opts, buf);
+     }
+     if (unixsocket)
+     {
+         sprintf(buf, "-k %s\n", unixsocket);
+         strcat(opts, buf);
+     }
      if (assert)
      {
          sprintf(buf, "-A %d\n", assert);
Index: src/bin/pg_dump/pg_dump.c
*** src/bin/pg_dump/pg_dump.c    2000/06/30 21:15:44    1.1
--- src/bin/pg_dump/pg_dump.c    2000/07/01 18:41:22    1.2
***************
*** 140,145 ****
--- 140,146 ----
           "  -D, --attribute-inserts  dump data as INSERT commands with attribute names\n"
           "  -h, --host <hostname>    server host name\n"
           "  -i, --ignore-version     proceed when database version != pg_dump version\n"
+          "  -k, --unixsocket <path>  server Unix-domain socket name\n"
      "  -n, --no-quotes          suppress most quotes around identifiers\n"
       "  -N, --quotes             enable most quotes around identifiers\n"
           "  -o, --oids               dump object ids (oids)\n"
***************
*** 158,163 ****
--- 159,165 ----
           "  -D                       dump data as INSERT commands with attribute names\n"
           "  -h <hostname>            server host name\n"
           "  -i                       proceed when database version != pg_dump version\n"
+          "  -k <path>                server Unix-domain socket name\n"
      "  -n                       suppress most quotes around identifiers\n"
       "  -N                       enable most quotes around identifiers\n"
           "  -o                       dump object ids (oids)\n"
***************
*** 579,584 ****
--- 581,587 ----
      const char *dbname = NULL;
      const char *pghost = NULL;
      const char *pgport = NULL;
+     const char *pgunixsocket = NULL;
      char       *tablename = NULL;
      bool        oids = false;
      TableInfo  *tblinfo;
***************
*** 598,603 ****
--- 601,607 ----
          {"attribute-inserts", no_argument, NULL, 'D'},
          {"host", required_argument, NULL, 'h'},
          {"ignore-version", no_argument, NULL, 'i'},
+         {"unixsocket", required_argument, NULL, 'k'},
          {"no-quotes", no_argument, NULL, 'n'},
          {"quotes", no_argument, NULL, 'N'},
          {"oids", no_argument, NULL, 'o'},
***************
*** 662,667 ****
--- 666,674 ----
              case 'i':            /* ignore database version mismatch */
                  ignore_version = true;
                  break;
+             case 'k':            /* server Unix-domain socket */
+                 pgunixsocket = optarg;
+                 break;
              case 'n':            /* Do not force double-quotes on
                                   * identifiers */
                  force_quotes = false;
***************
*** 782,788 ****
          exit(1);
      }

-     /* g_conn = PQsetdb(pghost, pgport, NULL, NULL, dbname); */
      if (pghost != NULL)
      {
          sprintf(tmp_string, "host=%s ", pghost);
--- 789,794 ----
***************
*** 791,796 ****
--- 797,807 ----
      if (pgport != NULL)
      {
          sprintf(tmp_string, "port=%s ", pgport);
+         strcat(connect_string, tmp_string);
+     }
+     if (pgunixsocket != NULL)
+     {
+         sprintf(tmp_string, "unixsocket=%s ", pgunixsocket);
          strcat(connect_string, tmp_string);
      }
      if (dbname != NULL)
Index: src/bin/psql/command.c
*** src/bin/psql/command.c    2000/06/30 21:15:46    1.1
--- src/bin/psql/command.c    2000/07/01 18:20:40    1.2
***************
*** 1199,1204 ****
--- 1199,1205 ----
      SetVariable(pset.vars, "USER", NULL);
      SetVariable(pset.vars, "HOST", NULL);
      SetVariable(pset.vars, "PORT", NULL);
+     SetVariable(pset.vars, "UNIXSOCKET", NULL);
      SetVariable(pset.vars, "ENCODING", NULL);

      /* If dbname is "" then use old name, else new one (even if NULL) */
***************
*** 1228,1233 ****
--- 1229,1235 ----
      do
      {
          need_pass = false;
+         /* FIXME use PQconnectdb to support passing the Unix socket */
          pset.db = PQsetdbLogin(PQhost(oldconn), PQport(oldconn),
                                 NULL, NULL, dbparam, userparam, pwparam);

***************
*** 1303,1308 ****
--- 1305,1311 ----
      SetVariable(pset.vars, "USER", PQuser(pset.db));
      SetVariable(pset.vars, "HOST", PQhost(pset.db));
      SetVariable(pset.vars, "PORT", PQport(pset.db));
+     SetVariable(pset.vars, "UNIXSOCKET", PQunixsocket(pset.db));
      SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));

      pset.issuper = test_superuser(PQuser(pset.db));
Index: src/bin/psql/command.h
Index: src/bin/psql/common.c
*** src/bin/psql/common.c    2000/06/30 21:15:46    1.1
--- src/bin/psql/common.c    2000/07/01 18:20:40    1.2
***************
*** 330,335 ****
--- 330,336 ----
              SetVariable(pset.vars, "DBNAME", NULL);
              SetVariable(pset.vars, "HOST", NULL);
              SetVariable(pset.vars, "PORT", NULL);
+             SetVariable(pset.vars, "UNIXSOCKET", NULL);
              SetVariable(pset.vars, "USER", NULL);
              SetVariable(pset.vars, "ENCODING", NULL);
              return NULL;
***************
*** 509,514 ****
--- 510,516 ----
                  SetVariable(pset.vars, "DBNAME", NULL);
                  SetVariable(pset.vars, "HOST", NULL);
                  SetVariable(pset.vars, "PORT", NULL);
+                 SetVariable(pset.vars, "UNIXSOCKET", NULL);
                  SetVariable(pset.vars, "USER", NULL);
                  SetVariable(pset.vars, "ENCODING", NULL);
                  return false;
Index: src/bin/psql/help.c
*** src/bin/psql/help.c    2000/06/30 21:15:46    1.1
--- src/bin/psql/help.c    2000/07/01 18:20:40    1.2
***************
*** 103,108 ****
--- 103,118 ----
      puts(")");

      puts("  -H              HTML table output mode (-P format=html)");
+
+     /* Display default Unix-domain socket */
+     env = getenv("PGUNIXSOCKET");
+     printf("  -k <path>       Specify Unix domain socket name (default: ");
+     if (env)
+         fputs(env, stdout);
+     else
+         fputs("computed from the port", stdout);
+     puts(")");
+
      puts("  -l              List available databases, then exit");
      puts("  -n              Disable readline");
      puts("  -o <filename>   Send query output to filename (or |pipe)");
Index: src/bin/psql/prompt.c
*** src/bin/psql/prompt.c    2000/06/30 21:15:46    1.1
--- src/bin/psql/prompt.c    2000/07/01 18:20:40    1.2
***************
*** 189,194 ****
--- 189,199 ----
                      if (pset.db && PQport(pset.db))
                          strncpy(buf, PQport(pset.db), MAX_PROMPT_SIZE);
                      break;
+                     /* DB server Unix-domain socket */
+                 case '<':
+                     if (pset.db && PQunixsocket(pset.db))
+                         strncpy(buf, PQunixsocket(pset.db), MAX_PROMPT_SIZE);
+                     break;
                      /* DB server user name */
                  case 'n':
                      if (pset.db)
Index: src/bin/psql/prompt.h
Index: src/bin/psql/settings.h
Index: src/bin/psql/startup.c
*** src/bin/psql/startup.c    2000/06/30 21:15:46    1.1
--- src/bin/psql/startup.c    2000/07/01 18:20:40    1.2
***************
*** 66,71 ****
--- 66,72 ----
      char       *dbname;
      char       *host;
      char       *port;
+     char       *unixsocket;
      char       *username;
      enum _actions action;
      char       *action_string;
***************
*** 158,163 ****
--- 159,165 ----
      do
      {
          need_pass = false;
+         /* FIXME use PQconnectdb to allow setting the unix socket */
          pset.db = PQsetdbLogin(options.host, options.port, NULL, NULL,
              options.action == ACT_LIST_DB ? "template1" : options.dbname,
                                 username, password);
***************
*** 202,207 ****
--- 204,210 ----
      SetVariable(pset.vars, "USER", PQuser(pset.db));
      SetVariable(pset.vars, "HOST", PQhost(pset.db));
      SetVariable(pset.vars, "PORT", PQport(pset.db));
+     SetVariable(pset.vars, "UNIXSOCKET", PQunixsocket(pset.db));
      SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));

  #ifndef WIN32
***************
*** 313,318 ****
--- 316,322 ----
          {"field-separator", required_argument, NULL, 'F'},
          {"host", required_argument, NULL, 'h'},
          {"html", no_argument, NULL, 'H'},
+         {"unixsocket", required_argument, NULL, 'k'},
          {"list", no_argument, NULL, 'l'},
          {"no-readline", no_argument, NULL, 'n'},
          {"output", required_argument, NULL, 'o'},
***************
*** 346,359 ****
      memset(options, 0, sizeof *options);

  #ifdef HAVE_GETOPT_LONG
!     while ((c = getopt_long(argc, argv, "aAc:d:eEf:F:lh:Hno:p:P:qRsStT:uU:v:VWxX?", long_options, &optindex)) != -1)
  #else                            /* not HAVE_GETOPT_LONG */

      /*
       * Be sure to leave the '-' in here, so we can catch accidental long
       * options.
       */
!     while ((c = getopt(argc, argv, "aAc:d:eEf:F:lh:Hno:p:P:qRsStT:uU:v:VWxX?-")) != -1)
  #endif     /* not HAVE_GETOPT_LONG */
      {
          switch (c)
--- 350,363 ----
      memset(options, 0, sizeof *options);

  #ifdef HAVE_GETOPT_LONG
!     while ((c = getopt_long(argc, argv, "aAc:d:eEf:F:lh:Hk:no:p:P:qRsStT:uU:v:VWxX?", long_options, &optindex)) !=
-1)
  #else                            /* not HAVE_GETOPT_LONG */

      /*
       * Be sure to leave the '-' in here, so we can catch accidental long
       * options.
       */
!     while ((c = getopt(argc, argv, "aAc:d:eEf:F:lh:Hk:no:p:P:qRsStT:uU:v:VWxX?-")) != -1)
  #endif     /* not HAVE_GETOPT_LONG */
      {
          switch (c)
***************
*** 398,403 ****
--- 402,410 ----
                  break;
              case 'l':
                  options->action = ACT_LIST_DB;
+                 break;
+             case 'k':
+                 options->unixsocket = optarg;
                  break;
              case 'n':
                  options->no_readline = true;
Index: src/bin/scripts/createdb
*** src/bin/scripts/createdb    2000/06/30 21:15:46    1.1
--- src/bin/scripts/createdb    2000/07/04 04:46:45    1.2
***************
*** 50,55 ****
--- 50,64 ----
          --port=*)
                  PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
                  ;;
+     --unixsocket|-k)
+         PSQLOPT="$PSQLOPT -k $2"
+         shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
      --username|-U)
          PSQLOPT="$PSQLOPT -U $2"
          shift;;
***************
*** 114,119 ****
--- 123,129 ----
      echo "  -E, --encoding=ENCODING         Multibyte encoding for the database"
      echo "  -h, --host=HOSTNAME             Database server host"
      echo "  -p, --port=PORT                 Database server port"
+     echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
      echo "  -U, --username=USERNAME         Username to connect as"
      echo "  -W, --password                  Prompt for password"
      echo "  -e, --echo                      Show the query being sent to the backend"
Index: src/bin/scripts/createlang.sh
*** src/bin/scripts/createlang.sh    2000/06/30 21:15:46    1.1
--- src/bin/scripts/createlang.sh    2000/07/04 04:46:45    1.2
***************
*** 65,70 ****
--- 65,79 ----
          --port=*)
                  PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
                  ;;
+     --unixsocket|-k)
+         PSQLOPT="$PSQLOPT -k $2"
+         shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
      --username|-U)
          PSQLOPT="$PSQLOPT -U $2"
          shift;;
***************
*** 126,131 ****
--- 135,141 ----
      echo "Options:"
      echo "  -h, --host=HOSTNAME             Database server host"
      echo "  -p, --port=PORT                 Database server port"
+     echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
      echo "  -U, --username=USERNAME         Username to connect as"
      echo "  -W, --password                  Prompt for password"
      echo "  -d, --dbname=DBNAME             Database to install language in"
Index: src/bin/scripts/createuser
*** src/bin/scripts/createuser    2000/06/30 21:15:46    1.1
--- src/bin/scripts/createuser    2000/07/04 04:46:45    1.2
***************
*** 63,68 ****
--- 63,77 ----
          --port=*)
                  PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
                  ;;
+     --unixsocket|-k)
+         PSQLOPT="$PSQLOPT -k $2"
+         shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
  # Note: These two specify the user to connect as (like in psql),
  #       not the user you're creating.
      --username|-U)
***************
*** 135,140 ****
--- 144,150 ----
      echo "  -P, --pwprompt                  Assign a password to new user"
      echo "  -h, --host=HOSTNAME             Database server host"
      echo "  -p, --port=PORT                 Database server port"
+     echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
      echo "  -U, --username=USERNAME         Username to connect as (not the one to create)"
      echo "  -W, --password                  Prompt for password to connect"
      echo "  -e, --echo                      Show the query being sent to the backend"
Index: src/bin/scripts/dropdb
*** src/bin/scripts/dropdb    2000/06/30 21:15:46    1.1
--- src/bin/scripts/dropdb    2000/07/04 04:46:45    1.2
***************
*** 59,64 ****
--- 59,73 ----
          --port=*)
                  PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
                  ;;
+     --unixsocket|-k)
+         PSQLOPT="$PSQLOPT -k $2"
+         shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
      --username|-U)
          PSQLOPT="$PSQLOPT -U $2"
          shift;;
***************
*** 103,108 ****
--- 112,118 ----
      echo "Options:"
      echo "  -h, --host=HOSTNAME             Database server host"
      echo "  -p, --port=PORT                 Database server port"
+     echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
      echo "  -U, --username=USERNAME         Username to connect as"
      echo "  -W, --password                  Prompt for password"
      echo "  -i, --interactive               Prompt before deleting anything"
Index: src/bin/scripts/droplang
*** src/bin/scripts/droplang    2000/06/30 21:15:46    1.1
--- src/bin/scripts/droplang    2000/07/04 04:46:45    1.2
***************
*** 65,70 ****
--- 65,79 ----
          --port=*)
                  PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
                  ;;
+     --unixsocket|-k)
+         PSQLOPT="$PSQLOPT -k $2"
+         shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
      --username|-U)
          PSQLOPT="$PSQLOPT -U $2"
          shift;;
***************
*** 113,118 ****
--- 122,128 ----
      echo "Options:"
      echo "  -h, --host=HOSTNAME             Database server host"
      echo "  -p, --port=PORT                 Database server port"
+     echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
      echo "  -U, --username=USERNAME         Username to connect as"
      echo "  -W, --password                  Prompt for password"
      echo "  -d, --dbname=DBNAME             Database to remove language from"
Index: src/bin/scripts/dropuser
*** src/bin/scripts/dropuser    2000/06/30 21:15:46    1.1
--- src/bin/scripts/dropuser    2000/07/04 04:46:45    1.2
***************
*** 59,64 ****
--- 59,73 ----
          --port=*)
                  PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
                  ;;
+     --unixsocket|-k)
+         PSQLOPT="$PSQLOPT -k $2"
+         shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
  # Note: These two specify the user to connect as (like in psql),
  #       not the user you're dropping.
      --username|-U)
***************
*** 105,110 ****
--- 114,120 ----
      echo "Options:"
      echo "  -h, --host=HOSTNAME             Database server host"
      echo "  -p, --port=PORT                 Database server port"
+     echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
      echo "  -U, --username=USERNAME         Username to connect as (not the one to drop)"
      echo "  -W, --password                  Prompt for password to connect"
      echo "  -i, --interactive               Prompt before deleting anything"
Index: src/bin/scripts/vacuumdb
*** src/bin/scripts/vacuumdb    2000/06/30 21:15:46    1.1
--- src/bin/scripts/vacuumdb    2000/07/04 04:46:45    1.2
***************
*** 52,57 ****
--- 52,66 ----
          --port=*)
                  PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
                  ;;
+     --unixsocket|-k)
+         PSQLOPT="$PSQLOPT -k $2"
+         shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
      --username|-U)
          PSQLOPT="$PSQLOPT -U $2"
          shift;;
***************
*** 121,126 ****
--- 130,136 ----
          echo "Options:"
      echo "  -h, --host=HOSTNAME             Database server host"
      echo "  -p, --port=PORT                 Database server port"
+     echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
      echo "  -U, --username=USERNAME         Username to connect as"
      echo "  -W, --password                  Prompt for password"
      echo "  -d, --dbname=DBNAME             Database to vacuum"
Index: src/include/libpq/libpq.h
*** src/include/libpq/libpq.h    2000/06/30 21:15:47    1.1
--- src/include/libpq/libpq.h    2000/07/01 18:20:40    1.2
***************
*** 236,246 ****
  /*
   * prototypes for functions in pqcomm.c
   */
! extern int    StreamServerPort(char *hostName, unsigned short portName, int *fdP);
  extern int    StreamConnection(int server_fd, Port *port);
  extern void StreamClose(int sock);
  extern void pq_init(void);
  extern int    pq_getport(void);
  extern void pq_close(void);
  extern int    pq_getbytes(char *s, size_t len);
  extern int    pq_getstring(StringInfo s);
--- 236,247 ----
  /*
   * prototypes for functions in pqcomm.c
   */
! extern int    StreamServerPort(char *hostName, unsigned short portName, char *unixSocketName, int *fdP);
  extern int    StreamConnection(int server_fd, Port *port);
  extern void StreamClose(int sock);
  extern void pq_init(void);
  extern int    pq_getport(void);
+ extern char    *pq_getunixsocket(void);
  extern void pq_close(void);
  extern int    pq_getbytes(char *s, size_t len);
  extern int    pq_getstring(StringInfo s);
Index: src/include/libpq/password.h
Index: src/include/libpq/pqcomm.h
*** src/include/libpq/pqcomm.h    2000/06/30 21:15:47    1.1
--- src/include/libpq/pqcomm.h    2000/07/01 18:59:33    1.6
***************
*** 42,53 ****
  /* Configure the UNIX socket address for the well known port. */

  #if defined(SUN_LEN)
! #define UNIXSOCK_PATH(sun,port) \
!     (sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (port)), SUN_LEN(&(sun)))
  #else
! #define UNIXSOCK_PATH(sun,port) \
!     (sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (port)), \
!      strlen((sun).sun_path)+ offsetof(struct sockaddr_un, sun_path))
  #endif

  /*
--- 42,56 ----
  /* Configure the UNIX socket address for the well known port. */

  #if defined(SUN_LEN)
! #define UNIXSOCK_PATH(sun,port,defpath) \
!         (defpath ? (strncpy((sun).sun_path, defpath, sizeof((sun).sun_path)),
(sun).sun_path[sizeof((sun).sun_path)-1]= '\0') : sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (port))) 
! #define UNIXSOCK_LEN(sun) \
!         (SUN_LEN(&(sun)))
  #else
! #define UNIXSOCK_PATH(sun,port,defpath) \
!         (defpath ? (strncpy((sun).sun_path, defpath, sizeof((sun).sun_path)),
(sun).sun_path[sizeof((sun).sun_path)-1]= '\0') : sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (port))) 
! #define UNIXSOCK_LEN(sun) \
!         (strlen((sun).sun_path)+ offsetof(struct sockaddr_un, sun_path))
  #endif

  /*
Index: src/interfaces/libpq/fe-connect.c
*** src/interfaces/libpq/fe-connect.c    2000/06/30 21:15:51    1.1
--- src/interfaces/libpq/fe-connect.c    2000/07/01 18:50:47    1.3
***************
*** 125,130 ****
--- 125,133 ----
      {"port", "PGPORT", DEF_PGPORT, NULL,
      "Database-Port", "", 6},

+     {"unixsocket", "PGUNIXSOCKET", NULL, NULL,
+     "Unix-Socket", "", 80},
+
      {"tty", "PGTTY", DefaultTty, NULL,
      "Backend-Debug-TTY", "D", 40},

***************
*** 293,298 ****
--- 296,303 ----
      conn->pghost = tmp ? strdup(tmp) : NULL;
      tmp = conninfo_getval(connOptions, "port");
      conn->pgport = tmp ? strdup(tmp) : NULL;
+     tmp = conninfo_getval(connOptions, "unixsocket");
+     conn->pgunixsocket = tmp ? strdup(tmp) : NULL;
      tmp = conninfo_getval(connOptions, "tty");
      conn->pgtty = tmp ? strdup(tmp) : NULL;
      tmp = conninfo_getval(connOptions, "options");
***************
*** 369,374 ****
--- 374,382 ----
   *      PGPORT       identifies TCP port to which to connect if <pgport> argument
   *                   is NULL or a null string.
   *
+  *      PGUNIXSOCKET       identifies Unix-domain socket to which to connect; default
+  *                   is computed from the TCP port.
+  *
   *      PGTTY           identifies tty to which to send messages if <pgtty> argument
   *                   is NULL or a null string.
   *
***************
*** 422,427 ****
--- 430,439 ----
      else
          conn->pgport = strdup(pgport);

+     conn->pgunixsocket = getenv("PGUNIXSOCKET");
+     if (conn->pgunixsocket)
+         conn->pgunixsocket = strdup(conn->pgunixsocket);
+
      if ((pgtty == NULL) || pgtty[0] == '\0')
      {
          if ((tmp = getenv("PGTTY")) == NULL)
***************
*** 489,501 ****

  /*
   * update_db_info -
!  * get all additional infos out of dbName
   *
   */
  static int
  update_db_info(PGconn *conn)
  {
!     char       *tmp,
                 *old = conn->dbName;

      if (strchr(conn->dbName, '@') != NULL)
--- 501,513 ----

  /*
   * update_db_info -
!  * get all additional info out of dbName
   *
   */
  static int
  update_db_info(PGconn *conn)
  {
!     char       *tmp, *tmp2,
                 *old = conn->dbName;

      if (strchr(conn->dbName, '@') != NULL)
***************
*** 504,509 ****
--- 516,523 ----
          tmp = strrchr(conn->dbName, ':');
          if (tmp != NULL)        /* port number given */
          {
+             if (conn->pgport)
+                 free(conn->pgport);
              conn->pgport = strdup(tmp + 1);
              *tmp = '\0';
          }
***************
*** 511,516 ****
--- 525,532 ----
          tmp = strrchr(conn->dbName, '@');
          if (tmp != NULL)        /* host name given */
          {
+             if (conn->pghost)
+                 free(conn->pghost);
              conn->pghost = strdup(tmp + 1);
              *tmp = '\0';
          }
***************
*** 537,549 ****

              /*
               * new style:
!              * <tcp|unix>:postgresql://server[:port][/dbname][?options]
               */
              offset += strlen("postgresql://");

              tmp = strrchr(conn->dbName + offset, '?');
              if (tmp != NULL)    /* options given */
              {
                  conn->pgoptions = strdup(tmp + 1);
                  *tmp = '\0';
              }
--- 553,567 ----

              /*
               * new style:
!              * <tcp|unix>:postgresql://server[:port|:/unixsocket/path:][/dbname][?options]
               */
              offset += strlen("postgresql://");

              tmp = strrchr(conn->dbName + offset, '?');
              if (tmp != NULL)    /* options given */
              {
+                 if (conn->pgoptions)
+                     free(conn->pgoptions);
                  conn->pgoptions = strdup(tmp + 1);
                  *tmp = '\0';
              }
***************
*** 551,576 ****
              tmp = strrchr(conn->dbName + offset, '/');
              if (tmp != NULL)    /* database name given */
              {
                  conn->dbName = strdup(tmp + 1);
                  *tmp = '\0';
              }
              else
              {
                  if ((tmp = getenv("PGDATABASE")) != NULL)
                      conn->dbName = strdup(tmp);
                  else if (conn->pguser)
                      conn->dbName = strdup(conn->pguser);
              }

              tmp = strrchr(old + offset, ':');
!             if (tmp != NULL)    /* port number given */
              {
-                 conn->pgport = strdup(tmp + 1);
                  *tmp = '\0';
              }

              if (strncmp(old, "unix:", 5) == 0)
              {
                  conn->pghost = NULL;
                  if (strcmp(old + offset, "localhost") != 0)
                  {
--- 569,630 ----
              tmp = strrchr(conn->dbName + offset, '/');
              if (tmp != NULL)    /* database name given */
              {
+                 if (conn->dbName)
+                     free(conn->dbName);
                  conn->dbName = strdup(tmp + 1);
                  *tmp = '\0';
              }
              else
              {
+                 /* Why do we default only this value from the environment again?  */
                  if ((tmp = getenv("PGDATABASE")) != NULL)
+                 {
+                     if (conn->dbName)
+                         free(conn->dbName);
                      conn->dbName = strdup(tmp);
+                 }
                  else if (conn->pguser)
+                 {
+                     if (conn->dbName)
+                         free(conn->dbName);
                      conn->dbName = strdup(conn->pguser);
+                 }
              }

              tmp = strrchr(old + offset, ':');
!             if (tmp != NULL)    /* port number or Unix socket path given */
              {
                  *tmp = '\0';
+                 if ((tmp2 = strchr(tmp + 1, ':')) != NULL)
+                 {
+                     if (strncmp(old, "unix:", 5) != 0)
+                     {
+                         printfPQExpBuffer(&conn->errorMessage,
+                                   "connectDBStart() -- "
+                                   "socket name can only be specified with "
+                                   "non-TCP\n");
+                         return 1;
+                     }
+                     *tmp2 = '\0';
+                     if (conn->pgunixsocket)
+                         free(conn->pgunixsocket);
+                     conn->pgunixsocket = strdup(tmp + 1);
+                 }
+                 else
+                 {
+                     if (conn->pgport)
+                         free(conn->pgport);
+                     conn->pgport = strdup(tmp + 1);
+                     if (conn->pgunixsocket)
+                         free(conn->pgunixsocket);
+                     conn->pgunixsocket = NULL;
+                 }
              }

              if (strncmp(old, "unix:", 5) == 0)
              {
+                 if (conn->pghost)
+                     free(conn->pghost);
                  conn->pghost = NULL;
                  if (strcmp(old + offset, "localhost") != 0)
                  {
***************
*** 582,589 ****
                  }
              }
              else
                  conn->pghost = strdup(old + offset);
!
              free(old);
          }
      }
--- 636,646 ----
                  }
              }
              else
+             {
+                 if (conn->pghost)
+                     free(conn->pghost);
                  conn->pghost = strdup(old + offset);
!             }
              free(old);
          }
      }
***************
*** 743,749 ****
      }
  #if !defined(WIN32) && !defined(__CYGWIN32__)
      else
!         conn->raddr_len = UNIXSOCK_PATH(conn->raddr.un, portno);
  #endif


--- 800,809 ----
      }
  #if !defined(WIN32) && !defined(__CYGWIN32__)
      else
!     {
!         UNIXSOCK_PATH(conn->raddr.un, portno, conn->pgunixsocket);
!         conn->raddr_len = UNIXSOCK_LEN(conn->raddr.un);
!     }
  #endif


***************
*** 892,898 ****
                                conn->pghost ? conn->pghost : "localhost",
                                (family == AF_INET) ?
                                "TCP/IP port" : "Unix socket",
!                               conn->pgport);
              goto connect_errReturn;
          }
      }
--- 952,959 ----
                                conn->pghost ? conn->pghost : "localhost",
                                (family == AF_INET) ?
                                "TCP/IP port" : "Unix socket",
!                               (family == AF_UNIX && conn->pgunixsocket) ?
!                               conn->pgunixsocket : conn->pgport);
              goto connect_errReturn;
          }
      }
***************
*** 1123,1129 ****
                                 conn->pghost ? conn->pghost : "localhost",
                                    (conn->raddr.sa.sa_family == AF_INET) ?
                                        "TCP/IP port" : "Unix socket",
!                                       conn->pgport);
                      goto error_return;
                  }

--- 1184,1191 ----
                                 conn->pghost ? conn->pghost : "localhost",
                                    (conn->raddr.sa.sa_family == AF_INET) ?
                                        "TCP/IP port" : "Unix socket",
!                               (conn->raddr.sa.sa_family == AF_UNIX && conn->pgunixsocket) ?
!                                       conn->pgunixsocket : conn->pgport);
                      goto error_return;
                  }

***************
*** 1799,1804 ****
--- 1861,1868 ----
          free(conn->pghostaddr);
      if (conn->pgport)
          free(conn->pgport);
+     if (conn->pgunixsocket)
+         free(conn->pgunixsocket);
      if (conn->pgtty)
          free(conn->pgtty);
      if (conn->pgoptions)
***************
*** 2383,2388 ****
--- 2447,2460 ----
      if (!conn)
          return (char *) NULL;
      return conn->pgport;
+ }
+
+ char *
+ PQunixsocket(const PGconn *conn)
+ {
+     if (!conn)
+         return (char *) NULL;
+     return conn->pgunixsocket;
  }

  char *
Index: src/interfaces/libpq/libpq-fe.h
*** src/interfaces/libpq/libpq-fe.h    2000/06/30 21:15:51    1.1
--- src/interfaces/libpq/libpq-fe.h    2000/07/01 18:20:40    1.2
***************
*** 214,219 ****
--- 214,220 ----
      extern char *PQpass(const PGconn *conn);
      extern char *PQhost(const PGconn *conn);
      extern char *PQport(const PGconn *conn);
+     extern char *PQunixsocket(const PGconn *conn);
      extern char *PQtty(const PGconn *conn);
      extern char *PQoptions(const PGconn *conn);
      extern ConnStatusType PQstatus(const PGconn *conn);
Index: src/interfaces/libpq/libpq-int.h
*** src/interfaces/libpq/libpq-int.h    2000/06/30 21:15:51    1.1
--- src/interfaces/libpq/libpq-int.h    2000/07/01 18:20:40    1.2
***************
*** 202,207 ****
--- 202,209 ----
                                   * numbers-and-dots notation. Takes
                                   * precedence over above. */
      char       *pgport;            /* the server's communication port */
+     char       *pgunixsocket;        /* the Unix-domain socket that the server is listening on;
+                          * if NULL, uses a default constructed from pgport */
      char       *pgtty;            /* tty on which the backend messages is
                                   * displayed (NOT ACTUALLY USED???) */
      char       *pgoptions;        /* options to start the backend with */
Index: src/interfaces/libpq/libpqdll.def
*** src/interfaces/libpq/libpqdll.def    2000/06/30 21:15:51    1.1
--- src/interfaces/libpq/libpqdll.def    2000/07/01 18:20:40    1.2
***************
*** 79,81 ****
--- 79,82 ----
      destroyPQExpBuffer    @ 76
      createPQExpBuffer    @ 77
      PQconninfoFree        @ 78
+     PQunixsocket        @ 79

pgsql-patches by date:

Previous
From: "David J. MacKenzie"
Date:
Subject: PostgreSQL BSDI BSD/OS port
Next
From: Karel Zak
Date:
Subject: MemoryContextCheck()