v5-0004-libpq-Reconnect-if-requested-grease-but-version-i.patch
text/x-patch
Filename: v5-0004-libpq-Reconnect-if-requested-grease-but-version-i.patch
Type: text/x-patch
Part: 3
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v5-0004
Subject: libpq: Reconnect if requested grease but version is newer
| File | + | − |
|---|---|---|
| src/interfaces/libpq/fe-connect.c | 20 | 3 |
| src/interfaces/libpq/fe-protocol3.c | 23 | 11 |
From 60ed7f5624b007b7ab7b27167fa44f0aa51692ab Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <postgres@jeltef.nl>
Date: Thu, 15 Jan 2026 09:58:07 +0100
Subject: [PATCH v5 4/5] libpq: Reconnect if requested grease but version is
newer
While max_protocol_version=grease is mostly meant for testing, people
might still use it in production environments. So it seems better to
support reconnecting automatically if the server responds with a
downgrade to a higher version than libpq supports.
---
src/interfaces/libpq/fe-connect.c | 23 ++++++++++++++++---
src/interfaces/libpq/fe-protocol3.c | 34 +++++++++++++++++++----------
2 files changed, 43 insertions(+), 14 deletions(-)
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index fdc05cd3243..738655488f3 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -4196,10 +4196,27 @@ keep_going: /* We will come back to here until there is
libpq_append_conn_error(conn, "received duplicate protocol negotiation message");
goto error_return;
}
- if (pqGetNegotiateProtocolVersion3(conn))
{
- /* pqGetNegotiateProtocolVersion3 set error already */
- goto error_return;
+ int rc = pqGetNegotiateProtocolVersion3(conn);
+
+ if (rc == 1)
+ {
+ /*
+ * pqGetNegotiateProtocolVersion3 set error
+ * already
+ */
+ goto error_return;
+ }
+ if (rc == 2)
+ {
+ /*
+ * Server proposed newer version than libpq
+ * supports; retry with the latest supported
+ * version.
+ */
+ need_new_connection = true;
+ goto keep_going;
+ }
}
conn->pversion_negotiated = true;
diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c
index c0e0142798a..b7e30516516 100644
--- a/src/interfaces/libpq/fe-protocol3.c
+++ b/src/interfaces/libpq/fe-protocol3.c
@@ -1452,6 +1452,8 @@ reportErrorPosition(PQExpBuffer msg, const char *query, int loc, int encoding)
* Entry: 'v' message type and length have already been consumed.
* Exit: returns 0 if successfully consumed message.
* returns 1 on failure. The error message is filled in.
+ * returns 2 if server proposed a newer version and we were using GREASE;
+ * caller should retry the connection with the latest supported version.
*/
int
pqGetNegotiateProtocolVersion3(PGconn *conn)
@@ -1465,6 +1467,21 @@ pqGetNegotiateProtocolVersion3(PGconn *conn)
if (pqGetInt(&their_version, 4, conn) != 0)
goto eof;
+ /*
+ * If the server responds with a version newer than what this libpq
+ * supports, and we were using GREASE, retry with the latest supported
+ * version. This can happen if a future server legitimately supports a
+ * newer minor version than us. We don't try to parse the rest of the
+ * message since we don't know what format a newer protocol version might
+ * use. The GREASE checks for protocol extensions will still happen on the
+ * retry.
+ */
+ if (their_version > PG_PROTOCOL_LATEST && PG_PROTOCOL_IS_GREASE(conn->pversion))
+ {
+ conn->max_pversion = PG_PROTOCOL_LATEST;
+ return 2;
+ }
+
if (pqGetInt(&num, 4, conn) != 0)
goto eof;
@@ -1496,22 +1513,17 @@ pqGetNegotiateProtocolVersion3(PGconn *conn)
goto failure;
}
- /*
- * If the server responds with a version newer than what this libpq
- * supports, disconnect. This can happen if we sent a GREASE version and a
- * future server legitimately supports a newer minor version than us.
- */
- if (their_version > PG_PROTOCOL_LATEST)
+ if (num < 0)
{
- libpq_append_conn_error(conn, "server proposed protocol version 3.%d, but libpq only supports up to 3.%d",
- PG_PROTOCOL_MINOR(their_version),
- PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST));
+ libpq_append_conn_error(conn, "received invalid protocol negotiation message: server reported negative number of unsupported parameters");
goto failure;
}
- if (num < 0)
+ if (their_version > PG_PROTOCOL_LATEST)
{
- libpq_append_conn_error(conn, "received invalid protocol negotiation message: server reported negative number of unsupported parameters");
+ libpq_append_conn_error(conn, "server proposed protocol version 3.%d, but libpq only supports up to 3.%d",
+ PG_PROTOCOL_MINOR(their_version),
+ PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST));
goto failure;
}
--
2.52.0