Skip to content
Snippets Groups Projects
sql.go 83.9 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	}
    	if err != nil {
    
    		db.putConnDBLocked(nil, err)
    
    		db.maybeOpenNewConnections()
    
    		return
    	}
    	dc := &driverConn{
    
    		db:        db,
    		createdAt: nowFunc(),
    		ci:        ci,
    
    	if db.putConnDBLocked(dc, err) {
    		db.addDepLocked(dc, dc)
    	} else {
    
    }
    
    // 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")
    
    
    // nextRequestKeyLocked returns the next connection request key.
    // It is assumed that nextRequest will not overflow.
    func (db *DB) nextRequestKeyLocked() uint64 {
    	next := db.nextRequest
    	db.nextRequest++
    	return next
    }
    
    
    // conn returns a newly-opened or cached *driverConn.
    
    func (db *DB) conn(ctx context.Context, strategy connReuseStrategy) (*driverConn, error) {
    
    		return nil, errDBClosed
    	}
    
    	// Check if the context is expired.
    
    	lifetime := db.maxLifetime
    
    	// Prefer a free connection, if possible.
    	numFree := len(db.freeConn)
    	if strategy == cachedOrNewConn && numFree > 0 {
    		conn := db.freeConn[0]
    		copy(db.freeConn, db.freeConn[1:])
    		db.freeConn = db.freeConn[:numFree-1]
    		conn.inUse = true
    		db.mu.Unlock()
    
    		if conn.expired(lifetime) {
    			conn.Close()
    			return nil, driver.ErrBadConn
    		}
    
    		// Lock around reading lastErr to ensure the session resetter finished.
    		conn.Lock()
    		err := conn.lastErr
    		conn.Unlock()
    		if err == driver.ErrBadConn {
    			conn.Close()
    			return nil, driver.ErrBadConn
    		}
    
    	// 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 db.maxOpen > 0 && db.numOpen >= db.maxOpen {
    
    		// Make the connRequest channel. It's buffered so that the
    		// connectionOpener doesn't block while waiting for the req to be read.
    
    		req := make(chan connRequest, 1)
    
    		reqKey := db.nextRequestKeyLocked()
    		db.connRequests[reqKey] = req
    
    		db.mu.Unlock()
    
    
    		// Timeout the connection request with the context.
    		select {
    		case <-ctx.Done():
    
    			// Remove the connection request and ensure no value has been sent
    			// on it after removing.
    			db.mu.Lock()
    			delete(db.connRequests, reqKey)
    
    					db.putConn(ret.conn, ret.err, false)
    
    			return nil, ctx.Err()
    		case ret, ok := <-req:
    			if !ok {
    				return nil, errDBClosed
    			}
    			if ret.err == nil && ret.conn.expired(lifetime) {
    				ret.conn.Close()
    				return nil, driver.ErrBadConn
    			}
    
    			if ret.conn == nil {
    				return nil, ret.err
    			}
    			// Lock around reading lastErr to ensure the session resetter finished.
    			ret.conn.Lock()
    			err := ret.conn.lastErr
    			ret.conn.Unlock()
    			if err == driver.ErrBadConn {
    				ret.conn.Close()
    				return nil, driver.ErrBadConn
    			}
    
    			return ret.conn, ret.err
    
    	db.numOpen++ // optimistically
    
    	db.mu.Unlock()
    
    	ci, err := db.connector.Connect(ctx)
    
    		db.mu.Lock()
    		db.numOpen-- // correct for earlier optimism
    
    		db.maybeOpenNewConnections()
    
    	db.mu.Lock()
    
    		db:        db,
    		createdAt: nowFunc(),
    		ci:        ci,
    
    // 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 *DB) noteUnusedDriverStatement(c *driverConn, ds *driverStmt) {
    
    	db.mu.Lock()
    	defer db.mu.Unlock()
    
    	if c.inUse {
    		c.onPut = append(c.onPut, func() {
    
    		fc := c.finalClosed
    		c.Unlock()
    		if !fc {
    			ds.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.
    
    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, resetSession bool) {
    
    			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()
    
    	if db.closed {
    		// Connections do not need to be reset if they will be closed.
    		// Prevents writing to resetterCh after the DB has closed.
    		resetSession = false
    	}
    
    		if _, resetSession = dc.ci.(driver.SessionResetter); resetSession {
    
    			// Lock the driverConn here so it isn't released until
    			// the connection is reset.
    			// The lock must be taken before the connection is put into
    			// the pool to prevent it from being taken out before it is reset.
    			dc.Lock()
    		}
    	}
    
    	added := db.putConnDBLocked(dc, nil)
    
    	db.mu.Unlock()
    
    	if !added {
    
    		dc.Close()
    
    		return
    	}
    	if !resetSession {
    		return
    	}
    	select {
    	default:
    		// If the resetterCh is blocking then mark the connection
    		// as bad and continue on.
    		dc.lastErr = driver.ErrBadConn
    		dc.Unlock()
    	case db.resetterCh <- dc:
    
    	}
    }
    
    // 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, nil, query)
    
    // 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 *DB) prepareDC(ctx context.Context, dc *driverConn, release func(error), cg stmtConnGrabber, query string) (*Stmt, error) {
    
    	var err error
    	defer func() {
    		release(err)
    	}()
    
    		ds, err = dc.prepareLocked(ctx, cg, query)
    
    	if err != nil {
    		return nil, err
    	}
    
    		db:    db,
    		query: query,
    		cg:    cg,
    		cgds:  ds,
    	}
    
    	// 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 cg == nil {
    		stmt.css = []connStmt{{dc, ds}}
    		stmt.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) {
    
    	execerCtx, ok := dc.ci.(driver.ExecerContext)
    	var execer driver.Execer
    	if !ok {
    		execer, ok = dc.ci.(driver.Execer)
    	}
    	if ok {
    		var nvdargs []driver.NamedValue
    
    		var resi driver.Result
    		withLock(dc, func() {
    
    			nvdargs, err = driverArgsConnLocked(dc.ci, nil, args)
    			if err != nil {
    				return
    			}
    
    			resi, err = ctxDriverExec(ctx, execerCtx, execer, query, nvdargs)
    
    		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, dc.ci, 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, nil, dc, dc.releaseConn, query, args)
    
    // 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 *DB) queryDC(ctx, txctx context.Context, dc *driverConn, releaseConn func(error), query string, args []interface{}) (*Rows, error) {
    
    	queryerCtx, ok := dc.ci.(driver.QueryerContext)
    	var queryer driver.Queryer
    	if !ok {
    		queryer, ok = dc.ci.(driver.Queryer)
    	}
    	if ok {
    
    			nvdargs, err = driverArgsConnLocked(dc.ci, nil, args)
    			if err != nil {
    				return
    			}
    
    			rowsi, err = ctxDriverQuery(ctx, queryerCtx, queryer, query, nvdargs)
    
    		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, txctx)
    
    	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, dc.ci, 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, txctx)
    
    	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.
    
    // If the query selects no rows, the *Row's Scan will return ErrNoRows.
    // Otherwise, the *Row's Scan scans the first selected row and discards
    // the rest.
    
    func (db *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.
    
    // If the query selects no rows, the *Row's Scan will return ErrNoRows.
    // Otherwise, the *Row's Scan scans the first selected row and discards
    // the rest.
    
    func (db *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 {
    
    // 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("database/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 *DB) Conn(ctx context.Context) (*Conn, error) {
    	var dc *driverConn
    	var err error
    	for i := 0; i < maxBadConnRetries; i++ {
    		dc, err = db.conn(ctx, cachedOrNewConn)
    		if err != driver.ErrBadConn {
    			break
    		}
    	}
    	if err == driver.ErrBadConn {
    		dc, err = db.conn(ctx, cachedOrNewConn)
    	}
    	if err != nil {
    		return nil, err
    	}
    
    	conn := &Conn{
    		db: db,
    		dc: dc,
    	}
    	return conn, nil
    }
    
    
    // Conn represents a single database connection rather than a pool of database
    // connections. Prefer running queries from DB unless there is a specific
    // need for a continuous single database connection.
    
    //
    // A Conn must call Close to return the connection to the database pool
    // and may do so concurrently with a running query.
    //
    // After a call to Close, all operations on the
    // connection fail with ErrConnDone.
    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 0 to 1 exactly once, on close.
    	// Once done, all operations fail with ErrConnDone.
    	// Use atomic operations on value when checking value.
    	done int32
    }
    
    
    func (c *Conn) grabConn(context.Context) (*driverConn, releaseConn, error) {
    
    	if atomic.LoadInt32(&c.done) != 0 {
    
    	c.closemu.RLock()
    	return c.dc, c.closemuRUnlockCondReleaseConn, nil
    
    }
    
    // PingContext verifies the connection to the database is still alive.
    func (c *Conn) PingContext(ctx context.Context) error {
    
    }
    
    // ExecContext executes a query without returning any rows.
    // The args are for any placeholder parameters in the query.
    func (c *Conn) ExecContext(ctx context.Context, query string, args ...interface{}) (Result, error) {
    
    	return c.db.execDC(ctx, dc, release, query, args)
    
    }
    
    // QueryContext executes a query that returns rows, typically a SELECT.
    // The args are for any placeholder parameters in the query.
    func (c *Conn) QueryContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
    
    	return c.db.queryDC(ctx, nil, dc, release, 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.
    
    // If the query selects no rows, the *Row's Scan will return ErrNoRows.
    // Otherwise, the *Row's Scan scans the first selected row and discards
    // the rest.
    
    func (c *Conn) QueryRowContext(ctx context.Context, query string, args ...interface{}) *Row {
    	rows, err := c.QueryContext(ctx, query, args...)
    	return &Row{rows: rows, err: err}
    }
    
    // PrepareContext creates a prepared statement for later queries or executions.
    // Multiple queries or executions may be run concurrently from the
    // returned statement.
    // The caller must call the statement's Close method
    // when the statement is no longer needed.
    //
    // The provided context is used for the preparation of the statement, not for the
    // execution of the statement.
    func (c *Conn) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
    
    	return c.db.prepareDC(ctx, dc, release, c, query)
    
    }
    
    // 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 (c *Conn) BeginTx(ctx context.Context, opts *TxOptions) (*Tx, error) {
    
    	return c.db.beginDC(ctx, dc, release, opts)
    
    }
    
    // closemuRUnlockCondReleaseConn read unlocks closemu
    // as the sql operation is done with the dc.
    func (c *Conn) closemuRUnlockCondReleaseConn(err error) {
    	c.closemu.RUnlock()
    	if err == driver.ErrBadConn {
    		c.close(err)
    	}
    }
    
    
    func (c *Conn) close(err error) error {
    	if !atomic.CompareAndSwapInt32(&c.done, 0, 1) {
    		return ErrConnDone
    	}
    
    	// Lock around releasing the driver connection
    	// to ensure all queries have been stopped before doing so.
    	c.closemu.Lock()
    	defer c.closemu.Unlock()
    
    	c.dc.releaseConn(err)
    	c.dc = nil
    	c.db = nil
    	return err
    }
    
    // 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 (c *Conn) Close() error {
    	return c.close(nil)
    }
    
    
    // Tx is an in-progress database transaction.
    
    //
    // A transaction must end with a call to Commit or Rollback.
    //
    // After a call to Commit or Rollback, all operations on the
    
    // transaction fail with ErrTxDone.
    
    //
    // The statements prepared for a transaction by calling
    // the transaction's Prepare or Stmt methods are closed
    // by the call to Commit or Rollback.
    
    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, releaseConn, error) {
    
    
    	// closeme.RLock must come before the check for isDone to prevent the Tx from
    	// closing while a query is executing.
    	tx.closemu.RLock()
    
    		tx.closemu.RUnlock()
    		return nil, nil, ErrTxDone
    
    	if hookTxGrabConn != nil { // test hook
    		hookTxGrabConn()
    	}
    
    	return tx.dc, tx.closemuRUnlockRelease, nil
    }
    
    func (tx *Tx) txCtx() context.Context {
    	return tx.ctx
    
    // closemuRUnlockRelease is used as a func(error) method value in
    // ExecContext and QueryContext. Unlocking in the releaseConn keeps
    // the driver conn from being returned to the connection pool until
    // the Rows has been closed.
    func (tx *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 {
    
    	// 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.
    
    		if atomic.LoadInt32(&tx.done) == 1 {
    			return ErrTxDone
    		}
    
    	if !atomic.CompareAndSwapInt32(&tx.done, 0, 1) {
    		return ErrTxDone
    	}
    
    	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)
    }
    
    
    // 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