Skip to content

Commit

Permalink
database/sql: close driver.Connector if it implements an io.Closer
Browse files Browse the repository at this point in the history
This change allows driver implementations to manage resources in
driver.Connector, e.g. to share the same underlying database handle
between multiple connections. That is, it allows embedded databases
with in-memory backends like SQLite and Genji to safely release the
resources once the sql.DB is closed.

This makes it possible to address oddities with in-memory stores in
SQLite and Genji drivers without introducing too much complexity in
the driver implementations.

See also:
- mattn/go-sqlite3#204
- mattn/go-sqlite3#511
- chaisql/chai#210
  • Loading branch information
tie committed Sep 30, 2020
1 parent 3caaadd commit 04bfcb1
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 1 deletion.
3 changes: 3 additions & 0 deletions src/database/sql/driver/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ type DriverContext interface {
// DriverContext's OpenConnector method, to allow drivers
// access to context and to avoid repeated parsing of driver
// configuration.
//
// A Connector may optionally implement io.Closer interface
// to release the resources when sql.DB is closed.
type Connector interface {
// Connect returns a connection to the database.
// Connect may return a cached connection (one previously
Expand Down
9 changes: 9 additions & 0 deletions src/database/sql/fakedb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ type fakeConnector struct {
name string

waiter func(context.Context)
closed bool
}

func (c *fakeConnector) Connect(context.Context) (driver.Conn, error) {
Expand All @@ -68,6 +69,14 @@ func (c *fakeConnector) Driver() driver.Driver {
return fdriver
}

func (c *fakeConnector) Close() error {
if c.closed {
return errors.New("fakedb: connector is closed")
}
c.closed = true
return nil
}

type fakeDriverCtx struct {
fakeDriver
}
Expand Down
3 changes: 3 additions & 0 deletions src/database/sql/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -850,6 +850,9 @@ func (db *DB) Close() error {
}
}
db.stop()
if c, ok := db.connector.(io.Closer); ok {
err = c.Close()
}
return err
}

Expand Down
11 changes: 10 additions & 1 deletion src/database/sql/sql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4022,9 +4022,18 @@ func TestOpenConnector(t *testing.T) {
}
defer db.Close()

if _, is := db.connector.(*fakeConnector); !is {
c, ok := db.connector.(*fakeConnector)
if !ok {
t.Fatal("not using *fakeConnector")
}

if err := db.Close(); err != nil {
t.Fatal(err)
}

if !c.closed {
t.Fatal("connector is not closed")
}
}

type ctxOnlyDriver struct {
Expand Down

0 comments on commit 04bfcb1

Please sign in to comment.