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