Commit b44b2feb authored by Daniel Theophanes's avatar Daniel Theophanes

database/sql: allow OpenConnector in a driver.Driver interface

While driver.Connector was previously added to allow non-string
connection arguments and access to the context, most users of
the sql package will continue to rely on a string DSN.

Allow drivers to implement a string DSN to Connector interface
that both allows a single parsing of the string DSN and uses
the Connector interface which passes available context to
the driver dialer.

Fixes #22713

Change-Id: Ia0b862262f4c4670effe2538d0d6d43733fea18d
Reviewed-on: https://go-review.googlesource.com/77550Reviewed-by: default avatarIan Lance Taylor <iant@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
parent 096b195d
......@@ -55,6 +55,17 @@ type Driver interface {
Open(name string) (Conn, error)
}
// DriverContext enhances the Driver interface by returning a Connector
// rather then a single Conn.
// It separates out the name parsing step from actually connecting to the
// database. It also gives dialers access to the context by using the
// Connector.
type DriverContext interface {
// OpenConnector must parse the name in the same format that Driver.Open
// parses the name parameter.
OpenConnector(name string) (Connector, error)
}
// Connector is an optional interface that drivers can implement.
// It allows drivers to provide more flexible methods to open
// database connections without requiring the use of a DSN string.
......
......@@ -71,6 +71,16 @@ func (c *fakeConnector) Driver() driver.Driver {
return fdriver
}
type fakeDriverCtx struct {
fakeDriver
}
var _ driver.DriverContext = &fakeDriverCtx{}
func (cc *fakeDriverCtx) OpenConnector(name string) (driver.Connector, error) {
return &fakeConnector{name: name}, nil
}
type fakeDB struct {
name string
......
......@@ -662,6 +662,14 @@ func Open(driverName, dataSourceName string) (*DB, error) {
return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName)
}
if driverCtx, ok := driveri.(driver.DriverContext); ok {
connector, err := driverCtx.OpenConnector(dataSourceName)
if err != nil {
return nil, err
}
return OpenDB(connector), nil
}
return OpenDB(dsnConnector{dsn: dataSourceName, driver: driveri}), nil
}
......
......@@ -3523,6 +3523,19 @@ func TestNamedValueCheckerSkip(t *testing.T) {
}
}
func TestOpenConnector(t *testing.T) {
Register("testctx", &fakeDriverCtx{})
db, err := Open("testctx", "people")
if err != nil {
t.Fatal(err)
}
defer db.Close()
if _, is := db.connector.(*fakeConnector); !is {
t.Fatal("not using *fakeConnector")
}
}
type ctxOnlyDriver struct {
fakeDriver
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment