github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/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  	"database/sql/driver"
     9  	"errors"
    10  	"fmt"
    11  	"io"
    12  	"log"
    13  	"sort"
    14  	"strconv"
    15  	"strings"
    16  	"sync"
    17  	"testing"
    18  	"time"
    19  )
    20  
    21  var _ = log.Printf
    22  
    23  // fakeDriver is a fake database that implements Go's driver.Driver
    24  // interface, just for testing.
    25  //
    26  // It speaks a query language that's semantically similar to but
    27  // syntactically different and simpler than SQL.  The syntax is as
    28  // follows:
    29  //
    30  //   WIPE
    31  //   CREATE|<tablename>|<col>=<type>,<col>=<type>,...
    32  //     where types are: "string", [u]int{8,16,32,64}, "bool"
    33  //   INSERT|<tablename>|col=val,col2=val2,col3=?
    34  //   SELECT|<tablename>|projectcol1,projectcol2|filtercol=?,filtercol2=?
    35  //
    36  // When opening a fakeDriver's database, it starts empty with no
    37  // tables.  All tables and data are stored in memory only.
    38  type fakeDriver struct {
    39  	mu         sync.Mutex // guards 3 following fields
    40  	openCount  int        // conn opens
    41  	closeCount int        // conn closes
    42  	waitCh     chan struct{}
    43  	waitingCh  chan struct{}
    44  	dbs        map[string]*fakeDB
    45  }
    46  
    47  type fakeDB struct {
    48  	name string
    49  
    50  	mu      sync.Mutex
    51  	free    []*fakeConn
    52  	tables  map[string]*table
    53  	badConn bool
    54  }
    55  
    56  type table struct {
    57  	mu      sync.Mutex
    58  	colname []string
    59  	coltype []string
    60  	rows    []*row
    61  }
    62  
    63  func (t *table) columnIndex(name string) int {
    64  	for n, nname := range t.colname {
    65  		if name == nname {
    66  			return n
    67  		}
    68  	}
    69  	return -1
    70  }
    71  
    72  type row struct {
    73  	cols []interface{} // must be same size as its table colname + coltype
    74  }
    75  
    76  func (r *row) clone() *row {
    77  	nrow := &row{cols: make([]interface{}, len(r.cols))}
    78  	copy(nrow.cols, r.cols)
    79  	return nrow
    80  }
    81  
    82  type fakeConn struct {
    83  	db *fakeDB // where to return ourselves to
    84  
    85  	currTx *fakeTx
    86  
    87  	// Stats for tests:
    88  	mu          sync.Mutex
    89  	stmtsMade   int
    90  	stmtsClosed int
    91  	numPrepare  int
    92  
    93  	// bad connection tests; see isBad()
    94  	bad       bool
    95  	stickyBad bool
    96  }
    97  
    98  func (c *fakeConn) incrStat(v *int) {
    99  	c.mu.Lock()
   100  	*v++
   101  	c.mu.Unlock()
   102  }
   103  
   104  type fakeTx struct {
   105  	c *fakeConn
   106  }
   107  
   108  type fakeStmt struct {
   109  	c *fakeConn
   110  	q string // just for debugging
   111  
   112  	cmd   string
   113  	table string
   114  
   115  	closed bool
   116  
   117  	colName      []string      // used by CREATE, INSERT, SELECT (selected columns)
   118  	colType      []string      // used by CREATE
   119  	colValue     []interface{} // used by INSERT (mix of strings and "?" for bound params)
   120  	placeholders int           // used by INSERT/SELECT: number of ? params
   121  
   122  	whereCol []string // used by SELECT (all placeholders)
   123  
   124  	placeholderConverter []driver.ValueConverter // used by INSERT
   125  }
   126  
   127  var fdriver driver.Driver = &fakeDriver{}
   128  
   129  func init() {
   130  	Register("test", fdriver)
   131  }
   132  
   133  func contains(list []string, y string) bool {
   134  	for _, x := range list {
   135  		if x == y {
   136  			return true
   137  		}
   138  	}
   139  	return false
   140  }
   141  
   142  type Dummy struct {
   143  	driver.Driver
   144  }
   145  
   146  func TestDrivers(t *testing.T) {
   147  	unregisterAllDrivers()
   148  	Register("test", fdriver)
   149  	Register("invalid", Dummy{})
   150  	all := Drivers()
   151  	if len(all) < 2 || !sort.StringsAreSorted(all) || !contains(all, "test") || !contains(all, "invalid") {
   152  		t.Fatalf("Drivers = %v, want sorted list with at least [invalid, test]", all)
   153  	}
   154  }
   155  
   156  // hook to simulate connection failures
   157  var hookOpenErr struct {
   158  	sync.Mutex
   159  	fn func() error
   160  }
   161  
   162  func setHookOpenErr(fn func() error) {
   163  	hookOpenErr.Lock()
   164  	defer hookOpenErr.Unlock()
   165  	hookOpenErr.fn = fn
   166  }
   167  
   168  // Supports dsn forms:
   169  //    <dbname>
   170  //    <dbname>;<opts>  (only currently supported option is `badConn`,
   171  //                      which causes driver.ErrBadConn to be returned on
   172  //                      every other conn.Begin())
   173  func (d *fakeDriver) Open(dsn string) (driver.Conn, error) {
   174  	hookOpenErr.Lock()
   175  	fn := hookOpenErr.fn
   176  	hookOpenErr.Unlock()
   177  	if fn != nil {
   178  		if err := fn(); err != nil {
   179  			return nil, err
   180  		}
   181  	}
   182  	parts := strings.Split(dsn, ";")
   183  	if len(parts) < 1 {
   184  		return nil, errors.New("fakedb: no database name")
   185  	}
   186  	name := parts[0]
   187  
   188  	db := d.getDB(name)
   189  
   190  	d.mu.Lock()
   191  	d.openCount++
   192  	d.mu.Unlock()
   193  	conn := &fakeConn{db: db}
   194  
   195  	if len(parts) >= 2 && parts[1] == "badConn" {
   196  		conn.bad = true
   197  	}
   198  	if d.waitCh != nil {
   199  		d.waitingCh <- struct{}{}
   200  		<-d.waitCh
   201  		d.waitCh = nil
   202  		d.waitingCh = nil
   203  	}
   204  	return conn, nil
   205  }
   206  
   207  func (d *fakeDriver) getDB(name string) *fakeDB {
   208  	d.mu.Lock()
   209  	defer d.mu.Unlock()
   210  	if d.dbs == nil {
   211  		d.dbs = make(map[string]*fakeDB)
   212  	}
   213  	db, ok := d.dbs[name]
   214  	if !ok {
   215  		db = &fakeDB{name: name}
   216  		d.dbs[name] = db
   217  	}
   218  	return db
   219  }
   220  
   221  func (db *fakeDB) wipe() {
   222  	db.mu.Lock()
   223  	defer db.mu.Unlock()
   224  	db.tables = nil
   225  }
   226  
   227  func (db *fakeDB) createTable(name string, columnNames, columnTypes []string) error {
   228  	db.mu.Lock()
   229  	defer db.mu.Unlock()
   230  	if db.tables == nil {
   231  		db.tables = make(map[string]*table)
   232  	}
   233  	if _, exist := db.tables[name]; exist {
   234  		return fmt.Errorf("table %q already exists", name)
   235  	}
   236  	if len(columnNames) != len(columnTypes) {
   237  		return fmt.Errorf("create table of %q len(names) != len(types): %d vs %d",
   238  			name, len(columnNames), len(columnTypes))
   239  	}
   240  	db.tables[name] = &table{colname: columnNames, coltype: columnTypes}
   241  	return nil
   242  }
   243  
   244  // must be called with db.mu lock held
   245  func (db *fakeDB) table(table string) (*table, bool) {
   246  	if db.tables == nil {
   247  		return nil, false
   248  	}
   249  	t, ok := db.tables[table]
   250  	return t, ok
   251  }
   252  
   253  func (db *fakeDB) columnType(table, column string) (typ string, ok bool) {
   254  	db.mu.Lock()
   255  	defer db.mu.Unlock()
   256  	t, ok := db.table(table)
   257  	if !ok {
   258  		return
   259  	}
   260  	for n, cname := range t.colname {
   261  		if cname == column {
   262  			return t.coltype[n], true
   263  		}
   264  	}
   265  	return "", false
   266  }
   267  
   268  func (c *fakeConn) isBad() bool {
   269  	if c.stickyBad {
   270  		return true
   271  	} else if c.bad {
   272  		// alternate between bad conn and not bad conn
   273  		c.db.badConn = !c.db.badConn
   274  		return c.db.badConn
   275  	} else {
   276  		return false
   277  	}
   278  }
   279  
   280  func (c *fakeConn) Begin() (driver.Tx, error) {
   281  	if c.isBad() {
   282  		return nil, driver.ErrBadConn
   283  	}
   284  	if c.currTx != nil {
   285  		return nil, errors.New("already in a transaction")
   286  	}
   287  	c.currTx = &fakeTx{c: c}
   288  	return c.currTx, nil
   289  }
   290  
   291  var hookPostCloseConn struct {
   292  	sync.Mutex
   293  	fn func(*fakeConn, error)
   294  }
   295  
   296  func setHookpostCloseConn(fn func(*fakeConn, error)) {
   297  	hookPostCloseConn.Lock()
   298  	defer hookPostCloseConn.Unlock()
   299  	hookPostCloseConn.fn = fn
   300  }
   301  
   302  var testStrictClose *testing.T
   303  
   304  // setStrictFakeConnClose sets the t to Errorf on when fakeConn.Close
   305  // fails to close. If nil, the check is disabled.
   306  func setStrictFakeConnClose(t *testing.T) {
   307  	testStrictClose = t
   308  }
   309  
   310  func (c *fakeConn) Close() (err error) {
   311  	drv := fdriver.(*fakeDriver)
   312  	defer func() {
   313  		if err != nil && testStrictClose != nil {
   314  			testStrictClose.Errorf("failed to close a test fakeConn: %v", err)
   315  		}
   316  		hookPostCloseConn.Lock()
   317  		fn := hookPostCloseConn.fn
   318  		hookPostCloseConn.Unlock()
   319  		if fn != nil {
   320  			fn(c, err)
   321  		}
   322  		if err == nil {
   323  			drv.mu.Lock()
   324  			drv.closeCount++
   325  			drv.mu.Unlock()
   326  		}
   327  	}()
   328  	if c.currTx != nil {
   329  		return errors.New("can't close fakeConn; in a Transaction")
   330  	}
   331  	if c.db == nil {
   332  		return errors.New("can't close fakeConn; already closed")
   333  	}
   334  	if c.stmtsMade > c.stmtsClosed {
   335  		return errors.New("can't close; dangling statement(s)")
   336  	}
   337  	c.db = nil
   338  	return nil
   339  }
   340  
   341  func checkSubsetTypes(args []driver.Value) error {
   342  	for n, arg := range args {
   343  		switch arg.(type) {
   344  		case int64, float64, bool, nil, []byte, string, time.Time:
   345  		default:
   346  			return fmt.Errorf("fakedb_test: invalid argument #%d: %v, type %T", n+1, arg, arg)
   347  		}
   348  	}
   349  	return nil
   350  }
   351  
   352  func (c *fakeConn) Exec(query string, args []driver.Value) (driver.Result, error) {
   353  	// This is an optional interface, but it's implemented here
   354  	// just to check that all the args are of the proper types.
   355  	// ErrSkip is returned so the caller acts as if we didn't
   356  	// implement this at all.
   357  	err := checkSubsetTypes(args)
   358  	if err != nil {
   359  		return nil, err
   360  	}
   361  	return nil, driver.ErrSkip
   362  }
   363  
   364  func (c *fakeConn) Query(query string, args []driver.Value) (driver.Rows, error) {
   365  	// This is an optional interface, but it's implemented here
   366  	// just to check that all the args are of the proper types.
   367  	// ErrSkip is returned so the caller acts as if we didn't
   368  	// implement this at all.
   369  	err := checkSubsetTypes(args)
   370  	if err != nil {
   371  		return nil, err
   372  	}
   373  	return nil, driver.ErrSkip
   374  }
   375  
   376  func errf(msg string, args ...interface{}) error {
   377  	return errors.New("fakedb: " + fmt.Sprintf(msg, args...))
   378  }
   379  
   380  // parts are table|selectCol1,selectCol2|whereCol=?,whereCol2=?
   381  // (note that where columns must always contain ? marks,
   382  //  just a limitation for fakedb)
   383  func (c *fakeConn) prepareSelect(stmt *fakeStmt, parts []string) (driver.Stmt, error) {
   384  	if len(parts) != 3 {
   385  		stmt.Close()
   386  		return nil, errf("invalid SELECT syntax with %d parts; want 3", len(parts))
   387  	}
   388  	stmt.table = parts[0]
   389  	stmt.colName = strings.Split(parts[1], ",")
   390  	for n, colspec := range strings.Split(parts[2], ",") {
   391  		if colspec == "" {
   392  			continue
   393  		}
   394  		nameVal := strings.Split(colspec, "=")
   395  		if len(nameVal) != 2 {
   396  			stmt.Close()
   397  			return nil, errf("SELECT on table %q has invalid column spec of %q (index %d)", stmt.table, colspec, n)
   398  		}
   399  		column, value := nameVal[0], nameVal[1]
   400  		_, ok := c.db.columnType(stmt.table, column)
   401  		if !ok {
   402  			stmt.Close()
   403  			return nil, errf("SELECT on table %q references non-existent column %q", stmt.table, column)
   404  		}
   405  		if value != "?" {
   406  			stmt.Close()
   407  			return nil, errf("SELECT on table %q has pre-bound value for where column %q; need a question mark",
   408  				stmt.table, column)
   409  		}
   410  		stmt.whereCol = append(stmt.whereCol, column)
   411  		stmt.placeholders++
   412  	}
   413  	return stmt, nil
   414  }
   415  
   416  // parts are table|col=type,col2=type2
   417  func (c *fakeConn) prepareCreate(stmt *fakeStmt, parts []string) (driver.Stmt, error) {
   418  	if len(parts) != 2 {
   419  		stmt.Close()
   420  		return nil, errf("invalid CREATE syntax with %d parts; want 2", len(parts))
   421  	}
   422  	stmt.table = parts[0]
   423  	for n, colspec := range strings.Split(parts[1], ",") {
   424  		nameType := strings.Split(colspec, "=")
   425  		if len(nameType) != 2 {
   426  			stmt.Close()
   427  			return nil, errf("CREATE table %q has invalid column spec of %q (index %d)", stmt.table, colspec, n)
   428  		}
   429  		stmt.colName = append(stmt.colName, nameType[0])
   430  		stmt.colType = append(stmt.colType, nameType[1])
   431  	}
   432  	return stmt, nil
   433  }
   434  
   435  // parts are table|col=?,col2=val
   436  func (c *fakeConn) prepareInsert(stmt *fakeStmt, parts []string) (driver.Stmt, error) {
   437  	if len(parts) != 2 {
   438  		stmt.Close()
   439  		return nil, errf("invalid INSERT syntax with %d parts; want 2", len(parts))
   440  	}
   441  	stmt.table = parts[0]
   442  	for n, colspec := range strings.Split(parts[1], ",") {
   443  		nameVal := strings.Split(colspec, "=")
   444  		if len(nameVal) != 2 {
   445  			stmt.Close()
   446  			return nil, errf("INSERT table %q has invalid column spec of %q (index %d)", stmt.table, colspec, n)
   447  		}
   448  		column, value := nameVal[0], nameVal[1]
   449  		ctype, ok := c.db.columnType(stmt.table, column)
   450  		if !ok {
   451  			stmt.Close()
   452  			return nil, errf("INSERT table %q references non-existent column %q", stmt.table, column)
   453  		}
   454  		stmt.colName = append(stmt.colName, column)
   455  
   456  		if value != "?" {
   457  			var subsetVal interface{}
   458  			// Convert to driver subset type
   459  			switch ctype {
   460  			case "string":
   461  				subsetVal = []byte(value)
   462  			case "blob":
   463  				subsetVal = []byte(value)
   464  			case "int32":
   465  				i, err := strconv.Atoi(value)
   466  				if err != nil {
   467  					stmt.Close()
   468  					return nil, errf("invalid conversion to int32 from %q", value)
   469  				}
   470  				subsetVal = int64(i) // int64 is a subset type, but not int32
   471  			default:
   472  				stmt.Close()
   473  				return nil, errf("unsupported conversion for pre-bound parameter %q to type %q", value, ctype)
   474  			}
   475  			stmt.colValue = append(stmt.colValue, subsetVal)
   476  		} else {
   477  			stmt.placeholders++
   478  			stmt.placeholderConverter = append(stmt.placeholderConverter, converterForType(ctype))
   479  			stmt.colValue = append(stmt.colValue, "?")
   480  		}
   481  	}
   482  	return stmt, nil
   483  }
   484  
   485  // hook to simulate broken connections
   486  var hookPrepareBadConn func() bool
   487  
   488  func (c *fakeConn) Prepare(query string) (driver.Stmt, error) {
   489  	c.numPrepare++
   490  	if c.db == nil {
   491  		panic("nil c.db; conn = " + fmt.Sprintf("%#v", c))
   492  	}
   493  
   494  	if c.stickyBad || (hookPrepareBadConn != nil && hookPrepareBadConn()) {
   495  		return nil, driver.ErrBadConn
   496  	}
   497  
   498  	parts := strings.Split(query, "|")
   499  	if len(parts) < 1 {
   500  		return nil, errf("empty query")
   501  	}
   502  	cmd := parts[0]
   503  	parts = parts[1:]
   504  	stmt := &fakeStmt{q: query, c: c, cmd: cmd}
   505  	c.incrStat(&c.stmtsMade)
   506  	switch cmd {
   507  	case "WIPE":
   508  		// Nothing
   509  	case "SELECT":
   510  		return c.prepareSelect(stmt, parts)
   511  	case "CREATE":
   512  		return c.prepareCreate(stmt, parts)
   513  	case "INSERT":
   514  		return c.prepareInsert(stmt, parts)
   515  	case "NOSERT":
   516  		// Do all the prep-work like for an INSERT but don't actually insert the row.
   517  		// Used for some of the concurrent tests.
   518  		return c.prepareInsert(stmt, parts)
   519  	default:
   520  		stmt.Close()
   521  		return nil, errf("unsupported command type %q", cmd)
   522  	}
   523  	return stmt, nil
   524  }
   525  
   526  func (s *fakeStmt) ColumnConverter(idx int) driver.ValueConverter {
   527  	if len(s.placeholderConverter) == 0 {
   528  		return driver.DefaultParameterConverter
   529  	}
   530  	return s.placeholderConverter[idx]
   531  }
   532  
   533  func (s *fakeStmt) Close() error {
   534  	if s.c == nil {
   535  		panic("nil conn in fakeStmt.Close")
   536  	}
   537  	if s.c.db == nil {
   538  		panic("in fakeStmt.Close, conn's db is nil (already closed)")
   539  	}
   540  	if !s.closed {
   541  		s.c.incrStat(&s.c.stmtsClosed)
   542  		s.closed = true
   543  	}
   544  	return nil
   545  }
   546  
   547  var errClosed = errors.New("fakedb: statement has been closed")
   548  
   549  // hook to simulate broken connections
   550  var hookExecBadConn func() bool
   551  
   552  func (s *fakeStmt) Exec(args []driver.Value) (driver.Result, error) {
   553  	if s.closed {
   554  		return nil, errClosed
   555  	}
   556  
   557  	if s.c.stickyBad || (hookExecBadConn != nil && hookExecBadConn()) {
   558  		return nil, driver.ErrBadConn
   559  	}
   560  
   561  	err := checkSubsetTypes(args)
   562  	if err != nil {
   563  		return nil, err
   564  	}
   565  
   566  	db := s.c.db
   567  	switch s.cmd {
   568  	case "WIPE":
   569  		db.wipe()
   570  		return driver.ResultNoRows, nil
   571  	case "CREATE":
   572  		if err := db.createTable(s.table, s.colName, s.colType); err != nil {
   573  			return nil, err
   574  		}
   575  		return driver.ResultNoRows, nil
   576  	case "INSERT":
   577  		return s.execInsert(args, true)
   578  	case "NOSERT":
   579  		// Do all the prep-work like for an INSERT but don't actually insert the row.
   580  		// Used for some of the concurrent tests.
   581  		return s.execInsert(args, false)
   582  	}
   583  	fmt.Printf("EXEC statement, cmd=%q: %#v\n", s.cmd, s)
   584  	return nil, fmt.Errorf("unimplemented statement Exec command type of %q", s.cmd)
   585  }
   586  
   587  // When doInsert is true, add the row to the table.
   588  // When doInsert is false do prep-work and error checking, but don't
   589  // actually add the row to the table.
   590  func (s *fakeStmt) execInsert(args []driver.Value, doInsert bool) (driver.Result, error) {
   591  	db := s.c.db
   592  	if len(args) != s.placeholders {
   593  		panic("error in pkg db; should only get here if size is correct")
   594  	}
   595  	db.mu.Lock()
   596  	t, ok := db.table(s.table)
   597  	db.mu.Unlock()
   598  	if !ok {
   599  		return nil, fmt.Errorf("fakedb: table %q doesn't exist", s.table)
   600  	}
   601  
   602  	t.mu.Lock()
   603  	defer t.mu.Unlock()
   604  
   605  	var cols []interface{}
   606  	if doInsert {
   607  		cols = make([]interface{}, len(t.colname))
   608  	}
   609  	argPos := 0
   610  	for n, colname := range s.colName {
   611  		colidx := t.columnIndex(colname)
   612  		if colidx == -1 {
   613  			return nil, fmt.Errorf("fakedb: column %q doesn't exist or dropped since prepared statement was created", colname)
   614  		}
   615  		var val interface{}
   616  		if strvalue, ok := s.colValue[n].(string); ok && strvalue == "?" {
   617  			val = args[argPos]
   618  			argPos++
   619  		} else {
   620  			val = s.colValue[n]
   621  		}
   622  		if doInsert {
   623  			cols[colidx] = val
   624  		}
   625  	}
   626  
   627  	if doInsert {
   628  		t.rows = append(t.rows, &row{cols: cols})
   629  	}
   630  	return driver.RowsAffected(1), nil
   631  }
   632  
   633  // hook to simulate broken connections
   634  var hookQueryBadConn func() bool
   635  
   636  func (s *fakeStmt) Query(args []driver.Value) (driver.Rows, error) {
   637  	if s.closed {
   638  		return nil, errClosed
   639  	}
   640  
   641  	if s.c.stickyBad || (hookQueryBadConn != nil && hookQueryBadConn()) {
   642  		return nil, driver.ErrBadConn
   643  	}
   644  
   645  	err := checkSubsetTypes(args)
   646  	if err != nil {
   647  		return nil, err
   648  	}
   649  
   650  	db := s.c.db
   651  	if len(args) != s.placeholders {
   652  		panic("error in pkg db; should only get here if size is correct")
   653  	}
   654  
   655  	db.mu.Lock()
   656  	t, ok := db.table(s.table)
   657  	db.mu.Unlock()
   658  	if !ok {
   659  		return nil, fmt.Errorf("fakedb: table %q doesn't exist", s.table)
   660  	}
   661  
   662  	if s.table == "magicquery" {
   663  		if len(s.whereCol) == 2 && s.whereCol[0] == "op" && s.whereCol[1] == "millis" {
   664  			if args[0] == "sleep" {
   665  				time.Sleep(time.Duration(args[1].(int64)) * time.Millisecond)
   666  			}
   667  		}
   668  	}
   669  
   670  	t.mu.Lock()
   671  	defer t.mu.Unlock()
   672  
   673  	colIdx := make(map[string]int) // select column name -> column index in table
   674  	for _, name := range s.colName {
   675  		idx := t.columnIndex(name)
   676  		if idx == -1 {
   677  			return nil, fmt.Errorf("fakedb: unknown column name %q", name)
   678  		}
   679  		colIdx[name] = idx
   680  	}
   681  
   682  	mrows := []*row{}
   683  rows:
   684  	for _, trow := range t.rows {
   685  		// Process the where clause, skipping non-match rows. This is lazy
   686  		// and just uses fmt.Sprintf("%v") to test equality.  Good enough
   687  		// for test code.
   688  		for widx, wcol := range s.whereCol {
   689  			idx := t.columnIndex(wcol)
   690  			if idx == -1 {
   691  				return nil, fmt.Errorf("db: invalid where clause column %q", wcol)
   692  			}
   693  			tcol := trow.cols[idx]
   694  			if bs, ok := tcol.([]byte); ok {
   695  				// lazy hack to avoid sprintf %v on a []byte
   696  				tcol = string(bs)
   697  			}
   698  			if fmt.Sprintf("%v", tcol) != fmt.Sprintf("%v", args[widx]) {
   699  				continue rows
   700  			}
   701  		}
   702  		mrow := &row{cols: make([]interface{}, len(s.colName))}
   703  		for seli, name := range s.colName {
   704  			mrow.cols[seli] = trow.cols[colIdx[name]]
   705  		}
   706  		mrows = append(mrows, mrow)
   707  	}
   708  
   709  	cursor := &rowsCursor{
   710  		pos:    -1,
   711  		rows:   mrows,
   712  		cols:   s.colName,
   713  		errPos: -1,
   714  	}
   715  	return cursor, nil
   716  }
   717  
   718  func (s *fakeStmt) NumInput() int {
   719  	return s.placeholders
   720  }
   721  
   722  // hook to simulate broken connections
   723  var hookCommitBadConn func() bool
   724  
   725  func (tx *fakeTx) Commit() error {
   726  	tx.c.currTx = nil
   727  	if hookCommitBadConn != nil && hookCommitBadConn() {
   728  		return driver.ErrBadConn
   729  	}
   730  	return nil
   731  }
   732  
   733  // hook to simulate broken connections
   734  var hookRollbackBadConn func() bool
   735  
   736  func (tx *fakeTx) Rollback() error {
   737  	tx.c.currTx = nil
   738  	if hookRollbackBadConn != nil && hookRollbackBadConn() {
   739  		return driver.ErrBadConn
   740  	}
   741  	return nil
   742  }
   743  
   744  type rowsCursor struct {
   745  	cols   []string
   746  	pos    int
   747  	rows   []*row
   748  	closed bool
   749  
   750  	// errPos and err are for making Next return early with error.
   751  	errPos int
   752  	err    error
   753  
   754  	// a clone of slices to give out to clients, indexed by the
   755  	// the original slice's first byte address.  we clone them
   756  	// just so we're able to corrupt them on close.
   757  	bytesClone map[*byte][]byte
   758  }
   759  
   760  func (rc *rowsCursor) Close() error {
   761  	if !rc.closed {
   762  		for _, bs := range rc.bytesClone {
   763  			bs[0] = 255 // first byte corrupted
   764  		}
   765  	}
   766  	rc.closed = true
   767  	return nil
   768  }
   769  
   770  func (rc *rowsCursor) Columns() []string {
   771  	return rc.cols
   772  }
   773  
   774  var rowsCursorNextHook func(dest []driver.Value) error
   775  
   776  func (rc *rowsCursor) Next(dest []driver.Value) error {
   777  	if rowsCursorNextHook != nil {
   778  		return rowsCursorNextHook(dest)
   779  	}
   780  
   781  	if rc.closed {
   782  		return errors.New("fakedb: cursor is closed")
   783  	}
   784  	rc.pos++
   785  	if rc.pos == rc.errPos {
   786  		return rc.err
   787  	}
   788  	if rc.pos >= len(rc.rows) {
   789  		return io.EOF // per interface spec
   790  	}
   791  	for i, v := range rc.rows[rc.pos].cols {
   792  		// TODO(bradfitz): convert to subset types? naah, I
   793  		// think the subset types should only be input to
   794  		// driver, but the sql package should be able to handle
   795  		// a wider range of types coming out of drivers. all
   796  		// for ease of drivers, and to prevent drivers from
   797  		// messing up conversions or doing them differently.
   798  		dest[i] = v
   799  
   800  		if bs, ok := v.([]byte); ok {
   801  			if rc.bytesClone == nil {
   802  				rc.bytesClone = make(map[*byte][]byte)
   803  			}
   804  			clone, ok := rc.bytesClone[&bs[0]]
   805  			if !ok {
   806  				clone = make([]byte, len(bs))
   807  				copy(clone, bs)
   808  				rc.bytesClone[&bs[0]] = clone
   809  			}
   810  			dest[i] = clone
   811  		}
   812  	}
   813  	return nil
   814  }
   815  
   816  // fakeDriverString is like driver.String, but indirects pointers like
   817  // DefaultValueConverter.
   818  //
   819  // This could be surprising behavior to retroactively apply to
   820  // driver.String now that Go1 is out, but this is convenient for
   821  // our TestPointerParamsAndScans.
   822  //
   823  type fakeDriverString struct{}
   824  
   825  func (fakeDriverString) ConvertValue(v interface{}) (driver.Value, error) {
   826  	switch c := v.(type) {
   827  	case string, []byte:
   828  		return v, nil
   829  	case *string:
   830  		if c == nil {
   831  			return nil, nil
   832  		}
   833  		return *c, nil
   834  	}
   835  	return fmt.Sprintf("%v", v), nil
   836  }
   837  
   838  func converterForType(typ string) driver.ValueConverter {
   839  	switch typ {
   840  	case "bool":
   841  		return driver.Bool
   842  	case "nullbool":
   843  		return driver.Null{Converter: driver.Bool}
   844  	case "int32":
   845  		return driver.Int32
   846  	case "string":
   847  		return driver.NotNull{Converter: fakeDriverString{}}
   848  	case "nullstring":
   849  		return driver.Null{Converter: fakeDriverString{}}
   850  	case "int64":
   851  		// TODO(coopernurse): add type-specific converter
   852  		return driver.NotNull{Converter: driver.DefaultParameterConverter}
   853  	case "nullint64":
   854  		// TODO(coopernurse): add type-specific converter
   855  		return driver.Null{Converter: driver.DefaultParameterConverter}
   856  	case "float64":
   857  		// TODO(coopernurse): add type-specific converter
   858  		return driver.NotNull{Converter: driver.DefaultParameterConverter}
   859  	case "nullfloat64":
   860  		// TODO(coopernurse): add type-specific converter
   861  		return driver.Null{Converter: driver.DefaultParameterConverter}
   862  	case "datetime":
   863  		return driver.DefaultParameterConverter
   864  	}
   865  	panic("invalid fakedb column type of " + typ)
   866  }