diff --git a/conn.go b/conn.go index d79a4e97..6078cca2 100644 --- a/conn.go +++ b/conn.go @@ -550,6 +550,15 @@ func ParseDSN(s string) (ConnConfig, error) { return cp, nil } +// ParseConnectionString parses either a URI or a DSN connection string. +// see ParseURI and ParseDSN for details. +func ParseConnectionString(s string) (ConnConfig, error) { + if strings.HasPrefix(s, "postgres://") || strings.HasPrefix(s, "postgresql://") { + return ParseURI(s) + } + return ParseDSN(s) +} + // ParseEnvLibpq parses the environment like libpq does into a ConnConfig // // See http://www.postgresql.org/docs/9.4/static/libpq-envars.html for details diff --git a/conn_test.go b/conn_test.go index 4550e63a..50ea68f6 100644 --- a/conn_test.go +++ b/conn_test.go @@ -530,6 +530,225 @@ func TestParseDSN(t *testing.T) { } } +func TestParseConnectionString(t *testing.T) { + t.Parallel() + + tests := []struct { + url string + connParams pgx.ConnConfig + }{ + { + url: "postgres://jack:secret@localhost:5432/mydb?sslmode=prefer", + connParams: pgx.ConnConfig{ + User: "jack", + Password: "secret", + Host: "localhost", + Port: 5432, + Database: "mydb", + TLSConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + UseFallbackTLS: true, + FallbackTLSConfig: nil, + RuntimeParams: map[string]string{}, + }, + }, + { + url: "postgres://jack:secret@localhost:5432/mydb?sslmode=disable", + connParams: pgx.ConnConfig{ + User: "jack", + Password: "secret", + Host: "localhost", + Port: 5432, + Database: "mydb", + TLSConfig: nil, + UseFallbackTLS: false, + FallbackTLSConfig: nil, + RuntimeParams: map[string]string{}, + }, + }, + { + url: "postgres://jack:secret@localhost:5432/mydb", + connParams: pgx.ConnConfig{ + User: "jack", + Password: "secret", + Host: "localhost", + Port: 5432, + Database: "mydb", + TLSConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + UseFallbackTLS: true, + FallbackTLSConfig: nil, + RuntimeParams: map[string]string{}, + }, + }, + { + url: "postgresql://jack:secret@localhost:5432/mydb", + connParams: pgx.ConnConfig{ + User: "jack", + Password: "secret", + Host: "localhost", + Port: 5432, + Database: "mydb", + TLSConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + UseFallbackTLS: true, + FallbackTLSConfig: nil, + RuntimeParams: map[string]string{}, + }, + }, + { + url: "postgres://jack@localhost:5432/mydb", + connParams: pgx.ConnConfig{ + User: "jack", + Host: "localhost", + Port: 5432, + Database: "mydb", + TLSConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + UseFallbackTLS: true, + FallbackTLSConfig: nil, + RuntimeParams: map[string]string{}, + }, + }, + { + url: "postgres://jack@localhost/mydb", + connParams: pgx.ConnConfig{ + User: "jack", + Host: "localhost", + Database: "mydb", + TLSConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + UseFallbackTLS: true, + FallbackTLSConfig: nil, + RuntimeParams: map[string]string{}, + }, + }, + { + url: "postgres://jack@localhost/mydb?application_name=pgxtest&search_path=myschema", + connParams: pgx.ConnConfig{ + User: "jack", + Host: "localhost", + Database: "mydb", + TLSConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + UseFallbackTLS: true, + FallbackTLSConfig: nil, + RuntimeParams: map[string]string{ + "application_name": "pgxtest", + "search_path": "myschema", + }, + }, + }, + { + url: "user=jack password=secret host=localhost port=5432 dbname=mydb sslmode=disable", + connParams: pgx.ConnConfig{ + User: "jack", + Password: "secret", + Host: "localhost", + Port: 5432, + Database: "mydb", + RuntimeParams: map[string]string{}, + }, + }, + { + url: "user=jack password=secret host=localhost port=5432 dbname=mydb sslmode=prefer", + connParams: pgx.ConnConfig{ + User: "jack", + Password: "secret", + Host: "localhost", + Port: 5432, + Database: "mydb", + TLSConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + UseFallbackTLS: true, + FallbackTLSConfig: nil, + RuntimeParams: map[string]string{}, + }, + }, + { + url: "user=jack password=secret host=localhost port=5432 dbname=mydb", + connParams: pgx.ConnConfig{ + User: "jack", + Password: "secret", + Host: "localhost", + Port: 5432, + Database: "mydb", + TLSConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + UseFallbackTLS: true, + FallbackTLSConfig: nil, + RuntimeParams: map[string]string{}, + }, + }, + { + url: "user=jack host=localhost port=5432 dbname=mydb", + connParams: pgx.ConnConfig{ + User: "jack", + Host: "localhost", + Port: 5432, + Database: "mydb", + TLSConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + UseFallbackTLS: true, + FallbackTLSConfig: nil, + RuntimeParams: map[string]string{}, + }, + }, + { + url: "user=jack host=localhost dbname=mydb", + connParams: pgx.ConnConfig{ + User: "jack", + Host: "localhost", + Database: "mydb", + TLSConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + UseFallbackTLS: true, + FallbackTLSConfig: nil, + RuntimeParams: map[string]string{}, + }, + }, + { + url: "user=jack host=localhost dbname=mydb application_name=pgxtest search_path=myschema", + connParams: pgx.ConnConfig{ + User: "jack", + Host: "localhost", + Database: "mydb", + TLSConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + UseFallbackTLS: true, + FallbackTLSConfig: nil, + RuntimeParams: map[string]string{ + "application_name": "pgxtest", + "search_path": "myschema", + }, + }, + }, + } + + for i, tt := range tests { + connParams, err := pgx.ParseConnectionString(tt.url) + if err != nil { + t.Errorf("%d. Unexpected error from pgx.ParseDSN(%q) => %v", i, tt.url, err) + continue + } + + if !reflect.DeepEqual(connParams, tt.connParams) { + t.Errorf("%d. expected %#v got %#v", i, tt.connParams, connParams) + } + } +} + func TestParseEnvLibpq(t *testing.T) { pgEnvvars := []string{"PGHOST", "PGPORT", "PGDATABASE", "PGUSER", "PGPASSWORD", "PGAPPNAME", "PGSSLMODE"} diff --git a/stdlib/sql.go b/stdlib/sql.go index e3d46cab..000f0fbf 100644 --- a/stdlib/sql.go +++ b/stdlib/sql.go @@ -7,6 +7,13 @@ // return err // } // +// Or from a DSN string. +// +// db, err := sql.Open("pgx", "user=postgres password=secret host=localhost port=5432 database=pgx_test sslmode=disable") +// if err != nil { +// return err +// } +// // Or a normal pgx connection pool can be established and the database/sql // connection can be created through stdlib.OpenFromConnPool(). This allows // more control over the connection process (such as TLS), more control @@ -99,7 +106,7 @@ func (d *Driver) Open(name string) (driver.Conn, error) { return &Conn{conn: conn, pool: d.Pool}, nil } - connConfig, err := pgx.ParseURI(name) + connConfig, err := pgx.ParseConnectionString(name) if err != nil { return nil, err }