mirror of
https://github.com/postgres/postgres.git
synced 2025-06-26 12:21:12 +03:00
Rewrite PQping to be more like what we agreed to last week.
Basically, we want to distinguish all cases where the connection was not made from those where it was. A convenient proxy for this is to see if we got a message with a SQLSTATE code back from the postmaster. This presumes that the postmaster will always send us a SQLSTATE in a failure message, which is true for 7.4 and later postmasters in every case except fork failure. (We could possibly complicate the postmaster code to do something about that, but it seems not worth the trouble, especially since pg_ctl's response for that case should be to keep waiting anyway.) If we did get a SQLSTATE from the postmaster, there are basically only two cases, as per last week's discussion: ERRCODE_CANNOT_CONNECT_NOW and everything else. Any other error code implies that the postmaster is in principle willing to accept connections, it just didn't like or couldn't handle this particular request. We want to make a special case for ERRCODE_CANNOT_CONNECT_NOW so that "pg_ctl start -w" knows it should keep waiting. In passing, pick names for the enum constants that are a tad less likely to present collision hazards in future.
This commit is contained in:
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user