Skip to content
Snippets Groups Projects
sql.go 69.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	}
    }
    
    // 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.
    
    Shenghou Ma's avatar
    Shenghou Ma committed
    // err is optionally the last error that occurred on this connection.
    
    func (db *DB) putConn(dc *driverConn, err error) {
    
    			fmt.Printf("putConn(%v) DUPLICATE was: %s\n\nPREVIOUS was: %s", dc, stack(), db.lastPut[dc])
    
    		}
    		panic("sql: connection returned that was never out")
    	}
    	if debugGetPut {
    
    	if err == 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.
    
    		db.maybeOpenNewConnections()
    
    	added := db.putConnDBLocked(dc, nil)
    
    	db.mu.Unlock()
    
    	if !added {
    		dc.Close()
    	}
    }
    
    // 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.
    
    Robert Hencke's avatar
    Robert Hencke committed
    // If a connRequest was fulfilled or the *driverConn was placed in the
    
    // freeConn list, then true is returned, otherwise false is returned.
    func (db *DB) putConnDBLocked(dc *driverConn, err error) bool {
    
    	if db.maxOpen > 0 && db.numOpen > db.maxOpen {
    		return false
    	}
    
    	if c := len(db.connRequests); c > 0 {
    
    		var req chan connRequest
    		var reqKey uint64
    		for reqKey, req = range db.connRequests {
    			break
    		}
    		delete(db.connRequests, reqKey) // Remove from pending requests.
    
    			dc.inUse = true
    
    		}
    		return true
    
    	} else if err == nil && !db.closed && db.maxIdleConnsLocked() > len(db.freeConn) {
    		db.freeConn = append(db.freeConn, dc)
    
    		db.startCleanerLocked()
    
    		return true
    	}
    	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
    
    // PrepareContext creates a prepared statement for later queries or executions.
    
    // Multiple queries or executions may be run concurrently from the
    // returned statement.
    
    // The caller must call the statement's Close method
    // when the statement is no longer needed.
    
    // The provided context is used for the preparation of the statement, not for the
    // execution of the statement.
    
    func (db *DB) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
    
    	var stmt *Stmt
    	var err error
    
    	for i := 0; i < maxBadConnRetries; i++ {
    
    		stmt, err = db.prepare(ctx, query, cachedOrNewConn)
    
    		if err != driver.ErrBadConn {
    			break
    		}
    	}
    
    		return db.prepare(ctx, query, alwaysNewConn)
    
    // Prepare creates a prepared statement for later queries or executions.
    // Multiple queries or executions may be run concurrently from the
    // returned statement.
    // The caller must call the statement's Close method
    // when the statement is no longer needed.
    func (db *DB) Prepare(query string) (*Stmt, error) {
    	return db.PrepareContext(context.Background(), query)
    }
    
    func (db *DB) prepare(ctx context.Context, query string, strategy 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.
    
    	dc, err := db.conn(ctx, strategy)
    
    	if err != nil {
    		return nil, err
    	}
    
    	return db.prepareDC(ctx, dc, dc.releaseConn, query)
    }
    
    func (db *DB) prepareDC(ctx context.Context, dc *driverConn, release func(error), query string) (*Stmt, error) {
    
    	var err error
    	defer func() {
    		release(err)
    	}()
    
    		ds, err = dc.prepareLocked(ctx, query)
    
    	if err != nil {
    		return nil, err
    	}
    
    		css:           []connStmt{{dc, ds}},
    
    		lastNumClosed: atomic.LoadUint64(&db.numClosed),
    
    	db.addDep(stmt, stmt)
    
    // ExecContext executes a query without returning any rows.
    
    // The args are for any placeholder parameters in the query.
    
    func (db *DB) ExecContext(ctx context.Context, query string, args ...interface{}) (Result, error) {
    
    	var res Result
    
    	for i := 0; i < maxBadConnRetries; i++ {
    
    		res, err = db.exec(ctx, query, args, cachedOrNewConn)
    
    		if err != driver.ErrBadConn {
    			break
    		}
    
    		return db.exec(ctx, query, args, alwaysNewConn)
    
    // Exec executes a query without returning any rows.
    // The args are for any placeholder parameters in the query.
    func (db *DB) Exec(query string, args ...interface{}) (Result, error) {
    	return db.ExecContext(context.Background(), query, args...)
    }
    
    
    func (db *DB) exec(ctx context.Context, query string, args []interface{}, strategy connReuseStrategy) (Result, error) {
    
    	dc, err := db.conn(ctx, strategy)
    
    	if err != nil {
    		return nil, err
    	}
    
    	return db.execDC(ctx, dc, dc.releaseConn, query, args)
    }
    
    func (db *DB) execDC(ctx context.Context, dc *driverConn, release func(error), query string, args []interface{}) (res Result, err error) {
    
    	if execer, ok := dc.ci.(driver.Execer); ok {
    
    		dargs, err = driverArgs(nil, args)
    
    		var resi driver.Result
    		withLock(dc, func() {
    
    			resi, err = ctxDriverExec(ctx, execer, query, dargs)
    
    		if err != driver.ErrSkip {
    			if err != nil {
    				return nil, err
    			}
    
    			return driverResult{dc, resi}, nil
    
    	var si driver.Stmt
    	withLock(dc, func() {
    
    		si, err = ctxDriverPrepare(ctx, dc.ci, query)
    
    	if err != nil {
    		return nil, err
    	}
    
    	ds := &driverStmt{Locker: dc, si: si}
    	defer ds.Close()
    	return resultFromStatement(ctx, ds, args...)
    
    // QueryContext executes a query that returns rows, typically a SELECT.
    
    // The args are for any placeholder parameters in the query.
    
    func (db *DB) QueryContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
    
    	for i := 0; i < maxBadConnRetries; i++ {
    
    		rows, err = db.query(ctx, query, args, cachedOrNewConn)
    
    		return db.query(ctx, query, args, alwaysNewConn)
    
    // Query executes a query that returns rows, typically a SELECT.
    // The args are for any placeholder parameters in the query.
    func (db *DB) Query(query string, args ...interface{}) (*Rows, error) {
    	return db.QueryContext(context.Background(), query, args...)
    }
    
    func (db *DB) query(ctx context.Context, query string, args []interface{}, strategy connReuseStrategy) (*Rows, error) {
    
    	dc, err := db.conn(ctx, strategy)
    
    	if err != nil {
    		return nil, err
    	}
    
    	return db.queryDC(ctx, dc, dc.releaseConn, query, args)
    
    // queryDC executes a query on the given connection.
    
    // The connection gets released by the releaseConn function.
    
    func (db *DB) queryDC(ctx context.Context, dc *driverConn, releaseConn func(error), query string, args []interface{}) (*Rows, error) {
    
    	if queryer, ok := dc.ci.(driver.Queryer); ok {
    
    		dargs, err := driverArgs(nil, args)
    		if err != nil {
    			releaseConn(err)
    			return nil, err
    		}
    
    		var rowsi driver.Rows
    		withLock(dc, func() {
    
    			rowsi, err = ctxDriverQuery(ctx, queryer, query, dargs)
    
    		if err != driver.ErrSkip {
    			if err != nil {
    				releaseConn(err)
    				return nil, err
    			}
    
    			// Note: ownership of dc passes to the *Rows, to be freed
    
    			// with releaseConn.
    			rows := &Rows{
    
    				releaseConn: releaseConn,
    				rowsi:       rowsi,
    			}
    
    			rows.initContextClose(ctx)
    
    	var si driver.Stmt
    	var err error
    	withLock(dc, func() {
    
    		si, err = ctxDriverPrepare(ctx, dc.ci, query)
    
    	if err != nil {
    
    		return nil, err
    	}
    
    	ds := &driverStmt{Locker: dc, si: si}
    
    	rowsi, err := rowsiFromStatement(ctx, ds, args...)
    
    		return nil, err
    	}
    
    	// Note: ownership of ci passes to the *Rows, to be freed
    	// with releaseConn.
    	rows := &Rows{
    
    		releaseConn: releaseConn,
    		rowsi:       rowsi,
    
    	rows.initContextClose(ctx)
    
    	return rows, 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.
    func (db *DB) QueryRowContext(ctx context.Context, query string, args ...interface{}) *Row {
    	rows, err := db.QueryContext(ctx, query, args...)
    	return &Row{rows: rows, err: err}
    }
    
    
    // QueryRow executes a query that is expected to return at most one row.
    
    Evan Shaw's avatar
    Evan Shaw committed
    // QueryRow always returns a non-nil value. Errors are deferred until
    
    // Row's Scan method is called.
    func (db *DB) QueryRow(query string, args ...interface{}) *Row {
    
    	return db.QueryRowContext(context.Background(), query, args...)
    
    // 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 *DB) BeginTx(ctx context.Context, opts *TxOptions) (*Tx, error) {
    
    	var tx *Tx
    	var err error
    
    	for i := 0; i < maxBadConnRetries; i++ {
    
    		tx, err = db.begin(ctx, opts, cachedOrNewConn)
    
    		if err != driver.ErrBadConn {
    			break
    		}
    	}
    
    		return db.begin(ctx, opts, alwaysNewConn)
    
    // Begin starts a transaction. The default isolation level is dependent on
    // the driver.
    func (db *DB) Begin() (*Tx, error) {
    
    	return db.BeginTx(context.Background(), nil)
    
    func (db *DB) begin(ctx context.Context, opts *TxOptions, strategy connReuseStrategy) (tx *Tx, err error) {
    
    	dc, err := db.conn(ctx, strategy)
    
    	if err != nil {
    		return nil, err
    	}
    
    	return db.beginDC(ctx, dc, dc.releaseConn, opts)
    }
    
    // beginDC starts a transaction. The provided dc must be valid and ready to use.
    func (db *DB) beginDC(ctx context.Context, dc *driverConn, release func(error), opts *TxOptions) (tx *Tx, err error) {
    
    	var txi driver.Tx
    	withLock(dc, func() {
    
    		txi, err = ctxDriverBegin(ctx, opts, dc.ci)
    
    
    	// Schedule the transaction to rollback when the context is cancelled.
    	// The cancel function in Tx will be called after done is set to true.
    	ctx, cancel := context.WithCancel(ctx)
    	tx = &Tx{
    
    		db:          db,
    		dc:          dc,
    		releaseConn: release,
    		txi:         txi,
    		cancel:      cancel,
    		ctx:         ctx,
    
    	return tx, nil
    
    // Driver returns the database's underlying driver.
    
    func (db *DB) Driver() driver.Driver {
    	return db.driver
    }
    
    // Tx is an in-progress database transaction.
    
    //
    // A transaction must end with a call to Commit or Rollback.
    //
    // After a call to Commit or Rollback, all operations on the
    
    // transaction fail with ErrTxDone.
    
    //
    // The statements prepared for a transaction by calling
    // the transaction's Prepare or Stmt methods are closed
    // by the call to Commit or Rollback.
    
    type Tx struct {
    
    	// 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.
    
    	// releaseConn is called once the Tx is closed to release
    	// any held driverConn back to the pool.
    	releaseConn func(error)
    
    
    	// done transitions from 0 to 1 exactly once, on Commit
    
    	// or Rollback. once done, all operations fail with
    
    	// Use atomic operations on value when checking value.
    	done int32
    
    	// 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 *Tx) awaitDone() {
    	// Wait for either the transaction to be committed or rolled
    	// back, or for the associated context to be closed.
    	<-tx.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.
    	tx.rollback(true)
    }
    
    
    func (tx *Tx) isDone() bool {
    	return atomic.LoadInt32(&tx.done) != 0
    
    // 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.
    
    func (tx *Tx) close(err error) {
    
    	tx.closemu.Lock()
    	defer tx.closemu.Unlock()
    
    
    	tx.releaseConn(err)
    
    // hookTxGrabConn specifies an optional hook to be called on
    // a successful call to (*Tx).grabConn. For tests.
    var hookTxGrabConn func()
    
    
    func (tx *Tx) grabConn(ctx context.Context) (*driverConn, error) {
    
    	select {
    	default:
    	case <-ctx.Done():
    		return nil, ctx.Err()
    	}
    
    	if hookTxGrabConn != nil { // test hook
    		hookTxGrabConn()
    	}
    
    // closemuRUnlockRelease is used as a func(error) method value in
    // ExecContext and QueryContext. Unlocking in the releaseConn keeps
    // the driver conn from being returned to the connection pool until
    // the Rows has been closed.
    func (tx *Tx) closemuRUnlockRelease(error) {
    	tx.closemu.RUnlock()
    }
    
    
    // Closes all Stmts prepared for this transaction.
    func (tx *Tx) closePrepared() {
    	tx.stmts.Lock()
    
    // Commit commits the transaction.
    
    func (tx *Tx) Commit() error {
    
    	if !atomic.CompareAndSwapInt32(&tx.done, 0, 1) {
    
    	select {
    	default:
    	case <-tx.ctx.Done():
    		return tx.ctx.Err()
    	}
    
    	var err error
    	withLock(tx.dc, func() {
    		err = tx.txi.Commit()
    	})
    
    	if err != driver.ErrBadConn {
    		tx.closePrepared()
    	}
    
    // rollback aborts the transaction and optionally forces the pool to discard
    // the connection.
    func (tx *Tx) rollback(discardConn bool) error {
    
    	if !atomic.CompareAndSwapInt32(&tx.done, 0, 1) {
    
    	var err error
    	withLock(tx.dc, func() {
    		err = tx.txi.Rollback()
    	})
    
    	if err != driver.ErrBadConn {
    		tx.closePrepared()
    	}
    
    // Rollback aborts the transaction.
    func (tx *Tx) Rollback() error {
    	return tx.rollback(false)
    }
    
    
    // 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.
    
    //
    // 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 *Tx) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
    
    	tx.closemu.RLock()
    	defer tx.closemu.RUnlock()
    
    
    	dc, err := tx.grabConn(ctx)
    
    	var si driver.Stmt
    	withLock(dc, func() {
    
    		si, err = ctxDriverPrepare(ctx, dc.ci, query)
    
    	if err != nil {
    		return nil, err
    	}
    
    	stmt := &Stmt{
    
    	tx.stmts.Lock()
    	tx.stmts.v = append(tx.stmts.v, stmt)
    	tx.stmts.Unlock()
    
    // Prepare creates a prepared statement for use within a transaction.
    //
    // The returned statement operates within the transaction and can no longer
    // be used once the transaction has been committed or rolled back.
    //
    // To use an existing prepared statement on this transaction, see Tx.Stmt.
    func (tx *Tx) Prepare(query string) (*Stmt, error) {
    	return tx.PrepareContext(context.Background(), query)
    }
    
    // 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 returned statement operates within the transaction and will be closed
    // when the transaction has been committed or rolled back.
    
    func (tx *Tx) StmtContext(ctx context.Context, stmt *Stmt) *Stmt {
    
    	tx.closemu.RLock()
    	defer tx.closemu.RUnlock()
    
    
    	if tx.db != stmt.db {
    		return &Stmt{stickyErr: errors.New("sql: Tx.Stmt: statement from different database used")}
    	}
    
    	dc, err := tx.grabConn(ctx)
    
    	if err != nil {
    		return &Stmt{stickyErr: err}
    	}
    
    	var parentStmt *Stmt
    	stmt.mu.Lock()
    	if stmt.closed || stmt.tx != 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.
    		stmt.mu.Unlock()
    		withLock(dc, func() {
    			si, err = ctxDriverPrepare(ctx, dc.ci, stmt.query)
    		})
    		if err != nil {
    			return &Stmt{stickyErr: err}
    		}
    	} else {
    		stmt.removeClosedStmtLocked()
    		// See if the statement has already been prepared on this connection,
    		// and reuse it if possible.
    		for _, v := range stmt.css {
    			if v.dc == dc {
    				si = v.ds.si
    				break
    			}
    		}
    
    		stmt.mu.Unlock()
    
    		if si == nil {
    			cs, err := stmt.prepareOnConnLocked(ctx, dc)
    			if err != nil {
    				return &Stmt{stickyErr: err}
    			}
    			si = cs.si
    		}
    		parentStmt = stmt
    	}
    
    
    		parentStmt: parentStmt,
    		query:      stmt.query,
    	}
    	if parentStmt != nil {
    		tx.db.addDep(parentStmt, txs)
    
    	tx.stmts.Lock()
    	tx.stmts.v = append(tx.stmts.v, txs)
    	tx.stmts.Unlock()
    	return txs
    
    // 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.
    
    func (tx *Tx) Stmt(stmt *Stmt) *Stmt {
    	return tx.StmtContext(context.Background(), stmt)
    }
    
    // ExecContext executes a query that doesn't return rows.
    
    // For example: an INSERT and UPDATE.
    
    func (tx *Tx) ExecContext(ctx context.Context, query string, args ...interface{}) (Result, error) {
    
    	dc, err := tx.grabConn(ctx)
    
    	return tx.db.execDC(ctx, dc, tx.closemuRUnlockRelease, query, args)
    
    // Exec executes a query that doesn't return rows.
    // For example: an INSERT and UPDATE.
    func (tx *Tx) Exec(query string, args ...interface{}) (Result, error) {
    	return tx.ExecContext(context.Background(), query, args...)
    }
    
    // QueryContext executes a query that returns rows, typically a SELECT.
    func (tx *Tx) QueryContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
    
    	dc, err := tx.grabConn(ctx)
    
    
    	return tx.db.queryDC(ctx, dc, tx.closemuRUnlockRelease, query, args)
    
    }
    
    // Query executes a query that returns rows, typically a SELECT.
    func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error) {
    	return tx.QueryContext(context.Background(), query, args...)
    }
    
    // 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.
    func (tx *Tx) QueryRowContext(ctx context.Context, query string, args ...interface{}) *Row {
    	rows, err := tx.QueryContext(ctx, query, args...)
    	return &Row{rows: rows, err: err}
    
    }
    
    // QueryRow executes a query that is expected to return at most one row.
    
    Evan Shaw's avatar
    Evan Shaw committed
    // QueryRow always returns a non-nil value. Errors are deferred until
    
    // Row's Scan method is called.
    func (tx *Tx) QueryRow(query string, args ...interface{}) *Row {
    
    	return tx.QueryRowContext(context.Background(), query, args...)
    
    }
    
    // connStmt is a prepared statement on a particular connection.
    type connStmt struct {
    
    // Stmt is a prepared statement.
    // A Stmt is safe for concurrent use by multiple goroutines.
    
    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 in a transaction, else both nil:
    	tx   *Tx
    
    	// 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
    
    	// css is a list of underlying driver statement interfaces
    
    	// that are valid on particular connections. This is only
    
    	// used if tx == nil and one is found that has idle
    
    	// connections. If tx != nil, txds is always used.
    
    
    	// 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 (s *Stmt) ExecContext(ctx context.Context, args ...interface{}) (Result, error) {
    
    	s.closemu.RLock()
    	defer s.closemu.RUnlock()
    
    	var res Result
    	for i := 0; i < maxBadConnRetries; i++ {
    
    		_, releaseConn, ds, err := s.connStmt(ctx)
    
    		if err != nil {
    			if err == driver.ErrBadConn {
    				continue
    			}
    			return nil, err
    		}
    
    
    		res, err = resultFromStatement(ctx, ds, args...)
    
    		releaseConn(err)
    		if err != driver.ErrBadConn {
    			return res, err
    		}
    	}
    	return nil, driver.ErrBadConn
    
    // Exec executes a prepared statement with the given arguments and
    // returns a Result summarizing the effect of the statement.
    func (s *Stmt) Exec(args ...interface{}) (Result, error) {
    	return s.ExecContext(context.Background(), args...)
    }
    
    
    func driverNumInput(ds *driverStmt) int {
    
    	defer ds.Unlock() // in case NumInput panics
    	return ds.si.NumInput()
    }
    
    
    func resultFromStatement(ctx context.Context, ds *driverStmt, args ...interface{}) (Result, error) {
    
    	// -1 means the driver doesn't know how to count the number of
    	// placeholders, so we won't sanity check input here and instead let the
    	// driver deal with errors.
    
    	if want != -1 && len(args) != want {
    
    Brad Fitzpatrick's avatar
    Brad Fitzpatrick committed
    		return nil, fmt.Errorf("sql: expected %d arguments, got %d", want, len(args))
    
    	dargs, err := driverArgs(ds, args)
    
    
    	resi, err := ctxDriverStmtExec(ctx, ds.si, dargs)
    
    	if err != nil {
    		return nil, err
    	}
    
    	return driverResult{ds.Locker, resi}, 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 (s *Stmt) removeClosedStmtLocked() {
    	t := len(s.css)/2 + 1
    	if t > 10 {
    		t = 10
    	}
    	dbClosed := atomic.LoadUint64(&s.db.numClosed)
    	if dbClosed-s.lastNumClosed < uint64(t) {
    		return
    	}
    
    	s.db.mu.Lock()
    	for i := 0; i < len(s.css); i++ {
    		if s.css[i].dc.dbmuClosed {
    			s.css[i] = s.css[len(s.css)-1]
    			s.css = s.css[:len(s.css)-1]
    			i--
    		}
    	}
    	s.db.mu.Unlock()
    	s.lastNumClosed = dbClosed
    }
    
    
    // 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 (s *Stmt) connStmt(ctx context.Context) (ci *driverConn, releaseConn func(error), ds *driverStmt, err error) {
    
    	if err = s.stickyErr; err != nil {
    		return
    
    	s.mu.Lock()
    	if s.closed {
    
    Brad Fitzpatrick's avatar
    Brad Fitzpatrick committed
    		err = errors.New("sql: statement is closed")
    
    
    	// In a transaction, we always use the connection that the
    	// transaction was created on.
    	if s.tx != nil {
    		s.mu.Unlock()
    
    		ci, err = s.tx.grabConn(ctx) // blocks, waiting for the connection.
    
    		releaseConn = func(error) {}
    
    		return ci, releaseConn, s.txds, nil
    
    	s.removeClosedStmtLocked()
    
    	dc, err := s.db.conn(ctx, cachedOrNewConn)
    
    	if err != nil {
    		return nil, nil, nil, err
    	}
    
    	s.mu.Lock()
    	for _, v := range s.css {
    		if v.dc == dc {
    			s.mu.Unlock()
    
    			return dc, dc.releaseConn, v.ds, nil
    
    	s.mu.Unlock()
    
    	// No luck; we need to prepare the statement on this connection
    
    		ds, err = s.prepareOnConnLocked(ctx, dc)
    
    		dc.releaseConn(err)
    
    
    	return dc, dc.releaseConn, ds, 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 (s *Stmt) prepareOnConnLocked(ctx context.Context, dc *driverConn) (*driverStmt, error) {
    	si, err := dc.prepareLocked(ctx, s.query)
    	if err != nil {
    		return nil, err
    	}
    	cs := connStmt{dc, si}
    
    	s.mu.Lock()
    	s.css = append(s.css, cs)
    	s.mu.Unlock()
    
    // QueryContext executes a prepared query statement with the given arguments
    
    // and returns the query results as a *Rows.
    
    func (s *Stmt) QueryContext(ctx context.Context, args ...interface{}) (*Rows, error) {
    
    	s.closemu.RLock()
    	defer s.closemu.RUnlock()
    
    
    	var rowsi driver.Rows
    	for i := 0; i < maxBadConnRetries; i++ {
    
    		dc, releaseConn, ds, err := s.connStmt(ctx)
    
    		if err != nil {
    			if err == driver.ErrBadConn {
    				continue
    			}
    			return nil, err
    		}
    
    		rowsi, err = rowsiFromStatement(ctx, ds, args...)
    
    		if err == nil {
    			// Note: ownership of ci passes to the *Rows, to be freed
    			// with releaseConn.
    			rows := &Rows{
    				dc:    dc,
    				rowsi: rowsi,
    				// releaseConn set below
    			}
    
    			rows.initContextClose(ctx)
    
    			s.db.addDep(s, rows)
    			rows.releaseConn = func(err error) {
    				releaseConn(err)
    				s.db.removeDep(s, rows)