aboutsummaryrefslogtreecommitdiff
path: root/src/interfaces/libpq/fe-connect.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/interfaces/libpq/fe-connect.c')
-rw-r--r--src/interfaces/libpq/fe-connect.c82
1 files changed, 65 insertions, 17 deletions
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 43969ebbd1b..bff9b478f66 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -99,6 +99,8 @@ static int ldapServiceLookup(const char *purl, PQconninfoOption *options,
/* This is part of the protocol so just define it */
#define ERRCODE_INVALID_PASSWORD "28P01"
+/* This too */
+#define ERRCODE_CANNOT_CONNECT_NOW "57P03"
/*
* fall back options if they are not specified by arguments or defined
@@ -376,10 +378,15 @@ PQconnectdbParams(const char **keywords,
}
+/*
+ * PQpingParams
+ *
+ * check server status, accepting parameters identical to PQconnectdbParams
+ */
PGPing
PQpingParams(const char **keywords,
- const char **values,
- int expand_dbname)
+ const char **values,
+ int expand_dbname)
{
PGconn *conn = PQconnectStartParams(keywords, values, expand_dbname);
PGPing ret;
@@ -423,6 +430,11 @@ PQconnectdb(const char *conninfo)
return conn;
}
+/*
+ * PQping
+ *
+ * check server status, accepting parameters identical to PQconnectdb
+ */
PGPing
PQping(const char *conninfo)
{
@@ -1261,6 +1273,7 @@ connectDBStart(PGconn *conn)
appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("invalid port number: \"%s\"\n"),
conn->pgport);
+ conn->options_valid = false;
goto connect_errReturn;
}
}
@@ -1309,6 +1322,7 @@ connectDBStart(PGconn *conn)
portstr, gai_strerror(ret));
if (addrs)
pg_freeaddrinfo_all(hint.ai_family, addrs);
+ conn->options_valid = false;
goto connect_errReturn;
}
@@ -2555,27 +2569,61 @@ error_return:
/*
* internal_ping
- * Determine if a server is running and if we can connect to it.
+ * Determine if a server is running and if we can connect to it.
+ *
+ * The argument is a connection that's been started, but not completed.
*/
PGPing
internal_ping(PGconn *conn)
{
- if (conn && conn->status != CONNECTION_BAD)
- {
+ /* Say "no attempt" if we never got to PQconnectPoll */
+ if (!conn || !conn->options_valid)
+ return PQPING_NO_ATTEMPT;
+
+ /* Attempt to complete the connection */
+ if (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;
+ /* Definitely OK if we succeeded */
+ if (conn->status != CONNECTION_BAD)
+ return PQPING_OK;
+
+ /*
+ * Here is the interesting part of "ping": determine the cause of the
+ * failure in sufficient detail to decide what to return. We do not want
+ * to report that the server is not up just because we didn't have a valid
+ * password, for example.
+ *
+ * If we failed to get any ERROR response from the postmaster, report
+ * PQPING_NO_RESPONSE. This result could be somewhat misleading for a
+ * pre-7.4 server, since it won't send back a SQLSTATE, but those are long
+ * out of support. Another corner case where the server could return a
+ * failure without a SQLSTATE is fork failure, but NO_RESPONSE isn't
+ * totally unreasonable for that anyway. We expect that every other
+ * failure case in a modern server will produce a report with a SQLSTATE.
+ *
+ * NOTE: whenever we get around to making libpq generate SQLSTATEs for
+ * client-side errors, we should either not store those into
+ * last_sqlstate, or add an extra flag so we can tell client-side errors
+ * apart from server-side ones.
+ */
+ if (strlen(conn->last_sqlstate) != 5)
+ return PQPING_NO_RESPONSE;
+
+ /*
+ * Report PQPING_REJECT if server says it's not accepting connections.
+ * (We distinguish this case mainly for the convenience of pg_ctl.)
+ */
+ if (strcmp(conn->last_sqlstate, ERRCODE_CANNOT_CONNECT_NOW) == 0)
+ return PQPING_REJECT;
+
+ /*
+ * Any other SQLSTATE can be taken to indicate that the server is up.
+ * Presumably it didn't like our username, password, or database name; or
+ * perhaps it had some transient failure, but that should not be taken as
+ * meaning "it's down".
+ */
+ return PQPING_OK;
}