Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 8 additions & 10 deletions pgconn/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,9 @@ func parseKeywordValueSettings(s string) (map[string]string, error) {
"dbname": "database",
}

// Trim any leading whitespace so that the loop exits cleanly when only
// spaces remain (e.g. trailing spaces after the last value).
s = strings.TrimLeft(s, " \t\n\r\v\f")
for len(s) > 0 {
var key, val string
eqIdx := strings.IndexRune(s, '=')
Expand All @@ -655,11 +658,9 @@ func parseKeywordValueSettings(s string) (map[string]string, error) {
}
}
val = strings.Replace(strings.Replace(s[:end], "\\\\", "\\", -1), "\\'", "'", -1)
if end == len(s) {
s = ""
} else {
s = s[end+1:]
}
// Consume the value and trim any subsequent whitespace so that
// multiple trailing spaces don't cause a spurious parse failure.
s = strings.TrimLeft(s[end:], " \t\n\r\v\f")
} else { // quoted string
s = s[1:]
end := 0
Expand All @@ -675,11 +676,8 @@ func parseKeywordValueSettings(s string) (map[string]string, error) {
return nil, errors.New("unterminated quoted string in connection info string")
}
val = strings.Replace(strings.Replace(s[:end], "\\\\", "\\", -1), "\\'", "'", -1)
if end == len(s) {
s = ""
} else {
s = s[end+1:]
}
// Consume the closing quote and any subsequent whitespace.
s = strings.TrimLeft(s[end+1:], " \t\n\r\v\f")
}

if k, ok := nameMap[key]; ok {
Expand Down
38 changes: 38 additions & 0 deletions pgconn/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,44 @@ func TestParseConfigKVTrailingBackslash(t *testing.T) {
assert.Contains(t, err.Error(), "invalid backslash")
}

// https://github.com/jackc/pgx/issues/2284
// Multiple trailing spaces and trailing spaces after quoted values must be
// accepted as valid keyword/value connection strings.
func TestParseConfigKVTrailingWhitespace(t *testing.T) {
tests := []struct {
name string
connString string
}{
{
name: "single trailing space",
connString: "dbname=foo ",
},
{
name: "multiple trailing spaces",
connString: "dbname=foo ",
},
{
name: "trailing tab",
connString: "dbname=foo\t",
},
{
name: "quoted value with trailing spaces",
connString: "dbname='foo' ",
},
{
name: "two key-value pairs with trailing spaces",
connString: "port=5432 dbname=foo ",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, err := pgconn.ParseConfig(tt.connString)
require.NoErrorf(t, err, "conn string %q should not produce an error", tt.connString)
})
}
}

func TestConfigCopyReturnsEqualConfig(t *testing.T) {
connString := "postgres://jack:secret@localhost:5432/mydb?application_name=pgxtest&search_path=myschema&connect_timeout=5"
original, err := pgconn.ParseConfig(connString)
Expand Down
Loading