github.com/zxy12/go_duplicate_112_new@v0.0.0-20200807091221-747231827200/src/database/sql/fakedb_test.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package sql 6 7 import ( 8 "context" 9 "database/sql/driver" 10 "errors" 11 "fmt" 12 "io" 13 "log" 14 "reflect" 15 "sort" 16 "strconv" 17 "strings" 18 "sync" 19 "testing" 20 "time" 21 ) 22 23 var _ = log.Printf 24 25 // fakeDriver is a fake database that implements Go's driver.Driver 26 // interface, just for testing. 27 // 28 // It speaks a query language that's semantically similar to but 29 // syntactically different and simpler than SQL. The syntax is as 30 // follows: 31 // 32 // WIPE 33 // CREATE|<tablename>|<col>=<type>,<col>=<type>,... 34 // where types are: "string", [u]int{8,16,32,64}, "bool" 35 // INSERT|<tablename>|col=val,col2=val2,col3=? 36 // SELECT|<tablename>|projectcol1,projectcol2|filtercol=?,filtercol2=? 37 // SELECT|<tablename>|projectcol1,projectcol2|filtercol=?param1,filtercol2=?param2 38 // 39 // Any of these can be preceded by PANIC|<method>|, to cause the 40 // named method on fakeStmt to panic. 41 // 42 // Any of these can be proceeded by WAIT|<duration>|, to cause the 43 // named method on fakeStmt to sleep for the specified duration. 44 // 45 // Multiple of these can be combined when separated with a semicolon. 46 // 47 // When opening a fakeDriver's database, it starts empty with no 48 // tables. All tables and data are stored in memory only. 49 type fakeDriver struct { 50 mu sync.Mutex // guards 3 following fields 51 openCount int // conn opens 52 closeCount int // conn closes 53 waitCh chan struct{} 54 waitingCh chan struct{} 55 dbs map[string]*fakeDB 56 } 57 58 type fakeConnector struct { 59 name string 60 61 waiter func(context.Context) 62 } 63 64 func (c *fakeConnector) Connect(context.Context) (driver.Conn, error) { 65 conn, err := fdriver.Open(c.name) 66 conn.(*fakeConn).waiter = c.waiter 67 return conn, err 68 } 69 70 func (c *fakeConnector) Driver() driver.Driver { 71 return fdriver 72 } 73 74 type fakeDriverCtx struct { 75 fakeDriver 76 } 77 78 var _ driver.DriverContext = &fakeDriverCtx{} 79 80 func (cc *fakeDriverCtx) OpenConnector(name string) (driver.Connector, error) { 81 return &fakeConnector{name: name}, nil 82 } 83 84 type fakeDB struct { 85 name string 86 87 mu sync.Mutex 88 tables map[string]*table 89 badConn bool 90 allowAny bool 91 } 92 93 type table struct { 94 mu sync.Mutex 95 colname []string 96 coltype []string 97 rows []*row 98 } 99 100 func (t *table) columnIndex(name string) int { 101 for n, nname := range t.colname { 102 if name == nname { 103 return n 104 } 105 } 106 return -1 107 } 108 109 type row struct { 110 cols []interface{} // must be same size as its table colname + coltype 111 } 112 113 type memToucher interface { 114 // touchMem reads & writes some memory, to help find data races. 115 touchMem() 116 } 117 118 type fakeConn struct { 119 db *fakeDB // where to return ourselves to 120 121 currTx *fakeTx 122 123 // Every operation writes to line to enable the race detector 124 // check for data races. 125 line int64 126 127 // Stats for tests: 128 mu sync.Mutex 129 stmtsMade int 130 stmtsClosed int 131 numPrepare int 132 133 // bad connection tests; see isBad() 134 bad bool 135 stickyBad bool 136 137 skipDirtySession bool // tests that use Conn should set this to true. 138 139 // dirtySession tests ResetSession, true if a query has executed 140 // until ResetSession is called. 141 dirtySession bool 142 143 // The waiter is called before each query. May be used in place of the "WAIT" 144 // directive. 145 waiter func(context.Context) 146 } 147 148 func (c *fakeConn) touchMem() { 149 c.line++ 150 } 151 152 func (c *fakeConn) incrStat(v *int) { 153 c.mu.Lock() 154 *v++ 155 c.mu.Unlock() 156 } 157 158 type fakeTx struct { 159 c *fakeConn 160 } 161 162 type boundCol struct { 163 Column string 164 Placeholder string 165 Ordinal int 166 } 167 168 type fakeStmt struct { 169 memToucher 170 c *fakeConn 171 q string // just for debugging 172 173 cmd string 174 table string 175 panic string 176 wait time.Duration 177 178 next *fakeStmt // used for returning multiple results. 179 180 closed bool 181 182 colName []string // used by CREATE, INSERT, SELECT (selected columns) 183 colType []string // used by CREATE 184 colValue []interface{} // used by INSERT (mix of strings and "?" for bound params) 185 placeholders int // used by INSERT/SELECT: number of ? params 186 187 whereCol []boundCol // used by SELECT (all placeholders) 188 189 placeholderConverter []driver.ValueConverter // used by INSERT 190 } 191 192 var fdriver driver.Driver = &fakeDriver{} 193 194 func init() { 195 Register("test", fdriver) 196 } 197 198 func contains(list []string, y string) bool { 199 for _, x := range list { 200 if x == y { 201 return true 202 } 203 } 204 return false 205 } 206 207 type Dummy struct { 208 driver.Driver 209 } 210 211 func TestDrivers(t *testing.T) { 212 unregisterAllDrivers() 213 Register("test", fdriver) 214 Register("invalid", Dummy{}) 215 all := Drivers() 216 if len(all) < 2 || !sort.StringsAreSorted(all) || !contains(all, "test") || !contains(all, "invalid") { 217 t.Fatalf("Drivers = %v, want sorted list with at least [invalid, test]", all) 218 } 219 } 220 221 // hook to simulate connection failures 222 var hookOpenErr struct { 223 sync.Mutex 224 fn func() error 225 } 226 227 func setHookOpenErr(fn func() error) { 228 hookOpenErr.Lock() 229 defer hookOpenErr.Unlock() 230 hookOpenErr.fn = fn 231 } 232 233 // Supports dsn forms: 234 // <dbname> 235 // <dbname>;<opts> (only currently supported option is `badConn`, 236 // which causes driver.ErrBadConn to be returned on 237 // every other conn.Begin()) 238 func (d *fakeDriver) Open(dsn string) (driver.Conn, error) { 239 hookOpenErr.Lock() 240 fn := hookOpenErr.fn 241 hookOpenErr.Unlock() 242 if fn != nil { 243 if err := fn(); err != nil { 244 return nil, err 245 } 246 } 247 parts := strings.Split(dsn, ";") 248 if len(parts) < 1 { 249 return nil, errors.New("fakedb: no database name") 250 } 251 name := parts[0] 252 253 db := d.getDB(name) 254 255 d.mu.Lock() 256 d.openCount++ 257 d.mu.Unlock() 258 conn := &fakeConn{db: db} 259 260 if len(parts) >= 2 && parts[1] == "badConn" { 261 conn.bad = true 262 } 263 if d.waitCh != nil { 264 d.waitingCh <- struct{}{} 265 <-d.waitCh 266 d.waitCh = nil 267 d.waitingCh = nil 268 } 269 return conn, nil 270 } 271 272 func (d *fakeDriver) getDB(name string) *fakeDB { 273 d.mu.Lock() 274 defer d.mu.Unlock() 275 if d.dbs == nil { 276 d.dbs = make(map[string]*fakeDB) 277 } 278 db, ok := d.dbs[name] 279 if !ok { 280 db = &fakeDB{name: name} 281 d.dbs[name] = db 282 } 283 return db 284 } 285 286 func (db *fakeDB) wipe() { 287 db.mu.Lock() 288 defer db.mu.Unlock() 289 db.tables = nil 290 } 291 292 func (db *fakeDB) createTable(name string, columnNames, columnTypes []string) error { 293 db.mu.Lock() 294 defer db.mu.Unlock() 295 if db.tables == nil { 296 db.tables = make(map[string]*table) 297 } 298 if _, exist := db.tables[name]; exist { 299 return fmt.Errorf("fakedb: table %q already exists", name) 300 } 301 if len(columnNames) != len(columnTypes) { 302 return fmt.Errorf("fakedb: create table of %q len(names) != len(types): %d vs %d", 303 name, len(columnNames), len(columnTypes)) 304 } 305 db.tables[name] = &table{colname: columnNames, coltype: columnTypes} 306 return nil 307 } 308 309 // must be called with db.mu lock held 310 func (db *fakeDB) table(table string) (*table, bool) { 311 if db.tables == nil { 312 return nil, false 313 } 314 t, ok := db.tables[table] 315 return t, ok 316 } 317 318 func (db *fakeDB) columnType(table, column string) (typ string, ok bool) { 319 db.mu.Lock() 320 defer db.mu.Unlock() 321 t, ok := db.table(table) 322 if !ok { 323 return 324 } 325 for n, cname := range t.colname { 326 if cname == column { 327 return t.coltype[n], true 328 } 329 } 330 return "", false 331 } 332 333 func (c *fakeConn) isBad() bool { 334 if c.stickyBad { 335 return true 336 } else if c.bad { 337 if c.db == nil { 338 return false 339 } 340 // alternate between bad conn and not bad conn 341 c.db.badConn = !c.db.badConn 342 return c.db.badConn 343 } else { 344 return false 345 } 346 } 347 348 func (c *fakeConn) isDirtyAndMark() bool { 349 if c.skipDirtySession { 350 return false 351 } 352 if c.currTx != nil { 353 c.dirtySession = true 354 return false 355 } 356 if c.dirtySession { 357 return true 358 } 359 c.dirtySession = true 360 return false 361 } 362 363 func (c *fakeConn) Begin() (driver.Tx, error) { 364 if c.isBad() { 365 return nil, driver.ErrBadConn 366 } 367 if c.currTx != nil { 368 return nil, errors.New("fakedb: already in a transaction") 369 } 370 c.touchMem() 371 c.currTx = &fakeTx{c: c} 372 return c.currTx, nil 373 } 374 375 var hookPostCloseConn struct { 376 sync.Mutex 377 fn func(*fakeConn, error) 378 } 379 380 func setHookpostCloseConn(fn func(*fakeConn, error)) { 381 hookPostCloseConn.Lock() 382 defer hookPostCloseConn.Unlock() 383 hookPostCloseConn.fn = fn 384 } 385 386 var testStrictClose *testing.T 387 388 // setStrictFakeConnClose sets the t to Errorf on when fakeConn.Close 389 // fails to close. If nil, the check is disabled. 390 func setStrictFakeConnClose(t *testing.T) { 391 testStrictClose = t 392 } 393 394 func (c *fakeConn) ResetSession(ctx context.Context) error { 395 c.dirtySession = false 396 if c.isBad() { 397 return driver.ErrBadConn 398 } 399 return nil 400 } 401 402 func (c *fakeConn) Close() (err error) { 403 drv := fdriver.(*fakeDriver) 404 defer func() { 405 if err != nil && testStrictClose != nil { 406 testStrictClose.Errorf("failed to close a test fakeConn: %v", err) 407 } 408 hookPostCloseConn.Lock() 409 fn := hookPostCloseConn.fn 410 hookPostCloseConn.Unlock() 411 if fn != nil { 412 fn(c, err) 413 } 414 if err == nil { 415 drv.mu.Lock() 416 drv.closeCount++ 417 drv.mu.Unlock() 418 } 419 }() 420 c.touchMem() 421 if c.currTx != nil { 422 return errors.New("fakedb: can't close fakeConn; in a Transaction") 423 } 424 if c.db == nil { 425 return errors.New("fakedb: can't close fakeConn; already closed") 426 } 427 if c.stmtsMade > c.stmtsClosed { 428 return errors.New("fakedb: can't close; dangling statement(s)") 429 } 430 c.db = nil 431 return nil 432 } 433 434 func checkSubsetTypes(allowAny bool, args []driver.NamedValue) error { 435 for _, arg := range args { 436 switch arg.Value.(type) { 437 case int64, float64, bool, nil, []byte, string, time.Time: 438 default: 439 if !allowAny { 440 return fmt.Errorf("fakedb: invalid argument ordinal %[1]d: %[2]v, type %[2]T", arg.Ordinal, arg.Value) 441 } 442 } 443 } 444 return nil 445 } 446 447 func (c *fakeConn) Exec(query string, args []driver.Value) (driver.Result, error) { 448 // Ensure that ExecContext is called if available. 449 panic("ExecContext was not called.") 450 } 451 452 func (c *fakeConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) { 453 // This is an optional interface, but it's implemented here 454 // just to check that all the args are of the proper types. 455 // ErrSkip is returned so the caller acts as if we didn't 456 // implement this at all. 457 err := checkSubsetTypes(c.db.allowAny, args) 458 if err != nil { 459 return nil, err 460 } 461 return nil, driver.ErrSkip 462 } 463 464 func (c *fakeConn) Query(query string, args []driver.Value) (driver.Rows, error) { 465 // Ensure that ExecContext is called if available. 466 panic("QueryContext was not called.") 467 } 468 469 func (c *fakeConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) { 470 // This is an optional interface, but it's implemented here 471 // just to check that all the args are of the proper types. 472 // ErrSkip is returned so the caller acts as if we didn't 473 // implement this at all. 474 err := checkSubsetTypes(c.db.allowAny, args) 475 if err != nil { 476 return nil, err 477 } 478 return nil, driver.ErrSkip 479 } 480 481 func errf(msg string, args ...interface{}) error { 482 return errors.New("fakedb: " + fmt.Sprintf(msg, args...)) 483 } 484 485 // parts are table|selectCol1,selectCol2|whereCol=?,whereCol2=? 486 // (note that where columns must always contain ? marks, 487 // just a limitation for fakedb) 488 func (c *fakeConn) prepareSelect(stmt *fakeStmt, parts []string) (*fakeStmt, error) { 489 if len(parts) != 3 { 490 stmt.Close() 491 return nil, errf("invalid SELECT syntax with %d parts; want 3", len(parts)) 492 } 493 stmt.table = parts[0] 494 495 stmt.colName = strings.Split(parts[1], ",") 496 for n, colspec := range strings.Split(parts[2], ",") { 497 if colspec == "" { 498 continue 499 } 500 nameVal := strings.Split(colspec, "=") 501 if len(nameVal) != 2 { 502 stmt.Close() 503 return nil, errf("SELECT on table %q has invalid column spec of %q (index %d)", stmt.table, colspec, n) 504 } 505 column, value := nameVal[0], nameVal[1] 506 _, ok := c.db.columnType(stmt.table, column) 507 if !ok { 508 stmt.Close() 509 return nil, errf("SELECT on table %q references non-existent column %q", stmt.table, column) 510 } 511 if !strings.HasPrefix(value, "?") { 512 stmt.Close() 513 return nil, errf("SELECT on table %q has pre-bound value for where column %q; need a question mark", 514 stmt.table, column) 515 } 516 stmt.placeholders++ 517 stmt.whereCol = append(stmt.whereCol, boundCol{Column: column, Placeholder: value, Ordinal: stmt.placeholders}) 518 } 519 return stmt, nil 520 } 521 522 // parts are table|col=type,col2=type2 523 func (c *fakeConn) prepareCreate(stmt *fakeStmt, parts []string) (*fakeStmt, error) { 524 if len(parts) != 2 { 525 stmt.Close() 526 return nil, errf("invalid CREATE syntax with %d parts; want 2", len(parts)) 527 } 528 stmt.table = parts[0] 529 for n, colspec := range strings.Split(parts[1], ",") { 530 nameType := strings.Split(colspec, "=") 531 if len(nameType) != 2 { 532 stmt.Close() 533 return nil, errf("CREATE table %q has invalid column spec of %q (index %d)", stmt.table, colspec, n) 534 } 535 stmt.colName = append(stmt.colName, nameType[0]) 536 stmt.colType = append(stmt.colType, nameType[1]) 537 } 538 return stmt, nil 539 } 540 541 // parts are table|col=?,col2=val 542 func (c *fakeConn) prepareInsert(ctx context.Context, stmt *fakeStmt, parts []string) (*fakeStmt, error) { 543 if len(parts) != 2 { 544 stmt.Close() 545 return nil, errf("invalid INSERT syntax with %d parts; want 2", len(parts)) 546 } 547 stmt.table = parts[0] 548 for n, colspec := range strings.Split(parts[1], ",") { 549 nameVal := strings.Split(colspec, "=") 550 if len(nameVal) != 2 { 551 stmt.Close() 552 return nil, errf("INSERT table %q has invalid column spec of %q (index %d)", stmt.table, colspec, n) 553 } 554 column, value := nameVal[0], nameVal[1] 555 ctype, ok := c.db.columnType(stmt.table, column) 556 if !ok { 557 stmt.Close() 558 return nil, errf("INSERT table %q references non-existent column %q", stmt.table, column) 559 } 560 stmt.colName = append(stmt.colName, column) 561 562 if !strings.HasPrefix(value, "?") { 563 var subsetVal interface{} 564 // Convert to driver subset type 565 switch ctype { 566 case "string": 567 subsetVal = []byte(value) 568 case "blob": 569 subsetVal = []byte(value) 570 case "int32": 571 i, err := strconv.Atoi(value) 572 if err != nil { 573 stmt.Close() 574 return nil, errf("invalid conversion to int32 from %q", value) 575 } 576 subsetVal = int64(i) // int64 is a subset type, but not int32 577 case "table": // For testing cursor reads. 578 c.skipDirtySession = true 579 vparts := strings.Split(value, "!") 580 581 substmt, err := c.PrepareContext(ctx, fmt.Sprintf("SELECT|%s|%s|", vparts[0], strings.Join(vparts[1:], ","))) 582 if err != nil { 583 return nil, err 584 } 585 cursor, err := (substmt.(driver.StmtQueryContext)).QueryContext(ctx, []driver.NamedValue{}) 586 substmt.Close() 587 if err != nil { 588 return nil, err 589 } 590 subsetVal = cursor 591 default: 592 stmt.Close() 593 return nil, errf("unsupported conversion for pre-bound parameter %q to type %q", value, ctype) 594 } 595 stmt.colValue = append(stmt.colValue, subsetVal) 596 } else { 597 stmt.placeholders++ 598 stmt.placeholderConverter = append(stmt.placeholderConverter, converterForType(ctype)) 599 stmt.colValue = append(stmt.colValue, value) 600 } 601 } 602 return stmt, nil 603 } 604 605 // hook to simulate broken connections 606 var hookPrepareBadConn func() bool 607 608 func (c *fakeConn) Prepare(query string) (driver.Stmt, error) { 609 panic("use PrepareContext") 610 } 611 612 func (c *fakeConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) { 613 c.numPrepare++ 614 if c.db == nil { 615 panic("nil c.db; conn = " + fmt.Sprintf("%#v", c)) 616 } 617 618 if c.stickyBad || (hookPrepareBadConn != nil && hookPrepareBadConn()) { 619 return nil, driver.ErrBadConn 620 } 621 622 c.touchMem() 623 var firstStmt, prev *fakeStmt 624 for _, query := range strings.Split(query, ";") { 625 parts := strings.Split(query, "|") 626 if len(parts) < 1 { 627 return nil, errf("empty query") 628 } 629 stmt := &fakeStmt{q: query, c: c, memToucher: c} 630 if firstStmt == nil { 631 firstStmt = stmt 632 } 633 if len(parts) >= 3 { 634 switch parts[0] { 635 case "PANIC": 636 stmt.panic = parts[1] 637 parts = parts[2:] 638 case "WAIT": 639 wait, err := time.ParseDuration(parts[1]) 640 if err != nil { 641 return nil, errf("expected section after WAIT to be a duration, got %q %v", parts[1], err) 642 } 643 parts = parts[2:] 644 stmt.wait = wait 645 } 646 } 647 cmd := parts[0] 648 stmt.cmd = cmd 649 parts = parts[1:] 650 651 if c.waiter != nil { 652 c.waiter(ctx) 653 } 654 655 if stmt.wait > 0 { 656 wait := time.NewTimer(stmt.wait) 657 select { 658 case <-wait.C: 659 case <-ctx.Done(): 660 wait.Stop() 661 return nil, ctx.Err() 662 } 663 } 664 665 c.incrStat(&c.stmtsMade) 666 var err error 667 switch cmd { 668 case "WIPE": 669 // Nothing 670 case "SELECT": 671 stmt, err = c.prepareSelect(stmt, parts) 672 case "CREATE": 673 stmt, err = c.prepareCreate(stmt, parts) 674 case "INSERT": 675 stmt, err = c.prepareInsert(ctx, stmt, parts) 676 case "NOSERT": 677 // Do all the prep-work like for an INSERT but don't actually insert the row. 678 // Used for some of the concurrent tests. 679 stmt, err = c.prepareInsert(ctx, stmt, parts) 680 default: 681 stmt.Close() 682 return nil, errf("unsupported command type %q", cmd) 683 } 684 if err != nil { 685 return nil, err 686 } 687 if prev != nil { 688 prev.next = stmt 689 } 690 prev = stmt 691 } 692 return firstStmt, nil 693 } 694 695 func (s *fakeStmt) ColumnConverter(idx int) driver.ValueConverter { 696 if s.panic == "ColumnConverter" { 697 panic(s.panic) 698 } 699 if len(s.placeholderConverter) == 0 { 700 return driver.DefaultParameterConverter 701 } 702 return s.placeholderConverter[idx] 703 } 704 705 func (s *fakeStmt) Close() error { 706 if s.panic == "Close" { 707 panic(s.panic) 708 } 709 if s.c == nil { 710 panic("nil conn in fakeStmt.Close") 711 } 712 if s.c.db == nil { 713 panic("in fakeStmt.Close, conn's db is nil (already closed)") 714 } 715 s.touchMem() 716 if !s.closed { 717 s.c.incrStat(&s.c.stmtsClosed) 718 s.closed = true 719 } 720 if s.next != nil { 721 s.next.Close() 722 } 723 return nil 724 } 725 726 var errClosed = errors.New("fakedb: statement has been closed") 727 728 // hook to simulate broken connections 729 var hookExecBadConn func() bool 730 731 func (s *fakeStmt) Exec(args []driver.Value) (driver.Result, error) { 732 panic("Using ExecContext") 733 } 734 func (s *fakeStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) { 735 if s.panic == "Exec" { 736 panic(s.panic) 737 } 738 if s.closed { 739 return nil, errClosed 740 } 741 742 if s.c.stickyBad || (hookExecBadConn != nil && hookExecBadConn()) { 743 return nil, driver.ErrBadConn 744 } 745 if s.c.isDirtyAndMark() { 746 return nil, errors.New("fakedb: session is dirty") 747 } 748 749 err := checkSubsetTypes(s.c.db.allowAny, args) 750 if err != nil { 751 return nil, err 752 } 753 s.touchMem() 754 755 if s.wait > 0 { 756 time.Sleep(s.wait) 757 } 758 759 select { 760 default: 761 case <-ctx.Done(): 762 return nil, ctx.Err() 763 } 764 765 db := s.c.db 766 switch s.cmd { 767 case "WIPE": 768 db.wipe() 769 return driver.ResultNoRows, nil 770 case "CREATE": 771 if err := db.createTable(s.table, s.colName, s.colType); err != nil { 772 return nil, err 773 } 774 return driver.ResultNoRows, nil 775 case "INSERT": 776 return s.execInsert(args, true) 777 case "NOSERT": 778 // Do all the prep-work like for an INSERT but don't actually insert the row. 779 // Used for some of the concurrent tests. 780 return s.execInsert(args, false) 781 } 782 return nil, fmt.Errorf("fakedb: unimplemented statement Exec command type of %q", s.cmd) 783 } 784 785 // When doInsert is true, add the row to the table. 786 // When doInsert is false do prep-work and error checking, but don't 787 // actually add the row to the table. 788 func (s *fakeStmt) execInsert(args []driver.NamedValue, doInsert bool) (driver.Result, error) { 789 db := s.c.db 790 if len(args) != s.placeholders { 791 panic("error in pkg db; should only get here if size is correct") 792 } 793 db.mu.Lock() 794 t, ok := db.table(s.table) 795 db.mu.Unlock() 796 if !ok { 797 return nil, fmt.Errorf("fakedb: table %q doesn't exist", s.table) 798 } 799 800 t.mu.Lock() 801 defer t.mu.Unlock() 802 803 var cols []interface{} 804 if doInsert { 805 cols = make([]interface{}, len(t.colname)) 806 } 807 argPos := 0 808 for n, colname := range s.colName { 809 colidx := t.columnIndex(colname) 810 if colidx == -1 { 811 return nil, fmt.Errorf("fakedb: column %q doesn't exist or dropped since prepared statement was created", colname) 812 } 813 var val interface{} 814 if strvalue, ok := s.colValue[n].(string); ok && strings.HasPrefix(strvalue, "?") { 815 if strvalue == "?" { 816 val = args[argPos].Value 817 } else { 818 // Assign value from argument placeholder name. 819 for _, a := range args { 820 if a.Name == strvalue[1:] { 821 val = a.Value 822 break 823 } 824 } 825 } 826 argPos++ 827 } else { 828 val = s.colValue[n] 829 } 830 if doInsert { 831 cols[colidx] = val 832 } 833 } 834 835 if doInsert { 836 t.rows = append(t.rows, &row{cols: cols}) 837 } 838 return driver.RowsAffected(1), nil 839 } 840 841 // hook to simulate broken connections 842 var hookQueryBadConn func() bool 843 844 func (s *fakeStmt) Query(args []driver.Value) (driver.Rows, error) { 845 panic("Use QueryContext") 846 } 847 848 func (s *fakeStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) { 849 if s.panic == "Query" { 850 panic(s.panic) 851 } 852 if s.closed { 853 return nil, errClosed 854 } 855 856 if s.c.stickyBad || (hookQueryBadConn != nil && hookQueryBadConn()) { 857 return nil, driver.ErrBadConn 858 } 859 if s.c.isDirtyAndMark() { 860 return nil, errors.New("fakedb: session is dirty") 861 } 862 863 err := checkSubsetTypes(s.c.db.allowAny, args) 864 if err != nil { 865 return nil, err 866 } 867 868 s.touchMem() 869 db := s.c.db 870 if len(args) != s.placeholders { 871 panic("error in pkg db; should only get here if size is correct") 872 } 873 874 setMRows := make([][]*row, 0, 1) 875 setColumns := make([][]string, 0, 1) 876 setColType := make([][]string, 0, 1) 877 878 for { 879 db.mu.Lock() 880 t, ok := db.table(s.table) 881 db.mu.Unlock() 882 if !ok { 883 return nil, fmt.Errorf("fakedb: table %q doesn't exist", s.table) 884 } 885 886 if s.table == "magicquery" { 887 if len(s.whereCol) == 2 && s.whereCol[0].Column == "op" && s.whereCol[1].Column == "millis" { 888 if args[0].Value == "sleep" { 889 time.Sleep(time.Duration(args[1].Value.(int64)) * time.Millisecond) 890 } 891 } 892 } 893 894 t.mu.Lock() 895 896 colIdx := make(map[string]int) // select column name -> column index in table 897 for _, name := range s.colName { 898 idx := t.columnIndex(name) 899 if idx == -1 { 900 t.mu.Unlock() 901 return nil, fmt.Errorf("fakedb: unknown column name %q", name) 902 } 903 colIdx[name] = idx 904 } 905 906 mrows := []*row{} 907 rows: 908 for _, trow := range t.rows { 909 // Process the where clause, skipping non-match rows. This is lazy 910 // and just uses fmt.Sprintf("%v") to test equality. Good enough 911 // for test code. 912 for _, wcol := range s.whereCol { 913 idx := t.columnIndex(wcol.Column) 914 if idx == -1 { 915 t.mu.Unlock() 916 return nil, fmt.Errorf("fakedb: invalid where clause column %q", wcol) 917 } 918 tcol := trow.cols[idx] 919 if bs, ok := tcol.([]byte); ok { 920 // lazy hack to avoid sprintf %v on a []byte 921 tcol = string(bs) 922 } 923 var argValue interface{} 924 if wcol.Placeholder == "?" { 925 argValue = args[wcol.Ordinal-1].Value 926 } else { 927 // Assign arg value from placeholder name. 928 for _, a := range args { 929 if a.Name == wcol.Placeholder[1:] { 930 argValue = a.Value 931 break 932 } 933 } 934 } 935 if fmt.Sprintf("%v", tcol) != fmt.Sprintf("%v", argValue) { 936 continue rows 937 } 938 } 939 mrow := &row{cols: make([]interface{}, len(s.colName))} 940 for seli, name := range s.colName { 941 mrow.cols[seli] = trow.cols[colIdx[name]] 942 } 943 mrows = append(mrows, mrow) 944 } 945 946 var colType []string 947 for _, column := range s.colName { 948 colType = append(colType, t.coltype[t.columnIndex(column)]) 949 } 950 951 t.mu.Unlock() 952 953 setMRows = append(setMRows, mrows) 954 setColumns = append(setColumns, s.colName) 955 setColType = append(setColType, colType) 956 957 if s.next == nil { 958 break 959 } 960 s = s.next 961 } 962 963 cursor := &rowsCursor{ 964 parentMem: s.c, 965 posRow: -1, 966 rows: setMRows, 967 cols: setColumns, 968 colType: setColType, 969 errPos: -1, 970 } 971 return cursor, nil 972 } 973 974 func (s *fakeStmt) NumInput() int { 975 if s.panic == "NumInput" { 976 panic(s.panic) 977 } 978 return s.placeholders 979 } 980 981 // hook to simulate broken connections 982 var hookCommitBadConn func() bool 983 984 func (tx *fakeTx) Commit() error { 985 tx.c.currTx = nil 986 if hookCommitBadConn != nil && hookCommitBadConn() { 987 return driver.ErrBadConn 988 } 989 tx.c.touchMem() 990 return nil 991 } 992 993 // hook to simulate broken connections 994 var hookRollbackBadConn func() bool 995 996 func (tx *fakeTx) Rollback() error { 997 tx.c.currTx = nil 998 if hookRollbackBadConn != nil && hookRollbackBadConn() { 999 return driver.ErrBadConn 1000 } 1001 tx.c.touchMem() 1002 return nil 1003 } 1004 1005 type rowsCursor struct { 1006 parentMem memToucher 1007 cols [][]string 1008 colType [][]string 1009 posSet int 1010 posRow int 1011 rows [][]*row 1012 closed bool 1013 1014 // errPos and err are for making Next return early with error. 1015 errPos int 1016 err error 1017 1018 // a clone of slices to give out to clients, indexed by the 1019 // original slice's first byte address. we clone them 1020 // just so we're able to corrupt them on close. 1021 bytesClone map[*byte][]byte 1022 1023 // Every operation writes to line to enable the race detector 1024 // check for data races. 1025 // This is separate from the fakeConn.line to allow for drivers that 1026 // can start multiple queries on the same transaction at the same time. 1027 line int64 1028 } 1029 1030 func (rc *rowsCursor) touchMem() { 1031 rc.parentMem.touchMem() 1032 rc.line++ 1033 } 1034 1035 func (rc *rowsCursor) Close() error { 1036 rc.touchMem() 1037 rc.parentMem.touchMem() 1038 rc.closed = true 1039 return nil 1040 } 1041 1042 func (rc *rowsCursor) Columns() []string { 1043 return rc.cols[rc.posSet] 1044 } 1045 1046 func (rc *rowsCursor) ColumnTypeScanType(index int) reflect.Type { 1047 return colTypeToReflectType(rc.colType[rc.posSet][index]) 1048 } 1049 1050 var rowsCursorNextHook func(dest []driver.Value) error 1051 1052 func (rc *rowsCursor) Next(dest []driver.Value) error { 1053 if rowsCursorNextHook != nil { 1054 return rowsCursorNextHook(dest) 1055 } 1056 1057 if rc.closed { 1058 return errors.New("fakedb: cursor is closed") 1059 } 1060 rc.touchMem() 1061 rc.posRow++ 1062 if rc.posRow == rc.errPos { 1063 return rc.err 1064 } 1065 if rc.posRow >= len(rc.rows[rc.posSet]) { 1066 return io.EOF // per interface spec 1067 } 1068 for i, v := range rc.rows[rc.posSet][rc.posRow].cols { 1069 // TODO(bradfitz): convert to subset types? naah, I 1070 // think the subset types should only be input to 1071 // driver, but the sql package should be able to handle 1072 // a wider range of types coming out of drivers. all 1073 // for ease of drivers, and to prevent drivers from 1074 // messing up conversions or doing them differently. 1075 dest[i] = v 1076 1077 if bs, ok := v.([]byte); ok { 1078 if rc.bytesClone == nil { 1079 rc.bytesClone = make(map[*byte][]byte) 1080 } 1081 clone, ok := rc.bytesClone[&bs[0]] 1082 if !ok { 1083 clone = make([]byte, len(bs)) 1084 copy(clone, bs) 1085 rc.bytesClone[&bs[0]] = clone 1086 } 1087 dest[i] = clone 1088 } 1089 } 1090 return nil 1091 } 1092 1093 func (rc *rowsCursor) HasNextResultSet() bool { 1094 rc.touchMem() 1095 return rc.posSet < len(rc.rows)-1 1096 } 1097 1098 func (rc *rowsCursor) NextResultSet() error { 1099 rc.touchMem() 1100 if rc.HasNextResultSet() { 1101 rc.posSet++ 1102 rc.posRow = -1 1103 return nil 1104 } 1105 return io.EOF // Per interface spec. 1106 } 1107 1108 // fakeDriverString is like driver.String, but indirects pointers like 1109 // DefaultValueConverter. 1110 // 1111 // This could be surprising behavior to retroactively apply to 1112 // driver.String now that Go1 is out, but this is convenient for 1113 // our TestPointerParamsAndScans. 1114 // 1115 type fakeDriverString struct{} 1116 1117 func (fakeDriverString) ConvertValue(v interface{}) (driver.Value, error) { 1118 switch c := v.(type) { 1119 case string, []byte: 1120 return v, nil 1121 case *string: 1122 if c == nil { 1123 return nil, nil 1124 } 1125 return *c, nil 1126 } 1127 return fmt.Sprintf("%v", v), nil 1128 } 1129 1130 type anyTypeConverter struct{} 1131 1132 func (anyTypeConverter) ConvertValue(v interface{}) (driver.Value, error) { 1133 return v, nil 1134 } 1135 1136 func converterForType(typ string) driver.ValueConverter { 1137 switch typ { 1138 case "bool": 1139 return driver.Bool 1140 case "nullbool": 1141 return driver.Null{Converter: driver.Bool} 1142 case "int32": 1143 return driver.Int32 1144 case "string": 1145 return driver.NotNull{Converter: fakeDriverString{}} 1146 case "nullstring": 1147 return driver.Null{Converter: fakeDriverString{}} 1148 case "int64": 1149 // TODO(coopernurse): add type-specific converter 1150 return driver.NotNull{Converter: driver.DefaultParameterConverter} 1151 case "nullint64": 1152 // TODO(coopernurse): add type-specific converter 1153 return driver.Null{Converter: driver.DefaultParameterConverter} 1154 case "float64": 1155 // TODO(coopernurse): add type-specific converter 1156 return driver.NotNull{Converter: driver.DefaultParameterConverter} 1157 case "nullfloat64": 1158 // TODO(coopernurse): add type-specific converter 1159 return driver.Null{Converter: driver.DefaultParameterConverter} 1160 case "datetime": 1161 return driver.DefaultParameterConverter 1162 case "any": 1163 return anyTypeConverter{} 1164 } 1165 panic("invalid fakedb column type of " + typ) 1166 } 1167 1168 func colTypeToReflectType(typ string) reflect.Type { 1169 switch typ { 1170 case "bool": 1171 return reflect.TypeOf(false) 1172 case "nullbool": 1173 return reflect.TypeOf(NullBool{}) 1174 case "int32": 1175 return reflect.TypeOf(int32(0)) 1176 case "string": 1177 return reflect.TypeOf("") 1178 case "nullstring": 1179 return reflect.TypeOf(NullString{}) 1180 case "int64": 1181 return reflect.TypeOf(int64(0)) 1182 case "nullint64": 1183 return reflect.TypeOf(NullInt64{}) 1184 case "float64": 1185 return reflect.TypeOf(float64(0)) 1186 case "nullfloat64": 1187 return reflect.TypeOf(NullFloat64{}) 1188 case "datetime": 1189 return reflect.TypeOf(time.Time{}) 1190 case "any": 1191 return reflect.TypeOf(new(interface{})).Elem() 1192 } 1193 panic("invalid fakedb column type of " + typ) 1194 }