Skip to content

Commit 2f81f1f

Browse files
committed
Update max_protocol_version and min_protocol_version defaults
When `max_protocol_version` is not explicitly set, the default value is set to "3.0". This is reasonable and is inline with the same behavior as libpq[1]. Though, what libpq attempts to do that was not being done here is to reasonably upgrade or auto-raise the value of `max_protocol_version` when it has not been explicitly set. Here, we're providing the same functionality. In libpq, this determination is based on the parsed config values. We do the same here, parsing the values in ParseConfig to validate and determine the appropriate default for max_protocol_version. The string fields on Config are then set accordingly, and re-parsed at connection time as before. After parsing, when `max_protocol_version` has not been explicitly set, if `min_protocol_version` is greater than 3.0, `max_protocol_version` defaults to `latest`; otherwise it defaults to 3.0 for compatibility with older servers/poolers that don't support NegotiateProtocolVersion. [1] postgres/postgres@285613c
1 parent 4e4eaed commit 2f81f1f

3 files changed

Lines changed: 46 additions & 13 deletions

File tree

pgconn/config.go

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -454,23 +454,37 @@ func ParseConfigWithOptions(connString string, options ParseConfigOptions) (*Con
454454

455455
minProto, err := parseProtocolVersion(settings["min_protocol_version"])
456456
if err != nil {
457-
return nil, &ParseConfigError{ConnString: connString, msg: "invalid min_protocol_version", err: err}
457+
return nil, &ParseConfigError{ConnString: connString, msg: fmt.Sprintf("invalid min_protocol_version: %q", settings["min_protocol_version"]), err: err}
458458
}
459459
maxProto, err := parseProtocolVersion(settings["max_protocol_version"])
460460
if err != nil {
461-
return nil, &ParseConfigError{ConnString: connString, msg: "invalid max_protocol_version", err: err}
462-
}
463-
if minProto > maxProto {
464-
return nil, &ParseConfigError{ConnString: connString, msg: "min_protocol_version cannot be greater than max_protocol_version"}
461+
return nil, &ParseConfigError{ConnString: connString, msg: fmt.Sprintf("invalid max_protocol_version: %q", settings["max_protocol_version"]), err: err}
465462
}
466463

467464
config.MinProtocolVersion = settings["min_protocol_version"]
468465
config.MaxProtocolVersion = settings["max_protocol_version"]
466+
469467
if config.MinProtocolVersion == "" {
470468
config.MinProtocolVersion = "3.0"
471469
}
470+
471+
// When max_protocol_version is not explicitly set, default based on
472+
// min_protocol_version. This matches libpq behavior: if min > 3.0,
473+
// default max to latest; otherwise default to 3.0 for compatibility
474+
// with older servers/poolers that don't support NegotiateProtocolVersion.
472475
if config.MaxProtocolVersion == "" {
473-
config.MaxProtocolVersion = "3.0"
476+
if minProto > pgproto3.ProtocolVersion30 {
477+
config.MaxProtocolVersion = "latest"
478+
} else {
479+
config.MaxProtocolVersion = "3.0"
480+
}
481+
}
482+
483+
// Only error when max_protocol_version was explicitly set and conflicts
484+
// with min_protocol_version. When max_protocol_version is not explicitly
485+
// set, the auto-raise logic above already ensures a valid default.
486+
if minProto > maxProto && settings["max_protocol_version"] != "" {
487+
return nil, &ParseConfigError{ConnString: connString, msg: "min_protocol_version cannot be greater than max_protocol_version"}
474488
}
475489

476490
switch channelBinding := settings["channel_binding"]; channelBinding {

pgconn/config_test.go

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1228,14 +1228,20 @@ func TestParseConfigProtocolVersion(t *testing.T) {
12281228
expectedMin: "3.2",
12291229
expectedMax: "3.2",
12301230
},
1231+
{
1232+
name: "min_protocol_version=latest auto-raises max",
1233+
connString: "postgres://localhost/test?min_protocol_version=latest",
1234+
expectedMin: "latest",
1235+
expectedMax: "latest",
1236+
},
12311237
{
12321238
name: "max_protocol_version=latest",
12331239
connString: "postgres://localhost/test?max_protocol_version=latest",
12341240
expectedMin: "3.0",
12351241
expectedMax: "latest",
12361242
},
12371243
{
1238-
name: "min and max = latest",
1244+
name: "min_protocol_version and max_protocol_version = latest",
12391245
connString: "postgres://localhost/test?min_protocol_version=latest&max_protocol_version=latest",
12401246
expectedMin: "latest",
12411247
expectedMax: "latest",
@@ -1244,27 +1250,39 @@ func TestParseConfigProtocolVersion(t *testing.T) {
12441250
name: "invalid min_protocol_version",
12451251
connString: "postgres://localhost/test?min_protocol_version=2.0",
12461252
expectError: true,
1247-
expectedErrContain: "invalid min_protocol_version",
1253+
expectedErrContain: `invalid min_protocol_version: "2.0"`,
12481254
},
12491255
{
12501256
name: "invalid max_protocol_version",
12511257
connString: "postgres://localhost/test?max_protocol_version=4.0",
12521258
expectError: true,
1253-
expectedErrContain: "invalid max_protocol_version",
1259+
expectedErrContain: `invalid max_protocol_version: "4.0"`,
12541260
},
12551261
{
1256-
name: "min > max",
1262+
name: "min_protocol_version > max_protocol_version",
12571263
connString: "postgres://localhost/test?min_protocol_version=3.2&max_protocol_version=3.0",
12581264
expectError: true,
12591265
expectedErrContain: "min_protocol_version cannot be greater than max_protocol_version",
12601266
},
12611267
{
1262-
name: "environment variable PGMINPROTOCOLVERSION without matching max fails",
1263-
connString: "postgres://localhost/test",
1264-
envMin: "3.2",
1268+
name: "min_protocol_version (latest) > max_protocol_version",
1269+
connString: "postgres://localhost/test?min_protocol_version=latest&max_protocol_version=3.0",
12651270
expectError: true,
12661271
expectedErrContain: "min_protocol_version cannot be greater than max_protocol_version",
12671272
},
1273+
{
1274+
name: "min_protocol_version=3.2 auto-raises max",
1275+
connString: "postgres://localhost/test?min_protocol_version=3.2",
1276+
expectedMin: "3.2",
1277+
expectedMax: "latest",
1278+
},
1279+
{
1280+
name: "environment variable PGMINPROTOCOLVERSION auto-raises max",
1281+
connString: "postgres://localhost/test",
1282+
envMin: "3.2",
1283+
expectedMin: "3.2",
1284+
expectedMax: "latest",
1285+
},
12681286
{
12691287
name: "environment variables PGMINPROTOCOLVERSION and PGMAXPROTOCOLVERSION together",
12701288
connString: "postgres://localhost/test",

pgproto3/startup_message.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
const (
1414
ProtocolVersion30 = 196608 // 3.0
1515
ProtocolVersion32 = 196610 // 3.2
16+
ProtocolVersionLatest = ProtocolVersion32 // Latest is 3.2
1617
ProtocolVersionNumber = ProtocolVersion30 // Default is still 3.0
1718
)
1819

0 commit comments

Comments
 (0)