diff options
Diffstat (limited to 'src/interfaces/libpq/fe-connect.c')
-rw-r--r-- | src/interfaces/libpq/fe-connect.c | 82 |
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; } |