Add PQping and PQpingParams to libpq to allow detection of the server's

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.
This commit is contained in:
Bruce Momjian 2010-11-25 13:09:38 -05:00
parent 212a1c7b0b
commit afd7d9adca
5 changed files with 146 additions and 16 deletions

View 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>

View 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

View File

@ -157,3 +157,5 @@ PQescapeLiteral 154
PQescapeIdentifier 155
PQconnectdbParams 156
PQconnectStartParams 157
PQping 158
PQpingParams 159

View 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

View 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);