Skip to content

Commit 6b75efe

Browse files
mayorclaude
andcommitted
fix: handle host query parameter for unix socket connections in postgres driver
When host is specified as a query parameter (e.g., ?host=/var/run/postgresql for unix socket connections) and the URL has no host in the authority section, lib/pq silently connects to localhost:5432 instead. Convert to key-value connection string so the host parameter is reliably used. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 2bd822b commit 6b75efe

File tree

2 files changed

+43
-1
lines changed

2 files changed

+43
-1
lines changed

database/postgres/postgres.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,22 @@ func (p *Postgres) Open(url string) (database.Driver, error) {
155155
return nil, err
156156
}
157157

158-
db, err := sql.Open("postgres", migrate.FilterCustomQuery(purl).String())
158+
filteredURL := migrate.FilterCustomQuery(purl)
159+
connStr := filteredURL.String()
160+
161+
// When host is specified as a query parameter (e.g., for unix socket
162+
// connections via ?host=/var/run/postgresql) and the URL has no host in
163+
// the authority section, convert to a key-value connection string so
164+
// lib/pq reliably uses the host parameter. Without this, the driver
165+
// may silently connect to localhost:5432 instead of the specified host.
166+
if purl.Host == "" && purl.Query().Get("host") != "" {
167+
connStr, err = pq.ParseURL(connStr)
168+
if err != nil {
169+
return nil, err
170+
}
171+
}
172+
173+
db, err := sql.Open("postgres", connStr)
159174
if err != nil {
160175
return nil, err
161176
}

database/postgres/postgres_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ func Test(t *testing.T) {
9191
t.Run("testMultipleStatementsInMultiStatementMode", testMultipleStatementsInMultiStatementMode)
9292
t.Run("testErrorParsing", testErrorParsing)
9393
t.Run("testFilterCustomQuery", testFilterCustomQuery)
94+
t.Run("testHostQueryParam", testHostQueryParam)
9495
t.Run("testWithSchema", testWithSchema)
9596
t.Run("testMigrationTableOption", testMigrationTableOption)
9697
t.Run("testFailToCreateTableWithoutPermissions", testFailToCreateTableWithoutPermissions)
@@ -275,6 +276,32 @@ func testFilterCustomQuery(t *testing.T) {
275276
})
276277
}
277278

279+
func testHostQueryParam(t *testing.T) {
280+
dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) {
281+
ip, port, err := c.FirstPort()
282+
if err != nil {
283+
t.Fatal(err)
284+
}
285+
286+
// Test that host specified as a query parameter (instead of in the URL
287+
// authority) is correctly used for the connection. This is the pattern
288+
// used for unix socket connections: postgres:///db?host=/var/run/postgresql
289+
addr := fmt.Sprintf("postgres://postgres:%s@/postgres?host=%s&port=%s&sslmode=disable",
290+
pgPassword, ip, port)
291+
p := &Postgres{}
292+
d, err := p.Open(addr)
293+
if err != nil {
294+
t.Fatal(err)
295+
}
296+
defer func() {
297+
if err := d.Close(); err != nil {
298+
t.Error(err)
299+
}
300+
}()
301+
dt.Test(t, d, []byte("SELECT 1"))
302+
})
303+
}
304+
278305
func testWithSchema(t *testing.T) {
279306
dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) {
280307
ip, port, err := c.FirstPort()

0 commit comments

Comments
 (0)