Commit cf6e4238 authored by Daniel Theophanes's avatar Daniel Theophanes

database/sql: prefer to return Rows.lasterr rather then a static error

Fixes #25829

Change-Id: I400fdaf0ef3a23bc0d61c4873ffa298e0cf0fc6a
Reviewed-on: https://go-review.googlesource.com/c/145204Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent 37afd3e3
...@@ -2605,6 +2605,15 @@ type Rows struct { ...@@ -2605,6 +2605,15 @@ type Rows struct {
lastcols []driver.Value lastcols []driver.Value
} }
// lasterrOrErrLocked returns either lasterr or the provided err.
// rs.closemu must be read-locked.
func (rs *Rows) lasterrOrErrLocked(err error) error {
if rs.lasterr != nil && rs.lasterr != io.EOF {
return rs.lasterr
}
return err
}
func (rs *Rows) initContextClose(ctx, txctx context.Context) { func (rs *Rows) initContextClose(ctx, txctx context.Context) {
if ctx.Done() == nil && (txctx == nil || txctx.Done() == nil) { if ctx.Done() == nil && (txctx == nil || txctx.Done() == nil) {
return return
...@@ -2728,22 +2737,22 @@ func (rs *Rows) NextResultSet() bool { ...@@ -2728,22 +2737,22 @@ func (rs *Rows) NextResultSet() bool {
func (rs *Rows) Err() error { func (rs *Rows) Err() error {
rs.closemu.RLock() rs.closemu.RLock()
defer rs.closemu.RUnlock() defer rs.closemu.RUnlock()
if rs.lasterr == io.EOF { return rs.lasterrOrErrLocked(nil)
return nil
}
return rs.lasterr
} }
var errRowsClosed = errors.New("sql: Rows are closed")
var errNoRows = errors.New("sql: no Rows available")
// Columns returns the column names. // Columns returns the column names.
// Columns returns an error if the rows are closed. // Columns returns an error if the rows are closed.
func (rs *Rows) Columns() ([]string, error) { func (rs *Rows) Columns() ([]string, error) {
rs.closemu.RLock() rs.closemu.RLock()
defer rs.closemu.RUnlock() defer rs.closemu.RUnlock()
if rs.closed { if rs.closed {
return nil, errors.New("sql: Rows are closed") return nil, rs.lasterrOrErrLocked(errRowsClosed)
} }
if rs.rowsi == nil { if rs.rowsi == nil {
return nil, errors.New("sql: no Rows available") return nil, rs.lasterrOrErrLocked(errNoRows)
} }
rs.dc.Lock() rs.dc.Lock()
defer rs.dc.Unlock() defer rs.dc.Unlock()
...@@ -2757,10 +2766,10 @@ func (rs *Rows) ColumnTypes() ([]*ColumnType, error) { ...@@ -2757,10 +2766,10 @@ func (rs *Rows) ColumnTypes() ([]*ColumnType, error) {
rs.closemu.RLock() rs.closemu.RLock()
defer rs.closemu.RUnlock() defer rs.closemu.RUnlock()
if rs.closed { if rs.closed {
return nil, errors.New("sql: Rows are closed") return nil, rs.lasterrOrErrLocked(errRowsClosed)
} }
if rs.rowsi == nil { if rs.rowsi == nil {
return nil, errors.New("sql: no Rows available") return nil, rs.lasterrOrErrLocked(errNoRows)
} }
rs.dc.Lock() rs.dc.Lock()
defer rs.dc.Unlock() defer rs.dc.Unlock()
...@@ -2916,8 +2925,9 @@ func (rs *Rows) Scan(dest ...interface{}) error { ...@@ -2916,8 +2925,9 @@ func (rs *Rows) Scan(dest ...interface{}) error {
return rs.lasterr return rs.lasterr
} }
if rs.closed { if rs.closed {
err := rs.lasterrOrErrLocked(errRowsClosed)
rs.closemu.RUnlock() rs.closemu.RUnlock()
return errors.New("sql: Rows are closed") return err
} }
rs.closemu.RUnlock() rs.closemu.RUnlock()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment