diff options
Diffstat (limited to 'src/pkg/database/sql/fakedb_test.go')
-rw-r--r-- | src/pkg/database/sql/fakedb_test.go | 50 |
1 files changed, 42 insertions, 8 deletions
diff --git a/src/pkg/database/sql/fakedb_test.go b/src/pkg/database/sql/fakedb_test.go index d900e2ceb..a8adfdd94 100644 --- a/src/pkg/database/sql/fakedb_test.go +++ b/src/pkg/database/sql/fakedb_test.go @@ -38,6 +38,8 @@ type fakeDriver struct { mu sync.Mutex // guards 3 following fields openCount int // conn opens closeCount int // conn closes + waitCh chan struct{} + waitingCh chan struct{} dbs map[string]*fakeDB } @@ -146,6 +148,12 @@ func (d *fakeDriver) Open(dsn string) (driver.Conn, error) { if len(parts) >= 2 && parts[1] == "badConn" { conn.bad = true } + if d.waitCh != nil { + d.waitingCh <- struct{}{} + <-d.waitCh + d.waitCh = nil + d.waitingCh = nil + } return conn, nil } @@ -447,6 +455,10 @@ func (c *fakeConn) Prepare(query string) (driver.Stmt, error) { return c.prepareCreate(stmt, parts) case "INSERT": return c.prepareInsert(stmt, parts) + case "NOSERT": + // Do all the prep-work like for an INSERT but don't actually insert the row. + // Used for some of the concurrent tests. + return c.prepareInsert(stmt, parts) default: stmt.Close() return nil, errf("unsupported command type %q", cmd) @@ -497,13 +509,20 @@ func (s *fakeStmt) Exec(args []driver.Value) (driver.Result, error) { } return driver.ResultNoRows, nil case "INSERT": - return s.execInsert(args) + return s.execInsert(args, true) + case "NOSERT": + // Do all the prep-work like for an INSERT but don't actually insert the row. + // Used for some of the concurrent tests. + return s.execInsert(args, false) } fmt.Printf("EXEC statement, cmd=%q: %#v\n", s.cmd, s) return nil, fmt.Errorf("unimplemented statement Exec command type of %q", s.cmd) } -func (s *fakeStmt) execInsert(args []driver.Value) (driver.Result, error) { +// When doInsert is true, add the row to the table. +// When doInsert is false do prep-work and error checking, but don't +// actually add the row to the table. +func (s *fakeStmt) execInsert(args []driver.Value, doInsert bool) (driver.Result, error) { db := s.c.db if len(args) != s.placeholders { panic("error in pkg db; should only get here if size is correct") @@ -518,7 +537,10 @@ func (s *fakeStmt) execInsert(args []driver.Value) (driver.Result, error) { t.mu.Lock() defer t.mu.Unlock() - cols := make([]interface{}, len(t.colname)) + var cols []interface{} + if doInsert { + cols = make([]interface{}, len(t.colname)) + } argPos := 0 for n, colname := range s.colName { colidx := t.columnIndex(colname) @@ -532,10 +554,14 @@ func (s *fakeStmt) execInsert(args []driver.Value) (driver.Result, error) { } else { val = s.colValue[n] } - cols[colidx] = val + if doInsert { + cols[colidx] = val + } } - t.rows = append(t.rows, &row{cols: cols}) + if doInsert { + t.rows = append(t.rows, &row{cols: cols}) + } return driver.RowsAffected(1), nil } @@ -608,9 +634,10 @@ rows: } cursor := &rowsCursor{ - pos: -1, - rows: mrows, - cols: s.colName, + pos: -1, + rows: mrows, + cols: s.colName, + errPos: -1, } return cursor, nil } @@ -635,6 +662,10 @@ type rowsCursor struct { rows []*row closed bool + // errPos and err are for making Next return early with error. + errPos int + err error + // a clone of slices to give out to clients, indexed by the // the original slice's first byte address. we clone them // just so we're able to corrupt them on close. @@ -660,6 +691,9 @@ func (rc *rowsCursor) Next(dest []driver.Value) error { return errors.New("fakedb: cursor is closed") } rc.pos++ + if rc.pos == rc.errPos { + return rc.err + } if rc.pos >= len(rc.rows) { return io.EOF // per interface spec } |