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.
27 freedFrom
:= make(map[dbConn
]string)
29 getFreedFrom
:= func(c dbConn
) string {
34 setFreedFrom
:= func(c dbConn
, s
string) {
39 putConnHook
= func(db
*DB
, c
*driverConn
) {
41 for i
, v
:= range db
.freeConn
{
48 // print before panic, as panic may get lost due to conflicting panic
49 // (all goroutines asleep) elsewhere, since we might not unlock
50 // the mutex in freeConn here.
51 println("double free of conn. conflicts are:\nA) " + getFreedFrom(dbConn
{db
, c
}) + "\n\nand\nB) " + stack())
52 panic("double free of conn.")
54 setFreedFrom(dbConn
{db
, c
}, stack())
58 const fakeDBName
= "foo"
60 var chrisBirthday
= time
.Unix(123456789, 0)
62 func newTestDB(t testing
.TB
, name
string) *DB
{
63 db
, err
:= Open("test", fakeDBName
)
65 t
.Fatalf("Open: %v", err
)
67 if _
, err
:= db
.Exec("WIPE"); err
!= nil {
68 t
.Fatalf("exec wipe: %v", err
)
71 exec(t
, db
, "CREATE|people|name=string,age=int32,photo=blob,dead=bool,bdate=datetime")
72 exec(t
, db
, "INSERT|people|name=Alice,age=?,photo=APHOTO", 1)
73 exec(t
, db
, "INSERT|people|name=Bob,age=?,photo=BPHOTO", 2)
74 exec(t
, db
, "INSERT|people|name=Chris,age=?,photo=CPHOTO,bdate=?", 3, chrisBirthday
)
76 if name
== "magicquery" {
77 // Magic table name and column, known by fakedb_test.go.
78 exec(t
, db
, "CREATE|magicquery|op=string,millis=int32")
79 exec(t
, db
, "INSERT|magicquery|op=sleep,millis=10")
84 func TestDriverPanic(t
*testing
.T
) {
85 // Test that if driver panics, database/sql does not deadlock.
86 db
, err
:= Open("test", fakeDBName
)
88 t
.Fatalf("Open: %v", err
)
90 expectPanic
:= func(name
string, f
func()) {
94 t
.Fatalf("%s did not panic", name
)
100 expectPanic("Exec Exec", func() { db
.Exec("PANIC|Exec|WIPE") })
101 exec(t
, db
, "WIPE") // check not deadlocked
102 expectPanic("Exec NumInput", func() { db
.Exec("PANIC|NumInput|WIPE") })
103 exec(t
, db
, "WIPE") // check not deadlocked
104 expectPanic("Exec Close", func() { db
.Exec("PANIC|Close|WIPE") })
105 exec(t
, db
, "WIPE") // check not deadlocked
106 exec(t
, db
, "PANIC|Query|WIPE") // should run successfully: Exec does not call Query
107 exec(t
, db
, "WIPE") // check not deadlocked
109 exec(t
, db
, "CREATE|people|name=string,age=int32,photo=blob,dead=bool,bdate=datetime")
111 expectPanic("Query Query", func() { db
.Query("PANIC|Query|SELECT|people|age,name|") })
112 expectPanic("Query NumInput", func() { db
.Query("PANIC|NumInput|SELECT|people|age,name|") })
113 expectPanic("Query Close", func() {
114 rows
, err
:= db
.Query("PANIC|Close|SELECT|people|age,name|")
120 db
.Query("PANIC|Exec|SELECT|people|age,name|") // should run successfully: Query does not call Exec
121 exec(t
, db
, "WIPE") // check not deadlocked
124 func exec(t testing
.TB
, db
*DB
, query
string, args
...interface{}) {
125 _
, err
:= db
.Exec(query
, args
...)
127 t
.Fatalf("Exec of %q: %v", query
, err
)
131 func closeDB(t testing
.TB
, db
*DB
) {
132 if e
:= recover(); e
!= nil {
133 fmt
.Printf("Panic: %v\n", e
)
136 defer setHookpostCloseConn(nil)
137 setHookpostCloseConn(func(_
*fakeConn
, err error
) {
139 t
.Errorf("Error closing fakeConn: %v", err
)
142 for i
, dc
:= range db
.freeConn
{
143 if n
:= len(dc
.openStmt
); n
> 0 {
144 // Just a sanity check. This is legal in
145 // general, but if we make the tests clean up
146 // their statements first, then we can safely
147 // verify this is always zero here, and any
148 // other value is a leak.
149 t
.Errorf("while closing db, freeConn %d/%d had %d open stmts; want 0", i
, len(db
.freeConn
), n
)
154 t
.Fatalf("error closing DB: %v", err
)
158 if !waitCondition(5*time
.Second
, 5*time
.Millisecond
, func() bool {
159 numOpen
= db
.numOpenConns()
162 t
.Fatalf("%d connections still open after closing DB", numOpen
)
166 // numPrepares assumes that db has exactly 1 idle conn and returns
167 // its count of calls to Prepare
168 func numPrepares(t
*testing
.T
, db
*DB
) int {
169 if n
:= len(db
.freeConn
); n
!= 1 {
170 t
.Fatalf("free conns = %d; want 1", n
)
172 return db
.freeConn
[0].ci
.(*fakeConn
).numPrepare
175 func (db
*DB
) numDeps() int {
181 // Dependencies are closed via a goroutine, so this polls waiting for
182 // numDeps to fall to want, waiting up to d.
183 func (db
*DB
) numDepsPollUntil(want
int, d time
.Duration
) int {
184 deadline
:= time
.Now().Add(d
)
187 if n
<= want || time
.Now().After(deadline
) {
190 time
.Sleep(50 * time
.Millisecond
)
194 func (db
*DB
) numFreeConns() int {
197 return len(db
.freeConn
)
200 func (db
*DB
) numOpenConns() int {
206 // clearAllConns closes all connections in db.
207 func (db
*DB
) clearAllConns(t
*testing
.T
) {
208 db
.SetMaxIdleConns(0)
210 if g
, w
:= db
.numFreeConns(), 0; g
!= w
{
211 t
.Errorf("free conns = %d; want %d", g
, w
)
214 if n
:= db
.numDepsPollUntil(0, time
.Second
); n
> 0 {
215 t
.Errorf("number of dependencies = %d; expected 0", n
)
220 func (db
*DB
) dumpDeps(t
*testing
.T
) {
221 for fc
:= range db
.dep
{
222 db
.dumpDep(t
, 0, fc
, map[finalCloser
]bool{})
226 func (db
*DB
) dumpDep(t
*testing
.T
, depth
int, dep finalCloser
, seen
map[finalCloser
]bool) {
228 indent
:= strings
.Repeat(" ", depth
)
231 t
.Logf("%s%T (%p) waiting for -> %T (%p)", indent
, dep
, dep
, k
, k
)
232 if fc
, ok
:= k
.(finalCloser
); ok
{
234 db
.dumpDep(t
, depth
+1, fc
, seen
)
240 func TestQuery(t
*testing
.T
) {
241 db
:= newTestDB(t
, "people")
243 prepares0
:= numPrepares(t
, db
)
244 rows
, err
:= db
.Query("SELECT|people|age,name|")
246 t
.Fatalf("Query: %v", err
)
255 err
= rows
.Scan(&r
.age
, &r
.name
)
257 t
.Fatalf("Scan: %v", err
)
263 t
.Fatalf("Err: %v", err
)
266 {age
: 1, name
: "Alice"},
267 {age
: 2, name
: "Bob"},
268 {age
: 3, name
: "Chris"},
270 if !reflect
.DeepEqual(got
, want
) {
271 t
.Errorf("mismatch.\n got: %#v\nwant: %#v", got
, want
)
274 // And verify that the final rows.Next() call, which hit EOF,
275 // also closed the rows connection.
276 if n
:= db
.numFreeConns(); n
!= 1 {
277 t
.Fatalf("free conns after query hitting EOF = %d; want 1", n
)
279 if prepares
:= numPrepares(t
, db
) - prepares0
; prepares
!= 1 {
280 t
.Errorf("executed %d Prepare statements; want 1", prepares
)
284 // TestQueryContext tests canceling the context while scanning the rows.
285 func TestQueryContext(t
*testing
.T
) {
286 db
:= newTestDB(t
, "people")
288 prepares0
:= numPrepares(t
, db
)
290 ctx
, cancel
:= context
.WithCancel(context
.Background())
293 rows
, err
:= db
.QueryContext(ctx
, "SELECT|people|age,name|")
295 t
.Fatalf("Query: %v", err
)
306 waitForRowsClose(t
, rows
, 5*time
.Second
)
309 err
= rows
.Scan(&r
.age
, &r
.name
)
314 t
.Fatalf("Scan: %v", err
)
316 if index
== 2 && err
== nil {
317 t
.Fatal("expected an error on last scan")
324 if err
:= ctx
.Err(); err
!= context
.Canceled
{
325 t
.Fatalf("context err = %v; want context.Canceled")
328 t
.Fatalf("context err = nil; want context.Canceled")
331 {age
: 1, name
: "Alice"},
332 {age
: 2, name
: "Bob"},
334 if !reflect
.DeepEqual(got
, want
) {
335 t
.Errorf("mismatch.\n got: %#v\nwant: %#v", got
, want
)
338 // And verify that the final rows.Next() call, which hit EOF,
339 // also closed the rows connection.
340 waitForRowsClose(t
, rows
, 5*time
.Second
)
341 waitForFree(t
, db
, 5*time
.Second
, 1)
342 if prepares
:= numPrepares(t
, db
) - prepares0
; prepares
!= 1 {
343 t
.Errorf("executed %d Prepare statements; want 1", prepares
)
347 func waitCondition(waitFor
, checkEvery time
.Duration
, fn
func() bool) bool {
348 deadline
:= time
.Now().Add(waitFor
)
349 for time
.Now().Before(deadline
) {
353 time
.Sleep(checkEvery
)
358 // waitForFree checks db.numFreeConns until either it equals want or
359 // the maxWait time elapses.
360 func waitForFree(t
*testing
.T
, db
*DB
, maxWait time
.Duration
, want
int) {
362 if !waitCondition(maxWait
, 5*time
.Millisecond
, func() bool {
363 numFree
= db
.numFreeConns()
364 return numFree
== want
366 t
.Fatalf("free conns after hitting EOF = %d; want %d", numFree
, want
)
370 func waitForRowsClose(t
*testing
.T
, rows
*Rows
, maxWait time
.Duration
) {
371 if !waitCondition(maxWait
, 5*time
.Millisecond
, func() bool {
373 defer rows
.closemu
.RUnlock()
376 t
.Fatal("failed to close rows")
380 // TestQueryContextWait ensures that rows and all internal statements are closed when
381 // a query context is closed during execution.
382 func TestQueryContextWait(t
*testing
.T
) {
383 db
:= newTestDB(t
, "people")
385 prepares0
:= numPrepares(t
, db
)
387 // TODO(kardianos): convert this from using a timeout to using an explicit
388 // cancel when the query signals that is is "executing" the query.
389 ctx
, cancel
:= context
.WithTimeout(context
.Background(), 300*time
.Millisecond
)
392 // This will trigger the *fakeConn.Prepare method which will take time
393 // performing the query. The ctxDriverPrepare func will check the context
394 // after this and close the rows and return an error.
395 _
, err
:= db
.QueryContext(ctx
, "WAIT|1s|SELECT|people|age,name|")
396 if err
!= context
.DeadlineExceeded
{
397 t
.Fatalf("expected QueryContext to error with context deadline exceeded but returned %v", err
)
400 // Verify closed rows connection after error condition.
401 waitForFree(t
, db
, 5*time
.Second
, 1)
402 if prepares
:= numPrepares(t
, db
) - prepares0
; prepares
!= 1 {
403 // TODO(kardianos): if the context timeouts before the db.QueryContext
404 // executes this check may fail. After adjusting how the context
405 // is canceled above revert this back to a Fatal error.
406 t
.Logf("executed %d Prepare statements; want 1", prepares
)
410 // TestTxContextWait tests the transaction behavior when the tx context is canceled
411 // during execution of the query.
412 func TestTxContextWait(t
*testing
.T
) {
413 db
:= newTestDB(t
, "people")
416 ctx
, _
:= context
.WithTimeout(context
.Background(), time
.Millisecond
*15)
418 tx
, err
:= db
.BeginTx(ctx
, nil)
420 // Guard against the context being canceled before BeginTx completes.
421 if err
== context
.DeadlineExceeded
{
422 t
.Skip("tx context canceled prior to first use")
427 // This will trigger the *fakeConn.Prepare method which will take time
428 // performing the query. The ctxDriverPrepare func will check the context
429 // after this and close the rows and return an error.
430 _
, err
= tx
.QueryContext(ctx
, "WAIT|1s|SELECT|people|age,name|")
431 if err
!= context
.DeadlineExceeded
{
432 t
.Fatalf("expected QueryContext to error with context deadline exceeded but returned %v", err
)
435 waitForFree(t
, db
, 5*time
.Second
, 0)
438 func TestMultiResultSetQuery(t
*testing
.T
) {
439 db
:= newTestDB(t
, "people")
441 prepares0
:= numPrepares(t
, db
)
442 rows
, err
:= db
.Query("SELECT|people|age,name|;SELECT|people|name|")
444 t
.Fatalf("Query: %v", err
)
456 err
= rows
.Scan(&r
.age
, &r
.name
)
458 t
.Fatalf("Scan: %v", err
)
460 got1
= append(got1
, r
)
464 t
.Fatalf("Err: %v", err
)
467 {age
: 1, name
: "Alice"},
468 {age
: 2, name
: "Bob"},
469 {age
: 3, name
: "Chris"},
471 if !reflect
.DeepEqual(got1
, want1
) {
472 t
.Errorf("mismatch.\n got1: %#v\nwant: %#v", got1
, want1
)
475 if !rows
.NextResultSet() {
476 t
.Errorf("expected another result set")
482 err
= rows
.Scan(&r
.name
)
484 t
.Fatalf("Scan: %v", err
)
486 got2
= append(got2
, r
)
490 t
.Fatalf("Err: %v", err
)
497 if !reflect
.DeepEqual(got2
, want2
) {
498 t
.Errorf("mismatch.\n got: %#v\nwant: %#v", got2
, want2
)
500 if rows
.NextResultSet() {
501 t
.Errorf("expected no more result sets")
504 // And verify that the final rows.Next() call, which hit EOF,
505 // also closed the rows connection.
506 waitForFree(t
, db
, 5*time
.Second
, 1)
507 if prepares
:= numPrepares(t
, db
) - prepares0
; prepares
!= 1 {
508 t
.Errorf("executed %d Prepare statements; want 1", prepares
)
512 func TestQueryNamedArg(t
*testing
.T
) {
513 db
:= newTestDB(t
, "people")
515 prepares0
:= numPrepares(t
, db
)
516 rows
, err
:= db
.Query(
517 // Ensure the name and age parameters only match on placeholder name, not position.
518 "SELECT|people|age,name|name=?name,age=?age",
520 Named("name", "Bob"),
523 t
.Fatalf("Query: %v", err
)
532 err
= rows
.Scan(&r
.age
, &r
.name
)
534 t
.Fatalf("Scan: %v", err
)
540 t
.Fatalf("Err: %v", err
)
543 {age
: 2, name
: "Bob"},
545 if !reflect
.DeepEqual(got
, want
) {
546 t
.Errorf("mismatch.\n got: %#v\nwant: %#v", got
, want
)
549 // And verify that the final rows.Next() call, which hit EOF,
550 // also closed the rows connection.
551 if n
:= db
.numFreeConns(); n
!= 1 {
552 t
.Fatalf("free conns after query hitting EOF = %d; want 1", n
)
554 if prepares
:= numPrepares(t
, db
) - prepares0
; prepares
!= 1 {
555 t
.Errorf("executed %d Prepare statements; want 1", prepares
)
559 func TestPoolExhaustOnCancel(t
*testing
.T
) {
563 db
:= newTestDB(t
, "people")
568 db
.SetMaxOpenConns(max
)
570 // First saturate the connection pool.
571 // Then start new requests for a connection that is cancelled after it is requested.
573 var saturate
, saturateDone sync
.WaitGroup
575 saturateDone
.Add(max
)
577 for i
:= 0; i
< max
; i
++ {
580 rows
, err
:= db
.Query("WAIT|500ms|SELECT|people|name,photo|")
582 t
.Fatalf("Query: %v", err
)
591 // Now cancel the request while it is waiting.
592 ctx
, cancel
:= context
.WithTimeout(context
.Background(), time
.Second
*2)
595 for i
:= 0; i
< max
; i
++ {
596 ctxReq
, cancelReq
:= context
.WithCancel(ctx
)
598 time
.Sleep(time
.Millisecond
* 100)
601 err
:= db
.PingContext(ctxReq
)
602 if err
!= context
.Canceled
{
603 t
.Fatalf("PingContext (Exhaust): %v", err
)
609 // Now try to open a normal connection.
610 err
:= db
.PingContext(ctx
)
612 t
.Fatalf("PingContext (Normal): %v", err
)
616 func TestByteOwnership(t
*testing
.T
) {
617 db
:= newTestDB(t
, "people")
619 rows
, err
:= db
.Query("SELECT|people|name,photo|")
621 t
.Fatalf("Query: %v", err
)
630 err
= rows
.Scan(&r
.name
, &r
.photo
)
632 t
.Fatalf("Scan: %v", err
)
636 corruptMemory
:= []byte("\xffPHOTO")
638 {name
: []byte("Alice"), photo
: corruptMemory
},
639 {name
: []byte("Bob"), photo
: corruptMemory
},
640 {name
: []byte("Chris"), photo
: corruptMemory
},
642 if !reflect
.DeepEqual(got
, want
) {
643 t
.Errorf("mismatch.\n got: %#v\nwant: %#v", got
, want
)
647 err
= db
.QueryRow("SELECT|people|photo|name=?", "Alice").Scan(&photo
)
649 t
.Error("want error scanning into RawBytes from QueryRow")
653 func TestRowsColumns(t
*testing
.T
) {
654 db
:= newTestDB(t
, "people")
656 rows
, err
:= db
.Query("SELECT|people|age,name|")
658 t
.Fatalf("Query: %v", err
)
660 cols
, err
:= rows
.Columns()
662 t
.Fatalf("Columns: %v", err
)
664 want
:= []string{"age", "name"}
665 if !reflect
.DeepEqual(cols
, want
) {
666 t
.Errorf("got %#v; want %#v", cols
, want
)
668 if err
:= rows
.Close(); err
!= nil {
669 t
.Errorf("error closing rows: %s", err
)
673 func TestRowsColumnTypes(t
*testing
.T
) {
674 db
:= newTestDB(t
, "people")
676 rows
, err
:= db
.Query("SELECT|people|age,name|")
678 t
.Fatalf("Query: %v", err
)
680 tt
, err
:= rows
.ColumnTypes()
682 t
.Fatalf("ColumnTypes: %v", err
)
685 types
:= make([]reflect
.Type
, len(tt
))
686 for i
, tp
:= range tt
{
689 t
.Errorf("scantype is null for column %q", tp
.Name())
694 values
:= make([]interface{}, len(tt
))
695 for i
:= range values
{
696 values
[i
] = reflect
.New(types
[i
]).Interface()
700 err
= rows
.Scan(values
...)
702 t
.Fatalf("failed to scan values in %v", err
)
706 if values
[0].(string) != "Bob" {
707 t
.Errorf("Expected Bob, got %v", values
[0])
709 if values
[1].(int) != 2 {
710 t
.Errorf("Expected 2, got %v", values
[1])
715 t
.Errorf("expected 3 rows, got %d", ct
)
718 if err
:= rows
.Close(); err
!= nil {
719 t
.Errorf("error closing rows: %s", err
)
723 func TestQueryRow(t
*testing
.T
) {
724 db
:= newTestDB(t
, "people")
728 var birthday time
.Time
730 err
:= db
.QueryRow("SELECT|people|age,name|age=?", 3).Scan(&age
)
731 if err
== nil ||
!strings
.Contains(err
.Error(), "expected 2 destination arguments") {
732 t
.Errorf("expected error from wrong number of arguments; actually got: %v", err
)
735 err
= db
.QueryRow("SELECT|people|bdate|age=?", 3).Scan(&birthday
)
736 if err
!= nil ||
!birthday
.Equal(chrisBirthday
) {
737 t
.Errorf("chris birthday = %v, err = %v; want %v", birthday
, err
, chrisBirthday
)
740 err
= db
.QueryRow("SELECT|people|age,name|age=?", 2).Scan(&age
, &name
)
742 t
.Fatalf("age QueryRow+Scan: %v", err
)
745 t
.Errorf("expected name Bob, got %q", name
)
748 t
.Errorf("expected age 2, got %d", age
)
751 err
= db
.QueryRow("SELECT|people|age,name|name=?", "Alice").Scan(&age
, &name
)
753 t
.Fatalf("name QueryRow+Scan: %v", err
)
756 t
.Errorf("expected name Alice, got %q", name
)
759 t
.Errorf("expected age 1, got %d", age
)
763 err
= db
.QueryRow("SELECT|people|photo|name=?", "Alice").Scan(&photo
)
765 t
.Fatalf("photo QueryRow+Scan: %v", err
)
767 want
:= []byte("APHOTO")
768 if !reflect
.DeepEqual(photo
, want
) {
769 t
.Errorf("photo = %q; want %q", photo
, want
)
773 func TestTxRollbackCommitErr(t
*testing
.T
) {
774 db
:= newTestDB(t
, "people")
777 tx
, err
:= db
.Begin()
783 t
.Errorf("expected nil error from Rollback; got %v", err
)
786 if err
!= ErrTxDone
{
787 t
.Errorf("expected %q from Commit; got %q", ErrTxDone
, err
)
796 t
.Errorf("expected nil error from Commit; got %v", err
)
799 if err
!= ErrTxDone
{
800 t
.Errorf("expected %q from Rollback; got %q", ErrTxDone
, err
)
804 func TestStatementErrorAfterClose(t
*testing
.T
) {
805 db
:= newTestDB(t
, "people")
807 stmt
, err
:= db
.Prepare("SELECT|people|age|name=?")
809 t
.Fatalf("Prepare: %v", err
)
813 t
.Fatalf("Close: %v", err
)
816 err
= stmt
.QueryRow("foo").Scan(&name
)
818 t
.Errorf("expected error from QueryRow.Scan after Stmt.Close")
822 func TestStatementQueryRow(t
*testing
.T
) {
823 db
:= newTestDB(t
, "people")
825 stmt
, err
:= db
.Prepare("SELECT|people|age|name=?")
827 t
.Fatalf("Prepare: %v", err
)
831 for n
, tt
:= range []struct {
839 if err
:= stmt
.QueryRow(tt
.name
).Scan(&age
); err
!= nil {
840 t
.Errorf("%d: on %q, QueryRow/Scan: %v", n
, tt
.name
, err
)
841 } else if age
!= tt
.want
{
842 t
.Errorf("%d: age=%d, want %d", n
, age
, tt
.want
)
847 type stubDriverStmt
struct {
851 func (s stubDriverStmt
) Close() error
{
855 func (s stubDriverStmt
) NumInput() int {
859 func (s stubDriverStmt
) Exec(args
[]driver
.Value
) (driver
.Result
, error
) {
863 func (s stubDriverStmt
) Query(args
[]driver
.Value
) (driver
.Rows
, error
) {
867 // golang.org/issue/12798
868 func TestStatementClose(t
*testing
.T
) {
869 want
:= errors
.New("STMT ERROR")
875 {&Stmt
{stickyErr
: want
}, "stickyErr not propagated"},
876 {&Stmt
{tx
: &Tx
{}, txds
: &driverStmt
{Locker
: &sync
.Mutex
{}, si
: stubDriverStmt
{want
}}}, "driverStmt.Close() error not propagated"},
878 for _
, test
:= range tests
{
879 if err
:= test
.stmt
.Close(); err
!= want
{
880 t
.Errorf("%s. Got stmt.Close() = %v, want = %v", test
.msg
, err
, want
)
885 // golang.org/issue/3734
886 func TestStatementQueryRowConcurrent(t
*testing
.T
) {
887 db
:= newTestDB(t
, "people")
889 stmt
, err
:= db
.Prepare("SELECT|people|age|name=?")
891 t
.Fatalf("Prepare: %v", err
)
896 ch
:= make(chan error
, n
)
897 for i
:= 0; i
< n
; i
++ {
900 err
:= stmt
.QueryRow("Alice").Scan(&age
)
901 if err
== nil && age
!= 1 {
902 err
= fmt
.Errorf("unexpected age %d", age
)
907 for i
:= 0; i
< n
; i
++ {
908 if err
:= <-ch
; err
!= nil {
914 // just a test of fakedb itself
915 func TestBogusPreboundParameters(t
*testing
.T
) {
916 db
:= newTestDB(t
, "foo")
918 exec(t
, db
, "CREATE|t1|name=string,age=int32,dead=bool")
919 _
, err
:= db
.Prepare("INSERT|t1|name=?,age=bogusconversion")
921 t
.Fatalf("expected error")
923 if err
.Error() != `fakedb: invalid conversion to int32 from "bogusconversion"` {
924 t
.Errorf("unexpected error: %v", err
)
928 func TestExec(t
*testing
.T
) {
929 db
:= newTestDB(t
, "foo")
931 exec(t
, db
, "CREATE|t1|name=string,age=int32,dead=bool")
932 stmt
, err
:= db
.Prepare("INSERT|t1|name=?,age=?")
934 t
.Errorf("Stmt, err = %v, %v", stmt
, err
)
938 type execTest
struct {
942 execTests
:= []execTest
{
944 {[]interface{}{"Brad", 31}, ""},
945 {[]interface{}{"Brad", int64(31)}, ""},
946 {[]interface{}{"Bob", "32"}, ""},
947 {[]interface{}{7, 9}, ""},
949 // Invalid conversions:
950 {[]interface{}{"Brad", int64(0xFFFFFFFF)}, "sql: converting argument $2 type: sql/driver: value 4294967295 overflows int32"},
951 {[]interface{}{"Brad", "strconv fail"}, `sql: converting argument $2 type: sql/driver: value "strconv fail" can't be converted to int32`},
953 // Wrong number of args:
954 {[]interface{}{}, "sql: expected 2 arguments, got 0"},
955 {[]interface{}{1, 2, 3}, "sql: expected 2 arguments, got 3"},
957 for n
, et
:= range execTests
{
958 _
, err
:= stmt
.Exec(et
.args
...)
963 if errStr
!= et
.wantErr
{
964 t
.Errorf("stmt.Execute #%d: for %v, got error %q, want error %q",
965 n
, et
.args
, errStr
, et
.wantErr
)
970 func TestTxPrepare(t
*testing
.T
) {
971 db
:= newTestDB(t
, "")
973 exec(t
, db
, "CREATE|t1|name=string,age=int32,dead=bool")
974 tx
, err
:= db
.Begin()
976 t
.Fatalf("Begin = %v", err
)
978 stmt
, err
:= tx
.Prepare("INSERT|t1|name=?,age=?")
980 t
.Fatalf("Stmt, err = %v, %v", stmt
, err
)
983 _
, err
= stmt
.Exec("Bobby", 7)
985 t
.Fatalf("Exec = %v", err
)
989 t
.Fatalf("Commit = %v", err
)
991 // Commit() should have closed the statement
993 t
.Fatal("Stmt not closed after Commit")
997 func TestTxStmt(t
*testing
.T
) {
998 db
:= newTestDB(t
, "")
1000 exec(t
, db
, "CREATE|t1|name=string,age=int32,dead=bool")
1001 stmt
, err
:= db
.Prepare("INSERT|t1|name=?,age=?")
1003 t
.Fatalf("Stmt, err = %v, %v", stmt
, err
)
1006 tx
, err
:= db
.Begin()
1008 t
.Fatalf("Begin = %v", err
)
1010 txs
:= tx
.Stmt(stmt
)
1012 _
, err
= txs
.Exec("Bobby", 7)
1014 t
.Fatalf("Exec = %v", err
)
1018 t
.Fatalf("Commit = %v", err
)
1020 // Commit() should have closed the statement
1022 t
.Fatal("Stmt not closed after Commit")
1026 // Issue: https://golang.org/issue/2784
1027 // This test didn't fail before because we got lucky with the fakedb driver.
1028 // It was failing, and now not, in github.com/bradfitz/go-sql-test
1029 func TestTxQuery(t
*testing
.T
) {
1030 db
:= newTestDB(t
, "")
1031 defer closeDB(t
, db
)
1032 exec(t
, db
, "CREATE|t1|name=string,age=int32,dead=bool")
1033 exec(t
, db
, "INSERT|t1|name=Alice")
1035 tx
, err
:= db
.Begin()
1041 r
, err
:= tx
.Query("SELECT|t1|name|")
1051 t
.Fatal("expected one row")
1061 func TestTxQueryInvalid(t
*testing
.T
) {
1062 db
:= newTestDB(t
, "")
1063 defer closeDB(t
, db
)
1065 tx
, err
:= db
.Begin()
1071 _
, err
= tx
.Query("SELECT|t1|name|")
1073 t
.Fatal("Error expected")
1077 // Tests fix for issue 4433, that retries in Begin happen when
1078 // conn.Begin() returns ErrBadConn
1079 func TestTxErrBadConn(t
*testing
.T
) {
1080 db
, err
:= Open("test", fakeDBName
+";badConn")
1082 t
.Fatalf("Open: %v", err
)
1084 if _
, err
:= db
.Exec("WIPE"); err
!= nil {
1085 t
.Fatalf("exec wipe: %v", err
)
1087 defer closeDB(t
, db
)
1088 exec(t
, db
, "CREATE|t1|name=string,age=int32,dead=bool")
1089 stmt
, err
:= db
.Prepare("INSERT|t1|name=?,age=?")
1091 t
.Fatalf("Stmt, err = %v, %v", stmt
, err
)
1094 tx
, err
:= db
.Begin()
1096 t
.Fatalf("Begin = %v", err
)
1098 txs
:= tx
.Stmt(stmt
)
1100 _
, err
= txs
.Exec("Bobby", 7)
1102 t
.Fatalf("Exec = %v", err
)
1106 t
.Fatalf("Commit = %v", err
)
1110 // Tests fix for issue 2542, that we release a lock when querying on
1111 // a closed connection.
1112 func TestIssue2542Deadlock(t
*testing
.T
) {
1113 db
:= newTestDB(t
, "people")
1115 for i
:= 0; i
< 2; i
++ {
1116 _
, err
:= db
.Query("SELECT|people|age,name|")
1118 t
.Fatalf("expected error")
1123 // From golang.org/issue/3865
1124 func TestCloseStmtBeforeRows(t
*testing
.T
) {
1125 db
:= newTestDB(t
, "people")
1126 defer closeDB(t
, db
)
1128 s
, err
:= db
.Prepare("SELECT|people|name|")
1147 // Tests fix for issue 2788, that we bind nil to a []byte if the
1148 // value in the column is sql null
1149 func TestNullByteSlice(t
*testing
.T
) {
1150 db
:= newTestDB(t
, "")
1151 defer closeDB(t
, db
)
1152 exec(t
, db
, "CREATE|t|id=int32,name=nullstring")
1153 exec(t
, db
, "INSERT|t|id=10,name=?", nil)
1157 err
:= db
.QueryRow("SELECT|t|name|id=?", 10).Scan(&name
)
1162 t
.Fatalf("name []byte should be nil for null column value, got: %#v", name
)
1165 exec(t
, db
, "INSERT|t|id=11,name=?", "bob")
1166 err
= db
.QueryRow("SELECT|t|name|id=?", 11).Scan(&name
)
1170 if string(name
) != "bob" {
1171 t
.Fatalf("name []byte should be bob, got: %q", string(name
))
1175 func TestPointerParamsAndScans(t
*testing
.T
) {
1176 db
:= newTestDB(t
, "")
1177 defer closeDB(t
, db
)
1178 exec(t
, db
, "CREATE|t|id=int32,name=nullstring")
1184 exec(t
, db
, "INSERT|t|id=10,name=?", name
)
1186 exec(t
, db
, "INSERT|t|id=20,name=?", name
)
1188 err
:= db
.QueryRow("SELECT|t|name|id=?", 10).Scan(&name
)
1190 t
.Fatalf("querying id 10: %v", err
)
1193 t
.Errorf("id 10's name = nil; want bob")
1194 } else if *name
!= "bob" {
1195 t
.Errorf("id 10's name = %q; want bob", *name
)
1198 err
= db
.QueryRow("SELECT|t|name|id=?", 20).Scan(&name
)
1200 t
.Fatalf("querying id 20: %v", err
)
1203 t
.Errorf("id 20 = %q; want nil", *name
)
1207 func TestQueryRowClosingStmt(t
*testing
.T
) {
1208 db
:= newTestDB(t
, "people")
1209 defer closeDB(t
, db
)
1212 err
:= db
.QueryRow("SELECT|people|age,name|age=?", 3).Scan(&age
, &name
)
1216 if len(db
.freeConn
) != 1 {
1217 t
.Fatalf("expected 1 free conn")
1219 fakeConn
:= db
.freeConn
[0].ci
.(*fakeConn
)
1220 if made
, closed := fakeConn
.stmtsMade
, fakeConn
.stmtsClosed
; made
!= closed {
1221 t
.Errorf("statement close mismatch: made %d, closed %d", made
, closed)
1225 var atomicRowsCloseHook atomic
.Value
// of func(*Rows, *error)
1228 rowsCloseHook
= func() func(*Rows
, *error
) {
1229 fn
, _
:= atomicRowsCloseHook
.Load().(func(*Rows
, *error
))
1234 func setRowsCloseHook(fn
func(*Rows
, *error
)) {
1236 // Can't change an atomic.Value back to nil, so set it to this
1237 // no-op func instead.
1238 fn
= func(*Rows
, *error
) {}
1240 atomicRowsCloseHook
.Store(fn
)
1244 func TestIssue6651(t
*testing
.T
) {
1245 db
:= newTestDB(t
, "people")
1246 defer closeDB(t
, db
)
1250 want
:= "error in rows.Next"
1251 rowsCursorNextHook
= func(dest
[]driver
.Value
) error
{
1252 return fmt
.Errorf(want
)
1254 defer func() { rowsCursorNextHook
= nil }()
1256 err
:= db
.QueryRow("SELECT|people|name|").Scan(&v
)
1257 if err
== nil || err
.Error() != want
{
1258 t
.Errorf("error = %q; want %q", err
, want
)
1260 rowsCursorNextHook
= nil
1262 want
= "error in rows.Close"
1263 setRowsCloseHook(func(rows
*Rows
, err
*error
) {
1264 *err
= fmt
.Errorf(want
)
1266 defer setRowsCloseHook(nil)
1267 err
= db
.QueryRow("SELECT|people|name|").Scan(&v
)
1268 if err
== nil || err
.Error() != want
{
1269 t
.Errorf("error = %q; want %q", err
, want
)
1273 type nullTestRow
struct {
1274 nullParam
interface{}
1275 notNullParam
interface{}
1276 scanNullVal
interface{}
1279 type nullTestSpec
struct {
1285 func TestNullStringParam(t
*testing
.T
) {
1286 spec
:= nullTestSpec
{"nullstring", "string", [6]nullTestRow
{
1287 {NullString
{"aqua", true}, "", NullString
{"aqua", true}},
1288 {NullString
{"brown", false}, "", NullString
{"", false}},
1289 {"chartreuse", "", NullString
{"chartreuse", true}},
1290 {NullString
{"darkred", true}, "", NullString
{"darkred", true}},
1291 {NullString
{"eel", false}, "", NullString
{"", false}},
1292 {"foo", NullString
{"black", false}, nil},
1294 nullTestRun(t
, spec
)
1297 func TestNullInt64Param(t
*testing
.T
) {
1298 spec
:= nullTestSpec
{"nullint64", "int64", [6]nullTestRow
{
1299 {NullInt64
{31, true}, 1, NullInt64
{31, true}},
1300 {NullInt64
{-22, false}, 1, NullInt64
{0, false}},
1301 {22, 1, NullInt64
{22, true}},
1302 {NullInt64
{33, true}, 1, NullInt64
{33, true}},
1303 {NullInt64
{222, false}, 1, NullInt64
{0, false}},
1304 {0, NullInt64
{31, false}, nil},
1306 nullTestRun(t
, spec
)
1309 func TestNullFloat64Param(t
*testing
.T
) {
1310 spec
:= nullTestSpec
{"nullfloat64", "float64", [6]nullTestRow
{
1311 {NullFloat64
{31.2, true}, 1, NullFloat64
{31.2, true}},
1312 {NullFloat64
{13.1, false}, 1, NullFloat64
{0, false}},
1313 {-22.9, 1, NullFloat64
{-22.9, true}},
1314 {NullFloat64
{33.81, true}, 1, NullFloat64
{33.81, true}},
1315 {NullFloat64
{222, false}, 1, NullFloat64
{0, false}},
1316 {10, NullFloat64
{31.2, false}, nil},
1318 nullTestRun(t
, spec
)
1321 func TestNullBoolParam(t
*testing
.T
) {
1322 spec
:= nullTestSpec
{"nullbool", "bool", [6]nullTestRow
{
1323 {NullBool
{false, true}, true, NullBool
{false, true}},
1324 {NullBool
{true, false}, false, NullBool
{false, false}},
1325 {true, true, NullBool
{true, true}},
1326 {NullBool
{true, true}, false, NullBool
{true, true}},
1327 {NullBool
{true, false}, true, NullBool
{false, false}},
1328 {true, NullBool
{true, false}, nil},
1330 nullTestRun(t
, spec
)
1333 func nullTestRun(t
*testing
.T
, spec nullTestSpec
) {
1334 db
:= newTestDB(t
, "")
1335 defer closeDB(t
, db
)
1336 exec(t
, db
, fmt
.Sprintf("CREATE|t|id=int32,name=string,nullf=%s,notnullf=%s", spec
.nullType
, spec
.notNullType
))
1338 // Inserts with db.Exec:
1339 exec(t
, db
, "INSERT|t|id=?,name=?,nullf=?,notnullf=?", 1, "alice", spec
.rows
[0].nullParam
, spec
.rows
[0].notNullParam
)
1340 exec(t
, db
, "INSERT|t|id=?,name=?,nullf=?,notnullf=?", 2, "bob", spec
.rows
[1].nullParam
, spec
.rows
[1].notNullParam
)
1342 // Inserts with a prepared statement:
1343 stmt
, err
:= db
.Prepare("INSERT|t|id=?,name=?,nullf=?,notnullf=?")
1345 t
.Fatalf("prepare: %v", err
)
1348 if _
, err
:= stmt
.Exec(3, "chris", spec
.rows
[2].nullParam
, spec
.rows
[2].notNullParam
); err
!= nil {
1349 t
.Errorf("exec insert chris: %v", err
)
1351 if _
, err
:= stmt
.Exec(4, "dave", spec
.rows
[3].nullParam
, spec
.rows
[3].notNullParam
); err
!= nil {
1352 t
.Errorf("exec insert dave: %v", err
)
1354 if _
, err
:= stmt
.Exec(5, "eleanor", spec
.rows
[4].nullParam
, spec
.rows
[4].notNullParam
); err
!= nil {
1355 t
.Errorf("exec insert eleanor: %v", err
)
1358 // Can't put null val into non-null col
1359 if _
, err
:= stmt
.Exec(6, "bob", spec
.rows
[5].nullParam
, spec
.rows
[5].notNullParam
); err
== nil {
1360 t
.Errorf("expected error inserting nil val with prepared statement Exec")
1363 _
, err
= db
.Exec("INSERT|t|id=?,name=?,nullf=?", 999, nil, nil)
1365 // TODO: this test fails, but it's just because
1366 // fakeConn implements the optional Execer interface,
1367 // so arguably this is the correct behavior. But
1368 // maybe I should flesh out the fakeConn.Exec
1369 // implementation so this properly fails.
1370 // t.Errorf("expected error inserting nil name with Exec")
1373 paramtype
:= reflect
.TypeOf(spec
.rows
[0].nullParam
)
1374 bindVal
:= reflect
.New(paramtype
).Interface()
1376 for i
:= 0; i
< 5; i
++ {
1378 if err
:= db
.QueryRow("SELECT|t|nullf|id=?", id
).Scan(bindVal
); err
!= nil {
1379 t
.Errorf("id=%d Scan: %v", id
, err
)
1381 bindValDeref
:= reflect
.ValueOf(bindVal
).Elem().Interface()
1382 if !reflect
.DeepEqual(bindValDeref
, spec
.rows
[i
].scanNullVal
) {
1383 t
.Errorf("id=%d got %#v, want %#v", id
, bindValDeref
, spec
.rows
[i
].scanNullVal
)
1388 // golang.org/issue/4859
1389 func TestQueryRowNilScanDest(t
*testing
.T
) {
1390 db
:= newTestDB(t
, "people")
1391 defer closeDB(t
, db
)
1392 var name
*string // nil pointer
1393 err
:= db
.QueryRow("SELECT|people|name|").Scan(name
)
1394 want
:= "sql: Scan error on column index 0: destination pointer is nil"
1395 if err
== nil || err
.Error() != want
{
1396 t
.Errorf("error = %q; want %q", err
.Error(), want
)
1400 func TestIssue4902(t
*testing
.T
) {
1401 db
:= newTestDB(t
, "people")
1402 defer closeDB(t
, db
)
1404 driver
:= db
.driver
.(*fakeDriver
)
1405 opens0
:= driver
.openCount
1409 for i
:= 0; i
< 10; i
++ {
1410 stmt
, err
= db
.Prepare("SELECT|people|name|")
1420 opens
:= driver
.openCount
- opens0
1422 t
.Errorf("opens = %d; want <= 1", opens
)
1423 t
.Logf("db = %#v", db
)
1424 t
.Logf("driver = %#v", driver
)
1425 t
.Logf("stmt = %#v", stmt
)
1430 // This used to deadlock.
1431 func TestSimultaneousQueries(t
*testing
.T
) {
1432 db
:= newTestDB(t
, "people")
1433 defer closeDB(t
, db
)
1435 tx
, err
:= db
.Begin()
1441 r1
, err
:= tx
.Query("SELECT|people|name|")
1447 r2
, err
:= tx
.Query("SELECT|people|name|")
1454 func TestMaxIdleConns(t
*testing
.T
) {
1455 db
:= newTestDB(t
, "people")
1456 defer closeDB(t
, db
)
1458 tx
, err
:= db
.Begin()
1463 if got
:= len(db
.freeConn
); got
!= 1 {
1464 t
.Errorf("freeConns = %d; want 1", got
)
1467 db
.SetMaxIdleConns(0)
1469 if got
:= len(db
.freeConn
); got
!= 0 {
1470 t
.Errorf("freeConns after set to zero = %d; want 0", got
)
1473 tx
, err
= db
.Begin()
1478 if got
:= len(db
.freeConn
); got
!= 0 {
1479 t
.Errorf("freeConns = %d; want 0", got
)
1483 func TestMaxOpenConns(t
*testing
.T
) {
1484 if testing
.Short() {
1485 t
.Skip("skipping in short mode")
1487 defer setHookpostCloseConn(nil)
1488 setHookpostCloseConn(func(_
*fakeConn
, err error
) {
1490 t
.Errorf("Error closing fakeConn: %v", err
)
1494 db
:= newTestDB(t
, "magicquery")
1495 defer closeDB(t
, db
)
1497 driver
:= db
.driver
.(*fakeDriver
)
1499 // Force the number of open connections to 0 so we can get an accurate
1500 // count for the test
1504 opens0
:= driver
.openCount
1505 closes0
:= driver
.closeCount
1508 db
.SetMaxIdleConns(10)
1509 db
.SetMaxOpenConns(10)
1511 stmt
, err
:= db
.Prepare("SELECT|magicquery|op|op=?,millis=?")
1516 // Start 50 parallel slow queries.
1522 var wg sync
.WaitGroup
1523 for batch
:= 0; batch
< nbatch
; batch
++ {
1524 for i
:= 0; i
< nquery
; i
++ {
1529 if err
:= stmt
.QueryRow("sleep", sleepMillis
).Scan(&op
); err
!= nil && err
!= ErrNoRows
{
1534 // Sleep for twice the expected length of time for the
1535 // batch of 50 queries above to finish before starting
1537 time
.Sleep(2 * sleepMillis
* time
.Millisecond
)
1541 if g
, w
:= db
.numFreeConns(), 10; g
!= w
{
1542 t
.Errorf("free conns = %d; want %d", g
, w
)
1545 if n
:= db
.numDepsPollUntil(20, time
.Second
); n
> 20 {
1546 t
.Errorf("number of dependencies = %d; expected <= 20", n
)
1551 opens
:= driver
.openCount
- opens0
1552 closes
:= driver
.closeCount
- closes0
1556 t
.Logf("open calls = %d", opens
)
1557 t
.Logf("close calls = %d", closes
)
1558 t
.Errorf("db connections opened = %d; want <= 10", opens
)
1562 if err
:= stmt
.Close(); err
!= nil {
1566 if g
, w
:= db
.numFreeConns(), 10; g
!= w
{
1567 t
.Errorf("free conns = %d; want %d", g
, w
)
1570 if n
:= db
.numDepsPollUntil(10, time
.Second
); n
> 10 {
1571 t
.Errorf("number of dependencies = %d; expected <= 10", n
)
1575 db
.SetMaxOpenConns(5)
1577 if g
, w
:= db
.numFreeConns(), 5; g
!= w
{
1578 t
.Errorf("free conns = %d; want %d", g
, w
)
1581 if n
:= db
.numDepsPollUntil(5, time
.Second
); n
> 5 {
1582 t
.Errorf("number of dependencies = %d; expected 0", n
)
1586 db
.SetMaxOpenConns(0)
1588 if g
, w
:= db
.numFreeConns(), 5; g
!= w
{
1589 t
.Errorf("free conns = %d; want %d", g
, w
)
1592 if n
:= db
.numDepsPollUntil(5, time
.Second
); n
> 5 {
1593 t
.Errorf("number of dependencies = %d; expected 0", n
)
1600 // Issue 9453: tests that SetMaxOpenConns can be lowered at runtime
1601 // and affects the subsequent release of connections.
1602 func TestMaxOpenConnsOnBusy(t
*testing
.T
) {
1603 defer setHookpostCloseConn(nil)
1604 setHookpostCloseConn(func(_
*fakeConn
, err error
) {
1606 t
.Errorf("Error closing fakeConn: %v", err
)
1610 db
:= newTestDB(t
, "magicquery")
1611 defer closeDB(t
, db
)
1613 db
.SetMaxOpenConns(3)
1615 ctx
:= context
.Background()
1617 conn0
, err
:= db
.conn(ctx
, cachedOrNewConn
)
1619 t
.Fatalf("db open conn fail: %v", err
)
1622 conn1
, err
:= db
.conn(ctx
, cachedOrNewConn
)
1624 t
.Fatalf("db open conn fail: %v", err
)
1627 conn2
, err
:= db
.conn(ctx
, cachedOrNewConn
)
1629 t
.Fatalf("db open conn fail: %v", err
)
1632 if g
, w
:= db
.numOpen
, 3; g
!= w
{
1633 t
.Errorf("free conns = %d; want %d", g
, w
)
1636 db
.SetMaxOpenConns(2)
1637 if g
, w
:= db
.numOpen
, 3; g
!= w
{
1638 t
.Errorf("free conns = %d; want %d", g
, w
)
1641 conn0
.releaseConn(nil)
1642 conn1
.releaseConn(nil)
1643 if g
, w
:= db
.numOpen
, 2; g
!= w
{
1644 t
.Errorf("free conns = %d; want %d", g
, w
)
1647 conn2
.releaseConn(nil)
1648 if g
, w
:= db
.numOpen
, 2; g
!= w
{
1649 t
.Errorf("free conns = %d; want %d", g
, w
)
1653 // Issue 10886: tests that all connection attempts return when more than
1654 // DB.maxOpen connections are in flight and the first DB.maxOpen fail.
1655 func TestPendingConnsAfterErr(t
*testing
.T
) {
1658 tryOpen
= maxOpen
*2 + 2
1661 // No queries will be run.
1662 db
, err
:= Open("test", fakeDBName
)
1664 t
.Fatalf("Open: %v", err
)
1666 defer closeDB(t
, db
)
1668 for k
, v
:= range db
.lastPut
{
1669 t
.Logf("%p: %v", k
, v
)
1673 db
.SetMaxOpenConns(maxOpen
)
1674 db
.SetMaxIdleConns(0)
1676 errOffline
:= errors
.New("db offline")
1678 defer func() { setHookOpenErr(nil) }()
1680 errs
:= make(chan error
, tryOpen
)
1682 var opening sync
.WaitGroup
1683 opening
.Add(tryOpen
)
1685 setHookOpenErr(func() error
{
1686 // Wait for all connections to enqueue.
1691 for i
:= 0; i
< tryOpen
; i
++ {
1693 opening
.Done() // signal one connection is in flight
1694 _
, err
:= db
.Exec("will never run")
1699 opening
.Wait() // wait for all workers to begin running
1701 const timeout
= 5 * time
.Second
1702 to
:= time
.NewTimer(timeout
)
1705 // check that all connections fail without deadlock
1706 for i
:= 0; i
< tryOpen
; i
++ {
1709 if got
, want
:= err
, errOffline
; got
!= want
{
1710 t
.Errorf("unexpected err: got %v, want %v", got
, want
)
1713 t
.Fatalf("orphaned connection request(s), still waiting after %v", timeout
)
1717 // Wait a reasonable time for the database to close all connections.
1718 tick
:= time
.NewTicker(3 * time
.Millisecond
)
1724 if db
.numOpen
== 0 {
1730 // Closing the database will check for numOpen and fail the test.
1736 func TestSingleOpenConn(t
*testing
.T
) {
1737 db
:= newTestDB(t
, "people")
1738 defer closeDB(t
, db
)
1740 db
.SetMaxOpenConns(1)
1742 rows
, err
:= db
.Query("SELECT|people|name|")
1746 if err
= rows
.Close(); err
!= nil {
1749 // shouldn't deadlock
1750 rows
, err
= db
.Query("SELECT|people|name|")
1754 if err
= rows
.Close(); err
!= nil {
1759 func TestStats(t
*testing
.T
) {
1760 db
:= newTestDB(t
, "people")
1762 if got
:= stats
.OpenConnections
; got
!= 1 {
1763 t
.Errorf("stats.OpenConnections = %d; want 1", got
)
1766 tx
, err
:= db
.Begin()
1774 if got
:= stats
.OpenConnections
; got
!= 0 {
1775 t
.Errorf("stats.OpenConnections = %d; want 0", got
)
1779 func TestConnMaxLifetime(t
*testing
.T
) {
1780 t0
:= time
.Unix(1000000, 0)
1781 offset
:= time
.Duration(0)
1783 nowFunc
= func() time
.Time
{ return t0
.Add(offset
) }
1784 defer func() { nowFunc
= time
.Now
}()
1786 db
:= newTestDB(t
, "magicquery")
1787 defer closeDB(t
, db
)
1789 driver
:= db
.driver
.(*fakeDriver
)
1791 // Force the number of open connections to 0 so we can get an accurate
1792 // count for the test
1796 opens0
:= driver
.openCount
1797 closes0
:= driver
.closeCount
1800 db
.SetMaxIdleConns(10)
1801 db
.SetMaxOpenConns(10)
1803 tx
, err
:= db
.Begin()
1808 offset
= time
.Second
1809 tx2
, err
:= db
.Begin()
1818 opens
:= driver
.openCount
- opens0
1819 closes
:= driver
.closeCount
- closes0
1823 t
.Errorf("opens = %d; want 2", opens
)
1826 t
.Errorf("closes = %d; want 0", closes
)
1828 if g
, w
:= db
.numFreeConns(), 2; g
!= w
{
1829 t
.Errorf("free conns = %d; want %d", g
, w
)
1832 // Expire first conn
1833 offset
= time
.Second
* 11
1834 db
.SetConnMaxLifetime(time
.Second
* 10)
1839 tx
, err
= db
.Begin()
1843 tx2
, err
= db
.Begin()
1851 opens
= driver
.openCount
- opens0
1852 closes
= driver
.closeCount
- closes0
1856 t
.Errorf("opens = %d; want 3", opens
)
1859 t
.Errorf("closes = %d; want 1", closes
)
1863 // golang.org/issue/5323
1864 func TestStmtCloseDeps(t
*testing
.T
) {
1865 if testing
.Short() {
1866 t
.Skip("skipping in short mode")
1868 defer setHookpostCloseConn(nil)
1869 setHookpostCloseConn(func(_
*fakeConn
, err error
) {
1871 t
.Errorf("Error closing fakeConn: %v", err
)
1875 db
:= newTestDB(t
, "magicquery")
1876 defer closeDB(t
, db
)
1878 driver
:= db
.driver
.(*fakeDriver
)
1881 opens0
:= driver
.openCount
1882 closes0
:= driver
.closeCount
1884 openDelta0
:= opens0
- closes0
1886 stmt
, err
:= db
.Prepare("SELECT|magicquery|op|op=?,millis=?")
1891 // Start 50 parallel slow queries.
1897 var wg sync
.WaitGroup
1898 for batch
:= 0; batch
< nbatch
; batch
++ {
1899 for i
:= 0; i
< nquery
; i
++ {
1904 if err
:= stmt
.QueryRow("sleep", sleepMillis
).Scan(&op
); err
!= nil && err
!= ErrNoRows
{
1909 // Sleep for twice the expected length of time for the
1910 // batch of 50 queries above to finish before starting
1912 time
.Sleep(2 * sleepMillis
* time
.Millisecond
)
1916 if g
, w
:= db
.numFreeConns(), 2; g
!= w
{
1917 t
.Errorf("free conns = %d; want %d", g
, w
)
1920 if n
:= db
.numDepsPollUntil(4, time
.Second
); n
> 4 {
1921 t
.Errorf("number of dependencies = %d; expected <= 4", n
)
1926 opens
:= driver
.openCount
- opens0
1927 closes
:= driver
.closeCount
- closes0
1928 openDelta
:= (driver
.openCount
- driver
.closeCount
) - openDelta0
1932 t
.Logf("open calls = %d", opens
)
1933 t
.Logf("close calls = %d", closes
)
1934 t
.Logf("open delta = %d", openDelta
)
1935 t
.Errorf("db connections opened = %d; want <= 2", openDelta
)
1939 if !waitCondition(5*time
.Second
, 5*time
.Millisecond
, func() bool {
1940 return len(stmt
.css
) <= nquery
1942 t
.Errorf("len(stmt.css) = %d; want <= %d", len(stmt
.css
), nquery
)
1945 if err
:= stmt
.Close(); err
!= nil {
1949 if g
, w
:= db
.numFreeConns(), 2; g
!= w
{
1950 t
.Errorf("free conns = %d; want %d", g
, w
)
1953 if n
:= db
.numDepsPollUntil(2, time
.Second
); n
> 2 {
1954 t
.Errorf("number of dependencies = %d; expected <= 2", n
)
1961 // golang.org/issue/5046
1962 func TestCloseConnBeforeStmts(t
*testing
.T
) {
1963 db
:= newTestDB(t
, "people")
1964 defer closeDB(t
, db
)
1966 defer setHookpostCloseConn(nil)
1967 setHookpostCloseConn(func(_
*fakeConn
, err error
) {
1969 t
.Errorf("Error closing fakeConn: %v; from %s", err
, stack())
1971 t
.Errorf("DB = %#v", db
)
1975 stmt
, err
:= db
.Prepare("SELECT|people|name|")
1980 if len(db
.freeConn
) != 1 {
1981 t
.Fatalf("expected 1 freeConn; got %d", len(db
.freeConn
))
1983 dc
:= db
.freeConn
[0]
1985 t
.Errorf("conn shouldn't be closed")
1988 if n
:= len(dc
.openStmt
); n
!= 1 {
1989 t
.Errorf("driverConn num openStmt = %d; want 1", n
)
1993 t
.Errorf("db Close = %v", err
)
1996 t
.Errorf("after db.Close, driverConn should be closed")
1998 if n
:= len(dc
.openStmt
); n
!= 0 {
1999 t
.Errorf("driverConn num openStmt = %d; want 0", n
)
2004 t
.Errorf("Stmt close = %v", err
)
2008 t
.Errorf("conn should be closed")
2011 t
.Errorf("after Stmt Close, driverConn's Conn interface should be nil")
2015 // golang.org/issue/5283: don't release the Rows' connection in Close
2016 // before calling Stmt.Close.
2017 func TestRowsCloseOrder(t
*testing
.T
) {
2018 db
:= newTestDB(t
, "people")
2019 defer closeDB(t
, db
)
2021 db
.SetMaxIdleConns(0)
2022 setStrictFakeConnClose(t
)
2023 defer setStrictFakeConnClose(nil)
2025 rows
, err
:= db
.Query("SELECT|people|age,name|")
2035 func TestRowsImplicitClose(t
*testing
.T
) {
2036 db
:= newTestDB(t
, "people")
2037 defer closeDB(t
, db
)
2039 rows
, err
:= db
.Query("SELECT|people|age,name|")
2044 want
, fail
:= 2, errors
.New("fail")
2045 r
:= rows
.rowsi
.(*rowsCursor
)
2046 r
.errPos
, r
.err
= want
, fail
2053 t
.Errorf("got %d rows, want %d", got
, want
)
2055 if err
:= rows
.Err(); err
!= fail
{
2056 t
.Errorf("got error %v, want %v", err
, fail
)
2059 t
.Errorf("r.closed is false, want true")
2063 func TestStmtCloseOrder(t
*testing
.T
) {
2064 db
:= newTestDB(t
, "people")
2065 defer closeDB(t
, db
)
2067 db
.SetMaxIdleConns(0)
2068 setStrictFakeConnClose(t
)
2069 defer setStrictFakeConnClose(nil)
2071 _
, err
:= db
.Query("SELECT|non_existent|name|")
2073 t
.Fatal("Querying non-existent table should fail")
2077 // Test cases where there's more than maxBadConnRetries bad connections in the
2078 // pool (issue 8834)
2079 func TestManyErrBadConn(t
*testing
.T
) {
2080 manyErrBadConnSetup
:= func() *DB
{
2081 db
:= newTestDB(t
, "people")
2083 nconn
:= maxBadConnRetries
+ 1
2084 db
.SetMaxIdleConns(nconn
)
2085 db
.SetMaxOpenConns(nconn
)
2086 // open enough connections
2088 for i
:= 0; i
< nconn
; i
++ {
2089 rows
, err
:= db
.Query("SELECT|people|age,name|")
2098 defer db
.mu
.Unlock()
2099 if db
.numOpen
!= nconn
{
2100 t
.Fatalf("unexpected numOpen %d (was expecting %d)", db
.numOpen
, nconn
)
2101 } else if len(db
.freeConn
) != nconn
{
2102 t
.Fatalf("unexpected len(db.freeConn) %d (was expecting %d)", len(db
.freeConn
), nconn
)
2104 for _
, conn
:= range db
.freeConn
{
2105 conn
.ci
.(*fakeConn
).stickyBad
= true
2111 db
:= manyErrBadConnSetup()
2112 defer closeDB(t
, db
)
2113 rows
, err
:= db
.Query("SELECT|people|age,name|")
2117 if err
= rows
.Close(); err
!= nil {
2122 db
= manyErrBadConnSetup()
2123 defer closeDB(t
, db
)
2124 _
, err
= db
.Exec("INSERT|people|name=Julia,age=19")
2130 db
= manyErrBadConnSetup()
2131 defer closeDB(t
, db
)
2132 tx
, err
:= db
.Begin()
2136 if err
= tx
.Rollback(); err
!= nil {
2141 db
= manyErrBadConnSetup()
2142 defer closeDB(t
, db
)
2143 stmt
, err
:= db
.Prepare("SELECT|people|age,name|")
2147 if err
= stmt
.Close(); err
!= nil {
2152 // golang.org/issue/5718
2153 func TestErrBadConnReconnect(t
*testing
.T
) {
2154 db
:= newTestDB(t
, "foo")
2155 defer closeDB(t
, db
)
2156 exec(t
, db
, "CREATE|t1|name=string,age=int32,dead=bool")
2158 simulateBadConn
:= func(name
string, hook
*func() bool, op
func() error
) {
2159 broken
, retried
:= false, false
2160 numOpen
:= db
.numOpen
2162 // simulate a broken connection on the first try
2163 *hook
= func() bool {
2172 if err
:= op(); err
!= nil {
2173 t
.Errorf(name
+": %v", err
)
2177 if !broken ||
!retried
{
2178 t
.Error(name
+ ": Failed to simulate broken connection")
2182 if numOpen
!= db
.numOpen
{
2183 t
.Errorf(name
+": leaked %d connection(s)!", db
.numOpen
-numOpen
)
2184 numOpen
= db
.numOpen
2189 dbExec
:= func() error
{
2190 _
, err
:= db
.Exec("INSERT|t1|name=?,age=?,dead=?", "Gordon", 3, true)
2193 simulateBadConn("db.Exec prepare", &hookPrepareBadConn
, dbExec
)
2194 simulateBadConn("db.Exec exec", &hookExecBadConn
, dbExec
)
2197 dbQuery
:= func() error
{
2198 rows
, err
:= db
.Query("SELECT|t1|age,name|")
2204 simulateBadConn("db.Query prepare", &hookPrepareBadConn
, dbQuery
)
2205 simulateBadConn("db.Query query", &hookQueryBadConn
, dbQuery
)
2208 simulateBadConn("db.Prepare", &hookPrepareBadConn
, func() error
{
2209 stmt
, err
:= db
.Prepare("INSERT|t1|name=?,age=?,dead=?")
2217 // Provide a way to force a re-prepare of a statement on next execution
2218 forcePrepare
:= func(stmt
*Stmt
) {
2223 stmt1
, err
:= db
.Prepare("INSERT|t1|name=?,age=?,dead=?")
2225 t
.Fatalf("prepare: %v", err
)
2228 // make sure we must prepare the stmt first
2231 stmtExec
:= func() error
{
2232 _
, err
:= stmt1
.Exec("Gopher", 3, false)
2235 simulateBadConn("stmt.Exec prepare", &hookPrepareBadConn
, stmtExec
)
2236 simulateBadConn("stmt.Exec exec", &hookExecBadConn
, stmtExec
)
2239 stmt2
, err
:= db
.Prepare("SELECT|t1|age,name|")
2241 t
.Fatalf("prepare: %v", err
)
2244 // make sure we must prepare the stmt first
2247 stmtQuery
:= func() error
{
2248 rows
, err
:= stmt2
.Query()
2254 simulateBadConn("stmt.Query prepare", &hookPrepareBadConn
, stmtQuery
)
2255 simulateBadConn("stmt.Query exec", &hookQueryBadConn
, stmtQuery
)
2258 // golang.org/issue/11264
2259 func TestTxEndBadConn(t
*testing
.T
) {
2260 db
:= newTestDB(t
, "foo")
2261 defer closeDB(t
, db
)
2262 db
.SetMaxIdleConns(0)
2263 exec(t
, db
, "CREATE|t1|name=string,age=int32,dead=bool")
2264 db
.SetMaxIdleConns(1)
2266 simulateBadConn
:= func(name
string, hook
*func() bool, op
func() error
) {
2268 numOpen
:= db
.numOpen
2270 *hook
= func() bool {
2277 if err
:= op(); err
!= driver
.ErrBadConn
{
2278 t
.Errorf(name
+": %v", err
)
2283 t
.Error(name
+ ": Failed to simulate broken connection")
2287 if numOpen
!= db
.numOpen
{
2288 t
.Errorf(name
+": leaked %d connection(s)!", db
.numOpen
-numOpen
)
2293 dbExec
:= func(endTx
func(tx
*Tx
) error
) func() error
{
2294 return func() error
{
2295 tx
, err
:= db
.Begin()
2299 _
, err
= tx
.Exec("INSERT|t1|name=?,age=?,dead=?", "Gordon", 3, true)
2306 simulateBadConn("db.Tx.Exec commit", &hookCommitBadConn
, dbExec((*Tx
).Commit
))
2307 simulateBadConn("db.Tx.Exec rollback", &hookRollbackBadConn
, dbExec((*Tx
).Rollback
))
2310 dbQuery
:= func(endTx
func(tx
*Tx
) error
) func() error
{
2311 return func() error
{
2312 tx
, err
:= db
.Begin()
2316 rows
, err
:= tx
.Query("SELECT|t1|age,name|")
2325 simulateBadConn("db.Tx.Query commit", &hookCommitBadConn
, dbQuery((*Tx
).Commit
))
2326 simulateBadConn("db.Tx.Query rollback", &hookRollbackBadConn
, dbQuery((*Tx
).Rollback
))
2329 type concurrentTest
interface {
2330 init(t testing
.TB
, db
*DB
)
2331 finish(t testing
.TB
)
2332 test(t testing
.TB
) error
2335 type concurrentDBQueryTest
struct {
2339 func (c
*concurrentDBQueryTest
) init(t testing
.TB
, db
*DB
) {
2343 func (c
*concurrentDBQueryTest
) finish(t testing
.TB
) {
2347 func (c
*concurrentDBQueryTest
) test(t testing
.TB
) error
{
2348 rows
, err
:= c
.db
.Query("SELECT|people|name|")
2361 type concurrentDBExecTest
struct {
2365 func (c
*concurrentDBExecTest
) init(t testing
.TB
, db
*DB
) {
2369 func (c
*concurrentDBExecTest
) finish(t testing
.TB
) {
2373 func (c
*concurrentDBExecTest
) test(t testing
.TB
) error
{
2374 _
, err
:= c
.db
.Exec("NOSERT|people|name=Chris,age=?,photo=CPHOTO,bdate=?", 3, chrisBirthday
)
2382 type concurrentStmtQueryTest
struct {
2387 func (c
*concurrentStmtQueryTest
) init(t testing
.TB
, db
*DB
) {
2390 c
.stmt
, err
= db
.Prepare("SELECT|people|name|")
2396 func (c
*concurrentStmtQueryTest
) finish(t testing
.TB
) {
2404 func (c
*concurrentStmtQueryTest
) test(t testing
.TB
) error
{
2405 rows
, err
:= c
.stmt
.Query()
2407 t
.Errorf("error on query: %v", err
)
2419 type concurrentStmtExecTest
struct {
2424 func (c
*concurrentStmtExecTest
) init(t testing
.TB
, db
*DB
) {
2427 c
.stmt
, err
= db
.Prepare("NOSERT|people|name=Chris,age=?,photo=CPHOTO,bdate=?")
2433 func (c
*concurrentStmtExecTest
) finish(t testing
.TB
) {
2441 func (c
*concurrentStmtExecTest
) test(t testing
.TB
) error
{
2442 _
, err
:= c
.stmt
.Exec(3, chrisBirthday
)
2444 t
.Errorf("error on exec: %v", err
)
2450 type concurrentTxQueryTest
struct {
2455 func (c
*concurrentTxQueryTest
) init(t testing
.TB
, db
*DB
) {
2458 c
.tx
, err
= c
.db
.Begin()
2464 func (c
*concurrentTxQueryTest
) finish(t testing
.TB
) {
2472 func (c
*concurrentTxQueryTest
) test(t testing
.TB
) error
{
2473 rows
, err
:= c
.db
.Query("SELECT|people|name|")
2486 type concurrentTxExecTest
struct {
2491 func (c
*concurrentTxExecTest
) init(t testing
.TB
, db
*DB
) {
2494 c
.tx
, err
= c
.db
.Begin()
2500 func (c
*concurrentTxExecTest
) finish(t testing
.TB
) {
2508 func (c
*concurrentTxExecTest
) test(t testing
.TB
) error
{
2509 _
, err
:= c
.tx
.Exec("NOSERT|people|name=Chris,age=?,photo=CPHOTO,bdate=?", 3, chrisBirthday
)
2517 type concurrentTxStmtQueryTest
struct {
2523 func (c
*concurrentTxStmtQueryTest
) init(t testing
.TB
, db
*DB
) {
2526 c
.tx
, err
= c
.db
.Begin()
2530 c
.stmt
, err
= c
.tx
.Prepare("SELECT|people|name|")
2536 func (c
*concurrentTxStmtQueryTest
) finish(t testing
.TB
) {
2548 func (c
*concurrentTxStmtQueryTest
) test(t testing
.TB
) error
{
2549 rows
, err
:= c
.stmt
.Query()
2551 t
.Errorf("error on query: %v", err
)
2563 type concurrentTxStmtExecTest
struct {
2569 func (c
*concurrentTxStmtExecTest
) init(t testing
.TB
, db
*DB
) {
2572 c
.tx
, err
= c
.db
.Begin()
2576 c
.stmt
, err
= c
.tx
.Prepare("NOSERT|people|name=Chris,age=?,photo=CPHOTO,bdate=?")
2582 func (c
*concurrentTxStmtExecTest
) finish(t testing
.TB
) {
2594 func (c
*concurrentTxStmtExecTest
) test(t testing
.TB
) error
{
2595 _
, err
:= c
.stmt
.Exec(3, chrisBirthday
)
2597 t
.Errorf("error on exec: %v", err
)
2603 type concurrentRandomTest
struct {
2604 tests
[]concurrentTest
2607 func (c
*concurrentRandomTest
) init(t testing
.TB
, db
*DB
) {
2608 c
.tests
= []concurrentTest
{
2609 new(concurrentDBQueryTest
),
2610 new(concurrentDBExecTest
),
2611 new(concurrentStmtQueryTest
),
2612 new(concurrentStmtExecTest
),
2613 new(concurrentTxQueryTest
),
2614 new(concurrentTxExecTest
),
2615 new(concurrentTxStmtQueryTest
),
2616 new(concurrentTxStmtExecTest
),
2618 for _
, ct
:= range c
.tests
{
2623 func (c
*concurrentRandomTest
) finish(t testing
.TB
) {
2624 for _
, ct
:= range c
.tests
{
2629 func (c
*concurrentRandomTest
) test(t testing
.TB
) error
{
2630 ct
:= c
.tests
[rand
.Intn(len(c
.tests
))]
2634 func doConcurrentTest(t testing
.TB
, ct concurrentTest
) {
2635 maxProcs
, numReqs
:= 1, 500
2636 if testing
.Short() {
2637 maxProcs
, numReqs
= 4, 50
2639 defer runtime
.GOMAXPROCS(runtime
.GOMAXPROCS(maxProcs
))
2641 db
:= newTestDB(t
, "people")
2642 defer closeDB(t
, db
)
2647 var wg sync
.WaitGroup
2650 reqs
:= make(chan bool)
2653 for i
:= 0; i
< maxProcs
*2; i
++ {
2666 for i
:= 0; i
< numReqs
; i
++ {
2673 func TestIssue6081(t
*testing
.T
) {
2674 db
:= newTestDB(t
, "people")
2675 defer closeDB(t
, db
)
2677 drv
:= db
.driver
.(*fakeDriver
)
2679 opens0
:= drv
.openCount
2680 closes0
:= drv
.closeCount
2683 stmt
, err
:= db
.Prepare("SELECT|people|name|")
2687 setRowsCloseHook(func(rows
*Rows
, err
*error
) {
2688 *err
= driver
.ErrBadConn
2690 defer setRowsCloseHook(nil)
2691 for i
:= 0; i
< 10; i
++ {
2692 rows
, err
:= stmt
.Query()
2698 if n
:= len(stmt
.css
); n
> 1 {
2699 t
.Errorf("len(css slice) = %d; want <= 1", n
)
2702 if n
:= len(stmt
.css
); n
!= 0 {
2703 t
.Errorf("len(css slice) after Close = %d; want 0", n
)
2707 opens
:= drv
.openCount
- opens0
2708 closes
:= drv
.closeCount
- closes0
2711 t
.Errorf("opens = %d; want >= 9", opens
)
2714 t
.Errorf("closes = %d; want >= 9", closes
)
2718 // TestIssue18429 attempts to stress rolling back the transaction from a
2719 // context cancel while simultaneously calling Tx.Rollback. Rolling back from a
2720 // context happens concurrently so tx.rollback and tx.Commit must guard against
2723 // In the test, a context is canceled while the query is in process so
2724 // the internal rollback will run concurrently with the explicitly called
2726 func TestIssue18429(t
*testing
.T
) {
2727 db
:= newTestDB(t
, "people")
2728 defer closeDB(t
, db
)
2730 ctx
:= context
.Background()
2731 sem
:= make(chan bool, 20)
2732 var wg sync
.WaitGroup
2734 const milliWait
= 30
2736 for i
:= 0; i
< 100; i
++ {
2744 qwait
:= (time
.Duration(rand
.Intn(milliWait
)) * time
.Millisecond
).String()
2746 ctx
, cancel
:= context
.WithTimeout(ctx
, time
.Duration(rand
.Intn(milliWait
))*time
.Millisecond
)
2749 tx
, err
:= db
.BeginTx(ctx
, nil)
2753 // This is expected to give a cancel error many, but not all the time.
2754 // Test failure will happen with a panic or other race condition being
2756 rows
, _
:= tx
.QueryContext(ctx
, "WAIT|"+qwait
+"|SELECT|people|name|")
2760 // This call will race with the context cancel rollback to complete
2761 // if the rollback itself isn't guarded.
2768 // TestIssue18719 closes the context right before use. The sql.driverConn
2769 // will nil out the ci on close in a lock, but if another process uses it right after
2770 // it will panic with on the nil ref.
2772 // See https://golang.org/cl/35550 .
2773 func TestIssue18719(t
*testing
.T
) {
2774 db
:= newTestDB(t
, "people")
2775 defer closeDB(t
, db
)
2777 ctx
, cancel
:= context
.WithCancel(context
.Background())
2780 tx
, err
:= db
.BeginTx(ctx
, nil)
2785 hookTxGrabConn
= func() {
2788 // Wait for the context to cancel and tx to rollback.
2789 for tx
.isDone() == false {
2790 time
.Sleep(time
.Millisecond
* 3)
2793 defer func() { hookTxGrabConn
= nil }()
2795 // This call will grab the connection and cancel the context
2796 // after it has done so. Code after must deal with the canceled state.
2797 rows
, err
:= tx
.QueryContext(ctx
, "SELECT|people|name|")
2800 t
.Fatalf("expected error %v but got %v", nil, err
)
2803 // Rows may be ignored because it will be closed when the context is canceled.
2805 // Do not explicitly rollback. The rollback will happen from the
2806 // canceled context.
2809 waitForRowsClose(t
, rows
, 5*time
.Second
)
2812 func TestConcurrency(t
*testing
.T
) {
2813 doConcurrentTest(t
, new(concurrentDBQueryTest
))
2814 doConcurrentTest(t
, new(concurrentDBExecTest
))
2815 doConcurrentTest(t
, new(concurrentStmtQueryTest
))
2816 doConcurrentTest(t
, new(concurrentStmtExecTest
))
2817 doConcurrentTest(t
, new(concurrentTxQueryTest
))
2818 doConcurrentTest(t
, new(concurrentTxExecTest
))
2819 doConcurrentTest(t
, new(concurrentTxStmtQueryTest
))
2820 doConcurrentTest(t
, new(concurrentTxStmtExecTest
))
2821 doConcurrentTest(t
, new(concurrentRandomTest
))
2824 func TestConnectionLeak(t
*testing
.T
) {
2825 db
:= newTestDB(t
, "people")
2826 defer closeDB(t
, db
)
2827 // Start by opening defaultMaxIdleConns
2828 rows
:= make([]*Rows
, defaultMaxIdleConns
)
2829 // We need to SetMaxOpenConns > MaxIdleConns, so the DB can open
2830 // a new connection and we can fill the idle queue with the released
2832 db
.SetMaxOpenConns(len(rows
) + 1)
2833 for ii
:= range rows
{
2834 r
, err
:= db
.Query("SELECT|people|name|")
2839 if err
:= r
.Err(); err
!= nil {
2844 // Now we have defaultMaxIdleConns busy connections. Open
2845 // a new one, but wait until the busy connections are released
2846 // before returning control to DB.
2847 drv
:= db
.driver
.(*fakeDriver
)
2848 drv
.waitCh
= make(chan struct{}, 1)
2849 drv
.waitingCh
= make(chan struct{}, 1)
2850 var wg sync
.WaitGroup
2853 r
, err
:= db
.Query("SELECT|people|name|")
2861 // Wait until the goroutine we've just created has started waiting.
2863 // Now close the busy connections. This provides a connection for
2864 // the blocked goroutine and then fills up the idle queue.
2865 for _
, v
:= range rows
{
2868 // At this point we give the new connection to DB. This connection is
2869 // now useless, since the idle queue is full and there are no pending
2870 // requests. DB should deal with this situation without leaking the
2872 drv
.waitCh
<- struct{}{}
2876 // badConn implements a bad driver.Conn, for TestBadDriver.
2877 // The Exec method panics.
2878 type badConn
struct{}
2880 func (bc badConn
) Prepare(query
string) (driver
.Stmt
, error
) {
2881 return nil, errors
.New("badConn Prepare")
2884 func (bc badConn
) Close() error
{
2888 func (bc badConn
) Begin() (driver
.Tx
, error
) {
2889 return nil, errors
.New("badConn Begin")
2892 func (bc badConn
) Exec(query
string, args
[]driver
.Value
) (driver
.Result
, error
) {
2893 panic("badConn.Exec")
2896 // badDriver is a driver.Driver that uses badConn.
2897 type badDriver
struct{}
2899 func (bd badDriver
) Open(name
string) (driver
.Conn
, error
) {
2900 return badConn
{}, nil
2904 func TestBadDriver(t
*testing
.T
) {
2905 Register("bad", badDriver
{})
2906 db
, err
:= Open("bad", "ignored")
2911 if r
:= recover(); r
== nil {
2912 t
.Error("expected panic")
2914 if want
:= "badConn.Exec"; r
.(string) != want
{
2915 t
.Errorf("panic was %v, expected %v", r
, want
)
2923 type pingDriver
struct {
2927 type pingConn
struct {
2932 var pingError
= errors
.New("Ping failed")
2934 func (pc pingConn
) Ping(ctx context
.Context
) error
{
2935 if pc
.driver
.fails
{
2941 var _ driver
.Pinger
= pingConn
{}
2943 func (pd
*pingDriver
) Open(name
string) (driver
.Conn
, error
) {
2944 return pingConn
{driver
: pd
}, nil
2947 func TestPing(t
*testing
.T
) {
2948 driver
:= &pingDriver
{}
2949 Register("ping", driver
)
2951 db
, err
:= Open("ping", "ignored")
2956 if err
:= db
.Ping(); err
!= nil {
2957 t
.Errorf("err was %#v, expected nil", err
)
2962 if err
:= db
.Ping(); err
!= pingError
{
2963 t
.Errorf("err was %#v, expected pingError", err
)
2967 func BenchmarkConcurrentDBExec(b
*testing
.B
) {
2969 ct
:= new(concurrentDBExecTest
)
2970 for i
:= 0; i
< b
.N
; i
++ {
2971 doConcurrentTest(b
, ct
)
2975 func BenchmarkConcurrentStmtQuery(b
*testing
.B
) {
2977 ct
:= new(concurrentStmtQueryTest
)
2978 for i
:= 0; i
< b
.N
; i
++ {
2979 doConcurrentTest(b
, ct
)
2983 func BenchmarkConcurrentStmtExec(b
*testing
.B
) {
2985 ct
:= new(concurrentStmtExecTest
)
2986 for i
:= 0; i
< b
.N
; i
++ {
2987 doConcurrentTest(b
, ct
)
2991 func BenchmarkConcurrentTxQuery(b
*testing
.B
) {
2993 ct
:= new(concurrentTxQueryTest
)
2994 for i
:= 0; i
< b
.N
; i
++ {
2995 doConcurrentTest(b
, ct
)
2999 func BenchmarkConcurrentTxExec(b
*testing
.B
) {
3001 ct
:= new(concurrentTxExecTest
)
3002 for i
:= 0; i
< b
.N
; i
++ {
3003 doConcurrentTest(b
, ct
)
3007 func BenchmarkConcurrentTxStmtQuery(b
*testing
.B
) {
3009 ct
:= new(concurrentTxStmtQueryTest
)
3010 for i
:= 0; i
< b
.N
; i
++ {
3011 doConcurrentTest(b
, ct
)
3015 func BenchmarkConcurrentTxStmtExec(b
*testing
.B
) {
3017 ct
:= new(concurrentTxStmtExecTest
)
3018 for i
:= 0; i
< b
.N
; i
++ {
3019 doConcurrentTest(b
, ct
)
3023 func BenchmarkConcurrentRandom(b
*testing
.B
) {
3025 ct
:= new(concurrentRandomTest
)
3026 for i
:= 0; i
< b
.N
; i
++ {
3027 doConcurrentTest(b
, ct
)
3031 func BenchmarkManyConcurrentQueries(b
*testing
.B
) {
3033 // To see lock contention in Go 1.4, 16~ cores and 128~ goroutines are required.
3034 const parallelism
= 16
3036 db
:= newTestDB(b
, "magicquery")
3037 defer closeDB(b
, db
)
3038 db
.SetMaxIdleConns(runtime
.GOMAXPROCS(0) * parallelism
)
3040 stmt
, err
:= db
.Prepare("SELECT|magicquery|op|op=?,millis=?")
3046 b
.SetParallelism(parallelism
)
3047 b
.RunParallel(func(pb
*testing
.PB
) {
3049 rows
, err
:= stmt
.Query("sleep", 1)