// Copyright 2011 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file. // Package sql provides a generic interface around SQL (or SQL-like)// databases.//// The sql package must be used in conjunction with a database driver.// See https://golang.org/s/sqldrivers for a list of drivers.//// For more usage examples, see the wiki page at// https://golang.org/s/sqlwiki.package sql import ( "database/sql/driver" "errors" "fmt" "io" "runtime" "sort" "sync" "sync/atomic" "time") var ( driversMu sync.RWMutex drivers = make(map[string]driver.Driver)) // nowFunc returns the current time; it's overridden in tests.var nowFunc = time.Now // Register makes a database driver available by the provided name.// If Register is called twice with the same name or if driver is nil,// it panics.func Register(name string, driver driver.Driver) { driversMu.Lock() defer driversMu.Unlock() if driver == nil { panic("sql: Register driver is nil") } if _, dup := drivers[name]; dup { panic("sql: Register called twice for driver " + name) } drivers[name] = driver} func unregisterAllDrivers() { driversMu.Lock() defer driversMu.Unlock() // For tests. drivers = make(map[string]driver.Driver)} // Drivers returns a sorted list of the names of the registered drivers.func Drivers() []string { driversMu.RLock() defer driversMu.RUnlock() var list []string for name := range drivers { list = append(list, name) } sort.Strings(list) return list} // RawBytes is a byte slice that holds a reference to memory owned by// the database itself. After a Scan into a RawBytes, the slice is only// valid until the next call to Next, Scan, or Close.type RawBytes []byte // NullString represents a string that may be null.// NullString implements the Scanner interface so// it can be used as a scan destination://// var s NullString// err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&s)// ...// if s.Valid {// // use s.String// } else {// // NULL value// }//type NullString struct { String string Valid bool // Valid is true if String is not NULL} // Scan implements the Scanner interface.func (ns *NullString) Scan(value interface{}) error { if value == nil { ns.String, ns.Valid = "", false return nil } ns.Valid = true return convertAssign(&ns.String, value)} // Value implements the driver Valuer interface.func (ns NullString) Value() (driver.Value, error) { if !ns.Valid { return nil, nil } return ns.String, nil} // NullInt64 represents an int64 that may be null.// NullInt64 implements the Scanner interface so// it can be used as a scan destination, similar to NullString.type NullInt64 struct { Int64 int64 Valid bool // Valid is true if Int64 is not NULL} // Scan implements the Scanner interface.func (n *NullInt64) Scan(value interface{}) error { if value == nil { n.Int64, n.Valid = 0, false return nil } n.Valid = true return convertAssign(&n.Int64, value)} // Value implements the driver Valuer interface.func (n NullInt64) Value() (driver.Value, error) { if !n.Valid { return nil, nil } return n.Int64, nil} // NullFloat64 represents a float64 that may be null.// NullFloat64 implements the Scanner interface so// it can be used as a scan destination, similar to NullString.type NullFloat64 struct { Float64 float64 Valid bool // Valid is true if Float64 is not NULL} // Scan implements the Scanner interface.func (n *NullFloat64) Scan(value interface{}) error { if value == nil { n.Float64, n.Valid = 0, false return nil } n.Valid = true return convertAssign(&n.Float64, value)} // Value implements the driver Valuer interface.func (n NullFloat64) Value() (driver.Value, error) { if !n.Valid { return nil, nil } return n.Float64, nil} // NullBool represents a bool that may be null.// NullBool implements the Scanner interface so// it can be used as a scan destination, similar to NullString.type NullBool struct { Bool bool Valid bool // Valid is true if Bool is not NULL} // Scan implements the Scanner interface.func (n *NullBool) Scan(value interface{}) error { if value == nil { n.Bool, n.Valid = false, false return nil } n.Valid = true return convertAssign(&n.Bool, value)} // Value implements the driver Valuer interface.func (n NullBool) Value() (driver.Value, error) { if !n.Valid { return nil, nil } return n.Bool, nil} // Scanner is an interface used by Scan.type Scanner interface { // Scan assigns a value from a database driver. // // The src value will be of one of the following restricted // set of types: // // int64 // float64 // bool // []byte // string // time.Time // nil - for NULL values // // An error should be returned if the value can not be stored // without loss of information. Scan(src interface{}) error} // ErrNoRows is returned by Scan when QueryRow doesn't return a// row. In such a case, QueryRow returns a placeholder *Row value that// defers this error until a Scan.var ErrNoRows = errors.New("sql: no rows in result set") // DB is a database handle representing a pool of zero or more// underlying connections. It's safe for concurrent use by multiple// goroutines.//// The sql package creates and frees connections automatically; it// also maintains a free pool of idle connections. If the database has// a concept of per-connection state, such state can only be reliably// observed within a transaction. Once DB.Begin is called, the// returned Tx is bound to a single connection. Once Commit or// Rollback is called on the transaction, that transaction's// connection is returned to DB's idle connection pool. The pool size// can be controlled with SetMaxIdleConns.type DB struct { driver driver.Driver dsn string // numClosed is an atomic counter which represents a total number of // closed connections. Stmt.openStmt checks it before cleaning closed // connections in Stmt.css. numClosed uint64 mu sync.Mutex // protects following fields freeConn []*driverConn connRequests []chan connRequest numOpen int // number of opened and pending open connections // Used to signal the need for new connections // a goroutine running connectionOpener() reads on this chan and // maybeOpenNewConnections sends on the chan (one send per needed connection) // It is closed during db.Close(). The close tells the connectionOpener // goroutine to exit. openerCh chan struct{} closed bool dep map[finalCloser]depSet lastPut map[*driverConn]string // stacktrace of last conn's put; debug only maxIdle int // zero means defaultMaxIdleConns; negative means 0 maxOpen int // <= 0 means unlimited maxLifetime time.Duration // maximum amount of time a connection may be reused cleanerCh chan struct{}} // connReuseStrategy determines how (*DB).conn returns database connections.type connReuseStrategy uint8 const ( // alwaysNewConn forces a new connection to the database. alwaysNewConn connReuseStrategy = iota // cachedOrNewConn returns a cached connection, if available, else waits // for one to become available (if MaxOpenConns has been reached) or // creates a new database connection. cachedOrNewConn) // driverConn wraps a driver.Conn with a mutex, to// be held during all calls into the Conn. (including any calls onto// interfaces returned via that Conn, such as calls on Tx, Stmt,// Result, Rows)type driverConn struct { db *DB createdAt time.Time sync.Mutex // guards following ci driver.Conn closed bool finalClosed bool // ci.Close has been called openStmt map[driver.Stmt]bool // guarded by db.mu inUse bool onPut []func() // code (with db.mu held) run when conn is next returned dbmuClosed bool // same as closed, but guarded by db.mu, for removeClosedStmtLocked} func (dc *driverConn) releaseConn(err error) { dc.db.putConn(dc, err)} func (dc *driverConn) removeOpenStmt(si driver.Stmt) { dc.Lock() defer dc.Unlock() delete(dc.openStmt, si)} func (dc *driverConn) expired(timeout time.Duration) bool { if timeout <= 0 { return false } return dc.createdAt.Add(timeout).Before(nowFunc())} func (dc *driverConn) prepareLocked(query string) (driver.Stmt, error) { si, err := dc.ci.Prepare(query) if err == nil { // Track each driverConn's open statements, so we can close them // before closing the conn. // // TODO(bradfitz): let drivers opt out of caring about // stmt closes if the conn is about to close anyway? For now // do the safe thing, in case stmts need to be closed. // // TODO(bradfitz): after Go 1.2, closing driver.Stmts // should be moved to driverStmt, using unique // *driverStmts everywhere (including from // *Stmt.connStmt, instead of returning a // driver.Stmt), using driverStmt as a pointer // everywhere, and making it a finalCloser. if dc.openStmt == nil { dc.openStmt = make(map[driver.Stmt]bool) } dc.openStmt[si] = true } return si, err} // the dc.db's Mutex is held.func (dc *driverConn) closeDBLocked() func() error { dc.Lock() defer dc.Unlock() if dc.closed { return func() error { return errors.New("sql: duplicate driverConn close") } } dc.closed = true return dc.db.removeDepLocked(dc, dc)} func (dc *driverConn) Close() error { dc.Lock() if dc.closed { dc.Unlock() return errors.New("sql: duplicate driverConn close") } dc.closed = true dc.Unlock() // not defer; removeDep finalClose calls may need to lock // And now updates that require holding dc.mu.Lock. dc.db.mu.Lock() dc.dbmuClosed = true fn := dc.db.removeDepLocked(dc, dc) dc.db.mu.Unlock() return fn()} func (dc *driverConn) finalClose() error { dc.Lock() for si := range dc.openStmt { si.Close() } dc.openStmt = nil err := dc.ci.Close() dc.ci = nil dc.finalClosed = true dc.Unlock() dc.db.mu.Lock() dc.db.numOpen-- dc.db.maybeOpenNewConnections() dc.db.mu.Unlock() atomic.AddUint64(&dc.db.numClosed, 1) return err} // driverStmt associates a driver.Stmt with the// *driverConn from which it came, so the driverConn's lock can be// held during calls.type driverStmt struct { sync.Locker // the *driverConn si driver.Stmt} func (ds *driverStmt) Close() error { ds.Lock() defer ds.Unlock() return ds.si.Close()} // depSet is a finalCloser's outstanding dependenciestype depSet map[interface{}]bool // set of true bools // The finalCloser interface is used by (*DB).addDep and related// dependency reference counting.type finalCloser interface { // finalClose is called when the reference count of an object // goes to zero. (*DB).mu is not held while calling it. finalClose() error} // addDep notes that x now depends on dep, and x's finalClose won't be// called until all of x's dependencies are removed with removeDep.func (db *DB) addDep(x finalCloser, dep interface{}) { //println(fmt.Sprintf("addDep(%T %p, %T %p)", x, x, dep, dep)) db.mu.Lock() defer db.mu.Unlock() db.addDepLocked(x, dep)} func (db *DB) addDepLocked(x finalCloser, dep interface{}) { if db.dep == nil { db.dep = make(map[finalCloser]depSet) } xdep := db.dep[x] if xdep == nil { xdep = make(depSet) db.dep[x] = xdep } xdep[dep] = true} // removeDep notes that x no longer depends on dep.// If x still has dependencies, nil is returned.// If x no longer has any dependencies, its finalClose method will be// called and its error value will be returned.func (db *DB) removeDep(x finalCloser, dep interface{}) error { db.mu.Lock() fn := db.removeDepLocked(x, dep) db.mu.Unlock() return fn()} func (db *DB) removeDepLocked(x finalCloser, dep interface{}) func() error { //println(fmt.Sprintf("removeDep(%T %p, %T %p)", x, x, dep, dep)) xdep, ok := db.dep[x] if !ok { panic(fmt.Sprintf("unpaired removeDep: no deps for %T", x)) } l0 := len(xdep) delete(xdep, dep) switch len(xdep) { case l0: // Nothing removed. Shouldn't happen. panic(fmt.Sprintf("unpaired removeDep: no %T dep on %T", dep, x)) case 0: // No more dependencies. delete(db.dep, x) return x.finalClose default: // Dependencies remain. return func() error { return nil } }} // This is the size of the connectionOpener request chan (DB.openerCh).// This value should be larger than the maximum typical value// used for db.maxOpen. If maxOpen is significantly larger than// connectionRequestQueueSize then it is possible for ALL calls into the *DB// to block until the connectionOpener can satisfy the backlog of requests.var connectionRequestQueueSize = 1000000 // Open opens a database specified by its database driver name and a// driver-specific data source name, usually consisting of at least a// database name and connection information.//// Most users will open a database via a driver-specific connection// helper function that returns a *DB. No database drivers are included// in the Go standard library. See https://golang.org/s/sqldrivers for// a list of third-party drivers.//// Open may just validate its arguments without creating a connection// to the database. To verify that the data source name is valid, call// Ping.//// The returned DB is safe for concurrent use by multiple goroutines// and maintains its own pool of idle connections. Thus, the Open// function should be called just once. It is rarely necessary to// close a DB.func Open(driverName, dataSourceName string) (*DB, error) { driversMu.RLock() driveri, ok := drivers[driverName] driversMu.RUnlock() if !ok { return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName) } db := &DB{ driver: driveri, dsn: dataSourceName, openerCh: make(chan struct{}, connectionRequestQueueSize), lastPut: make(map[*driverConn]string), } go db.connectionOpener() return db, nil} // Ping verifies a connection to the database is still alive,// establishing a connection if necessary.func (db *DB) Ping() error {Lines 1–500 of 1932. Load more
// Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package sql provides a generic interface around SQL (or SQL-like) // databases. // // The sql package must be used in conjunction with a database driver. // See https://golang.org/s/sqldrivers for a list of drivers. // // For more usage examples, see the wiki page at // https://golang.org/s/sqlwiki. package sql import ( "database/sql/driver" "errors" "fmt" "io" "runtime" "sort" "sync" "sync/atomic" "time" ) var ( driversMu sync.RWMutex drivers = make(map[string]driver.Driver) ) // nowFunc returns the current time; it's overridden in tests. var nowFunc = time.Now // Register makes a database driver available by the provided name. // If Register is called twice with the same name or if driver is nil, // it panics. func Register(name string, driver driver.Driver) { driversMu.Lock() defer driversMu.Unlock() if driver == nil { panic("sql: Register driver is nil") } if _, dup := drivers[name]; dup { panic("sql: Register called twice for driver " + name) } drivers[name] = driver } func unregisterAllDrivers() { driversMu.Lock() defer driversMu.Unlock() // For tests. drivers = make(map[string]driver.Driver) } // Drivers returns a sorted list of the names of the registered drivers. func Drivers() []string { driversMu.RLock() defer driversMu.RUnlock() var list []string for name := range drivers { list = append(list, name) } sort.Strings(list) return list } // RawBytes is a byte slice that holds a reference to memory owned by // the database itself. After a Scan into a RawBytes, the slice is only // valid until the next call to Next, Scan, or Close. type RawBytes []byte // NullString represents a string that may be null. // NullString implements the Scanner interface so // it can be used as a scan destination: // // var s NullString // err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&s) // ... // if s.Valid { // // use s.String // } else { // // NULL value // } // type NullString struct { String string Valid bool // Valid is true if String is not NULL } // Scan implements the Scanner interface. func (ns *NullString) Scan(value interface{}) error { if value == nil { ns.String, ns.Valid = "", false return nil } ns.Valid = true return convertAssign(&ns.String, value) } // Value implements the driver Valuer interface. func (ns NullString) Value() (driver.Value, error) { if !ns.Valid { return nil, nil } return ns.String, nil } // NullInt64 represents an int64 that may be null. // NullInt64 implements the Scanner interface so // it can be used as a scan destination, similar to NullString. type NullInt64 struct { Int64 int64 Valid bool // Valid is true if Int64 is not NULL } // Scan implements the Scanner interface. func (n *NullInt64) Scan(value interface{}) error { if value == nil { n.Int64, n.Valid = 0, false return nil } n.Valid = true return convertAssign(&n.Int64, value) } // Value implements the driver Valuer interface. func (n NullInt64) Value() (driver.Value, error) { if !n.Valid { return nil, nil } return n.Int64, nil } // NullFloat64 represents a float64 that may be null. // NullFloat64 implements the Scanner interface so // it can be used as a scan destination, similar to NullString. type NullFloat64 struct { Float64 float64 Valid bool // Valid is true if Float64 is not NULL } // Scan implements the Scanner interface. func (n *NullFloat64) Scan(value interface{}) error { if value == nil { n.Float64, n.Valid = 0, false return nil } n.Valid = true return convertAssign(&n.Float64, value) } // Value implements the driver Valuer interface. func (n NullFloat64) Value() (driver.Value, error) { if !n.Valid { return nil, nil } return n.Float64, nil } // NullBool represents a bool that may be null. // NullBool implements the Scanner interface so // it can be used as a scan destination, similar to NullString. type NullBool struct { Bool bool Valid bool // Valid is true if Bool is not NULL } // Scan implements the Scanner interface. func (n *NullBool) Scan(value interface{}) error { if value == nil { n.Bool, n.Valid = false, false return nil } n.Valid = true return convertAssign(&n.Bool, value) } // Value implements the driver Valuer interface. func (n NullBool) Value() (driver.Value, error) { if !n.Valid { return nil, nil } return n.Bool, nil } // Scanner is an interface used by Scan. type Scanner interface { // Scan assigns a value from a database driver. // // The src value will be of one of the following restricted // set of types: // // int64 // float64 // bool // []byte // string // time.Time // nil - for NULL values // // An error should be returned if the value can not be stored // without loss of information. Scan(src interface{}) error } // ErrNoRows is returned by Scan when QueryRow doesn't return a // row. In such a case, QueryRow returns a placeholder *Row value that // defers this error until a Scan. var ErrNoRows = errors.New("sql: no rows in result set") // DB is a database handle representing a pool of zero or more // underlying connections. It's safe for concurrent use by multiple // goroutines. // // The sql package creates and frees connections automatically; it // also maintains a free pool of idle connections. If the database has // a concept of per-connection state, such state can only be reliably // observed within a transaction. Once DB.Begin is called, the // returned Tx is bound to a single connection. Once Commit or // Rollback is called on the transaction, that transaction's // connection is returned to DB's idle connection pool. The pool size // can be controlled with SetMaxIdleConns. type DB struct { driver driver.Driver dsn string // numClosed is an atomic counter which represents a total number of // closed connections. Stmt.openStmt checks it before cleaning closed // connections in Stmt.css. numClosed uint64 mu sync.Mutex // protects following fields freeConn []*driverConn connRequests []chan connRequest numOpen int // number of opened and pending open connections // Used to signal the need for new connections // a goroutine running connectionOpener() reads on this chan and // maybeOpenNewConnections sends on the chan (one send per needed connection) // It is closed during db.Close(). The close tells the connectionOpener // goroutine to exit. openerCh chan struct{} closed bool dep map[finalCloser]depSet lastPut map[*driverConn]string // stacktrace of last conn's put; debug only maxIdle int // zero means defaultMaxIdleConns; negative means 0 maxOpen int // <= 0 means unlimited maxLifetime time.Duration // maximum amount of time a connection may be reused cleanerCh chan struct{} } // connReuseStrategy determines how (*DB).conn returns database connections. type connReuseStrategy uint8 const ( // alwaysNewConn forces a new connection to the database. alwaysNewConn connReuseStrategy = iota // cachedOrNewConn returns a cached connection, if available, else waits // for one to become available (if MaxOpenConns has been reached) or // creates a new database connection. cachedOrNewConn ) // driverConn wraps a driver.Conn with a mutex, to // be held during all calls into the Conn. (including any calls onto // interfaces returned via that Conn, such as calls on Tx, Stmt, // Result, Rows) type driverConn struct { db *DB createdAt time.Time sync.Mutex // guards following ci driver.Conn closed bool finalClosed bool // ci.Close has been called openStmt map[driver.Stmt]bool // guarded by db.mu inUse bool onPut []func() // code (with db.mu held) run when conn is next returned dbmuClosed bool // same as closed, but guarded by db.mu, for removeClosedStmtLocked } func (dc *driverConn) releaseConn(err error) { dc.db.putConn(dc, err) } func (dc *driverConn) removeOpenStmt(si driver.Stmt) { dc.Lock() defer dc.Unlock() delete(dc.openStmt, si) } func (dc *driverConn) expired(timeout time.Duration) bool { if timeout <= 0 { return false } return dc.createdAt.Add(timeout).Before(nowFunc()) } func (dc *driverConn) prepareLocked(query string) (driver.Stmt, error) { si, err := dc.ci.Prepare(query) if err == nil { // Track each driverConn's open statements, so we can close them // before closing the conn. // // TODO(bradfitz): let drivers opt out of caring about // stmt closes if the conn is about to close anyway? For now // do the safe thing, in case stmts need to be closed. // // TODO(bradfitz): after Go 1.2, closing driver.Stmts // should be moved to driverStmt, using unique // *driverStmts everywhere (including from // *Stmt.connStmt, instead of returning a // driver.Stmt), using driverStmt as a pointer // everywhere, and making it a finalCloser. if dc.openStmt == nil { dc.openStmt = make(map[driver.Stmt]bool) } dc.openStmt[si] = true } return si, err } // the dc.db's Mutex is held. func (dc *driverConn) closeDBLocked() func() error { dc.Lock() defer dc.Unlock() if dc.closed { return func() error { return errors.New("sql: duplicate driverConn close") } } dc.closed = true return dc.db.removeDepLocked(dc, dc) } func (dc *driverConn) Close() error { dc.Lock() if dc.closed { dc.Unlock() return errors.New("sql: duplicate driverConn close") } dc.closed = true dc.Unlock() // not defer; removeDep finalClose calls may need to lock // And now updates that require holding dc.mu.Lock. dc.db.mu.Lock() dc.dbmuClosed = true fn := dc.db.removeDepLocked(dc, dc) dc.db.mu.Unlock() return fn() } func (dc *driverConn) finalClose() error { dc.Lock() for si := range dc.openStmt { si.Close() } dc.openStmt = nil err := dc.ci.Close() dc.ci = nil dc.finalClosed = true dc.Unlock() dc.db.mu.Lock() dc.db.numOpen-- dc.db.maybeOpenNewConnections() dc.db.mu.Unlock() atomic.AddUint64(&dc.db.numClosed, 1) return err } // driverStmt associates a driver.Stmt with the // *driverConn from which it came, so the driverConn's lock can be // held during calls. type driverStmt struct { sync.Locker // the *driverConn si driver.Stmt } func (ds *driverStmt) Close() error { ds.Lock() defer ds.Unlock() return ds.si.Close() } // depSet is a finalCloser's outstanding dependencies type depSet map[interface{}]bool // set of true bools // The finalCloser interface is used by (*DB).addDep and related // dependency reference counting. type finalCloser interface { // finalClose is called when the reference count of an object // goes to zero. (*DB).mu is not held while calling it. finalClose() error } // addDep notes that x now depends on dep, and x's finalClose won't be // called until all of x's dependencies are removed with removeDep. func (db *DB) addDep(x finalCloser, dep interface{}) { //println(fmt.Sprintf("addDep(%T %p, %T %p)", x, x, dep, dep)) db.mu.Lock() defer db.mu.Unlock() db.addDepLocked(x, dep) } func (db *DB) addDepLocked(x finalCloser, dep interface{}) { if db.dep == nil { db.dep = make(map[finalCloser]depSet) } xdep := db.dep[x] if xdep == nil { xdep = make(depSet) db.dep[x] = xdep } xdep[dep] = true } // removeDep notes that x no longer depends on dep. // If x still has dependencies, nil is returned. // If x no longer has any dependencies, its finalClose method will be // called and its error value will be returned. func (db *DB) removeDep(x finalCloser, dep interface{}) error { db.mu.Lock() fn := db.removeDepLocked(x, dep) db.mu.Unlock() return fn() } func (db *DB) removeDepLocked(x finalCloser, dep interface{}) func() error { //println(fmt.Sprintf("removeDep(%T %p, %T %p)", x, x, dep, dep)) xdep, ok := db.dep[x] if !ok { panic(fmt.Sprintf("unpaired removeDep: no deps for %T", x)) } l0 := len(xdep) delete(xdep, dep) switch len(xdep) { case l0: // Nothing removed. Shouldn't happen. panic(fmt.Sprintf("unpaired removeDep: no %T dep on %T", dep, x)) case 0: // No more dependencies. delete(db.dep, x) return x.finalClose default: // Dependencies remain. return func() error { return nil } } } // This is the size of the connectionOpener request chan (DB.openerCh). // This value should be larger than the maximum typical value // used for db.maxOpen. If maxOpen is significantly larger than // connectionRequestQueueSize then it is possible for ALL calls into the *DB // to block until the connectionOpener can satisfy the backlog of requests. var connectionRequestQueueSize = 1000000 // Open opens a database specified by its database driver name and a // driver-specific data source name, usually consisting of at least a // database name and connection information. // // Most users will open a database via a driver-specific connection // helper function that returns a *DB. No database drivers are included // in the Go standard library. See https://golang.org/s/sqldrivers for // a list of third-party drivers. // // Open may just validate its arguments without creating a connection // to the database. To verify that the data source name is valid, call // Ping. // // The returned DB is safe for concurrent use by multiple goroutines // and maintains its own pool of idle connections. Thus, the Open // function should be called just once. It is rarely necessary to // close a DB. func Open(driverName, dataSourceName string) (*DB, error) { driversMu.RLock() driveri, ok := drivers[driverName] driversMu.RUnlock() if !ok { return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName) } db := &DB{ driver: driveri, dsn: dataSourceName, openerCh: make(chan struct{}, connectionRequestQueueSize), lastPut: make(map[*driverConn]string), } go db.connectionOpener() return db, nil } // Ping verifies a connection to the database is still alive, // establishing a connection if necessary. func (db *DB) Ping() error {