Skip to content
Snippets Groups Projects
sql.go 42.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • // 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.
    
    type Tx struct {
    
    	// dc is owned exclusively until Commit or Rollback, at which point
    
    	// it's returned with putConn.
    
    	txi driver.Tx
    
    	// done transitions from false to true exactly once, on Commit
    	// or Rollback. once done, all operations fail with
    
    var ErrTxDone = errors.New("sql: Transaction has already been committed or rolled back")
    
    
    func (tx *Tx) close() {
    	if tx.done {
    		panic("double close") // internal error
    	}
    	tx.done = true
    
    	tx.db.putConn(tx.dc, nil)
    	tx.dc = nil
    
    func (tx *Tx) grabConn() (*driverConn, error) {
    
    // Commit commits the transaction.
    
    func (tx *Tx) Commit() error {
    
    	tx.dc.Lock()
    	defer tx.dc.Unlock()
    
    }
    
    // Rollback aborts the transaction.
    
    func (tx *Tx) Rollback() error {
    
    	tx.dc.Lock()
    	defer tx.dc.Unlock()
    
    	return tx.txi.Rollback()
    
    // 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) {
    
    	// TODO(bradfitz): We could be more efficient here and either
    	// provide a method to take an existing Stmt (created on
    	// perhaps a different Conn), and re-create it on this Conn if
    	// necessary. Or, better: keep a map in DB of query string to
    	// Stmts, and have Stmt.Execute do the right thing and
    	// re-prepare if the Conn in use doesn't have that prepared
    	// statement.  But we'll want to avoid caching the statement
    	// in the case where we only call conn.Prepare implicitly
    	// (such as in db.Exec or tx.Exec), but the caller package
    	// can't be holding a reference to the returned statement.
    	// Perhaps just looking at the reference count (by noting
    	// Stmt.Close) would be enough. We might also want a finalizer
    	// on Stmt to drop the reference count.
    
    	dc.Lock()
    	si, err := dc.ci.Prepare(query)
    	dc.Unlock()
    
    	if err != nil {
    		return nil, err
    	}
    
    	stmt := &Stmt{
    
    		db: tx.db,
    		tx: tx,
    		txsi: &driverStmt{
    			Locker: dc,
    			si:     si,
    		},
    
    // 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)
    func (tx *Tx) Stmt(stmt *Stmt) *Stmt {
    	// TODO(bradfitz): optimize this. Currently this re-prepares
    	// each time.  This is fine for now to illustrate the API but
    	// we should really cache already-prepared statements
    	// per-Conn. See also the big comment in Tx.Prepare.
    
    	if tx.db != stmt.db {
    		return &Stmt{stickyErr: errors.New("sql: Tx.Stmt: statement from different database used")}
    	}
    
    	if err != nil {
    		return &Stmt{stickyErr: err}
    	}
    
    	dc.Lock()
    	si, err := dc.ci.Prepare(stmt.query)
    	dc.Unlock()
    
    		db: tx.db,
    		tx: tx,
    		txsi: &driverStmt{
    			Locker: dc,
    			si:     si,
    		},
    
    // 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) {
    
    	if execer, ok := dc.ci.(driver.Execer); ok {
    
    		dargs, err := driverArgs(nil, args)
    		if err != nil {
    			return nil, err
    		}
    
    		resi, err := execer.Exec(query, dargs)
    
    		if err == nil {
    
    			return driverResult{dc, resi}, nil
    
    		}
    		if err != driver.ErrSkip {
    
    	dc.Lock()
    	si, err := dc.ci.Prepare(query)
    	dc.Unlock()
    
    	if err != nil {
    		return nil, err
    	}
    
    	defer withLock(dc, func() { si.Close() })
    
    	return resultFromStatement(driverStmt{dc, si}, args...)
    
    }
    
    // Query executes a query that returns rows, typically a SELECT.
    
    func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error) {
    
    	if err != nil {
    		return nil, err
    
    	releaseConn := func(error) {}
    	return tx.db.queryConn(dc, releaseConn, query, args)
    
    }
    
    // QueryRow executes a query that is expected to return at most one row.
    // QueryRow always return a non-nil value. Errors are deferred until
    // Row's Scan method is called.
    func (tx *Tx) QueryRow(query string, args ...interface{}) *Row {
    
    	rows, err := tx.Query(query, args...)
    	return &Row{rows: rows, err: err}
    
    }
    
    // connStmt is a prepared statement on a particular connection.
    type connStmt struct {
    
    	si driver.Stmt
    }
    
    // Stmt is a prepared statement. 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
    
    
    	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, txsi is always used.
    	css []connStmt
    
    }
    
    // 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) {
    
    	s.closemu.RLock()
    	defer s.closemu.RUnlock()
    
    	dc, releaseConn, si, err := s.connStmt()
    
    	if err != nil {
    		return nil, err
    	}
    
    	return resultFromStatement(driverStmt{dc, si}, args...)
    
    func resultFromStatement(ds driverStmt, args ...interface{}) (Result, error) {
    	ds.Lock()
    	want := ds.si.NumInput()
    	ds.Unlock()
    
    
    	// -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)
    
    	ds.Lock()
    	resi, err := ds.si.Exec(dargs)
    	ds.Unlock()
    
    	if err != nil {
    		return nil, err
    	}
    
    	return driverResult{ds.Locker, resi}, nil
    
    // 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() (ci *driverConn, releaseConn func(error), si driver.Stmt, 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() // blocks, waiting for the connection.
    		if err != nil {
    			return
    		}
    
    		releaseConn = func(error) {}
    
    		return ci, releaseConn, s.txsi.si, nil
    
    	var cs connStmt
    	match := false
    
    	for i := 0; i < len(s.css); i++ {
    		v := s.css[i]
    		_, err := s.db.connIfFree(v.dc)
    		if err == nil {
    			match = true
    
    		if err == errConnClosed {
    			// Lazily remove dead conn from our freelist.
    			s.css[i] = s.css[len(s.css)-1]
    			s.css = s.css[:len(s.css)-1]
    			i--
    		}
    
    
    	}
    	s.mu.Unlock()
    
    	// Make a new conn if all are busy.
    	// TODO(bradfitz): or wait for one? make configurable later?
    	if !match {
    
    		for i := 0; ; i++ {
    
    			if err != nil {
    				return nil, nil, nil, err
    			}
    
    			si, err := dc.prepareLocked(s.query)
    
    			if err == driver.ErrBadConn && i < 10 {
    				continue
    			}
    			if err != nil {
    				return nil, nil, nil, err
    			}
    			s.mu.Lock()
    
    			s.css = append(s.css, cs)
    			s.mu.Unlock()
    			break
    
    	return conn, conn.releaseConn, cs.si, nil
    
    }
    
    // Query executes a prepared query statement with the given arguments
    // and returns the query results as a *Rows.
    
    func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
    
    	s.closemu.RLock()
    	defer s.closemu.RUnlock()
    
    
    	dc, releaseConn, si, err := s.connStmt()
    
    	if err != nil {
    		return nil, err
    	}
    
    	ds := driverStmt{dc, si}
    	rowsi, err := rowsiFromStatement(ds, args...)
    
    	if err != nil {
    		releaseConn(err)
    		return nil, err
    	}
    
    	// Note: ownership of ci passes to the *Rows, to be freed
    	// with releaseConn.
    	rows := &Rows{
    
    		rowsi: rowsi,
    		// releaseConn set below
    	}
    	s.db.addDep(s, rows)
    	rows.releaseConn = func(err error) {
    		releaseConn(err)
    		s.db.removeDep(s, rows)
    
    func rowsiFromStatement(ds driverStmt, args ...interface{}) (driver.Rows, error) {
    	ds.Lock()
    	want := ds.si.NumInput()
    	ds.Unlock()
    
    
    	// -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 {
    		return nil, fmt.Errorf("sql: statement expects %d inputs; got %d", want, len(args))
    
    	dargs, err := driverArgs(&ds, args)
    
    	ds.Lock()
    	rowsi, err := ds.si.Query(dargs)
    	ds.Unlock()
    
    	if err != nil {
    		return nil, err
    	}
    
    }
    
    // QueryRow executes a prepared query statement with the given arguments.
    // If an error occurs during the execution of the statement, that error will
    // be returned by a call to Scan on the returned *Row, which is always non-nil.
    // If the query selects no rows, the *Row's Scan will return ErrNoRows.
    // Otherwise, the *Row's Scan scans the first selected row and discards
    // the rest.
    //
    // Example usage:
    //
    //  var name string
    
    //  err := nameByUseridStmt.QueryRow(id).Scan(&name)
    
    func (s *Stmt) QueryRow(args ...interface{}) *Row {
    	rows, err := s.Query(args...)
    	if err != nil {
    		return &Row{err: err}
    	}
    	return &Row{rows: rows}
    }
    
    // Close closes the statement.
    
    func (s *Stmt) Close() error {
    
    	s.closemu.Lock()
    	defer s.closemu.Unlock()
    
    
    	if s.stickyErr != nil {
    		return s.stickyErr
    	}
    
    	s.mu.Lock()
    	if s.closed {
    
    		s.mu.Unlock()
    
    		return nil
    	}
    	s.closed = true
    
    		s.mu.Unlock()
    
    	s.mu.Unlock()
    
    
    	return s.db.removeDep(s, s)
    }
    
    func (s *Stmt) finalClose() error {
    
    	s.mu.Lock()
    	defer s.mu.Unlock()
    	if s.css != nil {
    		for _, v := range s.css {
    			s.db.noteUnusedDriverStatement(v.dc, v.si)
    			v.dc.removeOpenStmt(v.si)
    		}
    		s.css = nil
    
    	}
    	return nil
    }
    
    // Rows is the result of a query. Its cursor starts before the first row
    // of the result set. Use Next to advance through the rows:
    //
    //     rows, err := db.Query("SELECT ...")
    //     ...
    //     for rows.Next() {
    //         var id int
    //         var name string
    //         err = rows.Scan(&id, &name)
    //         ...
    //     }
    
    //     err = rows.Err() // get any error encountered during iteration
    
    //     ...
    type Rows struct {
    
    	dc          *driverConn // owned; must call releaseConn when closed to release
    
    	closed    bool
    
    	lastcols  []driver.Value
    
    	lasterr   error       // non-nil only if closed is true
    
    	closeStmt driver.Stmt // if non-nil, statement to Close on close
    
    }
    
    // Next prepares the next result row for reading with the Scan method.
    // It returns true on success, false if there is no next result row.
    // Every call to Scan, even the first one, must be preceded by a call
    // to Next.
    func (rs *Rows) Next() bool {
    	if rs.closed {
    		return false
    	}
    	if rs.lastcols == nil {
    
    		rs.lastcols = make([]driver.Value, len(rs.rowsi.Columns()))
    
    	}
    	rs.lasterr = rs.rowsi.Next(rs.lastcols)
    
    		rs.Close()
    
    // Err returns the error, if any, that was encountered during iteration.
    
    // Err may be called after an explicit or implicit Close.
    
    	if rs.lasterr == io.EOF {
    
    Brad Fitzpatrick's avatar
    Brad Fitzpatrick committed
    // Columns returns the column names.
    // Columns returns an error if the rows are closed, or if the rows
    // are from QueryRow and there was a deferred error.
    func (rs *Rows) Columns() ([]string, error) {
    	if rs.closed {
    		return nil, errors.New("sql: Rows are closed")
    	}
    	if rs.rowsi == nil {
    		return nil, errors.New("sql: no Rows available")
    	}
    	return rs.rowsi.Columns(), nil
    }
    
    
    // Scan copies the columns in the current row into the values pointed
    
    // at by dest.
    //
    // If an 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. If the value
    // is of type []byte, a copy is made and the caller owns the result.
    
    func (rs *Rows) Scan(dest ...interface{}) error {
    
    		return errors.New("sql: Rows are closed")
    
    	}
    	if rs.lastcols == nil {
    
    Brad Fitzpatrick's avatar
    Brad Fitzpatrick committed
    		return errors.New("sql: Scan called without calling Next")
    
    	}
    	if len(dest) != len(rs.lastcols) {
    
    Brad Fitzpatrick's avatar
    Brad Fitzpatrick committed
    		return fmt.Errorf("sql: expected %d destination arguments in Scan, not %d", len(rs.lastcols), len(dest))
    
    	}
    	for i, sv := range rs.lastcols {
    		err := convertAssign(dest[i], sv)
    		if err != nil {
    
    Brad Fitzpatrick's avatar
    Brad Fitzpatrick committed
    			return fmt.Errorf("sql: Scan error on column index %d: %v", i, err)
    
    var rowsCloseHook func(*Rows, *error)
    
    
    // Close closes the Rows, preventing further enumeration. If Next returns
    // false, the Rows are closed automatically and it will suffice to check the
    // result of Err. Close is idempotent and does not affect the result of Err.
    
    func (rs *Rows) Close() error {
    
    	if rs.closed {
    		return nil
    	}
    	rs.closed = true
    	err := rs.rowsi.Close()
    
    	if fn := rowsCloseHook; fn != nil {
    		fn(rs, &err)
    	}
    
    	if rs.closeStmt != nil {
    		rs.closeStmt.Close()
    	}
    
    	return err
    }
    
    // Row is the result of calling 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.  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 (r *Row) Scan(dest ...interface{}) error {
    
    	if r.err != nil {
    		return r.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.
    
    		if _, ok := dp.(*RawBytes); ok {
    			return errors.New("sql: RawBytes isn't allowed on Row.Scan")
    		}
    
    
    	if !r.rows.Next() {
    		return ErrNoRows
    	}
    	err := r.rows.Scan(dest...)
    	if err != nil {
    		return err
    	}
    
    
    }
    
    // A Result summarizes an executed SQL command.
    type Result interface {
    
    	LastInsertId() (int64, error)
    	RowsAffected() (int64, error)
    
    type driverResult struct {
    	sync.Locker // the *driverConn
    	resi        driver.Result
    }
    
    func (dr driverResult) LastInsertId() (int64, error) {
    	dr.Lock()
    	defer dr.Unlock()
    	return dr.resi.LastInsertId()
    }
    
    func (dr driverResult) RowsAffected() (int64, error) {
    	dr.Lock()
    	defer dr.Unlock()
    	return dr.resi.RowsAffected()
    
    	return string(buf[:runtime.Stack(buf[:], false)])
    }
    
    
    // withLock runs while holding lk.
    func withLock(lk sync.Locker, fn func()) {
    	lk.Lock()
    	fn()
    	lk.Unlock()
    }