2
0

Port DSN parser from pgx v3

Original implementation: 2d9d8dc52a by
Joshua Barone <joshua.barone@gmail.com>.

Also changed DSN tests to use "dbname" as key rather than "database" as
that is what the PostgreSQL documentation specifies. "database" still
actually works but it should not be encouraged as it is non-standard.
This commit is contained in:
Jack Christensen
2019-09-14 18:37:33 -05:00
parent f8be2b60ce
commit 99f22ac8e4
4 changed files with 139 additions and 14 deletions
+4 -4
View File
@@ -17,15 +17,15 @@ env:
- GOPROXY=https://proxy.golang.org
- GOFLAGS=-mod=readonly
- PGX_TEST_CONN_STRING=postgres://pgx_md5:secret@127.0.0.1/pgx_test
- PGX_TEST_UNIX_SOCKET_CONN_STRING="host=/var/run/postgresql database=pgx_test"
- PGX_TEST_UNIX_SOCKET_CONN_STRING="host=/var/run/postgresql dbname=pgx_test"
- PGX_TEST_TCP_CONN_STRING=postgres://pgx_md5:secret@127.0.0.1/pgx_test
- PGX_TEST_TLS_CONN_STRING=postgres://pgx_md5:secret@127.0.0.1/pgx_test?sslmode=require
- PGX_TEST_MD5_PASSWORD_CONN_STRING=postgres://pgx_md5:secret@127.0.0.1/pgx_test
- PGX_TEST_PLAIN_PASSWORD_CONN_STRING=postgres://pgx_pw:secret@127.0.0.1/pgx_test
matrix:
- CRATEVERSION=2.1 PGX_TEST_CRATEDB_CONN_STRING="host=127.0.0.1 port=6543 user=pgx database=pgx_test"
- PGVERSION=10 PGX_TEST_REPLICATION_CONN_STRING="host=127.0.0.1 port=6543 user=pgx_replication password=secret database=pgx_test"
- PGVERSION=9.6 PGX_TEST_REPLICATION_CONN_STRING="host=127.0.0.1 port=6543 user=pgx_replication password=secret database=pgx_test"
- CRATEVERSION=2.1 PGX_TEST_CRATEDB_CONN_STRING="host=127.0.0.1 port=6543 user=pgx dbname=pgx_test"
- PGVERSION=10 PGX_TEST_REPLICATION_CONN_STRING="host=127.0.0.1 port=6543 user=pgx_replication password=secret dbname=pgx_test"
- PGVERSION=9.6 PGX_TEST_REPLICATION_CONN_STRING="host=127.0.0.1 port=6543 user=pgx_replication password=secret dbname=pgx_test"
- PGVERSION=9.5
- PGVERSION=9.4
- PGVERSION=9.3
+1 -1
View File
@@ -45,7 +45,7 @@ create database pgx_test;
Now you can run the tests:
```
PGX_TEST_CONN_STRING="host=/var/run/postgresql database=pgx_test" go test ./...
PGX_TEST_CONN_STRING="host=/var/run/postgresql dbname=pgx_test" go test ./...
```
### Connection and Authentication Tests
+56 -5
View File
@@ -13,7 +13,6 @@ import (
"os"
"os/user"
"path/filepath"
"regexp"
"strconv"
"strings"
"time"
@@ -389,13 +388,65 @@ func addURLSettings(settings map[string]string, connString string) error {
return nil
}
var dsnRegexp = regexp.MustCompile(`([a-zA-Z_]+)=((?:"[^"]+")|(?:[^ ]+))`)
var asciiSpace = [256]uint8{'\t': 1, '\n': 1, '\v': 1, '\f': 1, '\r': 1, ' ': 1}
func addDSNSettings(settings map[string]string, s string) error {
m := dsnRegexp.FindAllStringSubmatch(s, -1)
nameMap := map[string]string{
"dbname": "database",
}
for _, b := range m {
settings[b[1]] = b[2]
for len(s) > 0 {
var key, val string
eqIdx := strings.IndexRune(s, '=')
if eqIdx < 0 {
return errors.New("invalid dsn")
}
key = strings.Trim(s[:eqIdx], " \t\n\r\v\f")
s = strings.TrimLeft(s[eqIdx+1:], " \t\n\r\v\f")
if s[0] != '\'' {
end := 0
for ; end < len(s); end++ {
if asciiSpace[s[end]] == 1 {
break
}
if s[end] == '\\' {
end++
}
}
val = strings.Replace(strings.Replace(s[:end], "\\\\", "\\", -1), "\\'", "'", -1)
if end == len(s) {
s = ""
} else {
s = s[end+1:]
}
} else { // quoted string
s = s[1:]
end := 0
for ; end < len(s); end++ {
if s[end] == '\'' {
break
}
if s[end] == '\\' {
end++
}
}
if end == len(s) {
return 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:]
}
}
if k, ok := nameMap[key]; ok {
key = k
}
settings[key] = val
}
return nil
+78 -4
View File
@@ -228,7 +228,7 @@ func TestParseConfig(t *testing.T) {
},
{
name: "DSN everything",
connString: "user=jack password=secret host=localhost port=5432 database=mydb sslmode=disable application_name=pgxtest search_path=myschema",
connString: "user=jack password=secret host=localhost port=5432 dbname=mydb sslmode=disable application_name=pgxtest search_path=myschema",
config: &pgconn.Config{
User: "jack",
Password: "secret",
@@ -242,6 +242,80 @@ func TestParseConfig(t *testing.T) {
},
},
},
{
name: "DSN with escaped single quote",
connString: "user=jack\\'s password=secret host=localhost port=5432 dbname=mydb sslmode=disable",
config: &pgconn.Config{
User: "jack's",
Password: "secret",
Host: "localhost",
Port: 5432,
Database: "mydb",
TLSConfig: nil,
RuntimeParams: map[string]string{},
},
},
{
name: "DSN with escaped backslash",
connString: "user=jack password=sooper\\\\secret host=localhost port=5432 dbname=mydb sslmode=disable",
config: &pgconn.Config{
User: "jack",
Password: "sooper\\secret",
Host: "localhost",
Port: 5432,
Database: "mydb",
TLSConfig: nil,
RuntimeParams: map[string]string{},
},
},
{
name: "DSN with single quoted values",
connString: "user='jack' host='localhost' dbname='mydb' sslmode='disable'",
config: &pgconn.Config{
User: "jack",
Host: "localhost",
Port: 5432,
Database: "mydb",
TLSConfig: nil,
RuntimeParams: map[string]string{},
},
},
{
name: "DSN with single quoted value with escaped single quote",
connString: "user='jack\\'s' host='localhost' dbname='mydb' sslmode='disable'",
config: &pgconn.Config{
User: "jack's",
Host: "localhost",
Port: 5432,
Database: "mydb",
TLSConfig: nil,
RuntimeParams: map[string]string{},
},
},
{
name: "DSN with empty single quoted value",
connString: "user='jack' password='' host='localhost' dbname='mydb' sslmode='disable'",
config: &pgconn.Config{
User: "jack",
Host: "localhost",
Port: 5432,
Database: "mydb",
TLSConfig: nil,
RuntimeParams: map[string]string{},
},
},
{
name: "DSN with space between key and value",
connString: "user = 'jack' password = '' host = 'localhost' dbname = 'mydb' sslmode='disable'",
config: &pgconn.Config{
User: "jack",
Host: "localhost",
Port: 5432,
Database: "mydb",
TLSConfig: nil,
RuntimeParams: map[string]string{},
},
},
{
name: "URL multiple hosts",
connString: "postgres://jack:secret@foo,bar,baz/mydb?sslmode=disable",
@@ -294,7 +368,7 @@ func TestParseConfig(t *testing.T) {
},
{
name: "DSN multiple hosts one port",
connString: "user=jack password=secret host=foo,bar,baz port=5432 database=mydb sslmode=disable",
connString: "user=jack password=secret host=foo,bar,baz port=5432 dbname=mydb sslmode=disable",
config: &pgconn.Config{
User: "jack",
Password: "secret",
@@ -319,7 +393,7 @@ func TestParseConfig(t *testing.T) {
},
{
name: "DSN multiple hosts multiple ports",
connString: "user=jack password=secret host=foo,bar,baz port=1,2,3 database=mydb sslmode=disable",
connString: "user=jack password=secret host=foo,bar,baz port=1,2,3 dbname=mydb sslmode=disable",
config: &pgconn.Config{
User: "jack",
Password: "secret",
@@ -344,7 +418,7 @@ func TestParseConfig(t *testing.T) {
},
{
name: "multiple hosts and fallback tsl",
connString: "user=jack password=secret host=foo,bar,baz database=mydb sslmode=prefer",
connString: "user=jack password=secret host=foo,bar,baz dbname=mydb sslmode=prefer",
config: &pgconn.Config{
User: "jack",
Password: "secret",