exp/sql: close Rows on EOF

Fixes #2624

R=rsc
CC=golang-dev
https://golang.org/cl/5530068
This commit is contained in:
Brad Fitzpatrick 2012-01-10 12:51:27 -08:00
parent 25cf9bdea6
commit 4435c8bf2a
3 changed files with 31 additions and 11 deletions

View File

@ -110,25 +110,34 @@ func init() {
// Supports dsn forms: // Supports dsn forms:
// <dbname> // <dbname>
// <dbname>;wipe // <dbname>;<opts> (no currently supported options)
func (d *fakeDriver) Open(dsn string) (driver.Conn, error) { func (d *fakeDriver) Open(dsn string) (driver.Conn, error) {
d.mu.Lock()
defer d.mu.Unlock()
d.openCount++
if d.dbs == nil {
d.dbs = make(map[string]*fakeDB)
}
parts := strings.Split(dsn, ";") parts := strings.Split(dsn, ";")
if len(parts) < 1 { if len(parts) < 1 {
return nil, errors.New("fakedb: no database name") return nil, errors.New("fakedb: no database name")
} }
name := parts[0] name := parts[0]
db := d.getDB(name)
d.mu.Lock()
d.openCount++
d.mu.Unlock()
return &fakeConn{db: db}, nil
}
func (d *fakeDriver) getDB(name string) *fakeDB {
d.mu.Lock()
defer d.mu.Unlock()
if d.dbs == nil {
d.dbs = make(map[string]*fakeDB)
}
db, ok := d.dbs[name] db, ok := d.dbs[name]
if !ok { if !ok {
db = &fakeDB{name: name} db = &fakeDB{name: name}
d.dbs[name] = db d.dbs[name] = db
} }
return &fakeConn{db: db}, nil return db
} }
func (db *fakeDB) wipe() { func (db *fakeDB) wipe() {

View File

@ -549,8 +549,8 @@ func (s *Stmt) Exec(args ...interface{}) (Result, error) {
// statement, a function to call to release the connection, and a // statement, a function to call to release the connection, and a
// statement bound to that connection. // statement bound to that connection.
func (s *Stmt) connStmt() (ci driver.Conn, releaseConn func(), si driver.Stmt, err error) { func (s *Stmt) connStmt() (ci driver.Conn, releaseConn func(), si driver.Stmt, err error) {
if s.stickyErr != nil { if err = s.stickyErr; err != nil {
return nil, nil, nil, s.stickyErr return
} }
s.mu.Lock() s.mu.Lock()
if s.closed { if s.closed {
@ -726,6 +726,9 @@ func (rs *Rows) Next() bool {
rs.lastcols = make([]interface{}, len(rs.rowsi.Columns())) rs.lastcols = make([]interface{}, len(rs.rowsi.Columns()))
} }
rs.lasterr = rs.rowsi.Next(rs.lastcols) rs.lasterr = rs.rowsi.Next(rs.lastcols)
if rs.lasterr == io.EOF {
rs.Close()
}
return rs.lasterr == nil return rs.lasterr == nil
} }

View File

@ -10,8 +10,10 @@ import (
"testing" "testing"
) )
const fakeDBName = "foo"
func newTestDB(t *testing.T, name string) *DB { func newTestDB(t *testing.T, name string) *DB {
db, err := Open("test", "foo") db, err := Open("test", fakeDBName)
if err != nil { if err != nil {
t.Fatalf("Open: %v", err) t.Fatalf("Open: %v", err)
} }
@ -73,6 +75,12 @@ func TestQuery(t *testing.T) {
if !reflect.DeepEqual(got, want) { if !reflect.DeepEqual(got, want) {
t.Logf(" got: %#v\nwant: %#v", got, want) t.Logf(" got: %#v\nwant: %#v", got, want)
} }
// And verify that the final rows.Next() call, which hit EOF,
// also closed the rows connection.
if n := len(db.freeConn); n != 1 {
t.Errorf("free conns after query hitting EOF = %d; want 1", n)
}
} }
func TestRowsColumns(t *testing.T) { func TestRowsColumns(t *testing.T) {