// 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 sql import ( _ ) var driversMu sync.RWMutex // drivers should be an internal detail, // but widely used packages access it using linkname. // (It is extra wrong that they linkname drivers but not driversMu.) // Notable members of the hall of shame include: // - github.com/instana/go-sensor // // Do not remove or change the type signature. // See go.dev/issue/67401. // //go:linkname drivers var 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 ( string, driver.Driver) { driversMu.Lock() defer driversMu.Unlock() if == nil { panic("sql: Register driver is nil") } if , := drivers[]; { panic("sql: Register called twice for driver " + ) } drivers[] = } 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 () []string { driversMu.RLock() defer driversMu.RUnlock() := make([]string, 0, len(drivers)) for := range drivers { = append(, ) } slices.Sort() return } // A NamedArg is a named argument. NamedArg values may be used as // arguments to [DB.Query] or [DB.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. type NamedArg struct { _NamedFieldsRequired struct{} // 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. Name string // Value is the value of the parameter. // It may be assigned the same value types as the query // arguments. Value any } // 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}. return NamedArg{Name: , Value: } } // IsolationLevel is the transaction isolation level used in [TxOptions]. type IsolationLevel int // Various isolation levels that drivers may support in [DB.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 ( LevelDefault IsolationLevel = iota LevelReadUncommitted LevelReadCommitted LevelWriteCommitted LevelRepeatableRead LevelSnapshot LevelSerializable LevelLinearizable ) // String returns the name of the transaction isolation level. func ( IsolationLevel) () string { switch { case LevelDefault: return "Default" case LevelReadUncommitted: return "Read Uncommitted" case LevelReadCommitted: return "Read Committed" case LevelWriteCommitted: return "Write Committed" case LevelRepeatableRead: return "Repeatable Read" case LevelSnapshot: return "Snapshot" case LevelSerializable: return "Serializable" case LevelLinearizable: return "Linearizable" default: return "IsolationLevel(" + strconv.Itoa(int()) + ")" } } var _ fmt.Stringer = LevelDefault // TxOptions holds the transaction options to be used in [DB.BeginTx]. type TxOptions struct { // Isolation is the transaction isolation level. // If zero, the driver or database's default level is used. Isolation IsolationLevel ReadOnly bool } // RawBytes is a byte slice that holds a reference to memory owned by // the database itself. After a [Rows.Scan] into a RawBytes, the slice is only // valid until the next call to [Rows.Next], [Rows.Scan], or [Rows.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 ( *NullString) ( any) error { if == nil { .String, .Valid = "", false return nil } .Valid = true return convertAssign(&.String, ) } // Value implements the [driver.Valuer] interface. func ( NullString) () (driver.Value, error) { if !.Valid { return nil, 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]. type NullInt64 struct { Int64 int64 Valid bool // Valid is true if Int64 is not NULL } // Scan implements the [Scanner] interface. func ( *NullInt64) ( any) error { if == nil { .Int64, .Valid = 0, false return nil } .Valid = true return convertAssign(&.Int64, ) } // Value implements the [driver.Valuer] interface. func ( NullInt64) () (driver.Value, error) { if !.Valid { return nil, 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]. type NullInt32 struct { Int32 int32 Valid bool // Valid is true if Int32 is not NULL } // Scan implements the [Scanner] interface. func ( *NullInt32) ( any) error { if == nil { .Int32, .Valid = 0, false return nil } .Valid = true return convertAssign(&.Int32, ) } // Value implements the [driver.Valuer] interface. func ( NullInt32) () (driver.Value, error) { if !.Valid { return nil, nil } return int64(.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]. type NullInt16 struct { Int16 int16 Valid bool // Valid is true if Int16 is not NULL } // Scan implements the [Scanner] interface. func ( *NullInt16) ( any) error { if == nil { .Int16, .Valid = 0, false return nil } := convertAssign(&.Int16, ) .Valid = == nil return } // Value implements the [driver.Valuer] interface. func ( NullInt16) () (driver.Value, error) { if !.Valid { return nil, nil } return int64(.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]. type NullByte struct { Byte byte Valid bool // Valid is true if Byte is not NULL } // Scan implements the [Scanner] interface. func ( *NullByte) ( any) error { if == nil { .Byte, .Valid = 0, false return nil } := convertAssign(&.Byte, ) .Valid = == nil return } // Value implements the [driver.Valuer] interface. func ( NullByte) () (driver.Value, error) { if !.Valid { return nil, nil } return int64(.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]. type NullFloat64 struct { Float64 float64 Valid bool // Valid is true if Float64 is not NULL } // Scan implements the [Scanner] interface. func ( *NullFloat64) ( any) error { if == nil { .Float64, .Valid = 0, false return nil } .Valid = true return convertAssign(&.Float64, ) } // Value implements the [driver.Valuer] interface. func ( NullFloat64) () (driver.Value, error) { if !.Valid { return nil, 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]. type NullBool struct { Bool bool Valid bool // Valid is true if Bool is not NULL } // Scan implements the [Scanner] interface. func ( *NullBool) ( any) error { if == nil { .Bool, .Valid = false, false return nil } .Valid = true return convertAssign(&.Bool, ) } // Value implements the [driver.Valuer] interface. func ( NullBool) () (driver.Value, error) { if !.Valid { return nil, 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]. type NullTime struct { Time time.Time Valid bool // Valid is true if Time is not NULL } // Scan implements the [Scanner] interface. func ( *NullTime) ( any) error { if == nil { .Time, .Valid = time.Time{}, false return nil } .Valid = true return convertAssign(&.Time, ) } // Value implements the [driver.Valuer] interface. func ( NullTime) () (driver.Value, error) { if !.Valid { return nil, nil } return .Time, nil } // Null represents a value that may be null. // Null implements the [Scanner] interface so // it can be used as a scan destination: // // var s Null[string] // err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&s) // ... // if s.Valid { // // use s.V // } else { // // NULL value // } type Null[ any] struct { V Valid bool } func ( *Null[]) ( any) error { if == nil { .V, .Valid = *new(), false return nil } .Valid = true return convertAssign(&.V, ) } func ( Null[]) () (driver.Value, error) { if !.Valid { return nil, nil } return .V, nil } // Scanner is an interface used by [Rows.Scan]. type Scanner interface { // 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})) type Out struct { _NamedFieldsRequired struct{} // Dest is a pointer to the value that will be set to the result of the // stored procedure's OUTPUT parameter. Dest any // 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. In bool } // ErrNoRows is returned by [Row.Scan] when [DB.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 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 [Tx.Commit] or // [Tx.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 [DB.SetMaxIdleConns]. type DB struct { // Total time waited for new connections. waitDuration atomic.Int64 connector driver.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. numClosed atomic.Uint64 mu sync.Mutex // protects following fields freeConn []*driverConn // free connections ordered by returnedAt oldest to newest connRequests connRequestSet 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 maxIdleCount int // zero means defaultMaxIdleConns; negative means 0 maxOpen int // <= 0 means unlimited maxLifetime time.Duration // maximum amount of time a connection may be reused maxIdleTime time.Duration // maximum amount of time a connection may be idle before being closed cleanerCh chan struct{} waitCount int64 // Total number of connections waited for. maxIdleClosed int64 // Total number of connections closed due to idle count. maxIdleTimeClosed int64 // Total number of connections closed due to idle time. maxLifetimeClosed int64 // Total number of connections closed due to max connection lifetime limit. stop func() // stop cancels the connection opener. } // 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 needReset bool // The connection session should be reset before use if true. closed bool finalClosed bool // ci.Close has been called openStmt map[*driverStmt]bool // guarded by db.mu inUse bool dbmuClosed bool // same as closed, but guarded by db.mu, for removeClosedStmtLocked returnedAt time.Time // Time the connection was created or returned. onPut []func() // code (with db.mu held) run when conn is next returned } func ( *driverConn) ( error) { .db.putConn(, , true) } func ( *driverConn) ( *driverStmt) { .Lock() defer .Unlock() delete(.openStmt, ) } func ( *driverConn) ( time.Duration) bool { if <= 0 { return false } 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 { return nil } if , := .ci.(driver.SessionResetter); { return .ResetSession() } return nil } // 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() } return true } // 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 { return nil, } := &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[] = true return , nil } // the dc.db's Mutex is held. func ( *driverConn) () func() error { .Lock() defer .Unlock() if .closed { return func() error { return errors.New("sql: duplicate driverConn close") } } .closed = true return .db.removeDepLocked(, ) } func ( *driverConn) () error { .Lock() if .closed { .Unlock() return errors.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 { var error // Each *driverStmt has a lock to the dc. Copy the list out of the dc // before calling close on each stmt. var []*driverStmt withLock(, 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() .db.numClosed.Add(1) return } // 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 closed bool closeErr error // 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 dependencies type depSet map[any]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) ( 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(, ) switch len() { case : // Nothing removed. Shouldn't happen. panic(fmt.Sprintf("unpaired removeDep: no %T dep on %T", , )) case 0: // No more dependencies. delete(.dep, ) return .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 type dsnConnector struct { dsn string driver driver.Driver } func ( dsnConnector) ( context.Context) (driver.Conn, error) { return .driver.Open(.dsn) } func ( dsnConnector) () driver.Driver { return .driver } // OpenDB opens a database using a [driver.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 // [DB.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(chan struct{}, connectionRequestQueueSize), lastPut: make(map[*driverConn]string), 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 // [DB.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 ! { return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", ) } if , := .(driver.DriverContext); { , := .OpenConnector() if != nil { return nil, } return OpenDB(), nil } return OpenDB(dsnConnector{dsn: , driver: }), nil } func ( *DB) ( context.Context, *driverConn, func(error)) error { var error if , := .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 *driverConn var error = .retry(func( connReuseStrategy) error { , = .conn(, ) return }) 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 // [DB.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() return nil } if .cleanerCh != nil { close(.cleanerCh) } var error := make([]func() error, 0, len(.freeConn)) for , := range .freeConn { = append(, .closeDBLocked()) } .freeConn = nil .closed = true .connRequests.CloseAndRemoveAll() .mu.Unlock() for , := range { := () if != nil { = } } .stop() if , := .connector.(io.Closer); { := .Close() if != nil { = } } return } const defaultMaxIdleConns = 2 func ( *DB) () int { := .maxIdleCount switch { case == 0: // TODO(bradfitz): ask driver, if supported, for its default preference return defaultMaxIdleConns case < 0: return 0 default: return } } func ( *DB) () time.Duration { if .maxIdleTime <= 0 { return .maxLifetime } if .maxLifetime <= 0 { return .maxIdleTime } return min(.maxIdleTime, .maxLifetime) } // 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 maxOpen if .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(chan struct{}, 1) go .connectionCleaner(.shortestIdleTimeLocked()) } } func ( *DB) ( time.Duration) { const = time.Second if < { = } := 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) { var int64 var []*driverConn if .maxIdleTime > 0 { // As freeConn is ordered by returnedAt process // in reverse order to minimise the work needed. := nowFunc().Add(-.maxIdleTime) := len(.freeConn) - 1 for := ; >= 0; -- { := .freeConn[] if .returnedAt.Before() { ++ = .freeConn[::] .freeConn = .freeConn[:] = int64(len()) .maxIdleTimeClosed += break } } if len(.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[:] -- } else if := .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. type DBStats struct { MaxOpenConnections int // Maximum number of open connections to the database. // Pool Status OpenConnections int // The number of established connections both in use and idle. InUse int // The number of connections currently in use. Idle int // The number of idle connections. // Counters WaitCount int64 // The total number of connections waited for. WaitDuration time.Duration // The total time blocked waiting for a new connection. MaxIdleClosed int64 // The total number of connections closed due to SetMaxIdleConns. MaxIdleTimeClosed int64 // The total number of connections closed due to SetConnMaxIdleTime. MaxLifetimeClosed int64 // The total number of connections closed due to SetConnMaxLifetime. } // Stats returns database statistics. func ( *DB) () DBStats { := .waitDuration.Load() .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) () { := .connRequests.Len() if .maxOpen > 0 { := .maxOpen - .numOpen if > { = } } 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(): return case <-.openerCh: .openNewConnection() } } } // Open one new connection func ( *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. type connRequest struct { conn *driverConn err error } var errDBClosed = errors.New("sql: database is closed") // conn returns a newly-opened or cached *driverConn. func ( *DB) ( context.Context, connReuseStrategy) (*driverConn, error) { .mu.Lock() if .closed { .mu.Unlock() return nil, errDBClosed } // Check if the context is expired. select { default: case <-.Done(): .mu.Unlock() return nil, .Err() } := .maxLifetime // Prefer a free connection, if possible. := len(.freeConn) - 1 if == cachedOrNewConn && >= 0 { // Reuse the lowest idle time connection so we can close // connections which remain idle as soon as possible. := .freeConn[] .freeConn = .freeConn[:] .inUse = true if .expired() { .maxLifetimeClosed++ .mu.Unlock() .Close() return nil, driver.ErrBadConn } .mu.Unlock() // Reset the session if required. if := .resetSession(); errors.Is(, driver.ErrBadConn) { .Close() return nil, } 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(chan connRequest, 1) := .connRequests.Add() .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() := .connRequests.Delete() .mu.Unlock() .waitDuration.Add(int64(time.Since())) // If we failed to delete it, that means something else // grabbed it and is about to send on it. if ! { // TODO(bradfitz): rather than this best effort select, we // should probably start a goroutine to read from req. This best // effort select existed before the change to check 'deleted'. // But if we know for sure it wasn't deleted and a sender is // outstanding, we should probably block on req (in a new // goroutine) to get the connection back. select { default: case , := <-: if && .conn != nil { .putConn(.conn, .err, false) } } } return nil, .Err() case , := <-: .waitDuration.Add(int64(time.Since())) if ! { return nil, 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() return nil, driver.ErrBadConn } if .conn == nil { return nil, .err } // Reset the session if required. if := .conn.resetSession(); errors.Is(, driver.ErrBadConn) { .conn.Close() return nil, } return .conn, .err } } .numOpen++ // optimistically .mu.Unlock() , := .connector.Connect() if != nil { .mu.Lock() .numOpen-- // correct for earlier optimism .maybeOpenNewConnections() .mu.Unlock() return nil, } .mu.Lock() := &driverConn{ db: , createdAt: nowFunc(), returnedAt: nowFunc(), ci: , inUse: true, } .addDepLocked(, ) .mu.Unlock() return , nil } // putConnHook is a hook for testing. var putConnHook func(*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. const debugGetPut = 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() if debugGetPut { 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 } if debugGetPut { .lastPut[] = stack() } .inUse = false .returnedAt = nowFunc() for , := range .onPut { () } .onPut = nil if errors.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 } if putConnHook != 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 { return false } if .maxOpen > 0 && .numOpen > .maxOpen { return false } if , := .connRequests.TakeRandom(); { if == nil { .inUse = true } <- connRequest{ conn: , err: , } return true } else if == nil && !.closed { if .maxIdleConnsLocked() > len(.freeConn) { .freeConn = append(.freeConn, ) .startCleanerLocked() return true } .maxIdleClosed++ } return false } // 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. const maxBadConnRetries = 2 func ( *DB) ( func( connReuseStrategy) error) error { for := int64(0); < maxBadConnRetries; ++ { := (cachedOrNewConn) // retry if err is driver.ErrBadConn if == nil || !errors.Is(, driver.ErrBadConn) { return } } return (alwaysNewConn) } // 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 [*Stmt.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 *Stmt var error = .retry(func( connReuseStrategy) error { , = .prepare(, , ) return }) 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 [*Stmt.Close] method // when the statement is no longer needed. // // Prepare uses [context.Background] internally; to specify the context, use // [DB.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 { return nil, } 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 *driverStmt var error defer func() { () }() withLock(, func() { , = .prepareLocked(, , ) }) if != nil { return nil, } := &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 = .numClosed.Load() .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) { var Result var error = .retry(func( connReuseStrategy) error { , = .exec(, , , ) return }) 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 // [DB.ExecContext]. func ( *DB) ( string, ...any) (Result, error) { return .ExecContext(context.Background(), , ...) } func ( *DB) ( context.Context, string, []any, connReuseStrategy) (Result, error) { , := .conn(, ) if != nil { return nil, } return .execDC(, , .releaseConn, , ) } func ( *DB) ( context.Context, *driverConn, func(error), string, []any) ( Result, error) { defer func() { () }() , := .ci.(driver.ExecerContext) var driver.Execer if ! { , = .ci.(driver.Execer) } if { var []driver.NamedValue var driver.Result withLock(, func() { , = driverArgsConnLocked(.ci, nil, ) if != nil { return } , = ctxDriverExec(, , , , ) }) if != driver.ErrSkip { if != nil { return nil, } return driverResult{, }, nil } } var driver.Stmt withLock(, func() { , = ctxDriverPrepare(, .ci, ) }) if != nil { return nil, } := &driverStmt{Locker: , si: } defer .Close() return resultFromStatement(, .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 *Rows var error = .retry(func( connReuseStrategy) error { , = .query(, , , ) return }) 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 // [DB.QueryContext]. func ( *DB) ( string, ...any) (*Rows, error) { return .QueryContext(context.Background(), , ...) } func ( *DB) ( context.Context, string, []any, connReuseStrategy) (*Rows, error) { , := .conn(, ) if != nil { return nil, } 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) var driver.Queryer if ! { , = .ci.(driver.Queryer) } if { var []driver.NamedValue var driver.Rows var error withLock(, func() { , = driverArgsConnLocked(.ci, nil, ) if != nil { return } , = ctxDriverQuery(, , , , ) }) if != driver.ErrSkip { if != nil { () return nil, } // Note: ownership of dc passes to the *Rows, to be freed // with releaseConn. := &Rows{ dc: , releaseConn: , rowsi: , } .initContextClose(, ) return , nil } } var driver.Stmt var error withLock(, func() { , = ctxDriverPrepare(, .ci, ) }) if != nil { () return nil, } := &driverStmt{Locker: , si: } , := rowsiFromStatement(, .ci, , ...) if != nil { .Close() () return nil, } // 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.Scan] will return [ErrNoRows]. // Otherwise, [*Row.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.Scan] will return [ErrNoRows]. // Otherwise, [*Row.Scan] scans the first selected row and discards // the rest. // // QueryRow uses [context.Background] internally; to specify the context, use // [DB.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 *Tx var error = .retry(func( connReuseStrategy) error { , = .begin(, , ) return }) return , } // Begin starts a transaction. The default isolation level is dependent on // the driver. // // Begin uses [context.Background] internally; to specify the context, use // [DB.BeginTx]. func ( *DB) () (*Tx, error) { return .BeginTx(context.Background(), nil) } func ( *DB) ( context.Context, *TxOptions, connReuseStrategy) ( *Tx, error) { , := .conn(, ) if != nil { return nil, } 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) { var driver.Tx := false withLock(, func() { , := .ci.(driver.SessionResetter) , := .ci.(driver.Validator) = && , = ctxDriverBegin(, , .ci) }) if != nil { () return nil, } // 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. var ErrConnDone = 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 *driverConn var error = .retry(func( connReuseStrategy) error { , = .conn(, ) return }) if != nil { return nil, } := &Conn{ db: , dc: , } return , nil } type releaseConn func(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 [Conn.Close] to return the connection to the database pool // and may do so concurrently with a running query. // // After a call to [Conn.Close], all operations on the // connection fail with [ErrConnDone]. type Conn struct { 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. closemu sync.RWMutex // dc is owned until close, at which point // it's returned to the connection pool. dc *driverConn // done transitions from false to true exactly once, on close. // Once done, all operations fail with ErrConnDone. done atomic.Bool releaseConnOnce sync.Once // releaseConnCache is a cache of c.closemuRUnlockCondReleaseConn // to save allocations in a call to grabConn. releaseConnCache releaseConn } // grabConn takes a context to implement stmtConnGrabber // but the context is not used. func ( *Conn) (context.Context) (*driverConn, releaseConn, error) { if .done.Load() { return nil, nil, ErrConnDone } .releaseConnOnce.Do(func() { .releaseConnCache = .closemuRUnlockCondReleaseConn }) .closemu.RLock() return .dc, .releaseConnCache, 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 { return nil, } 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 { return nil, } 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 // the [*Row.Scan] method is called. // If the query selects no rows, the [*Row.Scan] will return [ErrNoRows]. // Otherwise, the [*Row.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 [*Stmt.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 { return nil, } 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 *driverConn var releaseConn // grabConn takes a context to implement stmtConnGrabber, but the context is not used. , , = .grabConn(nil) if != nil { return } := true .Mutex.Lock() defer func() { .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) = false return } // 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 { return nil, } return .db.beginDC(, , , ) } // closemuRUnlockCondReleaseConn read unlocks closemu // as the sql operation is done with the dc. func ( *Conn) ( error) { .closemu.RUnlock() if errors.Is(, driver.ErrBadConn) { .close() } } func ( *Conn) () context.Context { return nil } func ( *Conn) ( error) error { if !.done.CompareAndSwap(false, true) { return ErrConnDone } // 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 = nil return } // 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 [Tx.Commit] or [Tx.Rollback]. // // After a call to [Tx.Commit] or [Tx.Rollback], all operations on the // transaction fail with [ErrTxDone]. // // The statements prepared for a transaction by calling // the transaction's [Tx.Prepare] or [Tx.Stmt] methods are closed // by the call to [Tx.Commit] or [Tx.Rollback]. type Tx struct { 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. closemu sync.RWMutex // dc is owned exclusively until Commit or Rollback, at which point // it's returned with putConn. dc *driverConn txi driver.Tx // releaseConn is called once the Tx is closed to release // any held driverConn back to the pool. releaseConn func(error) // done transitions from false to true exactly once, on Commit // or Rollback. once done, all operations fail with // ErrTxDone. done atomic.Bool // keepConnOnRollback is true if the driver knows // how to reset the connection's session and if need be discard // the connection. keepConnOnRollback bool // All Stmts prepared for this transaction. These will be closed after the // transaction has been committed or rolled back. stmts struct { sync.Mutex v []*Stmt } // cancel is called after done transitions from 0 to 1. cancel func() // ctx lives for the life of the transaction. ctx context.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 { return .done.Load() } // ErrTxDone is returned by any operation that is performed on a transaction // that has already been committed or rolled back. var ErrTxDone = 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. var hookTxGrabConn func() func ( *Tx) ( context.Context) (*driverConn, releaseConn, error) { select { default: case <-.Done(): return nil, 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() return nil, nil, ErrTxDone } if hookTxGrabConn != nil { // test hook hookTxGrabConn() } return .dc, .closemuRUnlockRelease, nil } func ( *Tx) () context.Context { return .ctx } // closemuRUnlockRelease is used as a func(error) method value in // [DB.ExecContext] and [DB.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(): if .done.Load() { return ErrTxDone } return .ctx.Err() } if !.done.CompareAndSwap(false, true) { return ErrTxDone } // 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() var error withLock(.dc, func() { = .txi.Commit() }) if !errors.Is(, driver.ErrBadConn) { .closePrepared() } .close() return } var rollbackHook func() // rollback aborts the transaction and optionally forces the pool to discard // the connection. func ( *Tx) ( bool) error { if !.done.CompareAndSwap(false, true) { return ErrTxDone } if rollbackHook != 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() var error withLock(.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 { return nil, } , := .db.prepareDC(, , , , ) if != nil { return nil, } .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 // [Tx.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")} } var driver.Stmt var *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.si break } } .mu.Unlock() if == nil { var *driverStmt withLock(, 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 // [Tx.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 { return nil, } 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 // [Tx.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 { return nil, } return .db.queryDC(, .ctx, , , , ) } // Query executes a query that returns rows, typically a SELECT. // // Query uses [context.Background] internally; to specify the context, use // [Tx.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.Scan] will return [ErrNoRows]. // Otherwise, the [*Row.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.Scan] will return [ErrNoRows]. // Otherwise, the [*Row.Scan] scans the first selected row and discards // the rest. // // QueryRow uses [context.Background] internally; to specify the context, use // [Tx.QueryRowContext]. func ( *Tx) ( string, ...any) *Row { return .QueryRowContext(context.Background(), , ...) } // connStmt is a prepared statement on a particular connection. type connStmt struct { dc *driverConn ds *driverStmt } // stmtConnGrabber represents a Tx or Conn that will return the underlying // driverConn and release function. type stmtConnGrabber interface { // 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. type Stmt struct { // Immutable: db *DB // where we came from query string // that created the Stmt stickyErr error // if non-nil, this error is returned for all operations closemu sync.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. cg stmtConnGrabber cgds *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 *Stmt mu sync.Mutex // protects the rest of the fields closed bool // 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. lastNumClosed uint64 } // 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() var Result := .db.retry(func( connReuseStrategy) error { , , , := .connStmt(, ) if != nil { return } , = resultFromStatement(, .ci, , ...) () return }) return , } // 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 // [Stmt.ExecContext]. func ( *Stmt) ( ...any) (Result, error) { return .ExecContext(context.Background(), ...) } func resultFromStatement( context.Context, driver.Conn, *driverStmt, ...any) (Result, error) { .Lock() defer .Unlock() , := driverArgsConnLocked(, , ) if != nil { return nil, } , := ctxDriverStmtExec(, .si, ) if != nil { return nil, } return driverResult{.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 + 1 if > 10 { = 10 } := .db.numClosed.Load() if -.lastNumClosed < uint64() { return } .db.mu.Lock() for := 0; < len(.css); ++ { if .css[].dc.dbmuClosed { .css[] = .css[len(.css)-1] // Zero out the last element (for GC) before shrinking the slice. .css[len(.css)-1] = connStmt{} .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 { return nil, 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 connection withLock(, func() { , = .prepareOnConnLocked(, ) }) if != nil { .releaseConn() return nil, 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 { return nil, } := 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() var driver.Rows var *Rows := .db.retry(func( connReuseStrategy) error { , , , := .connStmt(, ) if != nil { return } , = 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(, ) } var context.Context if .cg != nil { = .cg.txCtx() } .initContextClose(, ) return nil } () return }) return , } // 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 // [Stmt.QueryContext]. func ( *Stmt) ( ...any) (*Rows, error) { return .QueryContext(context.Background(), ...) } func rowsiFromStatement( context.Context, driver.Conn, *driverStmt, ...any) (driver.Rows, error) { .Lock() defer .Unlock() , := driverArgsConnLocked(, , ) if != nil { return nil, } return ctxDriverStmtQuery(, .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.Scan] will return [ErrNoRows]. // Otherwise, the [*Row.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.Scan] will return [ErrNoRows]. // Otherwise, the [*Row.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 // [Stmt.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() return nil } .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 } return nil } // Rows is the result of a query. Its cursor starts before the first row // of the result set. Use [Rows.Next] to advance from row to row. type Rows struct { dc *driverConn // owned; must call releaseConn when closed to release releaseConn func(error) rowsi driver.Rows cancel func() // called when Rows is closed, may be nil. closeStmt *driverStmt // if non-nil, statement to Close on close contextDone atomic.Pointer[error] // error that awaitDone saw; set before close attempt // 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. closemu sync.RWMutex lasterr error // non-nil only if closed is true closed bool // closemuScanHold is whether the previous call to Scan kept closemu RLock'ed // without unlocking it. It does that when the user passes a *RawBytes scan // target. In that case, we need to prevent awaitDone from closing the Rows // while the user's still using the memory. See go.dev/issue/60304. // // It is only used by Scan, Next, and NextResultSet which are expected // not to be called concurrently. closemuScanHold bool // hitEOF is whether Next hit the end of the rows without // encountering an error. It's set in Next before // returning. It's only used by Next and Err which are // expected not to be called concurrently. hitEOF bool // lastcols is only used in Scan, Next, and NextResultSet which are expected // not to be called concurrently. lastcols []driver.Value // raw is a buffer for RawBytes that persists between Scan calls. // This is used when the driver returns a mismatched type that requires // a cloning allocation. For example, if the driver returns a *string and // the user is scanning into a *RawBytes, we need to copy the string. // The raw buffer here lets us reuse the memory for that copy across Scan calls. raw []byte } // 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. var bypassRowsAwaitDone = false func ( *Rows) (, context.Context) { if .Done() == nil && ( == nil || .Done() == nil) { return } if bypassRowsAwaitDone { return } , := context.WithCancel() .cancel = go .awaitDone(, , ) } // awaitDone blocks until ctx, txctx, or closectx is canceled. // The ctx is provided from the query context. // 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. // The closectx is closed by an explicit call to rs.Close. func ( *Rows) (, , context.Context) { var <-chan struct{} if != nil { = .Done() } select { case <-.Done(): := .Err() .contextDone.Store(&) case <-: := .Err() .contextDone.Store(&) case <-.Done(): // rs.cancel was called via Close(); don't store this into contextDone // to ensure Err() is unaffected. } .close(.Err()) } // Next prepares the next result row for reading with the [Rows.Scan] method. It // returns true on success, or false if there is no next result row or an error // happened while preparing it. [Rows.Err] should be consulted to distinguish between // the two cases. // // Every call to [Rows.Scan], even the first one, must be preceded by a call to [Rows.Next]. func ( *Rows) () bool { // If the user's calling Next, they're done with their previous row's Scan // results (any RawBytes memory), so we can release the read lock that would // be preventing awaitDone from calling close. .closemuRUnlockIfHeldByScan() if .contextDone.Load() != nil { return false } var , bool withLock(.closemu.RLocker(), func() { , = .nextLocked() }) if { .Close() } if && ! { .hitEOF = true } return } func ( *Rows) () (, bool) { if .closed { return false, 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 { return true, false } , := .rowsi.(driver.RowsNextResultSet) if ! { return true, 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 } return false, 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 [Rows.Err] method should be consulted // to distinguish between the two cases. // // After calling NextResultSet, the [Rows.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 { // If the user's calling NextResultSet, they're done with their previous // row's Scan results (any RawBytes memory), so we can release the read lock // that would be preventing awaitDone from calling close. .closemuRUnlockIfHeldByScan() var bool defer func() { if { .Close() } }() .closemu.RLock() defer .closemu.RUnlock() if .closed { return false } .lastcols = nil , := .rowsi.(driver.RowsNextResultSet) if ! { = true return 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() .lasterr = .NextResultSet() if .lasterr != nil { = true return false } return true } // Err returns the error, if any, that was encountered during iteration. // Err may be called after an explicit or implicit [Rows.Close]. func ( *Rows) () error { // Return any context error that might've happened during row iteration, // but only if we haven't reported the final Next() = false after rows // are done, in which case the user might've canceled their own context // before calling Rows.Err. if !.hitEOF { if := .contextDone.Load(); != nil { return * } } .closemu.RLock() defer .closemu.RUnlock() return .lasterrOrErrLocked(nil) } // rawbuf returns the buffer to append RawBytes values to. // This buffer is reused across calls to Rows.Scan. // // Usage: // // rawBytes = rows.setrawbuf(append(rows.rawbuf(), value...)) func ( *Rows) () []byte { if == nil { // convertAssignRows can take a nil *Rows; for simplicity handle it here return nil } return .raw } // setrawbuf updates the RawBytes buffer with the result of appending a new value to it. // It returns the new value. func ( *Rows) ( []byte) RawBytes { if == nil { // convertAssignRows can take a nil *Rows; for simplicity handle it here return RawBytes() } := len(.raw) .raw = return RawBytes(.raw[:]) } var errRowsClosed = errors.New("sql: Rows are closed") var errNoRows = 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 { return nil, .lasterrOrErrLocked(errRowsClosed) } if .rowsi == nil { return nil, .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 { return nil, .lasterrOrErrLocked(errRowsClosed) } if .rowsi == nil { return nil, .lasterrOrErrLocked(errNoRows) } .dc.Lock() defer .dc.Unlock() return rowsColumnInfoSetupConnLocked(.rowsi), nil } // ColumnType contains the name and type of a column. type ColumnType struct { name string hasNullable bool hasLength bool hasPrecisionScale bool nullable bool length int64 databaseType string precision int64 scale int64 scanType reflect.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. [ColumnType.Length] specifiers // are not included. // Common type names include "VARCHAR", "TEXT", "NVARCHAR", "DECIMAL", "BOOL", // "INT", and "BIGINT". func ( *ColumnType) () string { return .databaseType } func rowsColumnInfoSetupConnLocked( driver.Rows) []*ColumnType { := .Columns() := make([]*ColumnType, len()) for := range { := &ColumnType{ name: [], } [] = if , := .(driver.RowsColumnTypeScanType); { .scanType = .ColumnTypeScanType() } else { .scanType = reflect.TypeFor[any]() } 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 error. func ( *Rows) ( ...any) error { if .closemuScanHold { // This should only be possible if the user calls Scan twice in a row // without calling Next. return fmt.Errorf("sql: Scan called without calling Next (closemuScanHold)") } .closemu.RLock() if .lasterr != nil && .lasterr != io.EOF { .closemu.RUnlock() return .lasterr } if .closed { := .lasterrOrErrLocked(errRowsClosed) .closemu.RUnlock() return } if scanArgsContainRawBytes() { .closemuScanHold = true .raw = .raw[:0] } else { .closemu.RUnlock() } if .lastcols == nil { .closemuRUnlockIfHeldByScan() return errors.New("sql: Scan called without calling Next") } if len() != len(.lastcols) { .closemuRUnlockIfHeldByScan() return fmt.Errorf("sql: expected %d destination arguments in Scan, not %d", len(.lastcols), len()) } for , := range .lastcols { := convertAssignRows([], , ) if != nil { .closemuRUnlockIfHeldByScan() return fmt.Errorf(`sql: Scan error on column index %d, name %q: %w`, , .rowsi.Columns()[], ) } } return nil } // closemuRUnlockIfHeldByScan releases any closemu.RLock held open by a previous // call to Scan with *RawBytes. func ( *Rows) () { if .closemuScanHold { .closemuScanHold = false .closemu.RUnlock() } } func scanArgsContainRawBytes( []any) bool { for , := range { if , := .(*RawBytes); { return true } } return false } // rowsCloseHook returns a function so tests may install the // hook through a test only mutex. var rowsCloseHook = func() func(*Rows, *error) { return nil } // Close closes the [Rows], preventing further enumeration. If [Rows.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 [Rows.Err]. Close is idempotent and does not affect the result of [Rows.Err]. func ( *Rows) () error { // If the user's calling Close, they're done with their previous row's Scan // results (any RawBytes memory), so we can release the read lock that would // be preventing awaitDone from calling the unexported close before we do so. .closemuRUnlockIfHeldByScan() return .close(nil) } func ( *Rows) ( error) error { .closemu.Lock() defer .closemu.Unlock() if .closed { return nil } .closed = true if .lasterr == nil { .lasterr = } withLock(.dc, func() { = .rowsi.Close() }) if := rowsCloseHook(); != nil { (, &) } if .cancel != nil { .cancel() } if .closeStmt != nil { .closeStmt.Close() } .releaseConn() .lasterr = .lasterrOrErrLocked() return } // Row is the result of calling [DB.QueryRow] to select a single row. type Row struct { // One of these two will be non-nil: err error // deferred error for easy chaining rows *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() if scanArgsContainRawBytes() { return errors.New("sql: RawBytes isn't allowed on Row.Scan") } if !.rows.Next() { if := .rows.Err(); != nil { return } return ErrNoRows } := .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 [Row.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 [Row.Scan]. func ( *Row) () error { return .err } // A Result summarizes an executed SQL command. type Result interface { // 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) } type driverResult struct { sync.Locker // the *driverConn resi driver.Result } func ( driverResult) () (int64, error) { .Lock() defer .Unlock() return .resi.LastInsertId() } func ( driverResult) () (int64, error) { .Lock() defer .Unlock() return .resi.RowsAffected() } func stack() string { var [2 << 10]byte return string([:runtime.Stack([:], false)]) } // withLock runs while holding lk. func withLock( sync.Locker, func()) { .Lock() defer .Unlock() // in case fn panics () } // connRequestSet is a set of chan connRequest that's // optimized for: // // - adding an element // - removing an element (only by the caller who added it) // - taking (get + delete) a random element // // We previously used a map for this but the take of a random element // was expensive, making mapiters. This type avoids a map entirely // and just uses a slice. type connRequestSet struct { // s are the elements in the set. s []connRequestAndIndex } type connRequestAndIndex struct { // req is the element in the set. req chan connRequest // curIdx points to the current location of this element in // connRequestSet.s. It gets set to -1 upon removal. curIdx *int } // CloseAndRemoveAll closes all channels in the set // and clears the set. func ( *connRequestSet) () { for , := range .s { close(.req) } .s = nil } // Len returns the length of the set. func ( *connRequestSet) () int { return len(.s) } // connRequestDelHandle is an opaque handle to delete an // item from calling Add. type connRequestDelHandle struct { idx *int // pointer to index; or -1 if not in slice } // Add adds v to the set of waiting requests. // The returned connRequestDelHandle can be used to remove the item from // the set. func ( *connRequestSet) ( chan connRequest) connRequestDelHandle { := len(.s) // TODO(bradfitz): for simplicity, this always allocates a new int-sized // allocation to store the index. But generally the set will be small and // under a scannable-threshold. As an optimization, we could permit the *int // to be nil when the set is small and should be scanned. This works even if // the set grows over the threshold with delete handles outstanding because // an element can only move to a lower index. So if it starts with a nil // position, it'll always be in a low index and thus scannable. But that // can be done in a follow-up change. := & .s = append(.s, connRequestAndIndex{, }) return connRequestDelHandle{} } // Delete removes an element from the set. // // It reports whether the element was deleted. (It can return false if a caller // of TakeRandom took it meanwhile, or upon the second call to Delete) func ( *connRequestSet) ( connRequestDelHandle) bool { := *.idx if < 0 { return false } .deleteIndex() return true } func ( *connRequestSet) ( int) { // Mark item as deleted. *(.s[].curIdx) = -1 // Copy last element, updating its position // to its new home. if < len(.s)-1 { := .s[len(.s)-1] *.curIdx = .s[] = } // Zero out last element (for GC) before shrinking the slice. .s[len(.s)-1] = connRequestAndIndex{} .s = .s[:len(.s)-1] } // TakeRandom returns and removes a random element from s // and reports whether there was one to take. (It returns ok=false // if the set is empty.) func ( *connRequestSet) () ( chan connRequest, bool) { if len(.s) == 0 { return nil, false } := rand.IntN(len(.s)) := .s[] .deleteIndex() return .req, true }