Skip to content
Snippets Groups Projects
sql.go 34.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	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 _, v := range s.css {
    		// TODO(bradfitz): lazily clean up entries in this
    		// list with dead conns while enumerating
    
    		if _, match = s.db.connIfFree(v.dc); match {
    
    			cs = v
    			break
    		}
    	}
    	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
    			}
    
    			dc.Lock()
    			si, err := dc.ci.Prepare(s.query)
    			dc.Unlock()
    
    			if err == driver.ErrBadConn && i < 10 {
    				continue
    			}
    			if err != nil {
    				return nil, nil, nil, err
    			}
    
    			s.css = append(s.css, cs)
    			s.mu.Unlock()
    			break
    
    	releaseConn = func(err error) { s.db.putConn(conn, err) }
    
    	return 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
    	}
    
    	if s.closed {
    		return nil
    	}
    	s.closed = true
    
    		return nil
    	}
    
    	return s.db.removeDep(s, s)
    }
    
    func (s *Stmt) finalClose() error {
    	for _, v := range s.css {
    
    		s.db.noteUnusedDriverStatement(v.dc, v.si)
    
    	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
    
    	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.lasterr != nil {
    		return false
    	}
    	if rs.lastcols == nil {
    
    		rs.lastcols = make([]driver.Value, len(rs.rowsi.Columns()))
    
    	}
    	rs.lasterr = rs.rowsi.Next(rs.lastcols)
    
    	if rs.lasterr == io.EOF {
    		rs.Close()
    	}
    
    	return rs.lasterr == nil
    }
    
    
    // Err returns the error, if any, that was encountered during iteration.
    func (rs *Rows) Err() error {
    
    	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 {
    
    Brad Fitzpatrick's avatar
    Brad Fitzpatrick committed
    		return errors.New("sql: Rows closed")
    
    	}
    	if rs.lasterr != nil {
    		return rs.lasterr
    	}
    	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)
    
    		}
    	}
    	return nil
    }
    
    // Close closes the Rows, preventing further enumeration. If the
    // end is encountered, the Rows are closed automatically. Close
    // is idempotent.
    
    func (rs *Rows) Close() error {
    
    	if rs.closed {
    		return nil
    	}
    	rs.closed = true
    	err := rs.rowsi.Close()
    
    	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.
    	for _, dp := range dest {
    
    		if _, ok := dp.(*RawBytes); ok {
    			return errors.New("sql: RawBytes isn't allowed on Row.Scan")
    		}
    
    
    	defer r.rows.Close()
    	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()
    
    
    func stack() string {
    	var buf [1024]byte
    	return string(buf[:runtime.Stack(buf[:], false)])
    }
    
    
    // withLock runs while holding lk.
    func withLock(lk sync.Locker, fn func()) {
    	lk.Lock()
    	fn()
    	lk.Unlock()
    }