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
1 change: 1 addition & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
github: arp242
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ newer. Previously PostgreSQL 8.4 and newer were supported.

- Allow using a custom `tls.Config`, for example for encrypted keys ([#1228]).

- Add `Config`, `NewConfig()`, and `NewConnectorConfig()` to supply connection
details in a more structured way ([#1240]).

- Add `PQGO_DEBUG=1` print the communication with PostgreSQL to stderr, to aid
in debugging, testing, and bug reports ([#1223]).

Expand Down Expand Up @@ -100,6 +103,7 @@ newer. Previously PostgreSQL 8.4 and newer were supported.
[#1234]: https://github.com/lib/pq/pull/1234
[#1238]: https://github.com/lib/pq/pull/1238
[#1239]: https://github.com/lib/pq/pull/1239
[#1240]: https://github.com/lib/pq/pull/1240


v1.10.9 (2023-04-26)
Expand Down
25 changes: 6 additions & 19 deletions conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ func (c *Connector) open(ctx context.Context) (cn *conn, err error) {
}

func dial(ctx context.Context, d Dialer, o values) (net.Conn, error) {
network, address := network(o)
network, address := o.network()

// Zero or not specified means wait indefinitely.
if timeout, ok := o["connect_timeout"]; ok && timeout != "0" {
Expand Down Expand Up @@ -722,7 +722,7 @@ func toNamedValue(v []driver.Value) []driver.NamedValue {
}

// CheckNamedValue implements [driver.NamedValueChecker].
func (c *conn) CheckNamedValue(nv *driver.NamedValue) error {
func (cn *conn) CheckNamedValue(nv *driver.NamedValue) error {
// Ignore Valuer, for backward compatibility with pq.Array().
if _, ok := nv.Value.(driver.Valuer); ok {
return driver.ErrSkip
Expand Down Expand Up @@ -1077,23 +1077,10 @@ func (cn *conn) ssl(o values) error {
// startup packet.
func isDriverSetting(key string) bool {
switch key {
case "host", "port":
return true
case "password":
return true
case "sslmode", "sslcert", "sslkey", "sslrootcert", "sslinline", "sslsni":
return true
case "fallback_application_name":
return true
case "connect_timeout":
return true
case "disable_prepared_binary_result":
return true
case "binary_parameters":
return true
case "krbsrvname":
return true
case "krbspn":
case "host", "port", "password", "fallback_application_name",
"sslmode", "sslcert", "sslkey", "sslrootcert", "sslinline", "sslsni",
"connect_timeout", "binary_parameters", "disable_prepared_binary_result",
"krbsrvname", "krbspn":
return true
default:
return false
Expand Down
127 changes: 0 additions & 127 deletions conn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1334,133 +1334,6 @@ func TestErrorClass(t *testing.T) {
}
}

func TestParseOpts(t *testing.T) {
tests := []struct {
in string
expected values
valid bool
}{
{"dbname=hello user=goodbye", values{"dbname": "hello", "user": "goodbye"}, true},
{"dbname=hello user=goodbye ", values{"dbname": "hello", "user": "goodbye"}, true},
{"dbname = hello user=goodbye", values{"dbname": "hello", "user": "goodbye"}, true},
{"dbname=hello user =goodbye", values{"dbname": "hello", "user": "goodbye"}, true},
{"dbname=hello user= goodbye", values{"dbname": "hello", "user": "goodbye"}, true},
{"host=localhost password='correct horse battery staple'", values{"host": "localhost", "password": "correct horse battery staple"}, true},
{"dbname=データベース password=パスワード", values{"dbname": "データベース", "password": "パスワード"}, true},
{"dbname=hello user=''", values{"dbname": "hello", "user": ""}, true},
{"user='' dbname=hello", values{"dbname": "hello", "user": ""}, true},
// The last option value is an empty string if there's no non-whitespace after its =
{"dbname=hello user= ", values{"dbname": "hello", "user": ""}, true},

// The parser ignores spaces after = and interprets the next set of non-whitespace characters as the value.
{"user= password=foo", values{"user": "password=foo"}, true},

// Backslash escapes next char
{`user=a\ \'\\b`, values{"user": `a '\b`}, true},
{`user='a \'b'`, values{"user": `a 'b`}, true},

// Incomplete escape
{`user=x\`, values{}, false},

// No '=' after the key
{"postgre://marko@internet", values{}, false},
{"dbname user=goodbye", values{}, false},
{"user=foo blah", values{}, false},
{"user=foo blah ", values{}, false},

// Unterminated quoted value
{"dbname=hello user='unterminated", values{}, false},
}

for _, test := range tests {
o := make(values)
err := parseOpts(test.in, o)

switch {
case err != nil && test.valid:
t.Errorf("%q got unexpected error: %s", test.in, err)
case err == nil && test.valid && !reflect.DeepEqual(test.expected, o):
t.Errorf("%q got: %#v want: %#v", test.in, o, test.expected)
case err == nil && !test.valid:
t.Errorf("%q expected an error", test.in)
}
}
}

func TestRuntimeParameters(t *testing.T) {
t.Parallel()

tests := []struct {
conninfo string
param string
want string
success bool
skipPgbouncer bool
}{
// invalid parameter
{"DOESNOTEXIST=foo", "", "", false, false},

// we can only work with a specific value for these two
{"client_encoding=SQL_ASCII", "", "", false, false},
{"datestyle='ISO, YDM'", "", "", false, false},

// "options" should work exactly as it does in libpq
// Skipped on pgbouncer as it errors with:
// pq: unsupported startup parameter in options: search_path
{"options='-c search_path=pqgotest'", "search_path", "pqgotest", true, true},

// pq should override client_encoding in this case
// TODO: not set consistently with pgbouncer
{"options='-c client_encoding=SQL_ASCII'", "client_encoding", "UTF8", true, true},

// allow client_encoding to be set explicitly
{"client_encoding=UTF8", "client_encoding", "UTF8", true, false},

// test a runtime parameter not supported by libpq
// Skipped on pgbouncer as it errors with:
// pq: unsupported startup parameter: work_mem
{"work_mem='139kB'", "work_mem", "139kB", true, true},

// test fallback_application_name
{"application_name=foo fallback_application_name=bar", "application_name", "foo", true, false},
{"application_name='' fallback_application_name=bar", "application_name", "", true, false},
{"fallback_application_name=bar", "application_name", "bar", true, false},
}

for _, tt := range tests {
t.Run("", func(t *testing.T) {
if tt.skipPgbouncer {
pqtest.SkipPgbouncer(t)
}
db, err := pqtest.DB(tt.conninfo)
if err != nil {
t.Fatal(err)
}

tryGetParameterValue := func() (value string, success bool) {
defer db.Close()
row := db.QueryRow("SELECT current_setting($1)", tt.param)
err = row.Scan(&value)
if err != nil {
return "", false
}
return value, true
}

have, success := tryGetParameterValue()
if success != tt.success && !success {
t.Fatal(err)
}
if success != tt.success {
t.Fatalf("\nhave: %v\nwant: %v", success, tt.success)
}
if have != tt.want {
t.Fatalf("\nhave: %v\nwant: %v", have, tt.want)
}
})
}
}

func TestRowsResultTag(t *testing.T) {
type ResultTag interface {
Result() driver.Result
Expand Down
Loading
Loading