since-v3.diff.txt

text/plain

Filename: since-v3.diff.txt
Type: text/plain
Part: 0
Message: Re: libpq: Bump protocol version to version 3.2 at least until the first/second beta
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
      <varlistentry id="libpq-connect-max-protocol-version" xreflabel="max_protocol_version">
       <term><literal>max_protocol_version</literal></term>
       <listitem>
-       <para>
-        Specifies the protocol version to request from the server.
-        During the PostgreSQL 19 beta period, the default is to use
-        <literal>3.9999</literal>, 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
-        <xref linkend="libpq-PQfullProtocolVersion"/> to find out which exact
-        protocol version was negotiated.
-       </para>
+       <note>
+        <para>
+        During the PostgreSQL 19 beta period, libpq connections that do not
+        specify a <literal>max_protocol_version</literal> will "grease" the
+        handshake by sending unsupported startup parameters, including version
+        <literal>3.9999</literal>, in order to identify software that does not
+        correctly negotiate the connection. This replaces the default behavior
+        described below.
+        </para>
+        <para>
+        If you know that a server doesn't properly implement protocol version
+        negotiation, you can set <literal>max_protocol_version=3.0</literal> to
+        revert to the standard behavior (preferably after notifying the server's
+        maintainers that their software needs to be fixed).
+        </para>
+       </note>
 
        <para>
-        For servers that don't properly implement protocol version negotiation,
-        you can set <literal>max_protocol_version=3.0</literal> to connect
-        successfully.
+        Specifies the protocol version to request from the server.
+        The default is to use version <literal>3.0</literal> of the
+        <productname>PostgreSQL</productname> 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 <xref linkend="libpq-PQfullProtocolVersion"/> to
+        find out which exact protocol version was negotiated.
        </para>
 
        <para>
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 @@
   </sect2>
 
   <sect2 id="protocol-versions">
-   <title>Protocol Versions</title>
+   <title>Protocol Versions and Extensibility</title>
 
    <para>
-    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
-    <literal>max_protocol_version=3.0</literal> 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.
    </para>
 
+   <note>
+     <para>
+      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
+      <literal>max_protocol_version=3.0</literal> in their connection string.
+     </para>
+   </note>
+
    <para>
     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 @@
    <para>
     <xref linkend="protocol-versions-table"/> shows the currently supported
     protocol versions.
+    <xref linkend="other-protocol-versions-table"/>
+    documents protocol versions that are unsupported or otherwise reserved.
    </para>
 
    <table id="protocol-versions-table">
-    <title>Protocol Versions</title>
+    <title>Supported Protocol Versions</title>
 
     <tgroup cols="3">
      <thead>
@@ -241,20 +251,6 @@
      </thead>
 
      <tbody>
-      <row>
-      <entry>3.9999</entry>
-      <entry>-</entry>
-      <entry>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
-        <literal>NegotiateProtocolVersion</literal>. 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.
-      </entry>
-      </row>
       <row>
       <entry>3.2</entry>
       <entry>PostgreSQL 18 and later</entry>
@@ -265,6 +261,39 @@
       </entry>
       </row>
       <row>
+      <entry>3.0</entry>
+      <entry>PostgreSQL 7.4 and later</entry>
+      </row>
+     </tbody>
+    </tgroup>
+   </table>
+
+   <table id="other-protocol-versions-table">
+    <title>Other Protocol Versions</title>
+
+    <tgroup cols="3">
+     <thead>
+      <row>
+       <entry>Version</entry>
+       <entry>Supported by</entry>
+       <entry>Description</entry>
+      </row>
+     </thead>
+
+     <tbody>
+      <row>
+      <entry>3.9999</entry>
+      <entry>-</entry>
+      <entry>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 <emphasis>must not</emphasis> 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.
+      </entry>
+      </row>
+      <row>
       <entry>3.1</entry>
       <entry>-</entry>
       <entry>Reserved. Version 3.1 has not been used by any PostgreSQL
@@ -274,15 +303,93 @@
       </entry>
       </row>
       <row>
-      <entry>3.0</entry>
-      <entry>PostgreSQL 7.4 and later</entry>
-      </row>
-      <row>
       <entry>2.0</entry>
       <entry>up to PostgreSQL 13</entry>
-      <entry>See previous releases of
+      <entry>Obsolete. See previous releases of
       the <productname>PostgreSQL</productname> documentation for
-      details</entry>
+      details.</entry>
+      </row>
+     </tbody>
+    </tgroup>
+   </table>
+
+   <para id="protocol-extensions">
+    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. <xref linkend="protocol-extensions-table"/>
+    shows the current list of protocol extension parameters.
+   </para>
+
+   <table id="protocol-extensions-table" rowheader="firstcol">
+    <title>Protocol Extensions</title>
+
+    <tgroup cols="5">
+     <!-- For spanning, below. -->
+     <colspec colname="first" colsep="0"/>
+     <colspec colname="name" colnum="2"/>
+     <colspec colname="vals" colnum="3"/>
+     <colspec colname="support" colnum="4"/>
+     <colspec colname="last" colnum="5"/>
+
+     <!--
+       "all" spans the width of the table; it is used for the section headers.
+       "reserved" spans the Values and Supported columns, for the Reserved
+       names which define neither.
+     -->
+     <spanspec spanname="all" namest="first" nameend="last"/>
+     <spanspec spanname="reserved" namest="vals" nameend="support"/>
+
+     <thead>
+      <row>
+       <!--
+         Row header. Use namest="name" to skip to the next column.
+         XXX this causes a thin "indent" effect for the other rows
+       -->
+       <entry/>
+
+       <entry>Parameter&nbsp;Name</entry>
+       <entry>Values</entry>
+       <entry>Supported&nbsp;by</entry>
+       <entry>Description</entry>
+      </row>
+     </thead>
+
+     <tbody>
+      <row><entry spanname="all">Defined</entry></row>
+
+      <row>
+       <entry namest="last" align="center" valign="middle">
+        <emphasis>(No supported protocol extensions are currently defined.)</emphasis>
+       </entry>
+      </row>
+
+      <row><entry spanname="all">Reserved</entry></row>
+
+      <row>
+      <entry namest="name"><literal>_pq_.<replaceable>[name]</replaceable></literal></entry>
+      <entry spanname="reserved">-</entry>
+      <entry>Any other parameter names beginning with <literal>_pq_.</literal>,
+        that are not defined above, are reserved for future protocol expansion.
+        Servers <emphasis>must</emphasis> reject any that are received from a
+        client, by sending a NegotiateProtocolVersion message during the
+        <link linkend="protocol-flow-start-up">startup flow</link>, and should
+        otherwise continue the connection.
+      </entry>
+      </row>
+
+      <row>
+      <entry namest="name"><literal>_pq_.test_protocol_negotiation</literal></entry>
+      <entry spanname="reserved">-</entry>
+      <entry>Reserved for protocol greasing. libpq may send this extension to
+        test that servers and middleware properly implement protocol extension
+        negotiation. Servers <emphasis>must not</emphasis> add special-case
+        logic for this parameter; they should simply send the list of all
+        unsupported options (including this one) via a NegotiateProtocolVersion
+        message.
+      </entry>
       </row>
      </tbody>
     </tgroup>
@@ -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
     <filename>pg_hba.conf</filename>) to determine
@@ -6164,29 +6271,13 @@ psql "dbname=postgres replication=database" -c "IDENTIFY_SYSTEM;"
             </para>
            </listitem>
           </varlistentry>
-          <varlistentry>
-           <term><literal>_pq_.test_protocol_negotiation</literal></term>
-           <listitem>
-            <para>
-             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 <literal>NegotiateProtocolVersion</literal>
-             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.
-            </para>
-           </listitem>
-          </varlistentry>
          </variablelist>
 
          In addition to the above, other parameters may be listed.
          Parameter names beginning with <literal>_pq_.</literal> are
-         reserved for use as protocol extensions, while others are
+         reserved for use as
+         <link linkend="protocol-extensions">protocol extensions</link>,
+         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", "");