From afd7d9adca971d9aae97e87ce617d8608d25ab10 Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Thu, 25 Nov 2010 13:09:38 -0500 Subject: [PATCH] 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. --- doc/src/sgml/libpq.sgml | 68 +++++++++++++++++++++++++++++++ src/bin/pg_ctl/pg_ctl.c | 29 ++++++------- src/interfaces/libpq/exports.txt | 2 + src/interfaces/libpq/fe-connect.c | 53 ++++++++++++++++++++++++ src/interfaces/libpq/libpq-fe.h | 10 +++++ 5 files changed, 146 insertions(+), 16 deletions(-) diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index c95fc4fd64..d2a4811315 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -1511,6 +1511,74 @@ int PQbackendPID(const PGconn *conn); + + PQpingParamsPQpingParams + + + PQpingParams indicates the status of the + server. The currently recognized parameter key words are the + same as PQconnectParams. + + +PGPing PQpingParams(const char **keywords, const char **values, int expand_dbname); + + + It returns one of the following values: + + + + PQACCESS + + + The server is running and allows access. + + + + + + PQREJECT + + + The server is running but rejected a connection request. + + + + + + PQNORESPONSE + + + The server did not respond. + + + + + + + + + + + + PQpingPQping + + + Returns the status of the server. + + +PGPing PQping(const char *conninfo); + + + + + This function uses the same conninfo parameter + key words as PQconnectdb. It returns the same + values as PQpingParams above. + + + + + PQconnectionNeedsPasswordPQconnectionNeedsPassword diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c index 14d36b5fac..211e023c24 100644 --- a/src/bin/pg_ctl/pg_ctl.c +++ b/src/bin/pg_ctl/pg_ctl.c @@ -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 diff --git a/src/interfaces/libpq/exports.txt b/src/interfaces/libpq/exports.txt index ecbd54c881..a6c73af52e 100644 --- a/src/interfaces/libpq/exports.txt +++ b/src/interfaces/libpq/exports.txt @@ -157,3 +157,5 @@ PQescapeLiteral 154 PQescapeIdentifier 155 PQconnectdbParams 156 PQconnectStartParams 157 +PQping 158 +PQpingParams 159 diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 8011604e5c..6593f21d55 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -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 diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h index 659d82d74d..d1a6dd413a 100644 --- a/src/interfaces/libpq/libpq-fe.h +++ b/src/interfaces/libpq/libpq-fe.h @@ -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);