// 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.//// Drivers that do not support context cancellation will not return until// after the query is completed.//// For usage examples, see the wiki page at// https://golang.org/s/sqlwiki.
package sqlimport ()var (driversMusync.RWMutexdrivers = make(map[string]driver.Driver))// nowFunc returns the current time; it's overridden in tests.varnowFunc = 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 ( string, driver.Driver) {driversMu.Lock()deferdriversMu.Unlock()if == nil {panic("sql: Register driver is nil") }if , := drivers[]; {panic("sql: Register called twice for driver " + ) }drivers[] = }func () {driversMu.Lock()deferdriversMu.Unlock()// For tests.drivers = make(map[string]driver.Driver)}// Drivers returns a sorted list of the names of the registered drivers.func () []string {driversMu.RLock()deferdriversMu.RUnlock() := make([]string, 0, len(drivers))for := rangedrivers { = append(, ) }sort.Strings()return}// A NamedArg is a named argument. NamedArg values may be used as// arguments to Query or Exec and bind to the corresponding named// parameter in the SQL statement.//// For a more concise way to create NamedArg values, see// the Named function.typeNamedArgstruct {_Named_Fields_Requiredstruct{}// Name is the name of the parameter placeholder. // // If empty, the ordinal position in the argument list will be // used. // // Name must omit any symbol prefix.Namestring// Value is the value of the parameter. // It may be assigned the same value types as the query // arguments.Valueany}// Named provides a more concise way to create NamedArg values.//// Example usage://// db.ExecContext(ctx, `// delete from Invoice// where// TimeCreated < @end// and TimeCreated >= @start;`,// sql.Named("start", startTime),// sql.Named("end", endTime),// )func ( string, any) NamedArg {// This method exists because the go1compat promise // doesn't guarantee that structs don't grow more fields, // so unkeyed struct literals are a vet error. Thus, we don't // want to allow sql.NamedArg{name, value}.returnNamedArg{Name: , Value: }}// IsolationLevel is the transaction isolation level used in TxOptions.typeIsolationLevelint// Various isolation levels that drivers may support in BeginTx.// If a driver does not support a given isolation level an error may be returned.//// See https://en.wikipedia.org/wiki/Isolation_(database_systems)#Isolation_levels.const (LevelDefaultIsolationLevel = iotaLevelReadUncommittedLevelReadCommittedLevelWriteCommittedLevelRepeatableReadLevelSnapshotLevelSerializableLevelLinearizable)// String returns the name of the transaction isolation level.func ( IsolationLevel) () string {switch {caseLevelDefault:return"Default"caseLevelReadUncommitted:return"Read Uncommitted"caseLevelReadCommitted:return"Read Committed"caseLevelWriteCommitted:return"Write Committed"caseLevelRepeatableRead:return"Repeatable Read"caseLevelSnapshot:return"Snapshot"caseLevelSerializable:return"Serializable"caseLevelLinearizable:return"Linearizable"default:return"IsolationLevel(" + strconv.Itoa(int()) + ")" }}var _ fmt.Stringer = LevelDefault// TxOptions holds the transaction options to be used in DB.BeginTx.typeTxOptionsstruct {// Isolation is the transaction isolation level. // If zero, the driver or database's default level is used.IsolationIsolationLevelReadOnlybool}// 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.typeRawBytes []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// }//typeNullStringstruct {StringstringValidbool// Valid is true if String is not NULL}// Scan implements the Scanner interface.func ( *NullString) ( any) error {if == nil { .String, .Valid = "", falsereturnnil } .Valid = truereturnconvertAssign(&.String, )}// Value implements the driver Valuer interface.func ( NullString) () (driver.Value, error) {if !.Valid {returnnil, nil }return .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.typeNullInt64struct {Int64int64Validbool// Valid is true if Int64 is not NULL}// Scan implements the Scanner interface.func ( *NullInt64) ( any) error {if == nil { .Int64, .Valid = 0, falsereturnnil } .Valid = truereturnconvertAssign(&.Int64, )}// Value implements the driver Valuer interface.func ( NullInt64) () (driver.Value, error) {if !.Valid {returnnil, nil }return .Int64, nil}// NullInt32 represents an int32 that may be null.// NullInt32 implements the Scanner interface so// it can be used as a scan destination, similar to NullString.typeNullInt32struct {Int32int32Validbool// Valid is true if Int32 is not NULL}// Scan implements the Scanner interface.func ( *NullInt32) ( any) error {if == nil { .Int32, .Valid = 0, falsereturnnil } .Valid = truereturnconvertAssign(&.Int32, )}// Value implements the driver Valuer interface.func ( NullInt32) () (driver.Value, error) {if !.Valid {returnnil, nil }returnint64(.Int32), nil}// NullInt16 represents an int16 that may be null.// NullInt16 implements the Scanner interface so// it can be used as a scan destination, similar to NullString.typeNullInt16struct {Int16int16Validbool// Valid is true if Int16 is not NULL}// Scan implements the Scanner interface.func ( *NullInt16) ( any) error {if == nil { .Int16, .Valid = 0, falsereturnnil } := convertAssign(&.Int16, ) .Valid = == nilreturn}// Value implements the driver Valuer interface.func ( NullInt16) () (driver.Value, error) {if !.Valid {returnnil, nil }returnint64(.Int16), nil}// NullByte represents a byte that may be null.// NullByte implements the Scanner interface so// it can be used as a scan destination, similar to NullString.typeNullBytestruct {BytebyteValidbool// Valid is true if Byte is not NULL}// Scan implements the Scanner interface.func ( *NullByte) ( any) error {if == nil { .Byte, .Valid = 0, falsereturnnil } := convertAssign(&.Byte, ) .Valid = == nilreturn}// Value implements the driver Valuer interface.func ( NullByte) () (driver.Value, error) {if !.Valid {returnnil, nil }returnint64(.Byte), 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.typeNullFloat64struct {Float64float64Validbool// Valid is true if Float64 is not NULL}// Scan implements the Scanner interface.func ( *NullFloat64) ( any) error {if == nil { .Float64, .Valid = 0, falsereturnnil } .Valid = truereturnconvertAssign(&.Float64, )}// Value implements the driver Valuer interface.func ( NullFloat64) () (driver.Value, error) {if !.Valid {returnnil, nil }return .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.typeNullBoolstruct {BoolboolValidbool// Valid is true if Bool is not NULL}// Scan implements the Scanner interface.func ( *NullBool) ( any) error {if == nil { .Bool, .Valid = false, falsereturnnil } .Valid = truereturnconvertAssign(&.Bool, )}// Value implements the driver Valuer interface.func ( NullBool) () (driver.Value, error) {if !.Valid {returnnil, nil }return .Bool, nil}// NullTime represents a time.Time that may be null.// NullTime implements the Scanner interface so// it can be used as a scan destination, similar to NullString.typeNullTimestruct {Timetime.TimeValidbool// Valid is true if Time is not NULL}// Scan implements the Scanner interface.func ( *NullTime) ( any) error {if == nil { .Time, .Valid = time.Time{}, falsereturnnil } .Valid = truereturnconvertAssign(&.Time, )}// Value implements the driver Valuer interface.func ( NullTime) () (driver.Value, error) {if !.Valid {returnnil, nil }return .Time, nil}// Scanner is an interface used by Scan.typeScannerinterface {// Scan assigns a value from a database driver. // // The src value will be of one of the following types: // // int64 // float64 // bool // []byte // string // time.Time // nil - for NULL values // // An error should be returned if the value cannot be stored // without loss of information. // // Reference types such as []byte are only valid until the next call to Scan // and should not be retained. Their underlying memory is owned by the driver. // If retention is necessary, copy their values before the next call to Scan.Scan(src any) error}// Out may be used to retrieve OUTPUT value parameters from stored procedures.//// Not all drivers and databases support OUTPUT value parameters.//// Example usage://// var outArg string// _, err := db.ExecContext(ctx, "ProcName", sql.Named("Arg1", sql.Out{Dest: &outArg}))typeOutstruct {_Named_Fields_Requiredstruct{}// Dest is a pointer to the value that will be set to the result of the // stored procedure's OUTPUT parameter.Destany// In is whether the parameter is an INOUT parameter. If so, the input value to the stored // procedure is the dereferenced value of Dest's pointer, which is then replaced with // the output value.Inbool}// 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.varErrNoRows = 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 be reliably observed// within a transaction (Tx) or connection (Conn). 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.typeDBstruct {// Atomic access only. At top of struct to prevent mis-alignment // on 32-bit platforms. Of type time.Duration.waitDurationint64// Total time waited for new connections.connectordriver.Connector// numClosed is an atomic counter which represents a total number of // closed connections. Stmt.openStmt checks it before cleaning closed // connections in Stmt.css.numCloseduint64musync.Mutex// protects following fieldsfreeConn []*driverConn// free connections ordered by returnedAt oldest to newestconnRequestsmap[uint64]chanconnRequestnextRequestuint64// Next key to use in connRequests.numOpenint// 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.openerChchanstruct{}closedbooldepmap[finalCloser]depSetlastPutmap[*driverConn]string// stacktrace of last conn's put; debug onlymaxIdleCountint// zero means defaultMaxIdleConns; negative means 0maxOpenint// <= 0 means unlimitedmaxLifetimetime.Duration// maximum amount of time a connection may be reusedmaxIdleTimetime.Duration// maximum amount of time a connection may be idle before being closedcleanerChchanstruct{}waitCountint64// Total number of connections waited for.maxIdleClosedint64// Total number of connections closed due to idle count.maxIdleTimeClosedint64// Total number of connections closed due to idle time.maxLifetimeClosedint64// Total number of connections closed due to max connection lifetime limit.stopfunc() // stop cancels the connection opener.}// connReuseStrategy determines how (*DB).conn returns database connections.typeconnReuseStrategyuint8const (// alwaysNewConn forces a new connection to the database.alwaysNewConnconnReuseStrategy = 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)typedriverConnstruct {db *DBcreatedAttime.Timesync.Mutex// guards followingcidriver.ConnneedResetbool// The connection session should be reset before use if true.closedboolfinalClosedbool// ci.Close has been calledopenStmtmap[*driverStmt]bool// guarded by db.muinUseboolreturnedAttime.Time// Time the connection was created or returned.onPut []func() // code (with db.mu held) run when conn is next returneddbmuClosedbool// same as closed, but guarded by db.mu, for removeClosedStmtLocked}func ( *driverConn) ( error) { .db.putConn(, , true)}func ( *driverConn) ( *driverStmt) { .Lock()defer .Unlock()delete(.openStmt, )}func ( *driverConn) ( time.Duration) bool {if <= 0 {returnfalse }return .createdAt.Add().Before(nowFunc())}// resetSession checks if the driver connection needs the// session to be reset and if required, resets it.func ( *driverConn) ( context.Context) error { .Lock()defer .Unlock()if !.needReset {returnnil }if , := .ci.(driver.SessionResetter); {return .ResetSession() }returnnil}// validateConnection checks if the connection is valid and can// still be used. It also marks the session for reset if required.func ( *driverConn) ( bool) bool { .Lock()defer .Unlock()if { .needReset = true }if , := .ci.(driver.Validator); {return .IsValid() }returntrue}// prepareLocked prepares the query on dc. When cg == nil the dc must keep track of// the prepared statements in a pool.func ( *driverConn) ( context.Context, stmtConnGrabber, string) (*driverStmt, error) { , := ctxDriverPrepare(, .ci, )if != nil {returnnil, } := &driverStmt{Locker: , si: }// No need to manage open statements if there is a single connection grabber.if != nil {return , nil }// Track each driverConn's open statements, so we can close them // before closing the conn. // // Wrap all driver.Stmt is *driverStmt to ensure they are only closed once.if .openStmt == nil { .openStmt = make(map[*driverStmt]bool) } .openStmt[] = truereturn , nil}// the dc.db's Mutex is held.func ( *driverConn) () func() error { .Lock()defer .Unlock()if .closed {returnfunc() error { returnerrors.New("sql: duplicate driverConn close") } } .closed = truereturn .db.removeDepLocked(, )}func ( *driverConn) () error { .Lock()if .closed { .Unlock()returnerrors.New("sql: duplicate driverConn close") } .closed = true .Unlock() // not defer; removeDep finalClose calls may need to lock// And now updates that require holding dc.mu.Lock. .db.mu.Lock() .dbmuClosed = true := .db.removeDepLocked(, ) .db.mu.Unlock()return ()}func ( *driverConn) () error {varerror// Each *driverStmt has a lock to the dc. Copy the list out of the dc // before calling close on each stmt.var []*driverStmtwithLock(, func() { = make([]*driverStmt, 0, len(.openStmt))for := range .openStmt { = append(, ) } .openStmt = nil })for , := range { .Close() }withLock(, func() { .finalClosed = true = .ci.Close() .ci = nil }) .db.mu.Lock() .db.numOpen-- .db.maybeOpenNewConnections() .db.mu.Unlock()atomic.AddUint64(&.db.numClosed, 1)return}// driverStmt associates a driver.Stmt with the// *driverConn from which it came, so the driverConn's lock can be// held during calls.typedriverStmtstruct {sync.Locker// the *driverConnsidriver.StmtclosedboolcloseErrerror// return value of previous Close call}// Close ensures driver.Stmt is only closed once and always returns the same// result.func ( *driverStmt) () error { .Lock()defer .Unlock()if .closed {return .closeErr } .closed = true .closeErr = .si.Close()return .closeErr}// depSet is a finalCloser's outstanding dependenciestypedepSetmap[any]bool// set of true bools// The finalCloser interface is used by (*DB).addDep and related// dependency reference counting.typefinalCloserinterface {// 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) ( finalCloser, any) { .mu.Lock()defer .mu.Unlock() .addDepLocked(, )}func ( *DB) ( finalCloser, any) {if .dep == nil { .dep = make(map[finalCloser]depSet) } := .dep[]if == nil { = make(depSet) .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) ( finalCloser, any) error { .mu.Lock() := .removeDepLocked(, ) .mu.Unlock()return ()}func ( *DB) ( finalCloser, any) func() error { , := .dep[]if ! {panic(fmt.Sprintf("unpaired removeDep: no deps for %T", )) } := len()delete(, )switchlen() {case :// Nothing removed. Shouldn't happen.panic(fmt.Sprintf("unpaired removeDep: no %T dep on %T", , ))case0:// No more dependencies.delete(.dep, )return .finalClosedefault:// Dependencies remain.returnfunc() error { returnnil } }}// 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.varconnectionRequestQueueSize = 1000000typedsnConnectorstruct {dsnstringdriverdriver.Driver}func ( dsnConnector) ( context.Context) (driver.Conn, error) {return .driver.Open(.dsn)}func ( dsnConnector) () driver.Driver {return .driver}// OpenDB opens a database using a Connector, allowing drivers to// bypass a string based data source name.//// 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.//// OpenDB 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 OpenDB// function should be called just once. It is rarely necessary to// close a DB.func ( driver.Connector) *DB { , := context.WithCancel(context.Background()) := &DB{connector: ,openerCh: make(chanstruct{}, connectionRequestQueueSize),lastPut: make(map[*driverConn]string),connRequests: make(map[uint64]chanconnRequest),stop: , }go .connectionOpener()return}// 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 (, string) (*DB, error) {driversMu.RLock() , := drivers[]driversMu.RUnlock()if ! {returnnil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", ) }if , := .(driver.DriverContext); { , := .OpenConnector()if != nil {returnnil, }returnOpenDB(), nil }returnOpenDB(dsnConnector{dsn: , driver: }), nil}func ( *DB) ( context.Context, *driverConn, func(error)) error {varerrorif , := .ci.(driver.Pinger); {withLock(, func() { = .Ping() }) } ()return}// PingContext verifies a connection to the database is still alive,// establishing a connection if necessary.func ( *DB) ( context.Context) error {var *driverConnvarerrorvarboolfor := 0; < maxBadConnRetries; ++ { , = .conn(, cachedOrNewConn) = errors.Is(, driver.ErrBadConn)if ! {break } }if { , = .conn(, alwaysNewConn) }if != nil {return }return .pingDC(, , .releaseConn)}// Ping verifies a connection to the database is still alive,// establishing a connection if necessary.//// Ping uses context.Background internally; to specify the context, use// PingContext.func ( *DB) () error {return .PingContext(context.Background())}// Close closes the database and prevents new queries from starting.// Close then waits for all queries that have started processing on the server// to finish.//// It is rare to Close a DB, as the DB handle is meant to be// long-lived and shared between many goroutines.func ( *DB) () error { .mu.Lock()if .closed { // Make DB.Close idempotent .mu.Unlock()returnnil }if .cleanerCh != nil {close(.cleanerCh) }varerror := make([]func() error, 0, len(.freeConn))for , := range .freeConn { = append(, .closeDBLocked()) } .freeConn = nil .closed = truefor , := range .connRequests {close() } .mu.Unlock()for , := range { := ()if != nil { = } } .stop()if , := .connector.(io.Closer); { := .Close()if != nil { = } }return}constdefaultMaxIdleConns = 2func ( *DB) () int { := .maxIdleCountswitch {case == 0:// TODO(bradfitz): ask driver, if supported, for its default preferencereturndefaultMaxIdleConnscase < 0:return0default:return }}func ( *DB) () time.Duration {if .maxIdleTime <= 0 {return .maxLifetime }if .maxLifetime <= 0 {return .maxIdleTime } := .maxIdleTimeif > .maxLifetime { = .maxLifetime }return}// SetMaxIdleConns sets the maximum number of connections in the idle// connection pool.//// If MaxOpenConns is greater than 0 but less than the new MaxIdleConns,// then the new MaxIdleConns will be reduced to match the MaxOpenConns limit.//// If n <= 0, no idle connections are retained.//// The default max idle connections is currently 2. This may change in// a future release.func ( *DB) ( int) { .mu.Lock()if > 0 { .maxIdleCount = } else {// No idle connections. .maxIdleCount = -1 }// Make sure maxIdle doesn't exceed maxOpenif .maxOpen > 0 && .maxIdleConnsLocked() > .maxOpen { .maxIdleCount = .maxOpen }var []*driverConn := len(.freeConn) := .maxIdleConnsLocked()if > { = .freeConn[:] .freeConn = .freeConn[:] } .maxIdleClosed += int64(len()) .mu.Unlock()for , := range { .Close() }}// SetMaxOpenConns sets the maximum number of open connections to the database.//// If MaxIdleConns is greater than 0 and the new MaxOpenConns is less than// MaxIdleConns, then MaxIdleConns will be reduced to match the new// MaxOpenConns limit.//// If n <= 0, then there is no limit on the number of open connections.// The default is 0 (unlimited).func ( *DB) ( int) { .mu.Lock() .maxOpen = if < 0 { .maxOpen = 0 } := .maxOpen > 0 && .maxIdleConnsLocked() > .maxOpen .mu.Unlock()if { .SetMaxIdleConns() }}// SetConnMaxLifetime sets the maximum amount of time a connection may be reused.//// Expired connections may be closed lazily before reuse.//// If d <= 0, connections are not closed due to a connection's age.func ( *DB) ( time.Duration) {if < 0 { = 0 } .mu.Lock()// Wake cleaner up when lifetime is shortened.if > 0 && < .maxLifetime && .cleanerCh != nil {select {case .cleanerCh<-struct{}{}:default: } } .maxLifetime = .startCleanerLocked() .mu.Unlock()}// SetConnMaxIdleTime sets the maximum amount of time a connection may be idle.//// Expired connections may be closed lazily before reuse.//// If d <= 0, connections are not closed due to a connection's idle time.func ( *DB) ( time.Duration) {if < 0 { = 0 } .mu.Lock()defer .mu.Unlock()// Wake cleaner up when idle time is shortened.if > 0 && < .maxIdleTime && .cleanerCh != nil {select {case .cleanerCh<-struct{}{}:default: } } .maxIdleTime = .startCleanerLocked()}// startCleanerLocked starts connectionCleaner if needed.func ( *DB) () {if (.maxLifetime > 0 || .maxIdleTime > 0) && .numOpen > 0 && .cleanerCh == nil { .cleanerCh = make(chanstruct{}, 1)go .connectionCleaner(.shortestIdleTimeLocked()) }}func ( *DB) ( time.Duration) {const = time.Secondif < { = } := time.NewTimer()for {select {case<-.C:case<-.cleanerCh: // maxLifetime was changed or db was closed. } .mu.Lock() = .shortestIdleTimeLocked()if .closed || .numOpen == 0 || <= 0 { .cleanerCh = nil .mu.Unlock()return } , := .connectionCleanerRunLocked() .mu.Unlock()for , := range { .Close() }if < { = }if !.Stop() {select {case<-.C:default: } } .Reset() }}// connectionCleanerRunLocked removes connections that should be closed from// freeConn and returns them along side an updated duration to the next check// if a quicker check is required to ensure connections are checked appropriately.func ( *DB) ( time.Duration) (time.Duration, []*driverConn) {varint64var []*driverConnif .maxIdleTime > 0 {// As freeConn is ordered by returnedAt process // in reverse order to minimise the work needed. := nowFunc().Add(-.maxIdleTime) := len(.freeConn) - 1for := ; >= 0; -- { := .freeConn[]if .returnedAt.Before() { ++ = .freeConn[::] .freeConn = .freeConn[:] = int64(len()) .maxIdleTimeClosed += break } }iflen(.freeConn) > 0 { := .freeConn[0]if := .returnedAt.Sub(); < {// Ensure idle connections are cleaned up as soon as // possible. = } } }if .maxLifetime > 0 { := nowFunc().Add(-.maxLifetime)for := 0; < len(.freeConn); ++ { := .freeConn[]if .createdAt.Before() { = append(, ) := len(.freeConn) - 1// Use slow delete as order is required to ensure // connections are reused least idle time first.copy(.freeConn[:], .freeConn[+1:]) .freeConn[] = nil .freeConn = .freeConn[:] -- } elseif := .createdAt.Sub(); < {// Prevent connections sitting the freeConn when they // have expired by updating our next deadline d. = } } .maxLifetimeClosed += int64(len()) - }return , }// DBStats contains database statistics.typeDBStatsstruct {MaxOpenConnectionsint// Maximum number of open connections to the database.// Pool StatusOpenConnectionsint// The number of established connections both in use and idle.InUseint// The number of connections currently in use.Idleint// The number of idle connections.// CountersWaitCountint64// The total number of connections waited for.WaitDurationtime.Duration// The total time blocked waiting for a new connection.MaxIdleClosedint64// The total number of connections closed due to SetMaxIdleConns.MaxIdleTimeClosedint64// The total number of connections closed due to SetConnMaxIdleTime.MaxLifetimeClosedint64// The total number of connections closed due to SetConnMaxLifetime.}// Stats returns database statistics.func ( *DB) () DBStats { := atomic.LoadInt64(&.waitDuration) .mu.Lock()defer .mu.Unlock() := DBStats{MaxOpenConnections: .maxOpen,Idle: len(.freeConn),OpenConnections: .numOpen,InUse: .numOpen - len(.freeConn),WaitCount: .waitCount,WaitDuration: time.Duration(),MaxIdleClosed: .maxIdleClosed,MaxIdleTimeClosed: .maxIdleTimeClosed,MaxLifetimeClosed: .maxLifetimeClosed, }return}// Assumes db.mu is locked.// If there are connRequests and the connection limit hasn't been reached,// then tell the connectionOpener to open new connections.func ( *DB) () { := len(.connRequests)if .maxOpen > 0 { := .maxOpen - .numOpenif > { = } }for > 0 { .numOpen++ // optimistically --if .closed {return } .openerCh <- struct{}{} }}// Runs in a separate goroutine, opens new connections when requested.func ( *DB) ( context.Context) {for {select {case<-.Done():returncase<-.openerCh: .openNewConnection() } }}// Open one new connectionfunc ( *DB) ( context.Context) {// maybeOpenNewConnections has already executed db.numOpen++ before it sent // on db.openerCh. This function must execute db.numOpen-- if the // connection fails or is closed before returning. , := .connector.Connect() .mu.Lock()defer .mu.Unlock()if .closed {if == nil { .Close() } .numOpen--return }if != nil { .numOpen-- .putConnDBLocked(nil, ) .maybeOpenNewConnections()return } := &driverConn{db: ,createdAt: nowFunc(),returnedAt: nowFunc(),ci: , }if .putConnDBLocked(, ) { .addDepLocked(, ) } else { .numOpen-- .Close() }}// connRequest represents one request for a new connection// When there are no idle connections available, DB.conn will create// a new connRequest and put it on the db.connRequests list.typeconnRequeststruct {conn *driverConnerrerror}varerrDBClosed = errors.New("sql: database is closed")// nextRequestKeyLocked returns the next connection request key.// It is assumed that nextRequest will not overflow.func ( *DB) () uint64 { := .nextRequest .nextRequest++return}// conn returns a newly-opened or cached *driverConn.func ( *DB) ( context.Context, connReuseStrategy) (*driverConn, error) { .mu.Lock()if .closed { .mu.Unlock()returnnil, errDBClosed }// Check if the context is expired.select {default:case<-.Done(): .mu.Unlock()returnnil, .Err() } := .maxLifetime// Prefer a free connection, if possible. := len(.freeConn) - 1if == cachedOrNewConn && >= 0 {// Reuse the lowest idle time connection so we can close // connections which remain idle as soon as possible. := .freeConn[] .freeConn = .freeConn[:] .inUse = trueif .expired() { .maxLifetimeClosed++ .mu.Unlock() .Close()returnnil, driver.ErrBadConn } .mu.Unlock()// Reset the session if required.if := .resetSession(); errors.Is(, driver.ErrBadConn) { .Close()returnnil, }return , nil }// Out of free connections or we were asked not to use one. If we're not // allowed to open any more connections, make a request and wait.if .maxOpen > 0 && .numOpen >= .maxOpen {// Make the connRequest channel. It's buffered so that the // connectionOpener doesn't block while waiting for the req to be read. := make(chanconnRequest, 1) := .nextRequestKeyLocked() .connRequests[] = .waitCount++ .mu.Unlock() := nowFunc()// Timeout the connection request with the context.select {case<-.Done():// Remove the connection request and ensure no value has been sent // on it after removing. .mu.Lock()delete(.connRequests, ) .mu.Unlock()atomic.AddInt64(&.waitDuration, int64(time.Since()))select {default:case , := <-:if && .conn != nil { .putConn(.conn, .err, false) } }returnnil, .Err()case , := <-:atomic.AddInt64(&.waitDuration, int64(time.Since()))if ! {returnnil, errDBClosed }// Only check if the connection is expired if the strategy is cachedOrNewConns. // If we require a new connection, just re-use the connection without looking // at the expiry time. If it is expired, it will be checked when it is placed // back into the connection pool. // This prioritizes giving a valid connection to a client over the exact connection // lifetime, which could expire exactly after this point anyway.if == cachedOrNewConn && .err == nil && .conn.expired() { .mu.Lock() .maxLifetimeClosed++ .mu.Unlock() .conn.Close()returnnil, driver.ErrBadConn }if .conn == nil {returnnil, .err }// Reset the session if required.if := .conn.resetSession(); errors.Is(, driver.ErrBadConn) { .conn.Close()returnnil, }return .conn, .err } } .numOpen++ // optimistically .mu.Unlock() , := .connector.Connect()if != nil { .mu.Lock() .numOpen-- // correct for earlier optimism .maybeOpenNewConnections() .mu.Unlock()returnnil, } .mu.Lock() := &driverConn{db: ,createdAt: nowFunc(),returnedAt: nowFunc(),ci: ,inUse: true, } .addDepLocked(, ) .mu.Unlock()return , nil}// putConnHook is a hook for testing.varputConnHookfunc(*DB, *driverConn)// noteUnusedDriverStatement notes that ds is no longer used and should// be closed whenever possible (when c is next not in use), unless c is// already closed.func ( *DB) ( *driverConn, *driverStmt) { .mu.Lock()defer .mu.Unlock()if .inUse { .onPut = append(.onPut, func() { .Close() }) } else { .Lock() := .finalClosed .Unlock()if ! { .Close() } }}// debugGetPut determines whether getConn & putConn calls' stack traces// are returned for more verbose crashes.constdebugGetPut = false// putConn adds a connection to the db's free pool.// err is optionally the last error that occurred on this connection.func ( *DB) ( *driverConn, error, bool) {if !errors.Is(, driver.ErrBadConn) {if !.validateConnection() { = driver.ErrBadConn } } .mu.Lock()if !.inUse { .mu.Unlock()ifdebugGetPut {fmt.Printf("putConn(%v) DUPLICATE was: %s\n\nPREVIOUS was: %s", , stack(), .lastPut[]) }panic("sql: connection returned that was never out") }if !errors.Is(, driver.ErrBadConn) && .expired(.maxLifetime) { .maxLifetimeClosed++ = driver.ErrBadConn }ifdebugGetPut { .lastPut[] = stack() } .inUse = false .returnedAt = nowFunc()for , := range .onPut { () } .onPut = niliferrors.Is(, driver.ErrBadConn) {// Don't reuse bad connections. // Since the conn is considered bad and is being discarded, treat it // as closed. Don't decrement the open count here, finalClose will // take care of that. .maybeOpenNewConnections() .mu.Unlock() .Close()return }ifputConnHook != nil {putConnHook(, ) } := .putConnDBLocked(, nil) .mu.Unlock()if ! { .Close()return }}// Satisfy a connRequest or put the driverConn in the idle pool and return true// or return false.// putConnDBLocked will satisfy a connRequest if there is one, or it will// return the *driverConn to the freeConn list if err == nil and the idle// connection limit will not be exceeded.// If err != nil, the value of dc is ignored.// If err == nil, then dc must not equal nil.// If a connRequest was fulfilled or the *driverConn was placed in the// freeConn list, then true is returned, otherwise false is returned.func ( *DB) ( *driverConn, error) bool {if .closed {returnfalse }if .maxOpen > 0 && .numOpen > .maxOpen {returnfalse }if := len(.connRequests); > 0 {varchanconnRequestvaruint64for , = range .connRequests {break }delete(.connRequests, ) // Remove from pending requests.if == nil { .inUse = true } <- connRequest{conn: ,err: , }returntrue } elseif == nil && !.closed {if .maxIdleConnsLocked() > len(.freeConn) { .freeConn = append(.freeConn, ) .startCleanerLocked()returntrue } .maxIdleClosed++ }returnfalse}// maxBadConnRetries is the number of maximum retries if the driver returns// driver.ErrBadConn to signal a broken connection before forcing a new// connection to be opened.constmaxBadConnRetries = 2// PrepareContext creates a prepared statement for later queries or executions.// Multiple queries or executions may be run concurrently from the// returned statement.// The caller must call the statement's Close method// when the statement is no longer needed.//// The provided context is used for the preparation of the statement, not for the// execution of the statement.func ( *DB) ( context.Context, string) (*Stmt, error) {var *Stmtvarerrorvarboolfor := 0; < maxBadConnRetries; ++ { , = .prepare(, , cachedOrNewConn) = errors.Is(, driver.ErrBadConn)if ! {break } }if {return .prepare(, , alwaysNewConn) }return , }// Prepare creates a prepared statement for later queries or executions.// Multiple queries or executions may be run concurrently from the// returned statement.// The caller must call the statement's Close method// when the statement is no longer needed.//// Prepare uses context.Background internally; to specify the context, use// PrepareContext.func ( *DB) ( string) (*Stmt, error) {return .PrepareContext(context.Background(), )}func ( *DB) ( context.Context, string, connReuseStrategy) (*Stmt, error) {// TODO: check if db.driver supports an optional // driver.Preparer interface and call that instead, if so, // otherwise we make a prepared statement that's bound // to a connection, and to execute this prepared statement // we either need to use this connection (if it's free), else // get a new connection + re-prepare + execute on that one. , := .conn(, )if != nil {returnnil, }return .prepareDC(, , .releaseConn, nil, )}// prepareDC prepares a query on the driverConn and calls release before// returning. When cg == nil it implies that a connection pool is used, and// when cg != nil only a single driver connection is used.func ( *DB) ( context.Context, *driverConn, func(error), stmtConnGrabber, string) (*Stmt, error) {var *driverStmtvarerrordeferfunc() { () }()withLock(, func() { , = .prepareLocked(, , ) })if != nil {returnnil, } := &Stmt{db: ,query: ,cg: ,cgds: , }// When cg == nil this statement will need to keep track of various // connections they are prepared on and record the stmt dependency on // the DB.if == nil { .css = []connStmt{{, }} .lastNumClosed = atomic.LoadUint64(&.numClosed) .addDep(, ) }return , nil}// ExecContext executes a query without returning any rows.// The args are for any placeholder parameters in the query.func ( *DB) ( context.Context, string, ...any) (Result, error) {varResultvarerrorvarboolfor := 0; < maxBadConnRetries; ++ { , = .exec(, , , cachedOrNewConn) = errors.Is(, driver.ErrBadConn)if ! {break } }if {return .exec(, , , alwaysNewConn) }return , }// Exec executes a query without returning any rows.// The args are for any placeholder parameters in the query.//// Exec uses context.Background internally; to specify the context, use// ExecContext.func ( *DB) ( string, ...any) (Result, error) {return .ExecContext(context.Background(), , ...)}func ( *DB) ( context.Context, string, []any, connReuseStrategy) (Result, error) { , := .conn(, )if != nil {returnnil, }return .execDC(, , .releaseConn, , )}func ( *DB) ( context.Context, *driverConn, func(error), string, []any) ( Result, error) {deferfunc() { () }() , := .ci.(driver.ExecerContext)vardriver.Execerif ! { , = .ci.(driver.Execer) }if {var []driver.NamedValuevardriver.ResultwithLock(, func() { , = driverArgsConnLocked(.ci, nil, )if != nil {return } , = ctxDriverExec(, , , , ) })if != driver.ErrSkip {if != nil {returnnil, }returndriverResult{, }, nil } }vardriver.StmtwithLock(, func() { , = ctxDriverPrepare(, .ci, ) })if != nil {returnnil, } := &driverStmt{Locker: , si: }defer .Close()returnresultFromStatement(, .ci, , ...)}// QueryContext executes a query that returns rows, typically a SELECT.// The args are for any placeholder parameters in the query.func ( *DB) ( context.Context, string, ...any) (*Rows, error) {var *Rowsvarerrorvarboolfor := 0; < maxBadConnRetries; ++ { , = .query(, , , cachedOrNewConn) = errors.Is(, driver.ErrBadConn)if ! {break } }if {return .query(, , , alwaysNewConn) }return , }// Query executes a query that returns rows, typically a SELECT.// The args are for any placeholder parameters in the query.//// Query uses context.Background internally; to specify the context, use// QueryContext.func ( *DB) ( string, ...any) (*Rows, error) {return .QueryContext(context.Background(), , ...)}func ( *DB) ( context.Context, string, []any, connReuseStrategy) (*Rows, error) { , := .conn(, )if != nil {returnnil, }return .queryDC(, nil, , .releaseConn, , )}// queryDC executes a query on the given connection.// The connection gets released by the releaseConn function.// The ctx context is from a query method and the txctx context is from an// optional transaction context.func ( *DB) (, context.Context, *driverConn, func(error), string, []any) (*Rows, error) { , := .ci.(driver.QueryerContext)vardriver.Queryerif ! { , = .ci.(driver.Queryer) }if {var []driver.NamedValuevardriver.RowsvarerrorwithLock(, func() { , = driverArgsConnLocked(.ci, nil, )if != nil {return } , = ctxDriverQuery(, , , , ) })if != driver.ErrSkip {if != nil { ()returnnil, }// Note: ownership of dc passes to the *Rows, to be freed // with releaseConn. := &Rows{dc: ,releaseConn: ,rowsi: , } .initContextClose(, )return , nil } }vardriver.StmtvarerrorwithLock(, func() { , = ctxDriverPrepare(, .ci, ) })if != nil { ()returnnil, } := &driverStmt{Locker: , si: } , := rowsiFromStatement(, .ci, , ...)if != nil { .Close() ()returnnil, }// Note: ownership of ci passes to the *Rows, to be freed // with releaseConn. := &Rows{dc: ,releaseConn: ,rowsi: ,closeStmt: , } .initContextClose(, )return , nil}// QueryRowContext executes a query that is expected to return at most one row.// QueryRowContext always returns a non-nil value. Errors are deferred until// Row's Scan method is called.// If the query selects no rows, the *Row's Scan will return ErrNoRows.// Otherwise, the *Row's Scan scans the first selected row and discards// the rest.func ( *DB) ( context.Context, string, ...any) *Row { , := .QueryContext(, , ...)return &Row{rows: , err: }}// QueryRow executes a query that is expected to return at most one row.// QueryRow always returns a non-nil value. Errors are deferred until// Row's Scan method is called.// If the query selects no rows, the *Row's Scan will return ErrNoRows.// Otherwise, the *Row's Scan scans the first selected row and discards// the rest.//// QueryRow uses context.Background internally; to specify the context, use// QueryRowContext.func ( *DB) ( string, ...any) *Row {return .QueryRowContext(context.Background(), , ...)}// BeginTx starts a transaction.//// The provided context is used until the transaction is committed or rolled back.// If the context is canceled, the sql package will roll back// the transaction. Tx.Commit will return an error if the context provided to// BeginTx is canceled.//// The provided TxOptions is optional and may be nil if defaults should be used.// If a non-default isolation level is used that the driver doesn't support,// an error will be returned.func ( *DB) ( context.Context, *TxOptions) (*Tx, error) {var *Txvarerrorvarboolfor := 0; < maxBadConnRetries; ++ { , = .begin(, , cachedOrNewConn) = errors.Is(, driver.ErrBadConn)if ! {break } }if {return .begin(, , alwaysNewConn) }return , }// Begin starts a transaction. The default isolation level is dependent on// the driver.//// Begin uses context.Background internally; to specify the context, use// BeginTx.func ( *DB) () (*Tx, error) {return .BeginTx(context.Background(), nil)}func ( *DB) ( context.Context, *TxOptions, connReuseStrategy) ( *Tx, error) { , := .conn(, )if != nil {returnnil, }return .beginDC(, , .releaseConn, )}// beginDC starts a transaction. The provided dc must be valid and ready to use.func ( *DB) ( context.Context, *driverConn, func(error), *TxOptions) ( *Tx, error) {vardriver.Tx := falsewithLock(, func() { , := .ci.(driver.SessionResetter) , := .ci.(driver.Validator) = && , = ctxDriverBegin(, , .ci) })if != nil { ()returnnil, }// Schedule the transaction to rollback when the context is canceled. // The cancel function in Tx will be called after done is set to true. , := context.WithCancel() = &Tx{db: ,dc: ,releaseConn: ,txi: ,cancel: ,keepConnOnRollback: ,ctx: , }go .awaitDone()return , nil}// Driver returns the database's underlying driver.func ( *DB) () driver.Driver {return .connector.Driver()}// ErrConnDone is returned by any operation that is performed on a connection// that has already been returned to the connection pool.varErrConnDone = errors.New("sql: connection is already closed")// Conn returns a single connection by either opening a new connection// or returning an existing connection from the connection pool. Conn will// block until either a connection is returned or ctx is canceled.// Queries run on the same Conn will be run in the same database session.//// Every Conn must be returned to the database pool after use by// calling Conn.Close.func ( *DB) ( context.Context) (*Conn, error) {var *driverConnvarerrorvarboolfor := 0; < maxBadConnRetries; ++ { , = .conn(, cachedOrNewConn) = errors.Is(, driver.ErrBadConn)if ! {break } }if { , = .conn(, alwaysNewConn) }if != nil {returnnil, } := &Conn{db: ,dc: , }return , nil}typereleaseConnfunc(error)// Conn represents a single database connection rather than a pool of database// connections. Prefer running queries from DB unless there is a specific// need for a continuous single database connection.//// A Conn must call Close to return the connection to the database pool// and may do so concurrently with a running query.//// After a call to Close, all operations on the// connection fail with ErrConnDone.typeConnstruct {db *DB// closemu prevents the connection from closing while there // is an active query. It is held for read during queries // and exclusively during close.closemusync.RWMutex// dc is owned until close, at which point // it's returned to the connection pool.dc *driverConn// done transitions from 0 to 1 exactly once, on close. // Once done, all operations fail with ErrConnDone. // Use atomic operations on value when checking value.doneint32}// grabConn takes a context to implement stmtConnGrabber// but the context is not used.func ( *Conn) (context.Context) (*driverConn, releaseConn, error) {ifatomic.LoadInt32(&.done) != 0 {returnnil, nil, ErrConnDone } .closemu.RLock()return .dc, .closemuRUnlockCondReleaseConn, nil}// PingContext verifies the connection to the database is still alive.func ( *Conn) ( context.Context) error { , , := .grabConn()if != nil {return }return .db.pingDC(, , )}// ExecContext executes a query without returning any rows.// The args are for any placeholder parameters in the query.func ( *Conn) ( context.Context, string, ...any) (Result, error) { , , := .grabConn()if != nil {returnnil, }return .db.execDC(, , , , )}// QueryContext executes a query that returns rows, typically a SELECT.// The args are for any placeholder parameters in the query.func ( *Conn) ( context.Context, string, ...any) (*Rows, error) { , , := .grabConn()if != nil {returnnil, }return .db.queryDC(, nil, , , , )}// QueryRowContext executes a query that is expected to return at most one row.// QueryRowContext always returns a non-nil value. Errors are deferred until// Row's Scan method is called.// If the query selects no rows, the *Row's Scan will return ErrNoRows.// Otherwise, the *Row's Scan scans the first selected row and discards// the rest.func ( *Conn) ( context.Context, string, ...any) *Row { , := .QueryContext(, , ...)return &Row{rows: , err: }}// PrepareContext creates a prepared statement for later queries or executions.// Multiple queries or executions may be run concurrently from the// returned statement.// The caller must call the statement's Close method// when the statement is no longer needed.//// The provided context is used for the preparation of the statement, not for the// execution of the statement.func ( *Conn) ( context.Context, string) (*Stmt, error) { , , := .grabConn()if != nil {returnnil, }return .db.prepareDC(, , , , )}// Raw executes f exposing the underlying driver connection for the// duration of f. The driverConn must not be used outside of f.//// Once f returns and err is not driver.ErrBadConn, the Conn will continue to be usable// until Conn.Close is called.func ( *Conn) ( func( any) error) ( error) {var *driverConnvarreleaseConn// grabConn takes a context to implement stmtConnGrabber, but the context is not used. , , = .grabConn(nil)if != nil {return } := true .Mutex.Lock()deferfunc() { .Mutex.Unlock()// If f panics fPanic will remain true. // Ensure an error is passed to release so the connection // may be discarded.if { = driver.ErrBadConn } () }() = (.ci) = falsereturn}// BeginTx starts a transaction.//// The provided context is used until the transaction is committed or rolled back.// If the context is canceled, the sql package will roll back// the transaction. Tx.Commit will return an error if the context provided to// BeginTx is canceled.//// The provided TxOptions is optional and may be nil if defaults should be used.// If a non-default isolation level is used that the driver doesn't support,// an error will be returned.func ( *Conn) ( context.Context, *TxOptions) (*Tx, error) { , , := .grabConn()if != nil {returnnil, }return .db.beginDC(, , , )}// closemuRUnlockCondReleaseConn read unlocks closemu// as the sql operation is done with the dc.func ( *Conn) ( error) { .closemu.RUnlock()iferrors.Is(, driver.ErrBadConn) { .close() }}func ( *Conn) () context.Context {returnnil}func ( *Conn) ( error) error {if !atomic.CompareAndSwapInt32(&.done, 0, 1) {returnErrConnDone }// Lock around releasing the driver connection // to ensure all queries have been stopped before doing so. .closemu.Lock()defer .closemu.Unlock() .dc.releaseConn() .dc = nil .db = nilreturn}// Close returns the connection to the connection pool.// All operations after a Close will return with ErrConnDone.// Close is safe to call concurrently with other operations and will// block until all other operations finish. It may be useful to first// cancel any used context and then call close directly after.func ( *Conn) () error {return .close(nil)}// Tx is an in-progress database transaction.//// A transaction must end with a call to Commit or Rollback.//// After a call to Commit or Rollback, all operations on the// transaction fail with ErrTxDone.//// The statements prepared for a transaction by calling// the transaction's Prepare or Stmt methods are closed// by the call to Commit or Rollback.typeTxstruct {db *DB// closemu prevents the transaction from closing while there // is an active query. It is held for read during queries // and exclusively during close.closemusync.RWMutex// dc is owned exclusively until Commit or Rollback, at which point // it's returned with putConn.dc *driverConntxidriver.Tx// releaseConn is called once the Tx is closed to release // any held driverConn back to the pool.releaseConnfunc(error)// done transitions from 0 to 1 exactly once, on Commit // or Rollback. once done, all operations fail with // ErrTxDone. // Use atomic operations on value when checking value.doneint32// keepConnOnRollback is true if the driver knows // how to reset the connection's session and if need be discard // the connection.keepConnOnRollbackbool// All Stmts prepared for this transaction. These will be closed after the // transaction has been committed or rolled back.stmtsstruct {sync.Mutex v []*Stmt }// cancel is called after done transitions from 0 to 1.cancelfunc()// ctx lives for the life of the transaction.ctxcontext.Context}// awaitDone blocks until the context in Tx is canceled and rolls back// the transaction if it's not already done.func ( *Tx) () {// Wait for either the transaction to be committed or rolled // back, or for the associated context to be closed. <-.ctx.Done()// Discard and close the connection used to ensure the // transaction is closed and the resources are released. This // rollback does nothing if the transaction has already been // committed or rolled back. // Do not discard the connection if the connection knows // how to reset the session. := !.keepConnOnRollback .rollback()}func ( *Tx) () bool {returnatomic.LoadInt32(&.done) != 0}// ErrTxDone is returned by any operation that is performed on a transaction// that has already been committed or rolled back.varErrTxDone = errors.New("sql: transaction has already been committed or rolled back")// close returns the connection to the pool and// must only be called by Tx.rollback or Tx.Commit while// tx is already canceled and won't be executed concurrently.func ( *Tx) ( error) { .releaseConn() .dc = nil .txi = nil}// hookTxGrabConn specifies an optional hook to be called on// a successful call to (*Tx).grabConn. For tests.varhookTxGrabConnfunc()func ( *Tx) ( context.Context) (*driverConn, releaseConn, error) {select {default:case<-.Done():returnnil, nil, .Err() }// closemu.RLock must come before the check for isDone to prevent the Tx from // closing while a query is executing. .closemu.RLock()if .isDone() { .closemu.RUnlock()returnnil, nil, ErrTxDone }ifhookTxGrabConn != nil { // test hookhookTxGrabConn() }return .dc, .closemuRUnlockRelease, nil}func ( *Tx) () context.Context {return .ctx}// closemuRUnlockRelease is used as a func(error) method value in// ExecContext and QueryContext. Unlocking in the releaseConn keeps// the driver conn from being returned to the connection pool until// the Rows has been closed.func ( *Tx) (error) { .closemu.RUnlock()}// Closes all Stmts prepared for this transaction.func ( *Tx) () { .stmts.Lock()defer .stmts.Unlock()for , := range .stmts.v { .Close() }}// Commit commits the transaction.func ( *Tx) () error {// Check context first to avoid transaction leak. // If put it behind tx.done CompareAndSwap statement, we can't ensure // the consistency between tx.done and the real COMMIT operation.select {default:case<-.ctx.Done():ifatomic.LoadInt32(&.done) == 1 {returnErrTxDone }return .ctx.Err() }if !atomic.CompareAndSwapInt32(&.done, 0, 1) {returnErrTxDone }// Cancel the Tx to release any active R-closemu locks. // This is safe to do because tx.done has already transitioned // from 0 to 1. Hold the W-closemu lock prior to rollback // to ensure no other connection has an active query. .cancel() .closemu.Lock() .closemu.Unlock()varerrorwithLock(.dc, func() { = .txi.Commit() })if !errors.Is(, driver.ErrBadConn) { .closePrepared() } .close()return}varrollbackHookfunc()// rollback aborts the transaction and optionally forces the pool to discard// the connection.func ( *Tx) ( bool) error {if !atomic.CompareAndSwapInt32(&.done, 0, 1) {returnErrTxDone }ifrollbackHook != nil {rollbackHook() }// Cancel the Tx to release any active R-closemu locks. // This is safe to do because tx.done has already transitioned // from 0 to 1. Hold the W-closemu lock prior to rollback // to ensure no other connection has an active query. .cancel() .closemu.Lock() .closemu.Unlock()varerrorwithLock(.dc, func() { = .txi.Rollback() })if !errors.Is(, driver.ErrBadConn) { .closePrepared() }if { = driver.ErrBadConn } .close()return}// Rollback aborts the transaction.func ( *Tx) () error {return .rollback(false)}// PrepareContext creates a prepared statement for use within a transaction.//// The returned statement operates within the transaction and will be closed// when the transaction has been committed or rolled back.//// To use an existing prepared statement on this transaction, see Tx.Stmt.//// The provided context will be used for the preparation of the context, not// for the execution of the returned statement. The returned statement// will run in the transaction context.func ( *Tx) ( context.Context, string) (*Stmt, error) { , , := .grabConn()if != nil {returnnil, } , := .db.prepareDC(, , , , )if != nil {returnnil, } .stmts.Lock() .stmts.v = append(.stmts.v, ) .stmts.Unlock()return , nil}// Prepare creates a prepared statement for use within a transaction.//// The returned statement operates within the transaction and will be closed// when the transaction has been committed or rolled back.//// To use an existing prepared statement on this transaction, see Tx.Stmt.//// Prepare uses context.Background internally; to specify the context, use// PrepareContext.func ( *Tx) ( string) (*Stmt, error) {return .PrepareContext(context.Background(), )}// StmtContext returns a transaction-specific prepared statement from// an existing statement.//// Example:// updateMoney, err := db.Prepare("UPDATE balance SET money=money+? WHERE id=?")// ...// tx, err := db.Begin()// ...// res, err := tx.StmtContext(ctx, updateMoney).Exec(123.45, 98293203)//// The provided context is used for the preparation of the statement, not for the// execution of the statement.//// The returned statement operates within the transaction and will be closed// when the transaction has been committed or rolled back.func ( *Tx) ( context.Context, *Stmt) *Stmt { , , := .grabConn()if != nil {return &Stmt{stickyErr: } }defer (nil)if .db != .db {return &Stmt{stickyErr: errors.New("sql: Tx.Stmt: statement from different database used")} }vardriver.Stmtvar *Stmt .mu.Lock()if .closed || .cg != nil {// If the statement has been closed or already belongs to a // transaction, we can't reuse it in this connection. // Since tx.StmtContext should never need to be called with a // Stmt already belonging to tx, we ignore this edge case and // re-prepare the statement in this case. No need to add // code-complexity for this. .mu.Unlock()withLock(, func() { , = ctxDriverPrepare(, .ci, .query) })if != nil {return &Stmt{stickyErr: } } } else { .removeClosedStmtLocked()// See if the statement has already been prepared on this connection, // and reuse it if possible.for , := range .css {if .dc == { = .ds.sibreak } } .mu.Unlock()if == nil {var *driverStmtwithLock(, func() { , = .prepareOnConnLocked(, ) })if != nil {return &Stmt{stickyErr: } } = .si } = } := &Stmt{db: .db,cg: ,cgds: &driverStmt{Locker: ,si: , },parentStmt: ,query: .query, }if != nil { .db.addDep(, ) } .stmts.Lock() .stmts.v = append(.stmts.v, ) .stmts.Unlock()return}// Stmt returns a transaction-specific prepared statement from// an existing statement.//// Example:// updateMoney, err := db.Prepare("UPDATE balance SET money=money+? WHERE id=?")// ...// tx, err := db.Begin()// ...// res, err := tx.Stmt(updateMoney).Exec(123.45, 98293203)//// The returned statement operates within the transaction and will be closed// when the transaction has been committed or rolled back.//// Stmt uses context.Background internally; to specify the context, use// StmtContext.func ( *Tx) ( *Stmt) *Stmt {return .StmtContext(context.Background(), )}// ExecContext executes a query that doesn't return rows.// For example: an INSERT and UPDATE.func ( *Tx) ( context.Context, string, ...any) (Result, error) { , , := .grabConn()if != nil {returnnil, }return .db.execDC(, , , , )}// Exec executes a query that doesn't return rows.// For example: an INSERT and UPDATE.//// Exec uses context.Background internally; to specify the context, use// ExecContext.func ( *Tx) ( string, ...any) (Result, error) {return .ExecContext(context.Background(), , ...)}// QueryContext executes a query that returns rows, typically a SELECT.func ( *Tx) ( context.Context, string, ...any) (*Rows, error) { , , := .grabConn()if != nil {returnnil, }return .db.queryDC(, .ctx, , , , )}// Query executes a query that returns rows, typically a SELECT.//// Query uses context.Background internally; to specify the context, use// QueryContext.func ( *Tx) ( string, ...any) (*Rows, error) {return .QueryContext(context.Background(), , ...)}// QueryRowContext executes a query that is expected to return at most one row.// QueryRowContext always returns a non-nil value. Errors are deferred until// Row's Scan method is called.// If the query selects no rows, the *Row's Scan will return ErrNoRows.// Otherwise, the *Row's Scan scans the first selected row and discards// the rest.func ( *Tx) ( context.Context, string, ...any) *Row { , := .QueryContext(, , ...)return &Row{rows: , err: }}// QueryRow executes a query that is expected to return at most one row.// QueryRow always returns a non-nil value. Errors are deferred until// Row's Scan method is called.// If the query selects no rows, the *Row's Scan will return ErrNoRows.// Otherwise, the *Row's Scan scans the first selected row and discards// the rest.//// QueryRow uses context.Background internally; to specify the context, use// QueryRowContext.func ( *Tx) ( string, ...any) *Row {return .QueryRowContext(context.Background(), , ...)}// connStmt is a prepared statement on a particular connection.typeconnStmtstruct {dc *driverConnds *driverStmt}// stmtConnGrabber represents a Tx or Conn that will return the underlying// driverConn and release function.typestmtConnGrabberinterface {// grabConn returns the driverConn and the associated release function // that must be called when the operation completes.grabConn(context.Context) (*driverConn, releaseConn, error)// txCtx returns the transaction context if available. // The returned context should be selected on along with // any query context when awaiting a cancel.txCtx() context.Context}var ( _ stmtConnGrabber = &Tx{} _ stmtConnGrabber = &Conn{})// Stmt is a prepared statement.// A Stmt is safe for concurrent use by multiple goroutines.//// If a Stmt is prepared on a Tx or Conn, it will be bound to a single// underlying connection forever. If the Tx or Conn closes, the Stmt will// become unusable and all operations will return an error.// If a Stmt is prepared on a DB, it will remain usable for the lifetime of the// DB. When the Stmt needs to execute on a new underlying connection, it will// prepare itself on the new connection automatically.typeStmtstruct {// Immutable:db *DB// where we came fromquerystring// that created the StmtstickyErrerror// if non-nil, this error is returned for all operationsclosemusync.RWMutex// held exclusively during close, for read otherwise.// If Stmt is prepared on a Tx or Conn then cg is present and will // only ever grab a connection from cg. // If cg is nil then the Stmt must grab an arbitrary connection // from db and determine if it must prepare the stmt again by // inspecting css.cgstmtConnGrabbercgds *driverStmt// parentStmt is set when a transaction-specific statement // is requested from an identical statement prepared on the same // conn. parentStmt is used to track the dependency of this statement // on its originating ("parent") statement so that parentStmt may // be closed by the user without them having to know whether or not // any transactions are still using it.parentStmt *Stmtmusync.Mutex// protects the rest of the fieldsclosedbool// css is a list of underlying driver statement interfaces // that are valid on particular connections. This is only // used if cg == nil and one is found that has idle // connections. If cg != nil, cgds is always used.css []connStmt// lastNumClosed is copied from db.numClosed when Stmt is created // without tx and closed connections in css are removed.lastNumCloseduint64}// ExecContext executes a prepared statement with the given arguments and// returns a Result summarizing the effect of the statement.func ( *Stmt) ( context.Context, ...any) (Result, error) { .closemu.RLock()defer .closemu.RUnlock()varResult := cachedOrNewConnfor := 0; < maxBadConnRetries+1; ++ {if == maxBadConnRetries { = alwaysNewConn } , , , := .connStmt(, )if != nil {iferrors.Is(, driver.ErrBadConn) {continue }returnnil, } , = resultFromStatement(, .ci, , ...) ()if !errors.Is(, driver.ErrBadConn) {return , } }returnnil, driver.ErrBadConn}// Exec executes a prepared statement with the given arguments and// returns a Result summarizing the effect of the statement.//// Exec uses context.Background internally; to specify the context, use// ExecContext.func ( *Stmt) ( ...any) (Result, error) {return .ExecContext(context.Background(), ...)}func ( context.Context, driver.Conn, *driverStmt, ...any) (Result, error) { .Lock()defer .Unlock() , := driverArgsConnLocked(, , )if != nil {returnnil, } , := ctxDriverStmtExec(, .si, )if != nil {returnnil, }returndriverResult{.Locker, }, nil}// removeClosedStmtLocked removes closed conns in s.css.//// To avoid lock contention on DB.mu, we do it only when// s.db.numClosed - s.lastNum is large enough.func ( *Stmt) () { := len(.css)/2 + 1if > 10 { = 10 } := atomic.LoadUint64(&.db.numClosed)if -.lastNumClosed < uint64() {return } .db.mu.Lock()for := 0; < len(.css); ++ {if .css[].dc.dbmuClosed { .css[] = .css[len(.css)-1] .css = .css[:len(.css)-1] -- } } .db.mu.Unlock() .lastNumClosed = }// connStmt returns a free driver connection on which to execute the// statement, a function to call to release the connection, and a// statement bound to that connection.func ( *Stmt) ( context.Context, connReuseStrategy) ( *driverConn, func(error), *driverStmt, error) {if = .stickyErr; != nil {return } .mu.Lock()if .closed { .mu.Unlock() = errors.New("sql: statement is closed")return }// In a transaction or connection, we always use the connection that the // stmt was created on.if .cg != nil { .mu.Unlock() , , = .cg.grabConn() // blocks, waiting for the connection.if != nil {return }return , , .cgds, nil } .removeClosedStmtLocked() .mu.Unlock() , = .db.conn(, )if != nil {returnnil, nil, nil, } .mu.Lock()for , := range .css {if .dc == { .mu.Unlock()return , .releaseConn, .ds, nil } } .mu.Unlock()// No luck; we need to prepare the statement on this connectionwithLock(, func() { , = .prepareOnConnLocked(, ) })if != nil { .releaseConn()returnnil, nil, nil, }return , .releaseConn, , nil}// prepareOnConnLocked prepares the query in Stmt s on dc and adds it to the list of// open connStmt on the statement. It assumes the caller is holding the lock on dc.func ( *Stmt) ( context.Context, *driverConn) (*driverStmt, error) { , := .prepareLocked(, .cg, .query)if != nil {returnnil, } := connStmt{, } .mu.Lock() .css = append(.css, ) .mu.Unlock()return .ds, nil}// QueryContext executes a prepared query statement with the given arguments// and returns the query results as a *Rows.func ( *Stmt) ( context.Context, ...any) (*Rows, error) { .closemu.RLock()defer .closemu.RUnlock()vardriver.Rows := cachedOrNewConnfor := 0; < maxBadConnRetries+1; ++ {if == maxBadConnRetries { = alwaysNewConn } , , , := .connStmt(, )if != nil {iferrors.Is(, driver.ErrBadConn) {continue }returnnil, } , = rowsiFromStatement(, .ci, , ...)if == nil {// Note: ownership of ci passes to the *Rows, to be freed // with releaseConn. := &Rows{dc: ,rowsi: ,// releaseConn set below }// addDep must be added before initContextClose or it could attempt // to removeDep before it has been added. .db.addDep(, )// releaseConn must be set before initContextClose or it could // release the connection before it is set. .releaseConn = func( error) { () .db.removeDep(, ) }varcontext.Contextif .cg != nil { = .cg.txCtx() } .initContextClose(, )return , nil } ()if !errors.Is(, driver.ErrBadConn) {returnnil, } }returnnil, driver.ErrBadConn}// Query executes a prepared query statement with the given arguments// and returns the query results as a *Rows.//// Query uses context.Background internally; to specify the context, use// QueryContext.func ( *Stmt) ( ...any) (*Rows, error) {return .QueryContext(context.Background(), ...)}func ( context.Context, driver.Conn, *driverStmt, ...any) (driver.Rows, error) { .Lock()defer .Unlock() , := driverArgsConnLocked(, , )if != nil {returnnil, }returnctxDriverStmtQuery(, .si, )}// QueryRowContext executes a prepared query statement with the given arguments.// If an error occurs during the execution of the statement, that error will// be returned by a call to Scan on the returned *Row, which is always non-nil.// If the query selects no rows, the *Row's Scan will return ErrNoRows.// Otherwise, the *Row's Scan scans the first selected row and discards// the rest.func ( *Stmt) ( context.Context, ...any) *Row { , := .QueryContext(, ...)if != nil {return &Row{err: } }return &Row{rows: }}// QueryRow executes a prepared query statement with the given arguments.// If an error occurs during the execution of the statement, that error will// be returned by a call to Scan on the returned *Row, which is always non-nil.// If the query selects no rows, the *Row's Scan will return ErrNoRows.// Otherwise, the *Row's Scan scans the first selected row and discards// the rest.//// Example usage://// var name string// err := nameByUseridStmt.QueryRow(id).Scan(&name)//// QueryRow uses context.Background internally; to specify the context, use// QueryRowContext.func ( *Stmt) ( ...any) *Row {return .QueryRowContext(context.Background(), ...)}// Close closes the statement.func ( *Stmt) () error { .closemu.Lock()defer .closemu.Unlock()if .stickyErr != nil {return .stickyErr } .mu.Lock()if .closed { .mu.Unlock()returnnil } .closed = true := .cgds .cgds = nil .mu.Unlock()if .cg == nil {return .db.removeDep(, ) }if .parentStmt != nil {// If parentStmt is set, we must not close s.txds since it's stored // in the css array of the parentStmt.return .db.removeDep(.parentStmt, ) }return .Close()}func ( *Stmt) () error { .mu.Lock()defer .mu.Unlock()if .css != nil {for , := range .css { .db.noteUnusedDriverStatement(.dc, .ds) .dc.removeOpenStmt(.ds) } .css = nil }returnnil}// Rows is the result of a query. Its cursor starts before the first row// of the result set. Use Next to advance from row to row.typeRowsstruct {dc *driverConn// owned; must call releaseConn when closed to releasereleaseConnfunc(error)rowsidriver.Rowscancelfunc() // called when Rows is closed, may be nil.closeStmt *driverStmt// if non-nil, statement to Close on close// closemu prevents Rows from closing while there // is an active streaming result. It is held for read during non-close operations // and exclusively during close. // // closemu guards lasterr and closed.closemusync.RWMutexclosedboollasterrerror// non-nil only if closed is true// lastcols is only used in Scan, Next, and NextResultSet which are expected // not to be called concurrently.lastcols []driver.Value}// lasterrOrErrLocked returns either lasterr or the provided err.// rs.closemu must be read-locked.func ( *Rows) ( error) error {if .lasterr != nil && .lasterr != io.EOF {return .lasterr }return}// bypassRowsAwaitDone is only used for testing.// If true, it will not close the Rows automatically from the context.varbypassRowsAwaitDone = falsefunc ( *Rows) (, context.Context) {if .Done() == nil && ( == nil || .Done() == nil) {return }ifbypassRowsAwaitDone {return } , .cancel = context.WithCancel()go .awaitDone(, )}// awaitDone blocks until either ctx or txctx is canceled. The ctx is provided// from the query context and is canceled when the query Rows is closed.// If the query was issued in a transaction, the transaction's context// is also provided in txctx to ensure Rows is closed if the Tx is closed.func ( *Rows) (, context.Context) {var <-chanstruct{}if != nil { = .Done() }select {case<-.Done():case<-: } .close(.Err())}// Next prepares the next result row for reading with the Scan method. It// returns true on success, or false if there is no next result row or an error// happened while preparing it. Err should be consulted to distinguish between// the two cases.//// Every call to Scan, even the first one, must be preceded by a call to Next.func ( *Rows) () bool {var , boolwithLock(.closemu.RLocker(), func() { , = .nextLocked() })if { .Close() }return}func ( *Rows) () (, bool) {if .closed {returnfalse, false }// Lock the driver connection before calling the driver interface // rowsi to prevent a Tx from rolling back the connection at the same time. .dc.Lock()defer .dc.Unlock()if .lastcols == nil { .lastcols = make([]driver.Value, len(.rowsi.Columns())) } .lasterr = .rowsi.Next(.lastcols)if .lasterr != nil {// Close the connection if there is a driver error.if .lasterr != io.EOF {returntrue, false } , := .rowsi.(driver.RowsNextResultSet)if ! {returntrue, false }// The driver is at the end of the current result set. // Test to see if there is another result set after the current one. // Only close Rows if there is no further result sets to read.if !.HasNextResultSet() { = true }return , false }returnfalse, true}// NextResultSet prepares the next result set for reading. It reports whether// there is further result sets, or false if there is no further result set// or if there is an error advancing to it. The Err method should be consulted// to distinguish between the two cases.//// After calling NextResultSet, the Next method should always be called before// scanning. If there are further result sets they may not have rows in the result// set.func ( *Rows) () bool {varbooldeferfunc() {if { .Close() } }() .closemu.RLock()defer .closemu.RUnlock()if .closed {returnfalse } .lastcols = nil , := .rowsi.(driver.RowsNextResultSet)if ! { = truereturnfalse }// Lock the driver connection before calling the driver interface // rowsi to prevent a Tx from rolling back the connection at the same time. .dc.Lock()defer .dc.Unlock() .lasterr = .NextResultSet()if .lasterr != nil { = truereturnfalse }returntrue}// Err returns the error, if any, that was encountered during iteration.// Err may be called after an explicit or implicit Close.func ( *Rows) () error { .closemu.RLock()defer .closemu.RUnlock()return .lasterrOrErrLocked(nil)}varerrRowsClosed = errors.New("sql: Rows are closed")varerrNoRows = errors.New("sql: no Rows available")// Columns returns the column names.// Columns returns an error if the rows are closed.func ( *Rows) () ([]string, error) { .closemu.RLock()defer .closemu.RUnlock()if .closed {returnnil, .lasterrOrErrLocked(errRowsClosed) }if .rowsi == nil {returnnil, .lasterrOrErrLocked(errNoRows) } .dc.Lock()defer .dc.Unlock()return .rowsi.Columns(), nil}// ColumnTypes returns column information such as column type, length,// and nullable. Some information may not be available from some drivers.func ( *Rows) () ([]*ColumnType, error) { .closemu.RLock()defer .closemu.RUnlock()if .closed {returnnil, .lasterrOrErrLocked(errRowsClosed) }if .rowsi == nil {returnnil, .lasterrOrErrLocked(errNoRows) } .dc.Lock()defer .dc.Unlock()returnrowsColumnInfoSetupConnLocked(.rowsi), nil}// ColumnType contains the name and type of a column.typeColumnTypestruct {namestringhasNullableboolhasLengthboolhasPrecisionScaleboolnullableboollengthint64databaseTypestringprecisionint64scaleint64scanTypereflect.Type}// Name returns the name or alias of the column.func ( *ColumnType) () string {return .name}// Length returns the column type length for variable length column types such// as text and binary field types. If the type length is unbounded the value will// be math.MaxInt64 (any database limits will still apply).// If the column type is not variable length, such as an int, or if not supported// by the driver ok is false.func ( *ColumnType) () ( int64, bool) {return .length, .hasLength}// DecimalSize returns the scale and precision of a decimal type.// If not applicable or if not supported ok is false.func ( *ColumnType) () (, int64, bool) {return .precision, .scale, .hasPrecisionScale}// ScanType returns a Go type suitable for scanning into using Rows.Scan.// If a driver does not support this property ScanType will return// the type of an empty interface.func ( *ColumnType) () reflect.Type {return .scanType}// Nullable reports whether the column may be null.// If a driver does not support this property ok will be false.func ( *ColumnType) () (, bool) {return .nullable, .hasNullable}// DatabaseTypeName returns the database system name of the column type. If an empty// string is returned, then the driver type name is not supported.// Consult your driver documentation for a list of driver data types. Length specifiers// are not included.// Common type names include "VARCHAR", "TEXT", "NVARCHAR", "DECIMAL", "BOOL",// "INT", and "BIGINT".func ( *ColumnType) () string {return .databaseType}func ( driver.Rows) []*ColumnType { := .Columns() := make([]*ColumnType, len())for := range { := &ColumnType{name: [], } [] = if , := .(driver.RowsColumnTypeScanType); { .scanType = .ColumnTypeScanType() } else { .scanType = reflect.TypeOf(new(any)).Elem() }if , := .(driver.RowsColumnTypeDatabaseTypeName); { .databaseType = .ColumnTypeDatabaseTypeName() }if , := .(driver.RowsColumnTypeLength); { .length, .hasLength = .ColumnTypeLength() }if , := .(driver.RowsColumnTypeNullable); { .nullable, .hasNullable = .ColumnTypeNullable() }if , := .(driver.RowsColumnTypePrecisionScale); { .precision, .scale, .hasPrecisionScale = .ColumnTypePrecisionScale() } }return}// Scan copies the columns in the current row into the values pointed// at by dest. The number of values in dest must be the same as the// number of columns in Rows.//// Scan converts columns read from the database into the following// common Go types and special types provided by the sql package://// *string// *[]byte// *int, *int8, *int16, *int32, *int64// *uint, *uint8, *uint16, *uint32, *uint64// *bool// *float32, *float64// *interface{}// *RawBytes// *Rows (cursor value)// any type implementing Scanner (see Scanner docs)//// In the most simple case, if the type of the value from the source// column is an integer, bool or string type T and dest is of type *T,// Scan simply assigns the value through the pointer.//// Scan also converts between string and numeric types, as long as no// information would be lost. While Scan stringifies all numbers// scanned from numeric database columns into *string, scans into// numeric types are checked for overflow. For example, a float64 with// value 300 or a string with value "300" can scan into a uint16, but// not into a uint8, though float64(255) or "255" can scan into a// uint8. One exception is that scans of some float64 numbers to// strings may lose information when stringifying. In general, scan// floating point columns into *float64.//// If a dest argument has type *[]byte, Scan saves in that argument a// copy of the corresponding data. The copy is owned by the caller and// can be modified and held indefinitely. The copy can be avoided by// using an argument of type *RawBytes instead; see the documentation// for RawBytes for restrictions on its use.//// If an argument has type *interface{}, Scan copies the value// provided by the underlying driver without conversion. When scanning// from a source value of type []byte to *interface{}, a copy of the// slice is made and the caller owns the result.//// Source values of type time.Time may be scanned into values of type// *time.Time, *interface{}, *string, or *[]byte. When converting to// the latter two, time.RFC3339Nano is used.//// Source values of type bool may be scanned into types *bool,// *interface{}, *string, *[]byte, or *RawBytes.//// For scanning into *bool, the source may be true, false, 1, 0, or// string inputs parseable by strconv.ParseBool.//// Scan can also convert a cursor returned from a query, such as// "select cursor(select * from my_table) from dual", into a// *Rows value that can itself be scanned from. The parent// select query will close any cursor *Rows if the parent *Rows is closed.//// If any of the first arguments implementing Scanner returns an error,// that error will be wrapped in the returned errorfunc ( *Rows) ( ...any) error { .closemu.RLock()if .lasterr != nil && .lasterr != io.EOF { .closemu.RUnlock()return .lasterr }if .closed { := .lasterrOrErrLocked(errRowsClosed) .closemu.RUnlock()return } .closemu.RUnlock()if .lastcols == nil {returnerrors.New("sql: Scan called without calling Next") }iflen() != len(.lastcols) {returnfmt.Errorf("sql: expected %d destination arguments in Scan, not %d", len(.lastcols), len()) }for , := range .lastcols { := convertAssignRows([], , )if != nil {returnfmt.Errorf(`sql: Scan error on column index %d, name %q: %w`, , .rowsi.Columns()[], ) } }returnnil}// rowsCloseHook returns a function so tests may install the// hook through a test only mutex.varrowsCloseHook = func() func(*Rows, *error) { returnnil }// Close closes the Rows, preventing further enumeration. If Next is called// and returns false and there are no further result sets,// the Rows are closed automatically and it will suffice to check the// result of Err. Close is idempotent and does not affect the result of Err.func ( *Rows) () error {return .close(nil)}func ( *Rows) ( error) error { .closemu.Lock()defer .closemu.Unlock()if .closed {returnnil } .closed = trueif .lasterr == nil { .lasterr = }withLock(.dc, func() { = .rowsi.Close() })if := rowsCloseHook(); != nil { (, &) }if .cancel != nil { .cancel() }if .closeStmt != nil { .closeStmt.Close() } .releaseConn()return}// Row is the result of calling QueryRow to select a single row.typeRowstruct {// One of these two will be non-nil:errerror// deferred error for easy chainingrows *Rows}// Scan copies the columns from the matched row into the values// pointed at by dest. See the documentation on Rows.Scan for details.// If more than one row matches the query,// Scan uses the first row and discards the rest. If no row matches// the query, Scan returns ErrNoRows.func ( *Row) ( ...any) error {if .err != nil {return .err }// TODO(bradfitz): for now we need to defensively clone all // []byte that the driver returned (not permitting // *RawBytes in Rows.Scan), since we're about to close // the Rows in our defer, when we return from this function. // the contract with the driver.Next(...) interface is that it // can return slices into read-only temporary memory that's // only valid until the next Scan/Close. But the TODO is that // for a lot of drivers, this copy will be unnecessary. We // should provide an optional interface for drivers to // implement to say, "don't worry, the []bytes that I return // from Next will not be modified again." (for instance, if // they were obtained from the network anyway) But for now we // don't care.defer .rows.Close()for , := range {if , := .(*RawBytes); {returnerrors.New("sql: RawBytes isn't allowed on Row.Scan") } }if !.rows.Next() {if := .rows.Err(); != nil {return }returnErrNoRows } := .rows.Scan(...)if != nil {return }// Make sure the query can be processed to completion with no errors.return .rows.Close()}// Err provides a way for wrapping packages to check for// query errors without calling Scan.// Err returns the error, if any, that was encountered while running the query.// If this error is not nil, this error will also be returned from Scan.func ( *Row) () error {return .err}// A Result summarizes an executed SQL command.typeResultinterface {// LastInsertId returns the integer generated by the database // in response to a command. Typically this will be from an // "auto increment" column when inserting a new row. Not all // databases support this feature, and the syntax of such // statements varies.LastInsertId() (int64, error)// RowsAffected returns the number of rows affected by an // update, insert, or delete. Not every database or database // driver may support this.RowsAffected() (int64, error)}typedriverResultstruct {sync.Locker// the *driverConnresidriver.Result}func ( driverResult) () (int64, error) { .Lock()defer .Unlock()return .resi.LastInsertId()}func ( driverResult) () (int64, error) { .Lock()defer .Unlock()return .resi.RowsAffected()}func () string {var [2 << 10]bytereturnstring([:runtime.Stack([:], false)])}// withLock runs while holding lk.func ( sync.Locker, func()) { .Lock()defer .Unlock() // in case fn panics ()}
The pages are generated with Goldsv0.4.9. (GOOS=linux GOARCH=amd64)