diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index fb6ce177f0d..e08d46782cc 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -2211,23 +2211,34 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname max_protocol_version - - Specifies the protocol version to request from the server. - During the PostgreSQL 19 beta period, the default is to use - 3.9999, a GREASE (Generate Random Extensions And - Sustain Extensibility) value that tests proper protocol negotiation - implementation. If the server does not support the protocol version - requested by the client, the connection is automatically downgraded to - a lower minor protocol version that the server supports. After the - connection attempt has completed you can use - to find out which exact - protocol version was negotiated. - + + + During the PostgreSQL 19 beta period, libpq connections that do not + specify a max_protocol_version will "grease" the + handshake by sending unsupported startup parameters, including version + 3.9999, in order to identify software that does not + correctly negotiate the connection. This replaces the default behavior + described below. + + + If you know that a server doesn't properly implement protocol version + negotiation, you can set max_protocol_version=3.0 to + revert to the standard behavior (preferably after notifying the server's + maintainers that their software needs to be fixed). + + - For servers that don't properly implement protocol version negotiation, - you can set max_protocol_version=3.0 to connect - successfully. + Specifies the protocol version to request from the server. + The default is to use version 3.0 of the + PostgreSQL protocol, unless the connection + string specifies a feature that relies on a higher protocol version, + in which case the latest version supported by libpq is used. If the + server does not support the protocol version requested by the client, + the connection is automatically downgraded to a lower minor protocol + version that the server supports. After the connection attempt has + completed you can use to + find out which exact protocol version was negotiated. diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml index c61dd2bf948..45148a71d63 100644 --- a/doc/src/sgml/protocol.sgml +++ b/doc/src/sgml/protocol.sgml @@ -189,18 +189,26 @@ - Protocol Versions + Protocol Versions and Extensibility - The current, latest version of the protocol is version 3.2. During the - PostgreSQL 19 beta period, libpq defaults to requesting protocol version - 3.9999 to test that servers and middleware properly implement protocol - version negotiation. Servers that support negotiation will automatically - downgrade to version 3.2 or 3.0. For servers that don't support - negotiation, users can connect by explicitly setting - max_protocol_version=3.0 in their connection string. + The current, latest version of the protocol is version 3.2. However, for + backwards compatibility with old server versions and middleware that don't + support the version negotiation yet, libpq still uses protocol version 3.0 + by default. + + + During the PostgreSQL 19 beta period, libpq will instead default to + requesting protocol version 3.9999, to test that servers and middleware + properly implement protocol version negotiation. Servers that support + negotiation will automatically downgrade to version 3.2 or 3.0. Users can + bypass this beta-only behavior by explicitly setting + max_protocol_version=3.0 in their connection string. + + + A single server can support multiple protocol versions. The initial startup-request message tells the server which protocol version the client @@ -226,10 +234,12 @@ shows the currently supported protocol versions. + + documents protocol versions that are unsupported or otherwise reserved. - Protocol Versions + Supported Protocol Versions @@ -241,20 +251,6 @@ - - 3.9999 - - - GREASE (Generate Random Extensions And Sustain Extensibility) - version. This version number is intentionally reserved and will never - be implemented. During the PostgreSQL 19 beta period, libpq requests - this version by default to test that servers and middleware properly - implement protocol version negotiation via - NegotiateProtocolVersion. Servers should respond - by downgrading to a supported version. This mechanism helps ensure - the ecosystem is ready for future protocol versions. libpq will revert - to defaulting to version 3.2 before the PostgreSQL 19 final release. - - 3.2 PostgreSQL 18 and later @@ -265,6 +261,39 @@ + 3.0 + PostgreSQL 7.4 and later + + + +
+ + + Other Protocol Versions + + + + + Version + Supported by + Description + + + + + + 3.9999 + - + Reserved for protocol greasing. libpq may use this version, which + is higher than any minor version the project ever expects to use, to + test that servers and middleware properly implement protocol version + negotiation. Servers must not add special-case + logic for this version; they should simply compare it to their latest + supported version (which will always be smaller) and downgrade via a + NegotiateProtocolVersion message. + + + 3.1 - Reserved. Version 3.1 has not been used by any PostgreSQL @@ -274,15 +303,93 @@ - 3.0 - PostgreSQL 7.4 and later - - 2.0 up to PostgreSQL 13 - See previous releases of + Obsolete. See previous releases of the PostgreSQL documentation for - details + details. + + + +
+ + + Servers and clients may additionally negotiate individual extensions to the + protocol version in use. These are offered by the client as specially-named + parameters in the startup message. Servers reject any unknown or unsupported + extensions by sending a NegotiateProtocolVersion message containing the list + of rejected parameter names, at which point the client may choose whether to + continue with the connection. + shows the current list of protocol extension parameters. + + + + Protocol Extensions + + + + + + + + + + + + + + + + + + + Parameter Name + Values + Supported by + Description + + + + + Defined + + + + (No supported protocol extensions are currently defined.) + + + + Reserved + + + _pq_.[name] + - + Any other parameter names beginning with _pq_., + that are not defined above, are reserved for future protocol expansion. + Servers must reject any that are received from a + client, by sending a NegotiateProtocolVersion message during the + startup flow, and should + otherwise continue the connection. + + + + + _pq_.test_protocol_negotiation + - + Reserved for protocol greasing. libpq may send this extension to + test that servers and middleware properly implement protocol extension + negotiation. Servers must not add special-case + logic for this parameter; they should simply send the list of all + unsupported options (including this one) via a NegotiateProtocolVersion + message. + @@ -312,8 +419,8 @@ To begin a session, a frontend opens a connection to the server and sends a startup message. This message includes the names of the user and of the database the user wants to connect to; it also identifies the particular - protocol version to be used. (Optionally, the startup message can include - additional settings for run-time parameters.) + protocol version to be used. (Optionally, the startup message can request + protocol extensions and include additional settings for run-time parameters.) The server then uses this information and the contents of its configuration files (such as pg_hba.conf) to determine @@ -6164,29 +6271,13 @@ psql "dbname=postgres replication=database" -c "IDENTIFY_SYSTEM;" - - _pq_.test_protocol_negotiation - - - A reserved protocol extension requested by libpq during the - PostgreSQL 19 beta period to test that servers properly implement - protocol version negotiation. When the client requests the GREASE - protocol version (3.9999), this parameter is automatically - included in the startup packet too. Servers should report it as - unsupported in their NegotiateProtocolVersion - response. In GREASE mode the connection will fail if the server - doesn't report this parameter as unsupported, ensuring - comprehensive implementation of protocol negotiation. This - parameter is reserved and will never actually be implemented by a - server. - - - In addition to the above, other parameters may be listed. Parameter names beginning with _pq_. are - reserved for use as protocol extensions, while others are + reserved for use as + protocol extensions, + while others are treated as run-time parameters to be set at backend start time. Such settings will be applied during backend start (after parsing the command-line arguments if any) and will diff --git a/src/include/libpq/pqcomm.h b/src/include/libpq/pqcomm.h index 0c3583ce4d9..a29c9c94d79 100644 --- a/src/include/libpq/pqcomm.h +++ b/src/include/libpq/pqcomm.h @@ -90,16 +90,9 @@ is_unixsock_path(const char *path) /* * The earliest and latest frontend/backend protocol version supported. - * - * PG_PROTOCOL_GREASE is an intentionally unsupported protocol version used - * for GREASE (Generate Random Extensions And Sustain Extensibility). This - * helps ensure that servers properly implement protocol version negotiation - * via NegotiateProtocolVersion. Version 3.9999 was chosen to be safely within - * the valid range but unlikely to ever be implemented. */ #define PG_PROTOCOL_EARLIEST PG_PROTOCOL(3,0) #define PG_PROTOCOL_LATEST PG_PROTOCOL(3,2) -#define PG_PROTOCOL_GREASE PG_PROTOCOL(3,9999) /* * Reserved protocol numbers, which have special semantics: @@ -111,6 +104,16 @@ is_unixsock_path(const char *path) */ #define PG_PROTOCOL_RESERVED_31 PG_PROTOCOL(3,1) +/* + * PG_PROTOCOL_GREASE is an intentionally unsupported protocol version used + * for "greasing" (the practice of sending valid, but extraneous or otherwise + * unusual, messages to keep peer implementations honest). This helps ensure + * that servers properly implement protocol version negotiation. Version 3.9999 + * was chosen since it is safely within the valid range, it is representable + * via PQfullProtocolVersion, and it is unlikely to ever be needed in practice. + */ +#define PG_PROTOCOL_GREASE PG_PROTOCOL(3,9999) + /* * A client can send a cancel-current-operation request to the postmaster. * This is uglier than sending it directly to the client's backend, but it diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 9fcf094a36f..c42f38cbc99 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -2142,10 +2142,11 @@ pqConnectOptions2(PGconn *conn) else { /* - * Default to the GREASE protocol version to test that servers - * properly implement NegotiateProtocolVersion. The server will - * automatically downgrade to a supported version. This will be - * changed to a supported version before the PG19 release. + * Default to PG_PROTOCOL_GREASE, which is larger than all real + * versions, to test negotiation. The server should automatically + * downgrade to a supported version. + * + * This behavior is for 19beta only. It will be reverted before RC1. */ conn->max_pversion = PG_PROTOCOL_GREASE; } @@ -4386,7 +4387,7 @@ keep_going: /* We will come back to here until there is if (conn->max_pversion == PG_PROTOCOL_GREASE && conn->pversion == PG_PROTOCOL_GREASE) { - libpq_append_conn_error(conn, "server incorrectly accepted reserved GREASE protocol version 3.9999 without negotiation"); + libpq_append_conn_error(conn, "server incorrectly accepted \"grease\" protocol version 3.9999 without negotiation"); goto error_return; } diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c index 4f78b88b3a8..fc011e89450 100644 --- a/src/interfaces/libpq/fe-protocol3.c +++ b/src/interfaces/libpq/fe-protocol3.c @@ -1453,7 +1453,19 @@ pqGetNegotiateProtocolVersion3(PGconn *conn) if (pqGetInt(&num, 4, conn) != 0) goto eof; - /* Check the protocol version */ + /* + * Check the protocol version. + * + * PG_PROTOCOL_GREASE is intentionally unsupported and reserved. It's + * higher than any real version, so check for that first, to get the most + * specific error message. Then check the upper and lower bounds. + */ + if (their_version == PG_PROTOCOL_GREASE) + { + libpq_append_conn_error(conn, "received invalid protocol negotiation message: server requested \"grease\" protocol version 3.9999"); + goto failure; + } + if (their_version > conn->pversion) { libpq_append_conn_error(conn, "received invalid protocol negotiation message: server requested downgrade to a higher-numbered version"); @@ -1473,13 +1485,6 @@ pqGetNegotiateProtocolVersion3(PGconn *conn) goto failure; } - /* The GREASE protocol version is intentionally unsupported and reserved */ - if (their_version == PG_PROTOCOL_GREASE) - { - libpq_append_conn_error(conn, "received invalid protocol negotiation message: server claimed to support reserved GREASE protocol version 3.9999"); - goto failure; - } - if (num < 0) { libpq_append_conn_error(conn, "received invalid protocol negotiation message: server reported negative number of unsupported parameters"); @@ -1527,19 +1532,21 @@ pqGetNegotiateProtocolVersion3(PGconn *conn) } /* Check if this is the expected test parameter */ - if (expect_test_protocol_negotiation && strcmp(conn->workBuffer.data, "_pq_.test_protocol_negotiation") == 0) + if (expect_test_protocol_negotiation && + strcmp(conn->workBuffer.data, "_pq_.test_protocol_negotiation") == 0) { found_test_protocol_negotiation = true; } else { - libpq_append_conn_error(conn, "received invalid protocol negotiation message: server reported an unsupported parameter that was not requested (\"%s\")", conn->workBuffer.data); + libpq_append_conn_error(conn, "received invalid protocol negotiation message: server reported an unsupported parameter that was not requested (\"%s\")", + conn->workBuffer.data); goto failure; } } /* - * If we requested the GREASE protocol version, the server must report + * If we requested protocol grease, the server must report * _pq_.test_protocol_negotiation as unsupported. This ensures * comprehensive NegotiateProtocolVersion implementation. */ @@ -2497,9 +2504,9 @@ build_startup_packet(const PGconn *conn, char *packet, ADD_STARTUP_OPTION("client_encoding", conn->client_encoding_initial); /* - * Add the test protocol negotiation option if we're using the GREASE - * protocol version. This tests that servers properly report unsupported - * protocol options in their NegotiateProtocolVersion response. + * Add the test_protocol_negotiation option when greasing, to test that + * servers properly report unsupported protocol options in addition to + * unsupported minor versions. */ if (conn->pversion == PG_PROTOCOL_GREASE) ADD_STARTUP_OPTION("_pq_.test_protocol_negotiation", "");