Skip to content

Commit 3d9a0b4

Browse files
hlinnakaCommitfest Bot
authored and
Commitfest Bot
committed
Bump protocol version to 3.2
In preparation of new additions to the protocol in the next commit, this bumps the minor protocol version number. Instead of bumping the version number to 3.1, which would be the next minor version, we skip that one and bump straight to 3.2. The reason for this is that many PgBouncer releases have, due to an off-by-one bug, reported 3.1 as supported. These versions would interpret 3.1 as equivalent to 3.0. So if we would now add extra messages to the 3.1 protocol, clients would succeed to connect to PgBouncer, but would then cause connection failures when sending such new messages. So instead of bumping to 3.1, we bump the protocol version to 3.2, for which these buggy PgBouncer releases will correctly close the connection at the startup packet. It's a bit strange to skip a version number due to a bug in a third-party application, but PgBouncer is used widely enough that it seems worth it to not cause user confusion when connecting to recent versions of it. Especially since skipping a single minor version number in the protocol versioning doesn't really cost us anything. So, while this is not the most theoretically sound decission, it is the most pragmatic one. Author: Jelte Fennema-Nio <[email protected]> Discussion: https://www.postgresql.org/message-id/CAGECzQTfc_O%2BHXqAo5_-xG4r3EFVsTefUeQzSvhEyyLDba-O9w%40mail.gmail.com Discussion: https://www.postgresql.org/message-id/CAGECzQRbAGqJnnJJxTdKewTsNOovUt4bsx3NFfofz3m2j-t7tA@mail.gmail.com Discussion: pgbouncer/pgbouncer#1007
1 parent ae09433 commit 3d9a0b4

File tree

6 files changed

+145
-28
lines changed

6 files changed

+145
-28
lines changed

doc/src/sgml/libpq.sgml

+7-5
Original file line numberDiff line numberDiff line change
@@ -2158,10 +2158,11 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
21582158

21592159
<para>
21602160
The current supported values are
2161-
<literal>3.0</literal>
2161+
<literal>3.0</literal>,
2162+
<literal>3.2</literal>,
21622163
and <literal>latest</literal>. The <literal>latest</literal> value is
21632164
equivalent to the latest protocol version that is supported by the used
2164-
libpq version, which currently is <literal>3.0</literal>.
2165+
libpq version, which currently is <literal>3.2</literal>.
21652166
</para>
21662167
</listitem>
21672168
</varlistentry>
@@ -2184,10 +2185,11 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
21842185

21852186
<para>
21862187
The current supported values are
2187-
<literal>3.0</literal>
2188+
<literal>3.0</literal>,
2189+
<literal>3.2</literal>,
21882190
and <literal>latest</literal>. The <literal>latest</literal> value is
2189-
equivalent to the latest protocol version that is supported by the
2190-
libpq version used, which is currently <literal>3.0</literal>.
2191+
equivalent to the latest protocol version that is supported by the used
2192+
libpq version, which currently is <literal>3.2</literal>.
21912193
</para>
21922194
</listitem>
21932195
</varlistentry>

doc/src/sgml/protocol.sgml

+25-6
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,37 @@
1818
</para>
1919

2020
<para>
21-
This document describes version 3.0 of the protocol, implemented in
21+
This document describes version 3.2 of the protocol, introduced in
22+
<productname>PostgreSQL</productname> version 17. The server is compatible with
23+
protocol version 3.0, implemented in
2224
<productname>PostgreSQL</productname> 7.4 and later. For descriptions
23-
of the earlier protocol versions, see previous releases of the
24-
<productname>PostgreSQL</productname> documentation. A single server
25+
of earlier protocol versions, see previous releases of the
26+
<productname>PostgreSQL</productname> documentation.
27+
</para>
28+
29+
<para>
30+
A single server
2531
can support multiple protocol versions. The initial startup-request
2632
message tells the server which protocol version the client is attempting to
2733
use. If the major version requested by the client is not supported by
2834
the server, the connection will be rejected (for example, this would occur
2935
if the client requested protocol version 4.0, which does not exist as of
3036
this writing). If the minor version requested by the client is not
31-
supported by the server (e.g., the client requests version 3.1, but the
37+
supported by the server (e.g., the client requests version 3.2, but the
3238
server supports only 3.0), the server may either reject the connection or
3339
may respond with a NegotiateProtocolVersion message containing the highest
3440
minor protocol version which it supports. The client may then choose either
3541
to continue with the connection using the specified protocol version or
3642
to abort the connection.
3743
</para>
3844

45+
<para>
46+
The protocol negotiation was introduced in
47+
<productname>PostgreSQL</productname> version 9.3.21. Earlier versions would
48+
reject the connection if the client requested a minor version that was not
49+
supported by the server.
50+
</para>
51+
3952
<para>
4053
In order to serve multiple clients efficiently, the server launches
4154
a new <quote>backend</quote> process for each client.
@@ -413,8 +426,14 @@
413426
this message indicates the highest supported minor version. This
414427
message will also be sent if the client requested unsupported protocol
415428
options (i.e., beginning with <literal>_pq_.</literal>) in the
416-
startup packet. This message will be followed by an ErrorResponse or
417-
a message indicating the success or failure of authentication.
429+
startup packet.
430+
</para>
431+
<para>
432+
After this message, the authentication will continue using the version
433+
indicated by the server. If the client does not support the older
434+
version, it should immediately close the connection. If the server
435+
does not send this message, it supports the client's requested
436+
protocol version and all the protocol options.
418437
</para>
419438
</listitem>
420439
</varlistentry>

src/include/libpq/pqcomm.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,10 @@ is_unixsock_path(const char *path)
9191

9292
/*
9393
* The earliest and latest frontend/backend protocol version supported.
94-
* (Only protocol version 3 is currently supported)
9594
*/
9695

9796
#define PG_PROTOCOL_EARLIEST PG_PROTOCOL(3,0)
98-
#define PG_PROTOCOL_LATEST PG_PROTOCOL(3,0)
97+
#define PG_PROTOCOL_LATEST PG_PROTOCOL(3,2)
9998

10099
typedef uint32 ProtocolVersion; /* FE/BE protocol version number */
101100

src/interfaces/libpq/fe-connect.c

+10
Original file line numberDiff line numberDiff line change
@@ -8225,6 +8225,16 @@ pqParseProtocolVersion(const char *value, ProtocolVersion *result, PGconn *conn,
82258225
return true;
82268226
}
82278227

8228+
/* 3.1 never existed, we went straight from 3.0 to 3.2 */
8229+
if (strcmp(value, "3.1") == 0)
8230+
{
8231+
conn->status = CONNECTION_BAD;
8232+
libpq_append_conn_error(conn, "invalid %s value: \"%s\"",
8233+
context,
8234+
value);
8235+
return false;
8236+
}
8237+
82288238
major = strtol(value, &end, 10);
82298239
if (*end != '.')
82308240
{

src/interfaces/libpq/fe-protocol3.c

+7
Original file line numberDiff line numberDiff line change
@@ -1432,6 +1432,13 @@ pqGetNegotiateProtocolVersion3(PGconn *conn)
14321432
goto failure;
14331433
}
14341434

1435+
/* 3.1 never existed, we went straight from 3.0 to 3.2 */
1436+
if (their_version == PG_PROTOCOL(3, 1))
1437+
{
1438+
libpq_append_conn_error(conn, "received invalid protocol negotiation message: server requests downgrade to non-existent 3.1 protocol version");
1439+
goto failure;
1440+
}
1441+
14351442
if (num < 0)
14361443
{
14371444
libpq_append_conn_error(conn, "received invalid protocol negotiation message: server reported negative number of unsupported parameters");

src/test/modules/libpq_pipeline/libpq_pipeline.c

+95-15
Original file line numberDiff line numberDiff line change
@@ -197,24 +197,15 @@ send_cancellable_query_impl(int line, PGconn *conn, PGconn *monitorConn)
197197
}
198198

199199
/*
200-
* Create a new connection with the same conninfo as the given one.
200+
* Fills keywords and vals, with the same options as the ones in the opts
201+
* linked-list. Returns the length of the filled in list.
201202
*/
202-
static PGconn *
203-
copy_connection(PGconn *conn)
203+
static
204+
int
205+
copy_connection_options(PQconninfoOption *opts, const char **keywords, const char **vals)
204206
{
205-
PGconn *copyConn;
206-
PQconninfoOption *opts = PQconninfo(conn);
207-
const char **keywords;
208-
const char **vals;
209-
int nopts = 1;
210207
int i = 0;
211208

212-
for (PQconninfoOption *opt = opts; opt->keyword != NULL; ++opt)
213-
nopts++;
214-
215-
keywords = pg_malloc(sizeof(char *) * nopts);
216-
vals = pg_malloc(sizeof(char *) * nopts);
217-
218209
for (PQconninfoOption *opt = opts; opt->keyword != NULL; ++opt)
219210
{
220211
if (opt->val)
@@ -224,8 +215,28 @@ copy_connection(PGconn *conn)
224215
i++;
225216
}
226217
}
227-
keywords[i] = vals[i] = NULL;
218+
return i;
219+
}
220+
221+
/*
222+
* Create a new connection with the same conninfo as the given one.
223+
*/
224+
static PGconn *
225+
copy_connection(PGconn *conn)
226+
{
227+
const char **keywords;
228+
const char **vals;
229+
PGconn *copyConn;
230+
PQconninfoOption *opts = PQconninfo(conn);
231+
int nopts = 1; /* 1 for the NULL terminator */
228232

233+
for (PQconninfoOption *opt = opts; opt->keyword != NULL; ++opt)
234+
nopts++;
235+
236+
keywords = pg_malloc0(sizeof(char *) * nopts);
237+
vals = pg_malloc0(sizeof(char *) * nopts);
238+
239+
copy_connection_options(opts, keywords, vals);
229240
copyConn = PQconnectdbParams(keywords, vals, false);
230241

231242
if (PQstatus(copyConn) != CONNECTION_OK)
@@ -1405,6 +1416,72 @@ test_prepared(PGconn *conn)
14051416
fprintf(stderr, "ok\n");
14061417
}
14071418

1419+
static void
1420+
test_protocol_version(PGconn *conn)
1421+
{
1422+
const char **keywords;
1423+
const char **vals;
1424+
int nopts = 2; /* NULL terminator + max_protocol_version */
1425+
PQconninfoOption *opts = PQconninfo(conn);
1426+
int protocol_version;
1427+
int max_protocol_version_index;
1428+
1429+
for (PQconninfoOption *opt = opts; opt->keyword != NULL; ++opt)
1430+
nopts++;
1431+
1432+
keywords = pg_malloc0(sizeof(char *) * nopts);
1433+
vals = pg_malloc0(sizeof(char *) * nopts);
1434+
1435+
max_protocol_version_index = copy_connection_options(opts, keywords, vals);
1436+
1437+
keywords[max_protocol_version_index] = "max_protocol_version";
1438+
vals[max_protocol_version_index] = "3.0";
1439+
1440+
conn = PQconnectdbParams(keywords, vals, false);
1441+
1442+
if (PQstatus(conn) != CONNECTION_OK)
1443+
pg_fatal("Connection to database failed: %s",
1444+
PQerrorMessage(conn));
1445+
1446+
protocol_version = PQfullProtocolVersion(conn);
1447+
if (protocol_version != 30000)
1448+
pg_fatal("expected 30000, got %d", protocol_version);
1449+
1450+
PQfinish(conn);
1451+
1452+
vals[max_protocol_version_index] = "3.1";
1453+
conn = PQconnectdbParams(keywords, vals, false);
1454+
1455+
if (PQstatus(conn) != CONNECTION_BAD)
1456+
pg_fatal("Connecting with max_protocol_version 3.1 should have failed.");
1457+
1458+
PQfinish(conn);
1459+
1460+
vals[max_protocol_version_index] = "3.2";
1461+
conn = PQconnectdbParams(keywords, vals, false);
1462+
1463+
if (PQstatus(conn) != CONNECTION_OK)
1464+
pg_fatal("Connection to database failed: %s",
1465+
PQerrorMessage(conn));
1466+
1467+
protocol_version = PQfullProtocolVersion(conn);
1468+
if (protocol_version != 30002)
1469+
pg_fatal("expected 30002, got %d", protocol_version);
1470+
PQfinish(conn);
1471+
1472+
vals[max_protocol_version_index] = "latest";
1473+
conn = PQconnectdbParams(keywords, vals, false);
1474+
1475+
if (PQstatus(conn) != CONNECTION_OK)
1476+
pg_fatal("Connection to database failed: %s",
1477+
PQerrorMessage(conn));
1478+
1479+
protocol_version = PQfullProtocolVersion(conn);
1480+
if (protocol_version != 30002)
1481+
pg_fatal("expected 30002, got %d", protocol_version);
1482+
PQfinish(conn);
1483+
}
1484+
14081485
/* Notice processor: print notices, and count how many we got */
14091486
static void
14101487
notice_processor(void *arg, const char *message)
@@ -2153,6 +2230,7 @@ print_test_list(void)
21532230
printf("pipeline_idle\n");
21542231
printf("pipelined_insert\n");
21552232
printf("prepared\n");
2233+
printf("protocol_version\n");
21562234
printf("simple_pipeline\n");
21572235
printf("singlerow\n");
21582236
printf("transaction\n");
@@ -2263,6 +2341,8 @@ main(int argc, char **argv)
22632341
test_pipelined_insert(conn, numrows);
22642342
else if (strcmp(testname, "prepared") == 0)
22652343
test_prepared(conn);
2344+
else if (strcmp(testname, "protocol_version") == 0)
2345+
test_protocol_version(conn);
22662346
else if (strcmp(testname, "simple_pipeline") == 0)
22672347
test_simple_pipeline(conn);
22682348
else if (strcmp(testname, "singlerow") == 0)

0 commit comments

Comments
 (0)