Add PQping and PQpingParams to libpq to allow detection of the server's
authorBruce Momjian <[email protected]>
Thu, 25 Nov 2010 18:09:38 +0000 (13:09 -0500)
committerBruce Momjian <[email protected]>
Thu, 25 Nov 2010 18:09:38 +0000 (13:09 -0500)
status, including a status where the server is running but refuses a
postgres connection.

Have pg_ctl use this new function.  This fixes the case where pg_ctl
reports that the server is not running (cannot connect) but in fact it
is running.

doc/src/sgml/libpq.sgml
src/bin/pg_ctl/pg_ctl.c
src/interfaces/libpq/exports.txt
src/interfaces/libpq/fe-connect.c
src/interfaces/libpq/libpq-fe.h

index c95fc4fd64d75ab54599bb8722c56537971585f1..d2a4811315705803d7e7e126cac9d4e643c64f3d 100644 (file)
@@ -1511,6 +1511,74 @@ int PQbackendPID(const PGconn *conn);
      </listitem>
     </varlistentry>
 
+    <varlistentry id="libpq-pqpingparams">
+     <term><function>PQpingParams</function><indexterm><primary>PQpingParams</></></term>
+     <listitem>
+      <para>
+       <function>PQpingParams</function> indicates the status of the
+       server.  The currently recognized parameter key words are the
+       same as <function>PQconnectParams</>.
+
+<synopsis>
+PGPing PQpingParams(const char **keywords, const char **values, int expand_dbname);
+</synopsis>
+
+       It returns one of the following values:
+
+       <variablelist>
+        <varlistentry id="libpq-pqpingparams-pqaccess">
+         <term><literal>PQACCESS</literal></term>
+         <listitem>
+          <para>
+           The server is running and allows access.
+          </para>
+         </listitem>
+        </varlistentry>
+
+        <varlistentry id="libpq-pqpingparams-pqreject">
+         <term><literal>PQREJECT</literal></term>
+         <listitem>
+          <para>
+           The server is running but rejected a connection request.
+          </para>
+         </listitem>
+        </varlistentry>
+
+        <varlistentry id="libpq-pqpingparams-pqnoresponse">
+         <term><literal>PQNORESPONSE</literal></term>
+         <listitem>
+          <para>
+           The server did not respond.
+          </para>
+         </listitem>
+        </varlistentry>
+       </variablelist>
+
+      </para>
+
+     </listitem>
+    </varlistentry>
+
+    <varlistentry id="libpq-pqping">
+     <term><function>PQping</function><indexterm><primary>PQping</></></term>
+     <listitem>
+      <para>
+       Returns the status of the server.
+
+<synopsis>
+PGPing PQping(const char *conninfo);
+</synopsis>
+      </para>
+
+      <para>
+       This function uses the same <literal>conninfo</literal> parameter
+       key words as <function>PQconnectdb</>.  It returns the same
+       values as <function>PQpingParams</> above.
+      </para>
+
+     </listitem>
+    </varlistentry>
+
     <varlistentry id="libpq-pqconnectionneedspassword">
      <term><function>PQconnectionNeedsPassword</function><indexterm><primary>PQconnectionNeedsPassword</></></term>
      <listitem>
index 14d36b5fac1e4d6040dc50a1ce0b5df877df8b08..211e023c24dfb0146ca787e20ee04eb284a52438 100644 (file)
@@ -136,7 +136,7 @@ static char **readfile(const char *path);
 static int start_postmaster(void);
 static void read_post_opts(void);
 
-static bool test_postmaster_connection(bool);
+static PGPing test_postmaster_connection(bool);
 static bool postmaster_is_alive(pid_t pid);
 
 static char postopts_file[MAXPGPATH];
@@ -400,11 +400,10 @@ start_postmaster(void)
  * Note that the checkpoint parameter enables a Windows service control
  * manager checkpoint, it's got nothing to do with database checkpoints!!
  */
-static bool
+static PGPing
 test_postmaster_connection(bool do_checkpoint)
 {
-   PGconn     *conn;
-   bool        success = false;
+   PGPing      ret = PQACCESS; /* assume success for zero wait */
    int         i;
    char        portstr[32];
    char       *p;
@@ -508,18 +507,10 @@ test_postmaster_connection(bool do_checkpoint)
 
    for (i = 0; i < wait_seconds; i++)
    {
-       if ((conn = PQconnectdb(connstr)) != NULL &&
-           (PQstatus(conn) == CONNECTION_OK ||
-            PQconnectionNeedsPassword(conn)))
-       {
-           PQfinish(conn);
-           success = true;
-           break;
-       }
+       if ((ret = PQping(connstr)) != PQNORESPONSE)
+           return ret;
        else
        {
-           PQfinish(conn);
-
 #if defined(WIN32)
            if (do_checkpoint)
            {
@@ -543,7 +534,8 @@ test_postmaster_connection(bool do_checkpoint)
        }
    }
 
-   return success;
+   /* value of last call to PQping */
+   return ret;
 }
 
 
@@ -746,9 +738,11 @@ do_start(void)
 
    if (do_wait)
    {
+       int status;
+       
        print_msg(_("waiting for server to start..."));
 
-       if (test_postmaster_connection(false) == false)
+       if ((status = test_postmaster_connection(false)) == PQNORESPONSE)
        {
            write_stderr(_("%s: could not start server\n"
                           "Examine the log output.\n"),
@@ -759,6 +753,9 @@ do_start(void)
        {
            print_msg(_(" done\n"));
            print_msg(_("server started\n"));
+           if (status == PQREJECT)
+               write_stderr(_("warning:  could not connect, perhaps due to invalid authentication or\n"
+                               "misconfiguration.\n"));
        }
    }
    else
index ecbd54c88150d0554077b862ea52d44ed6aa1bf2..a6c73af52e85c573e9589e2a9210b91874887e5c 100644 (file)
@@ -157,3 +157,5 @@ PQescapeLiteral           154
 PQescapeIdentifier        155
 PQconnectdbParams         156
 PQconnectStartParams      157
+PQping                    158
+PQpingParams              159
index 8011604e5cd1ad92cd2e0cca5f1980a813a318cd..6593f21d55e591e22263f611e4c189979178732a 100644 (file)
@@ -285,6 +285,7 @@ static bool connectOptions1(PGconn *conn, const char *conninfo);
 static bool connectOptions2(PGconn *conn);
 static int connectDBStart(PGconn *conn);
 static int connectDBComplete(PGconn *conn);
+static PGPing internal_ping(PGconn *conn);
 static PGconn *makeEmptyPGconn(void);
 static void fillPGconn(PGconn *conn, PQconninfoOption *connOptions);
 static void freePGconn(PGconn *conn);
@@ -375,6 +376,20 @@ PQconnectdbParams(const char **keywords,
 
 }
 
+PGPing
+PQpingParams(const char **keywords,
+                 const char **values,
+                 int expand_dbname)
+{
+   PGconn     *conn = PQconnectStartParams(keywords, values, expand_dbname);
+   PGPing      ret;
+
+   ret = internal_ping(conn);
+   PQfinish(conn);
+
+   return ret;
+}
+
 /*
  *     PQconnectdb
  *
@@ -408,6 +423,18 @@ PQconnectdb(const char *conninfo)
    return conn;
 }
 
+PGPing
+PQping(const char *conninfo)
+{
+   PGconn     *conn = PQconnectStart(conninfo);
+   PGPing      ret;
+
+   ret = internal_ping(conn);
+   PQfinish(conn);
+
+   return ret;
+}
+
 /*
  *     PQconnectStartParams
  *
@@ -2513,6 +2540,32 @@ error_return:
 }
 
 
+/*
+ * internal_ping
+ * Determine if a server is running and if we can connect to it.
+ */
+PGPing
+internal_ping(PGconn *conn)
+{
+   if (conn && conn->status != CONNECTION_BAD)
+   {
+       (void) connectDBComplete(conn);
+
+       /*
+        *  If the connection needs a password, we can consider the
+        *  server as accepting connections.
+        */
+       if (conn && (conn->status != CONNECTION_BAD ||
+           PQconnectionNeedsPassword(conn)))
+           return PQACCESS;
+       else
+           return PQREJECT;
+   }
+   else
+       return PQNORESPONSE;
+}
+
+
 /*
  * makeEmptyPGconn
  *  - create a PGconn data structure with (as yet) no interesting data
index 659d82d74d8c6e205eb5f286546c9679e1eec9b0..d1a6dd413a5db37e4d336a2fae37ae0a3e68b477 100644 (file)
@@ -107,6 +107,13 @@ typedef enum
    PQERRORS_VERBOSE            /* all the facts, ma'am */
 } PGVerbosity;
 
+typedef enum
+{
+   PQACCESS,                   /* connected to server */
+   PQREJECT,                   /* server rejected access */
+   PQNORESPONSE                /* server did not respond */
+} PGPing;
+
 /* PGconn encapsulates a connection to the backend.
  * The contents of this struct are not supposed to be known to applications.
  */
@@ -403,6 +410,9 @@ extern int  PQendcopy(PGconn *conn);
 extern int PQsetnonblocking(PGconn *conn, int arg);
 extern int PQisnonblocking(const PGconn *conn);
 extern int PQisthreadsafe(void);
+extern PGPing PQping(const char *conninfo);
+extern PGPing PQpingParams(const char **keywords,
+                 const char **values, int expand_dbname);
 
 /* Force the write buffer to be written (or at least try) */
 extern int PQflush(PGconn *conn);