OLD | NEW |
1 // Copyright 2011 The Go Authors. All rights reserved. | 1 // Copyright 2011 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 package sql | 5 package sql |
6 | 6 |
7 import ( | 7 import ( |
8 "database/sql/driver" | 8 "database/sql/driver" |
9 "errors" | 9 "errors" |
10 "fmt" | 10 "fmt" |
(...skipping 17 matching lines...) Expand all Loading... |
28 // | 28 // |
29 // WIPE | 29 // WIPE |
30 // CREATE|<tablename>|<col>=<type>,<col>=<type>,... | 30 // CREATE|<tablename>|<col>=<type>,<col>=<type>,... |
31 // where types are: "string", [u]int{8,16,32,64}, "bool" | 31 // where types are: "string", [u]int{8,16,32,64}, "bool" |
32 // INSERT|<tablename>|col=val,col2=val2,col3=? | 32 // INSERT|<tablename>|col=val,col2=val2,col3=? |
33 // SELECT|<tablename>|projectcol1,projectcol2|filtercol=?,filtercol2=? | 33 // SELECT|<tablename>|projectcol1,projectcol2|filtercol=?,filtercol2=? |
34 // | 34 // |
35 // When opening a fakeDriver's database, it starts empty with no | 35 // When opening a fakeDriver's database, it starts empty with no |
36 // tables. All tables and data are stored in memory only. | 36 // tables. All tables and data are stored in memory only. |
37 type fakeDriver struct { | 37 type fakeDriver struct { |
38 » mu sync.Mutex | 38 » mu sync.Mutex // guards all 4 fields |
39 » openCount int | 39 » openCount int // conn opens |
40 » dbs map[string]*fakeDB | 40 » closeCount int // conn closes |
| 41 » dbs map[string]*fakeDB |
41 } | 42 } |
42 | 43 |
43 type fakeDB struct { | 44 type fakeDB struct { |
44 name string | 45 name string |
45 | 46 |
46 mu sync.Mutex | 47 mu sync.Mutex |
47 free []*fakeConn | 48 free []*fakeConn |
48 tables map[string]*table | 49 tables map[string]*table |
49 badConn bool | 50 badConn bool |
50 } | 51 } |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
243 | 244 |
244 var testStrictClose *testing.T | 245 var testStrictClose *testing.T |
245 | 246 |
246 // setStrictFakeConnClose sets the t to Errorf on when fakeConn.Close | 247 // setStrictFakeConnClose sets the t to Errorf on when fakeConn.Close |
247 // fails to close. If nil, the check is disabled. | 248 // fails to close. If nil, the check is disabled. |
248 func setStrictFakeConnClose(t *testing.T) { | 249 func setStrictFakeConnClose(t *testing.T) { |
249 testStrictClose = t | 250 testStrictClose = t |
250 } | 251 } |
251 | 252 |
252 func (c *fakeConn) Close() (err error) { | 253 func (c *fakeConn) Close() (err error) { |
| 254 drv := fdriver.(*fakeDriver) |
253 defer func() { | 255 defer func() { |
254 if err != nil && testStrictClose != nil { | 256 if err != nil && testStrictClose != nil { |
255 testStrictClose.Errorf("failed to close a test fakeConn:
%v", err) | 257 testStrictClose.Errorf("failed to close a test fakeConn:
%v", err) |
256 } | 258 } |
257 hookPostCloseConn.Lock() | 259 hookPostCloseConn.Lock() |
258 fn := hookPostCloseConn.fn | 260 fn := hookPostCloseConn.fn |
259 hookPostCloseConn.Unlock() | 261 hookPostCloseConn.Unlock() |
260 if fn != nil { | 262 if fn != nil { |
261 fn(c, err) | 263 fn(c, err) |
262 } | 264 } |
| 265 if err == nil { |
| 266 drv.mu.Lock() |
| 267 drv.closeCount++ |
| 268 drv.mu.Unlock() |
| 269 } |
263 }() | 270 }() |
264 if c.currTx != nil { | 271 if c.currTx != nil { |
265 return errors.New("can't close fakeConn; in a Transaction") | 272 return errors.New("can't close fakeConn; in a Transaction") |
266 } | 273 } |
267 if c.db == nil { | 274 if c.db == nil { |
268 return errors.New("can't close fakeConn; already closed") | 275 return errors.New("can't close fakeConn; already closed") |
269 } | 276 } |
270 if c.stmtsMade > c.stmtsClosed { | 277 if c.stmtsMade > c.stmtsClosed { |
271 return errors.New("can't close; dangling statement(s)") | 278 return errors.New("can't close; dangling statement(s)") |
272 } | 279 } |
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
452 return driver.DefaultParameterConverter | 459 return driver.DefaultParameterConverter |
453 } | 460 } |
454 return s.placeholderConverter[idx] | 461 return s.placeholderConverter[idx] |
455 } | 462 } |
456 | 463 |
457 func (s *fakeStmt) Close() error { | 464 func (s *fakeStmt) Close() error { |
458 if s.c == nil { | 465 if s.c == nil { |
459 panic("nil conn in fakeStmt.Close") | 466 panic("nil conn in fakeStmt.Close") |
460 } | 467 } |
461 if s.c.db == nil { | 468 if s.c.db == nil { |
462 » » panic("in fakeSmt.Close, conn's db is nil (already closed)") | 469 » » panic("in fakeStmt.Close, conn's db is nil (already closed)") |
463 } | 470 } |
464 if !s.closed { | 471 if !s.closed { |
465 s.c.incrStat(&s.c.stmtsClosed) | 472 s.c.incrStat(&s.c.stmtsClosed) |
466 s.closed = true | 473 s.closed = true |
467 } | 474 } |
468 return nil | 475 return nil |
469 } | 476 } |
470 | 477 |
471 var errClosed = errors.New("fakedb: statement has been closed") | 478 var errClosed = errors.New("fakedb: statement has been closed") |
472 | 479 |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
545 if len(args) != s.placeholders { | 552 if len(args) != s.placeholders { |
546 panic("error in pkg db; should only get here if size is correct"
) | 553 panic("error in pkg db; should only get here if size is correct"
) |
547 } | 554 } |
548 | 555 |
549 db.mu.Lock() | 556 db.mu.Lock() |
550 t, ok := db.table(s.table) | 557 t, ok := db.table(s.table) |
551 db.mu.Unlock() | 558 db.mu.Unlock() |
552 if !ok { | 559 if !ok { |
553 return nil, fmt.Errorf("fakedb: table %q doesn't exist", s.table
) | 560 return nil, fmt.Errorf("fakedb: table %q doesn't exist", s.table
) |
554 } | 561 } |
| 562 |
| 563 if s.table == "magicquery" { |
| 564 if len(s.whereCol) == 2 && s.whereCol[0] == "op" && s.whereCol[1
] == "millis" { |
| 565 if args[0] == "sleep" { |
| 566 time.Sleep(time.Duration(args[1].(int64)) * time
.Millisecond) |
| 567 } |
| 568 } |
| 569 } |
| 570 |
555 t.mu.Lock() | 571 t.mu.Lock() |
556 defer t.mu.Unlock() | 572 defer t.mu.Unlock() |
557 | 573 |
558 colIdx := make(map[string]int) // select column name -> column index in
table | 574 colIdx := make(map[string]int) // select column name -> column index in
table |
559 for _, name := range s.colName { | 575 for _, name := range s.colName { |
560 idx := t.columnIndex(name) | 576 idx := t.columnIndex(name) |
561 if idx == -1 { | 577 if idx == -1 { |
562 return nil, fmt.Errorf("fakedb: unknown column name %q",
name) | 578 return nil, fmt.Errorf("fakedb: unknown column name %q",
name) |
563 } | 579 } |
564 colIdx[name] = idx | 580 colIdx[name] = idx |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
716 // TODO(coopernurse): add type-specific converter | 732 // TODO(coopernurse): add type-specific converter |
717 return driver.NotNull{Converter: driver.DefaultParameterConverte
r} | 733 return driver.NotNull{Converter: driver.DefaultParameterConverte
r} |
718 case "nullfloat64": | 734 case "nullfloat64": |
719 // TODO(coopernurse): add type-specific converter | 735 // TODO(coopernurse): add type-specific converter |
720 return driver.Null{Converter: driver.DefaultParameterConverter} | 736 return driver.Null{Converter: driver.DefaultParameterConverter} |
721 case "datetime": | 737 case "datetime": |
722 return driver.DefaultParameterConverter | 738 return driver.DefaultParameterConverter |
723 } | 739 } |
724 panic("invalid fakedb column type of " + typ) | 740 panic("invalid fakedb column type of " + typ) |
725 } | 741 } |
OLD | NEW |