blob: 68f17fb6b00f4bf4fb51ac53d00df44c63e95fea [file] [log] [blame]
Brad Fitzpatrick357f2cb2011-09-29 16:12:21 -07001// 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
5package sql
6
7import (
Brad Fitzpatrickca3ed9f2013-08-13 14:56:40 -07008 "database/sql/driver"
Nigel Taobc212652013-08-16 11:23:35 +10009 "errors"
James P. Cooperc21b3432012-01-25 17:47:32 -080010 "fmt"
Tad Glines41c5d8d2013-08-30 09:27:33 -070011 "math/rand"
Brad Fitzpatrick750d0e32011-11-20 14:56:49 -050012 "reflect"
James Tucker4f1ef562013-04-03 11:13:40 -070013 "runtime"
Brad Fitzpatrick357f2cb2011-09-29 16:12:21 -070014 "strings"
James Tucker4f1ef562013-04-03 11:13:40 -070015 "sync"
Brad Fitzpatrick357f2cb2011-09-29 16:12:21 -070016 "testing"
Brad Fitzpatrickbf734d62012-01-13 15:45:05 -080017 "time"
Brad Fitzpatrick357f2cb2011-09-29 16:12:21 -070018)
19
Brad Fitzpatrick3297fc62012-03-10 10:00:02 -080020func init() {
21 type dbConn struct {
22 db *DB
Brad Fitzpatrickf28c8fb2013-03-14 15:01:45 -070023 c *driverConn
Brad Fitzpatrick3297fc62012-03-10 10:00:02 -080024 }
25 freedFrom := make(map[dbConn]string)
Brad Fitzpatrickf28c8fb2013-03-14 15:01:45 -070026 putConnHook = func(db *DB, c *driverConn) {
Alberto García Hierro6fb6f4e2014-08-28 08:49:56 -070027 idx := -1
28 for i, v := range db.freeConn {
29 if v == c {
30 idx = i
31 break
32 }
33 }
34 if idx >= 0 {
Tad Glines41c5d8d2013-08-30 09:27:33 -070035 // print before panic, as panic may get lost due to conflicting panic
36 // (all goroutines asleep) elsewhere, since we might not unlock
37 // the mutex in freeConn here.
38 println("double free of conn. conflicts are:\nA) " + freedFrom[dbConn{db, c}] + "\n\nand\nB) " + stack())
39 panic("double free of conn.")
Brad Fitzpatrick3297fc62012-03-10 10:00:02 -080040 }
41 freedFrom[dbConn{db, c}] = stack()
42 }
43}
44
Brad Fitzpatrick4435c8b2012-01-10 12:51:27 -080045const fakeDBName = "foo"
46
Brad Fitzpatrickbf734d62012-01-13 15:45:05 -080047var chrisBirthday = time.Unix(123456789, 0)
48
Brad Fitzpatrick35d8bb32013-08-14 23:21:32 -070049func newTestDB(t testing.TB, name string) *DB {
Brad Fitzpatrick4435c8b2012-01-10 12:51:27 -080050 db, err := Open("test", fakeDBName)
Brad Fitzpatrick357f2cb2011-09-29 16:12:21 -070051 if err != nil {
52 t.Fatalf("Open: %v", err)
53 }
54 if _, err := db.Exec("WIPE"); err != nil {
55 t.Fatalf("exec wipe: %v", err)
56 }
57 if name == "people" {
Brad Fitzpatrickbf734d62012-01-13 15:45:05 -080058 exec(t, db, "CREATE|people|name=string,age=int32,photo=blob,dead=bool,bdate=datetime")
Brad Fitzpatrick701f70a2012-01-12 11:23:33 -080059 exec(t, db, "INSERT|people|name=Alice,age=?,photo=APHOTO", 1)
60 exec(t, db, "INSERT|people|name=Bob,age=?,photo=BPHOTO", 2)
Brad Fitzpatrickbf734d62012-01-13 15:45:05 -080061 exec(t, db, "INSERT|people|name=Chris,age=?,photo=CPHOTO,bdate=?", 3, chrisBirthday)
Brad Fitzpatrick357f2cb2011-09-29 16:12:21 -070062 }
Brad Fitzpatrick277047f2013-04-25 14:45:56 -070063 if name == "magicquery" {
64 // Magic table name and column, known by fakedb_test.go.
65 exec(t, db, "CREATE|magicquery|op=string,millis=int32")
66 exec(t, db, "INSERT|magicquery|op=sleep,millis=10")
67 }
Brad Fitzpatrick357f2cb2011-09-29 16:12:21 -070068 return db
69}
70
Russ Cox99ed71a2015-12-18 12:16:05 -050071func TestDriverPanic(t *testing.T) {
72 // Test that if driver panics, database/sql does not deadlock.
73 db, err := Open("test", fakeDBName)
74 if err != nil {
75 t.Fatalf("Open: %v", err)
76 }
77 expectPanic := func(name string, f func()) {
78 defer func() {
79 err := recover()
80 if err == nil {
81 t.Fatalf("%s did not panic", name)
82 }
83 }()
84 f()
85 }
86
87 expectPanic("Exec Exec", func() { db.Exec("PANIC|Exec|WIPE") })
88 exec(t, db, "WIPE") // check not deadlocked
89 expectPanic("Exec NumInput", func() { db.Exec("PANIC|NumInput|WIPE") })
90 exec(t, db, "WIPE") // check not deadlocked
91 expectPanic("Exec Close", func() { db.Exec("PANIC|Close|WIPE") })
92 exec(t, db, "WIPE") // check not deadlocked
93 exec(t, db, "PANIC|Query|WIPE") // should run successfully: Exec does not call Query
94 exec(t, db, "WIPE") // check not deadlocked
95
96 exec(t, db, "CREATE|people|name=string,age=int32,photo=blob,dead=bool,bdate=datetime")
97
98 expectPanic("Query Query", func() { db.Query("PANIC|Query|SELECT|people|age,name|") })
99 expectPanic("Query NumInput", func() { db.Query("PANIC|NumInput|SELECT|people|age,name|") })
100 expectPanic("Query Close", func() {
101 rows, err := db.Query("PANIC|Close|SELECT|people|age,name|")
102 if err != nil {
103 t.Fatal(err)
104 }
105 rows.Close()
106 })
107 db.Query("PANIC|Exec|SELECT|people|age,name|") // should run successfully: Query does not call Exec
108 exec(t, db, "WIPE") // check not deadlocked
109}
110
Brad Fitzpatrick35d8bb32013-08-14 23:21:32 -0700111func exec(t testing.TB, db *DB, query string, args ...interface{}) {
Brad Fitzpatrick357f2cb2011-09-29 16:12:21 -0700112 _, err := db.Exec(query, args...)
113 if err != nil {
114 t.Fatalf("Exec of %q: %v", query, err)
115 }
116}
117
Brad Fitzpatrick35d8bb32013-08-14 23:21:32 -0700118func closeDB(t testing.TB, db *DB) {
Brad Fitzpatrickf7a77162013-02-20 15:35:27 -0800119 if e := recover(); e != nil {
120 fmt.Printf("Panic: %v\n", e)
121 panic(e)
122 }
Brad Fitzpatrick209f6b12013-03-25 16:50:27 -0700123 defer setHookpostCloseConn(nil)
124 setHookpostCloseConn(func(_ *fakeConn, err error) {
125 if err != nil {
126 t.Errorf("Error closing fakeConn: %v", err)
127 }
128 })
Alberto García Hierro6fb6f4e2014-08-28 08:49:56 -0700129 for i, dc := range db.freeConn {
Brad Fitzpatrick277047f2013-04-25 14:45:56 -0700130 if n := len(dc.openStmt); n > 0 {
131 // Just a sanity check. This is legal in
132 // general, but if we make the tests clean up
133 // their statements first, then we can safely
134 // verify this is always zero here, and any
135 // other value is a leak.
Alberto García Hierro6fb6f4e2014-08-28 08:49:56 -0700136 t.Errorf("while closing db, freeConn %d/%d had %d open stmts; want 0", i, len(db.freeConn), n)
Brad Fitzpatrick277047f2013-04-25 14:45:56 -0700137 }
138 }
Brad Fitzpatrick0a8005c2011-11-14 10:48:26 -0800139 err := db.Close()
140 if err != nil {
141 t.Fatalf("error closing DB: %v", err)
142 }
Alberto García Hierro478f4b62013-10-16 09:17:25 -0700143 db.mu.Lock()
144 count := db.numOpen
145 db.mu.Unlock()
146 if count != 0 {
147 t.Fatalf("%d connections still open after closing DB", db.numOpen)
148 }
Brad Fitzpatrick0a8005c2011-11-14 10:48:26 -0800149}
150
Brad Fitzpatrick48eacd92012-03-06 14:10:58 -0800151// numPrepares assumes that db has exactly 1 idle conn and returns
152// its count of calls to Prepare
153func numPrepares(t *testing.T, db *DB) int {
Alberto García Hierro6fb6f4e2014-08-28 08:49:56 -0700154 if n := len(db.freeConn); n != 1 {
Brad Fitzpatrick48eacd92012-03-06 14:10:58 -0800155 t.Fatalf("free conns = %d; want 1", n)
156 }
Alberto García Hierro6fb6f4e2014-08-28 08:49:56 -0700157 return db.freeConn[0].ci.(*fakeConn).numPrepare
Brad Fitzpatrick48eacd92012-03-06 14:10:58 -0800158}
159
Brad Fitzpatrick277047f2013-04-25 14:45:56 -0700160func (db *DB) numDeps() int {
161 db.mu.Lock()
162 defer db.mu.Unlock()
163 return len(db.dep)
164}
165
166// Dependencies are closed via a goroutine, so this polls waiting for
167// numDeps to fall to want, waiting up to d.
168func (db *DB) numDepsPollUntil(want int, d time.Duration) int {
169 deadline := time.Now().Add(d)
170 for {
171 n := db.numDeps()
172 if n <= want || time.Now().After(deadline) {
173 return n
174 }
175 time.Sleep(50 * time.Millisecond)
176 }
177}
178
179func (db *DB) numFreeConns() int {
180 db.mu.Lock()
181 defer db.mu.Unlock()
Alberto García Hierro6fb6f4e2014-08-28 08:49:56 -0700182 return len(db.freeConn)
Brad Fitzpatrick277047f2013-04-25 14:45:56 -0700183}
184
INADA Naoki0c516c12015-03-03 21:27:07 +0900185// clearAllConns closes all connections in db.
186func (db *DB) clearAllConns(t *testing.T) {
187 db.SetMaxIdleConns(0)
188
189 if g, w := db.numFreeConns(), 0; g != w {
190 t.Errorf("free conns = %d; want %d", g, w)
191 }
192
193 if n := db.numDepsPollUntil(0, time.Second); n > 0 {
194 t.Errorf("number of dependencies = %d; expected 0", n)
195 db.dumpDeps(t)
196 }
197}
198
Brad Fitzpatrick277047f2013-04-25 14:45:56 -0700199func (db *DB) dumpDeps(t *testing.T) {
200 for fc := range db.dep {
201 db.dumpDep(t, 0, fc, map[finalCloser]bool{})
202 }
203}
204
205func (db *DB) dumpDep(t *testing.T, depth int, dep finalCloser, seen map[finalCloser]bool) {
206 seen[dep] = true
207 indent := strings.Repeat(" ", depth)
208 ds := db.dep[dep]
209 for k := range ds {
210 t.Logf("%s%T (%p) waiting for -> %T (%p)", indent, dep, dep, k, k)
211 if fc, ok := k.(finalCloser); ok {
212 if !seen[fc] {
213 db.dumpDep(t, depth+1, fc, seen)
214 }
215 }
216 }
217}
218
Brad Fitzpatrick357f2cb2011-09-29 16:12:21 -0700219func TestQuery(t *testing.T) {
220 db := newTestDB(t, "people")
Brad Fitzpatrick0a8005c2011-11-14 10:48:26 -0800221 defer closeDB(t, db)
Brad Fitzpatrick48eacd92012-03-06 14:10:58 -0800222 prepares0 := numPrepares(t, db)
Brad Fitzpatrick750d0e32011-11-20 14:56:49 -0500223 rows, err := db.Query("SELECT|people|age,name|")
224 if err != nil {
225 t.Fatalf("Query: %v", err)
226 }
227 type row struct {
228 age int
229 name string
230 }
231 got := []row{}
232 for rows.Next() {
233 var r row
234 err = rows.Scan(&r.age, &r.name)
235 if err != nil {
236 t.Fatalf("Scan: %v", err)
237 }
238 got = append(got, r)
239 }
240 err = rows.Err()
241 if err != nil {
242 t.Fatalf("Err: %v", err)
243 }
244 want := []row{
245 {age: 1, name: "Alice"},
246 {age: 2, name: "Bob"},
247 {age: 3, name: "Chris"},
248 }
249 if !reflect.DeepEqual(got, want) {
Brad Fitzpatrickebc80132012-01-17 10:44:35 -0800250 t.Errorf("mismatch.\n got: %#v\nwant: %#v", got, want)
Brad Fitzpatrick750d0e32011-11-20 14:56:49 -0500251 }
Brad Fitzpatrick4435c8b2012-01-10 12:51:27 -0800252
253 // And verify that the final rows.Next() call, which hit EOF,
254 // also closed the rows connection.
Brad Fitzpatrick277047f2013-04-25 14:45:56 -0700255 if n := db.numFreeConns(); n != 1 {
Brad Fitzpatrick48eacd92012-03-06 14:10:58 -0800256 t.Fatalf("free conns after query hitting EOF = %d; want 1", n)
257 }
258 if prepares := numPrepares(t, db) - prepares0; prepares != 1 {
259 t.Errorf("executed %d Prepare statements; want 1", prepares)
Brad Fitzpatrick4435c8b2012-01-10 12:51:27 -0800260 }
Brad Fitzpatrick750d0e32011-11-20 14:56:49 -0500261}
262
Brad Fitzpatrickebc80132012-01-17 10:44:35 -0800263func TestByteOwnership(t *testing.T) {
264 db := newTestDB(t, "people")
265 defer closeDB(t, db)
266 rows, err := db.Query("SELECT|people|name,photo|")
267 if err != nil {
268 t.Fatalf("Query: %v", err)
269 }
270 type row struct {
271 name []byte
272 photo RawBytes
273 }
274 got := []row{}
275 for rows.Next() {
276 var r row
277 err = rows.Scan(&r.name, &r.photo)
278 if err != nil {
279 t.Fatalf("Scan: %v", err)
280 }
281 got = append(got, r)
282 }
283 corruptMemory := []byte("\xffPHOTO")
284 want := []row{
285 {name: []byte("Alice"), photo: corruptMemory},
286 {name: []byte("Bob"), photo: corruptMemory},
287 {name: []byte("Chris"), photo: corruptMemory},
288 }
289 if !reflect.DeepEqual(got, want) {
290 t.Errorf("mismatch.\n got: %#v\nwant: %#v", got, want)
291 }
292
293 var photo RawBytes
294 err = db.QueryRow("SELECT|people|photo|name=?", "Alice").Scan(&photo)
295 if err == nil {
296 t.Error("want error scanning into RawBytes from QueryRow")
297 }
298}
299
Brad Fitzpatrickea51dd22011-12-15 10:14:57 -0800300func TestRowsColumns(t *testing.T) {
301 db := newTestDB(t, "people")
302 defer closeDB(t, db)
303 rows, err := db.Query("SELECT|people|age,name|")
304 if err != nil {
305 t.Fatalf("Query: %v", err)
306 }
307 cols, err := rows.Columns()
308 if err != nil {
309 t.Fatalf("Columns: %v", err)
310 }
311 want := []string{"age", "name"}
312 if !reflect.DeepEqual(cols, want) {
313 t.Errorf("got %#v; want %#v", cols, want)
314 }
Alberto García Hierro478f4b62013-10-16 09:17:25 -0700315 if err := rows.Close(); err != nil {
316 t.Errorf("error closing rows: %s", err)
317 }
Brad Fitzpatrickea51dd22011-12-15 10:14:57 -0800318}
319
Brad Fitzpatrick750d0e32011-11-20 14:56:49 -0500320func TestQueryRow(t *testing.T) {
321 db := newTestDB(t, "people")
322 defer closeDB(t, db)
Brad Fitzpatrick357f2cb2011-09-29 16:12:21 -0700323 var name string
324 var age int
Brad Fitzpatrickbf734d62012-01-13 15:45:05 -0800325 var birthday time.Time
Brad Fitzpatrick357f2cb2011-09-29 16:12:21 -0700326
327 err := db.QueryRow("SELECT|people|age,name|age=?", 3).Scan(&age)
Russ Coxc2049d22011-11-01 22:04:37 -0400328 if err == nil || !strings.Contains(err.Error(), "expected 2 destination arguments") {
Brad Fitzpatrick357f2cb2011-09-29 16:12:21 -0700329 t.Errorf("expected error from wrong number of arguments; actually got: %v", err)
330 }
331
Brad Fitzpatrickbf734d62012-01-13 15:45:05 -0800332 err = db.QueryRow("SELECT|people|bdate|age=?", 3).Scan(&birthday)
333 if err != nil || !birthday.Equal(chrisBirthday) {
334 t.Errorf("chris birthday = %v, err = %v; want %v", birthday, err, chrisBirthday)
335 }
336
Brad Fitzpatrick357f2cb2011-09-29 16:12:21 -0700337 err = db.QueryRow("SELECT|people|age,name|age=?", 2).Scan(&age, &name)
338 if err != nil {
339 t.Fatalf("age QueryRow+Scan: %v", err)
340 }
341 if name != "Bob" {
342 t.Errorf("expected name Bob, got %q", name)
343 }
344 if age != 2 {
345 t.Errorf("expected age 2, got %d", age)
346 }
347
348 err = db.QueryRow("SELECT|people|age,name|name=?", "Alice").Scan(&age, &name)
349 if err != nil {
350 t.Fatalf("name QueryRow+Scan: %v", err)
351 }
352 if name != "Alice" {
353 t.Errorf("expected name Alice, got %q", name)
354 }
355 if age != 1 {
356 t.Errorf("expected age 1, got %d", age)
357 }
Brad Fitzpatrick701f70a2012-01-12 11:23:33 -0800358
359 var photo []byte
360 err = db.QueryRow("SELECT|people|photo|name=?", "Alice").Scan(&photo)
361 if err != nil {
362 t.Fatalf("photo QueryRow+Scan: %v", err)
363 }
364 want := []byte("APHOTO")
365 if !reflect.DeepEqual(photo, want) {
366 t.Errorf("photo = %q; want %q", photo, want)
367 }
Brad Fitzpatrick357f2cb2011-09-29 16:12:21 -0700368}
369
Brad Fitzpatrick750d0e32011-11-20 14:56:49 -0500370func TestStatementErrorAfterClose(t *testing.T) {
371 db := newTestDB(t, "people")
372 defer closeDB(t, db)
373 stmt, err := db.Prepare("SELECT|people|age|name=?")
374 if err != nil {
375 t.Fatalf("Prepare: %v", err)
376 }
377 err = stmt.Close()
378 if err != nil {
379 t.Fatalf("Close: %v", err)
380 }
381 var name string
382 err = stmt.QueryRow("foo").Scan(&name)
383 if err == nil {
384 t.Errorf("expected error from QueryRow.Scan after Stmt.Close")
385 }
386}
387
Brad Fitzpatrick357f2cb2011-09-29 16:12:21 -0700388func TestStatementQueryRow(t *testing.T) {
389 db := newTestDB(t, "people")
Brad Fitzpatrick0a8005c2011-11-14 10:48:26 -0800390 defer closeDB(t, db)
Brad Fitzpatrick357f2cb2011-09-29 16:12:21 -0700391 stmt, err := db.Prepare("SELECT|people|age|name=?")
392 if err != nil {
393 t.Fatalf("Prepare: %v", err)
394 }
Gwenael Treguierc3954dd52012-03-10 15:21:44 -0800395 defer stmt.Close()
Brad Fitzpatrick357f2cb2011-09-29 16:12:21 -0700396 var age int
397 for n, tt := range []struct {
398 name string
399 want int
400 }{
401 {"Alice", 1},
402 {"Bob", 2},
403 {"Chris", 3},
404 } {
405 if err := stmt.QueryRow(tt.name).Scan(&age); err != nil {
406 t.Errorf("%d: on %q, QueryRow/Scan: %v", n, tt.name, err)
407 } else if age != tt.want {
Robert Henckec5018242011-10-13 13:34:01 +1100408 t.Errorf("%d: age=%d, want %d", n, age, tt.want)
Brad Fitzpatrick357f2cb2011-09-29 16:12:21 -0700409 }
410 }
Brad Fitzpatrick357f2cb2011-09-29 16:12:21 -0700411}
412
Ian Gudger73fe61232015-10-01 03:29:27 -0700413type stubDriverStmt struct {
414 err error
415}
416
417func (s stubDriverStmt) Close() error {
418 return s.err
419}
420
421func (s stubDriverStmt) NumInput() int {
422 return -1
423}
424
425func (s stubDriverStmt) Exec(args []driver.Value) (driver.Result, error) {
426 return nil, nil
427}
428
429func (s stubDriverStmt) Query(args []driver.Value) (driver.Rows, error) {
430 return nil, nil
431}
432
433// golang.org/issue/12798
434func TestStatementClose(t *testing.T) {
435 want := errors.New("STMT ERROR")
436
437 tests := []struct {
438 stmt *Stmt
439 msg string
440 }{
441 {&Stmt{stickyErr: want}, "stickyErr not propagated"},
442 {&Stmt{tx: &Tx{}, txsi: &driverStmt{&sync.Mutex{}, stubDriverStmt{want}}}, "driverStmt.Close() error not propagated"},
443 }
444 for _, test := range tests {
445 if err := test.stmt.Close(); err != want {
446 t.Errorf("%s. Got stmt.Close() = %v, want = %v", test.msg, err, want)
447 }
448 }
449}
450
Brad Fitzpatrickc53fab92013-02-20 22:15:36 -0800451// golang.org/issue/3734
452func TestStatementQueryRowConcurrent(t *testing.T) {
453 db := newTestDB(t, "people")
454 defer closeDB(t, db)
455 stmt, err := db.Prepare("SELECT|people|age|name=?")
456 if err != nil {
457 t.Fatalf("Prepare: %v", err)
458 }
459 defer stmt.Close()
460
461 const n = 10
462 ch := make(chan error, n)
463 for i := 0; i < n; i++ {
464 go func() {
465 var age int
466 err := stmt.QueryRow("Alice").Scan(&age)
467 if err == nil && age != 1 {
468 err = fmt.Errorf("unexpected age %d", age)
469 }
470 ch <- err
471 }()
472 }
473 for i := 0; i < n; i++ {
474 if err := <-ch; err != nil {
475 t.Error(err)
476 }
477 }
478}
479
Brad Fitzpatrick357f2cb2011-09-29 16:12:21 -0700480// just a test of fakedb itself
481func TestBogusPreboundParameters(t *testing.T) {
482 db := newTestDB(t, "foo")
Brad Fitzpatrick0a8005c2011-11-14 10:48:26 -0800483 defer closeDB(t, db)
Brad Fitzpatrick357f2cb2011-09-29 16:12:21 -0700484 exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool")
485 _, err := db.Prepare("INSERT|t1|name=?,age=bogusconversion")
486 if err == nil {
487 t.Fatalf("expected error")
488 }
Russ Coxc2049d22011-11-01 22:04:37 -0400489 if err.Error() != `fakedb: invalid conversion to int32 from "bogusconversion"` {
Brad Fitzpatrick357f2cb2011-09-29 16:12:21 -0700490 t.Errorf("unexpected error: %v", err)
491 }
492}
493
Brad Fitzpatricke77099d2011-11-28 11:00:32 -0500494func TestExec(t *testing.T) {
Brad Fitzpatrick357f2cb2011-09-29 16:12:21 -0700495 db := newTestDB(t, "foo")
Brad Fitzpatrick0a8005c2011-11-14 10:48:26 -0800496 defer closeDB(t, db)
Brad Fitzpatrick357f2cb2011-09-29 16:12:21 -0700497 exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool")
498 stmt, err := db.Prepare("INSERT|t1|name=?,age=?")
499 if err != nil {
500 t.Errorf("Stmt, err = %v, %v", stmt, err)
501 }
Gwenael Treguierc3954dd52012-03-10 15:21:44 -0800502 defer stmt.Close()
Brad Fitzpatrick357f2cb2011-09-29 16:12:21 -0700503
504 type execTest struct {
505 args []interface{}
506 wantErr string
507 }
508 execTests := []execTest{
509 // Okay:
510 {[]interface{}{"Brad", 31}, ""},
511 {[]interface{}{"Brad", int64(31)}, ""},
512 {[]interface{}{"Bob", "32"}, ""},
513 {[]interface{}{7, 9}, ""},
514
515 // Invalid conversions:
Brad Fitzpatrick93fe8c0c2012-05-29 11:09:09 -0700516 {[]interface{}{"Brad", int64(0xFFFFFFFF)}, "sql: converting argument #1's type: sql/driver: value 4294967295 overflows int32"},
517 {[]interface{}{"Brad", "strconv fail"}, "sql: converting argument #1's type: sql/driver: value \"strconv fail\" can't be converted to int32"},
Brad Fitzpatrick357f2cb2011-09-29 16:12:21 -0700518
519 // Wrong number of args:
Brad Fitzpatrickea51dd22011-12-15 10:14:57 -0800520 {[]interface{}{}, "sql: expected 2 arguments, got 0"},
521 {[]interface{}{1, 2, 3}, "sql: expected 2 arguments, got 3"},
Brad Fitzpatrick357f2cb2011-09-29 16:12:21 -0700522 }
523 for n, et := range execTests {
524 _, err := stmt.Exec(et.args...)
525 errStr := ""
526 if err != nil {
Russ Coxc2049d22011-11-01 22:04:37 -0400527 errStr = err.Error()
Brad Fitzpatrick357f2cb2011-09-29 16:12:21 -0700528 }
529 if errStr != et.wantErr {
530 t.Errorf("stmt.Execute #%d: for %v, got error %q, want error %q",
531 n, et.args, errStr, et.wantErr)
532 }
533 }
534}
Brad Fitzpatricke77099d2011-11-28 11:00:32 -0500535
Marko Tiikkaja5f739d92014-09-22 09:19:27 -0400536func TestTxPrepare(t *testing.T) {
537 db := newTestDB(t, "")
538 defer closeDB(t, db)
539 exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool")
540 tx, err := db.Begin()
541 if err != nil {
542 t.Fatalf("Begin = %v", err)
543 }
544 stmt, err := tx.Prepare("INSERT|t1|name=?,age=?")
545 if err != nil {
546 t.Fatalf("Stmt, err = %v, %v", stmt, err)
547 }
548 defer stmt.Close()
549 _, err = stmt.Exec("Bobby", 7)
550 if err != nil {
551 t.Fatalf("Exec = %v", err)
552 }
553 err = tx.Commit()
554 if err != nil {
555 t.Fatalf("Commit = %v", err)
556 }
557 // Commit() should have closed the statement
558 if !stmt.closed {
559 t.Fatal("Stmt not closed after Commit")
560 }
561}
562
Brad Fitzpatricke77099d2011-11-28 11:00:32 -0500563func TestTxStmt(t *testing.T) {
564 db := newTestDB(t, "")
565 defer closeDB(t, db)
566 exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool")
567 stmt, err := db.Prepare("INSERT|t1|name=?,age=?")
568 if err != nil {
569 t.Fatalf("Stmt, err = %v, %v", stmt, err)
570 }
Gwenael Treguierc3954dd52012-03-10 15:21:44 -0800571 defer stmt.Close()
Brad Fitzpatricke77099d2011-11-28 11:00:32 -0500572 tx, err := db.Begin()
573 if err != nil {
574 t.Fatalf("Begin = %v", err)
575 }
Gwenael Treguierc3954dd52012-03-10 15:21:44 -0800576 txs := tx.Stmt(stmt)
577 defer txs.Close()
578 _, err = txs.Exec("Bobby", 7)
Brad Fitzpatricke77099d2011-11-28 11:00:32 -0500579 if err != nil {
580 t.Fatalf("Exec = %v", err)
581 }
582 err = tx.Commit()
583 if err != nil {
584 t.Fatalf("Commit = %v", err)
585 }
Marko Tiikkaja5f739d92014-09-22 09:19:27 -0400586 // Commit() should have closed the statement
587 if !txs.closed {
588 t.Fatal("Stmt not closed after Commit")
589 }
Brad Fitzpatricke77099d2011-11-28 11:00:32 -0500590}
Brad Fitzpatrick06a9bc62011-12-12 13:56:56 -0800591
Brad Fitzpatrick2ae77372015-07-10 17:17:11 -0600592// Issue: https://golang.org/issue/2784
Robert Henckef999e142014-04-29 12:44:40 -0400593// This test didn't fail before because we got lucky with the fakedb driver.
Blake Mizeranybcb976c2012-01-25 17:49:30 -0800594// It was failing, and now not, in github.com/bradfitz/go-sql-test
595func TestTxQuery(t *testing.T) {
596 db := newTestDB(t, "")
597 defer closeDB(t, db)
598 exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool")
599 exec(t, db, "INSERT|t1|name=Alice")
600
601 tx, err := db.Begin()
602 if err != nil {
603 t.Fatal(err)
604 }
605 defer tx.Rollback()
606
607 r, err := tx.Query("SELECT|t1|name|")
608 if err != nil {
609 t.Fatal(err)
610 }
Gwenael Treguierc3954dd52012-03-10 15:21:44 -0800611 defer r.Close()
Blake Mizeranybcb976c2012-01-25 17:49:30 -0800612
613 if !r.Next() {
614 if r.Err() != nil {
615 t.Fatal(r.Err())
616 }
617 t.Fatal("expected one row")
618 }
619
620 var x string
621 err = r.Scan(&x)
622 if err != nil {
623 t.Fatal(err)
624 }
625}
626
Brad Fitzpatrick3297fc62012-03-10 10:00:02 -0800627func TestTxQueryInvalid(t *testing.T) {
628 db := newTestDB(t, "")
629 defer closeDB(t, db)
630
631 tx, err := db.Begin()
632 if err != nil {
633 t.Fatal(err)
634 }
635 defer tx.Rollback()
636
637 _, err = tx.Query("SELECT|t1|name|")
638 if err == nil {
639 t.Fatal("Error expected")
640 }
641}
642
James David Chalfant19e2f262012-12-14 09:00:33 -0800643// Tests fix for issue 4433, that retries in Begin happen when
644// conn.Begin() returns ErrBadConn
645func TestTxErrBadConn(t *testing.T) {
646 db, err := Open("test", fakeDBName+";badConn")
647 if err != nil {
648 t.Fatalf("Open: %v", err)
649 }
650 if _, err := db.Exec("WIPE"); err != nil {
651 t.Fatalf("exec wipe: %v", err)
652 }
653 defer closeDB(t, db)
654 exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool")
655 stmt, err := db.Prepare("INSERT|t1|name=?,age=?")
656 if err != nil {
657 t.Fatalf("Stmt, err = %v, %v", stmt, err)
658 }
659 defer stmt.Close()
660 tx, err := db.Begin()
661 if err != nil {
662 t.Fatalf("Begin = %v", err)
663 }
664 txs := tx.Stmt(stmt)
665 defer txs.Close()
666 _, err = txs.Exec("Bobby", 7)
667 if err != nil {
668 t.Fatalf("Exec = %v", err)
669 }
670 err = tx.Commit()
671 if err != nil {
672 t.Fatalf("Commit = %v", err)
673 }
674}
675
Brad Fitzpatrick06a9bc62011-12-12 13:56:56 -0800676// Tests fix for issue 2542, that we release a lock when querying on
677// a closed connection.
678func TestIssue2542Deadlock(t *testing.T) {
679 db := newTestDB(t, "people")
680 closeDB(t, db)
681 for i := 0; i < 2; i++ {
682 _, err := db.Query("SELECT|people|age,name|")
683 if err == nil {
684 t.Fatalf("expected error")
685 }
686 }
687}
Brad Fitzpatrick1c441e22012-01-13 15:25:07 -0800688
Brad Fitzpatrickf7a77162013-02-20 15:35:27 -0800689// From golang.org/issue/3865
Brad Fitzpatrick8f2430a2013-02-13 12:00:03 -0800690func TestCloseStmtBeforeRows(t *testing.T) {
Brad Fitzpatrick8f2430a2013-02-13 12:00:03 -0800691 db := newTestDB(t, "people")
692 defer closeDB(t, db)
693
694 s, err := db.Prepare("SELECT|people|name|")
695 if err != nil {
696 t.Fatal(err)
697 }
698
699 r, err := s.Query()
700 if err != nil {
701 s.Close()
702 t.Fatal(err)
703 }
704
705 err = s.Close()
706 if err != nil {
707 t.Fatal(err)
708 }
709
710 r.Close()
711}
712
James P. Cooper2a22f352012-01-26 15:12:48 -0800713// Tests fix for issue 2788, that we bind nil to a []byte if the
714// value in the column is sql null
715func TestNullByteSlice(t *testing.T) {
716 db := newTestDB(t, "")
717 defer closeDB(t, db)
718 exec(t, db, "CREATE|t|id=int32,name=nullstring")
719 exec(t, db, "INSERT|t|id=10,name=?", nil)
720
721 var name []byte
722
723 err := db.QueryRow("SELECT|t|name|id=?", 10).Scan(&name)
724 if err != nil {
725 t.Fatal(err)
726 }
727 if name != nil {
728 t.Fatalf("name []byte should be nil for null column value, got: %#v", name)
729 }
730
731 exec(t, db, "INSERT|t|id=11,name=?", "bob")
732 err = db.QueryRow("SELECT|t|name|id=?", 11).Scan(&name)
733 if err != nil {
734 t.Fatal(err)
735 }
736 if string(name) != "bob" {
737 t.Fatalf("name []byte should be bob, got: %q", string(name))
738 }
739}
740
Brad Fitzpatrick29df9372012-02-09 15:01:29 +1100741func TestPointerParamsAndScans(t *testing.T) {
742 db := newTestDB(t, "")
743 defer closeDB(t, db)
744 exec(t, db, "CREATE|t|id=int32,name=nullstring")
745
746 bob := "bob"
747 var name *string
748
749 name = &bob
750 exec(t, db, "INSERT|t|id=10,name=?", name)
751 name = nil
752 exec(t, db, "INSERT|t|id=20,name=?", name)
753
754 err := db.QueryRow("SELECT|t|name|id=?", 10).Scan(&name)
755 if err != nil {
756 t.Fatalf("querying id 10: %v", err)
757 }
758 if name == nil {
759 t.Errorf("id 10's name = nil; want bob")
760 } else if *name != "bob" {
761 t.Errorf("id 10's name = %q; want bob", *name)
762 }
763
764 err = db.QueryRow("SELECT|t|name|id=?", 20).Scan(&name)
765 if err != nil {
766 t.Fatalf("querying id 20: %v", err)
767 }
768 if name != nil {
769 t.Errorf("id 20 = %q; want nil", *name)
770 }
771}
772
Brad Fitzpatrick1c441e22012-01-13 15:25:07 -0800773func TestQueryRowClosingStmt(t *testing.T) {
774 db := newTestDB(t, "people")
775 defer closeDB(t, db)
776 var name string
777 var age int
778 err := db.QueryRow("SELECT|people|age,name|age=?", 3).Scan(&age, &name)
779 if err != nil {
780 t.Fatal(err)
781 }
Alberto García Hierro6fb6f4e2014-08-28 08:49:56 -0700782 if len(db.freeConn) != 1 {
Brad Fitzpatrick1c441e22012-01-13 15:25:07 -0800783 t.Fatalf("expected 1 free conn")
784 }
Alberto García Hierro6fb6f4e2014-08-28 08:49:56 -0700785 fakeConn := db.freeConn[0].ci.(*fakeConn)
Brad Fitzpatrick1c441e22012-01-13 15:25:07 -0800786 if made, closed := fakeConn.stmtsMade, fakeConn.stmtsClosed; made != closed {
Brad Fitzpatrickebc80132012-01-17 10:44:35 -0800787 t.Errorf("statement close mismatch: made %d, closed %d", made, closed)
Brad Fitzpatrick1c441e22012-01-13 15:25:07 -0800788 }
789}
Brad Fitzpatrickbc0139b2012-01-19 09:27:45 -0800790
Marko Tiikkaja1f20ab12013-12-16 12:48:35 -0800791// Test issue 6651
792func TestIssue6651(t *testing.T) {
793 db := newTestDB(t, "people")
794 defer closeDB(t, db)
795
796 var v string
797
798 want := "error in rows.Next"
799 rowsCursorNextHook = func(dest []driver.Value) error {
800 return fmt.Errorf(want)
801 }
802 defer func() { rowsCursorNextHook = nil }()
803 err := db.QueryRow("SELECT|people|name|").Scan(&v)
804 if err == nil || err.Error() != want {
805 t.Errorf("error = %q; want %q", err, want)
806 }
807 rowsCursorNextHook = nil
808
809 want = "error in rows.Close"
810 rowsCloseHook = func(rows *Rows, err *error) {
811 *err = fmt.Errorf(want)
812 }
813 defer func() { rowsCloseHook = nil }()
814 err = db.QueryRow("SELECT|people|name|").Scan(&v)
815 if err == nil || err.Error() != want {
816 t.Errorf("error = %q; want %q", err, want)
817 }
818}
819
James P. Cooperc21b3432012-01-25 17:47:32 -0800820type nullTestRow struct {
821 nullParam interface{}
822 notNullParam interface{}
823 scanNullVal interface{}
824}
825
826type nullTestSpec struct {
827 nullType string
828 notNullType string
829 rows [6]nullTestRow
830}
831
Brad Fitzpatrickbc0139b2012-01-19 09:27:45 -0800832func TestNullStringParam(t *testing.T) {
James P. Cooperc21b3432012-01-25 17:47:32 -0800833 spec := nullTestSpec{"nullstring", "string", [6]nullTestRow{
Robert Griesemer56cae1c2012-03-08 10:48:51 -0800834 {NullString{"aqua", true}, "", NullString{"aqua", true}},
835 {NullString{"brown", false}, "", NullString{"", false}},
836 {"chartreuse", "", NullString{"chartreuse", true}},
837 {NullString{"darkred", true}, "", NullString{"darkred", true}},
838 {NullString{"eel", false}, "", NullString{"", false}},
839 {"foo", NullString{"black", false}, nil},
James P. Cooperc21b3432012-01-25 17:47:32 -0800840 }}
841 nullTestRun(t, spec)
842}
843
844func TestNullInt64Param(t *testing.T) {
845 spec := nullTestSpec{"nullint64", "int64", [6]nullTestRow{
Robert Griesemer56cae1c2012-03-08 10:48:51 -0800846 {NullInt64{31, true}, 1, NullInt64{31, true}},
847 {NullInt64{-22, false}, 1, NullInt64{0, false}},
848 {22, 1, NullInt64{22, true}},
849 {NullInt64{33, true}, 1, NullInt64{33, true}},
850 {NullInt64{222, false}, 1, NullInt64{0, false}},
851 {0, NullInt64{31, false}, nil},
James P. Cooperc21b3432012-01-25 17:47:32 -0800852 }}
853 nullTestRun(t, spec)
854}
855
856func TestNullFloat64Param(t *testing.T) {
857 spec := nullTestSpec{"nullfloat64", "float64", [6]nullTestRow{
Robert Griesemer56cae1c2012-03-08 10:48:51 -0800858 {NullFloat64{31.2, true}, 1, NullFloat64{31.2, true}},
859 {NullFloat64{13.1, false}, 1, NullFloat64{0, false}},
860 {-22.9, 1, NullFloat64{-22.9, true}},
861 {NullFloat64{33.81, true}, 1, NullFloat64{33.81, true}},
862 {NullFloat64{222, false}, 1, NullFloat64{0, false}},
863 {10, NullFloat64{31.2, false}, nil},
James P. Cooperc21b3432012-01-25 17:47:32 -0800864 }}
865 nullTestRun(t, spec)
866}
867
868func TestNullBoolParam(t *testing.T) {
869 spec := nullTestSpec{"nullbool", "bool", [6]nullTestRow{
Robert Griesemer56cae1c2012-03-08 10:48:51 -0800870 {NullBool{false, true}, true, NullBool{false, true}},
871 {NullBool{true, false}, false, NullBool{false, false}},
872 {true, true, NullBool{true, true}},
873 {NullBool{true, true}, false, NullBool{true, true}},
874 {NullBool{true, false}, true, NullBool{false, false}},
875 {true, NullBool{true, false}, nil},
James P. Cooperc21b3432012-01-25 17:47:32 -0800876 }}
877 nullTestRun(t, spec)
878}
879
880func nullTestRun(t *testing.T, spec nullTestSpec) {
Brad Fitzpatrickbc0139b2012-01-19 09:27:45 -0800881 db := newTestDB(t, "")
882 defer closeDB(t, db)
James P. Cooperc21b3432012-01-25 17:47:32 -0800883 exec(t, db, fmt.Sprintf("CREATE|t|id=int32,name=string,nullf=%s,notnullf=%s", spec.nullType, spec.notNullType))
Brad Fitzpatrickbc0139b2012-01-19 09:27:45 -0800884
885 // Inserts with db.Exec:
James P. Cooperc21b3432012-01-25 17:47:32 -0800886 exec(t, db, "INSERT|t|id=?,name=?,nullf=?,notnullf=?", 1, "alice", spec.rows[0].nullParam, spec.rows[0].notNullParam)
887 exec(t, db, "INSERT|t|id=?,name=?,nullf=?,notnullf=?", 2, "bob", spec.rows[1].nullParam, spec.rows[1].notNullParam)
Brad Fitzpatrickbc0139b2012-01-19 09:27:45 -0800888
James P. Cooperc21b3432012-01-25 17:47:32 -0800889 // Inserts with a prepared statement:
890 stmt, err := db.Prepare("INSERT|t|id=?,name=?,nullf=?,notnullf=?")
891 if err != nil {
892 t.Fatalf("prepare: %v", err)
893 }
Gwenael Treguierc3954dd52012-03-10 15:21:44 -0800894 defer stmt.Close()
James P. Cooperc21b3432012-01-25 17:47:32 -0800895 if _, err := stmt.Exec(3, "chris", spec.rows[2].nullParam, spec.rows[2].notNullParam); err != nil {
896 t.Errorf("exec insert chris: %v", err)
897 }
898 if _, err := stmt.Exec(4, "dave", spec.rows[3].nullParam, spec.rows[3].notNullParam); err != nil {
899 t.Errorf("exec insert dave: %v", err)
900 }
901 if _, err := stmt.Exec(5, "eleanor", spec.rows[4].nullParam, spec.rows[4].notNullParam); err != nil {
902 t.Errorf("exec insert eleanor: %v", err)
903 }
904
905 // Can't put null val into non-null col
906 if _, err := stmt.Exec(6, "bob", spec.rows[5].nullParam, spec.rows[5].notNullParam); err == nil {
907 t.Errorf("expected error inserting nil val with prepared statement Exec")
908 }
909
910 _, err = db.Exec("INSERT|t|id=?,name=?,nullf=?", 999, nil, nil)
Brad Fitzpatrickbc0139b2012-01-19 09:27:45 -0800911 if err == nil {
912 // TODO: this test fails, but it's just because
913 // fakeConn implements the optional Execer interface,
914 // so arguably this is the correct behavior. But
915 // maybe I should flesh out the fakeConn.Exec
916 // implementation so this properly fails.
917 // t.Errorf("expected error inserting nil name with Exec")
918 }
919
James P. Cooperc21b3432012-01-25 17:47:32 -0800920 paramtype := reflect.TypeOf(spec.rows[0].nullParam)
921 bindVal := reflect.New(paramtype).Interface()
Brad Fitzpatrickbc0139b2012-01-19 09:27:45 -0800922
James P. Cooperc21b3432012-01-25 17:47:32 -0800923 for i := 0; i < 5; i++ {
924 id := i + 1
925 if err := db.QueryRow("SELECT|t|nullf|id=?", id).Scan(bindVal); err != nil {
Brad Fitzpatrickbc0139b2012-01-19 09:27:45 -0800926 t.Errorf("id=%d Scan: %v", id, err)
927 }
James P. Cooperc21b3432012-01-25 17:47:32 -0800928 bindValDeref := reflect.ValueOf(bindVal).Elem().Interface()
929 if !reflect.DeepEqual(bindValDeref, spec.rows[i].scanNullVal) {
930 t.Errorf("id=%d got %#v, want %#v", id, bindValDeref, spec.rows[i].scanNullVal)
Brad Fitzpatrickbc0139b2012-01-19 09:27:45 -0800931 }
932 }
933}
Brad Fitzpatrickbca3f5f2013-02-21 10:43:00 -0800934
935// golang.org/issue/4859
936func TestQueryRowNilScanDest(t *testing.T) {
937 db := newTestDB(t, "people")
938 defer closeDB(t, db)
939 var name *string // nil pointer
940 err := db.QueryRow("SELECT|people|name|").Scan(name)
941 want := "sql: Scan error on column index 0: destination pointer is nil"
942 if err == nil || err.Error() != want {
943 t.Errorf("error = %q; want %q", err.Error(), want)
944 }
945}
Brad Fitzpatrick3cdf8ba2013-03-08 10:04:17 -0800946
947func TestIssue4902(t *testing.T) {
948 db := newTestDB(t, "people")
949 defer closeDB(t, db)
950
951 driver := db.driver.(*fakeDriver)
952 opens0 := driver.openCount
953
954 var stmt *Stmt
955 var err error
956 for i := 0; i < 10; i++ {
957 stmt, err = db.Prepare("SELECT|people|name|")
958 if err != nil {
959 t.Fatal(err)
960 }
961 err = stmt.Close()
962 if err != nil {
963 t.Fatal(err)
964 }
965 }
966
967 opens := driver.openCount - opens0
968 if opens > 1 {
969 t.Errorf("opens = %d; want <= 1", opens)
970 t.Logf("db = %#v", db)
971 t.Logf("driver = %#v", driver)
972 t.Logf("stmt = %#v", stmt)
973 }
974}
Brad Fitzpatricka7a803c2013-03-18 11:39:00 -0700975
976// Issue 3857
977// This used to deadlock.
978func TestSimultaneousQueries(t *testing.T) {
979 db := newTestDB(t, "people")
980 defer closeDB(t, db)
981
982 tx, err := db.Begin()
983 if err != nil {
984 t.Fatal(err)
985 }
986 defer tx.Rollback()
987
988 r1, err := tx.Query("SELECT|people|name|")
989 if err != nil {
990 t.Fatal(err)
991 }
992 defer r1.Close()
993
994 r2, err := tx.Query("SELECT|people|name|")
995 if err != nil {
996 t.Fatal(err)
997 }
998 defer r2.Close()
999}
Brad Fitzpatrick3a2fe622013-03-18 15:33:04 -07001000
1001func TestMaxIdleConns(t *testing.T) {
1002 db := newTestDB(t, "people")
1003 defer closeDB(t, db)
1004
1005 tx, err := db.Begin()
1006 if err != nil {
1007 t.Fatal(err)
1008 }
1009 tx.Commit()
Alberto García Hierro6fb6f4e2014-08-28 08:49:56 -07001010 if got := len(db.freeConn); got != 1 {
Brad Fitzpatrick3a2fe622013-03-18 15:33:04 -07001011 t.Errorf("freeConns = %d; want 1", got)
1012 }
1013
1014 db.SetMaxIdleConns(0)
1015
Alberto García Hierro6fb6f4e2014-08-28 08:49:56 -07001016 if got := len(db.freeConn); got != 0 {
Brad Fitzpatrick3a2fe622013-03-18 15:33:04 -07001017 t.Errorf("freeConns after set to zero = %d; want 0", got)
1018 }
1019
1020 tx, err = db.Begin()
1021 if err != nil {
1022 t.Fatal(err)
1023 }
1024 tx.Commit()
Alberto García Hierro6fb6f4e2014-08-28 08:49:56 -07001025 if got := len(db.freeConn); got != 0 {
Brad Fitzpatrick3a2fe622013-03-18 15:33:04 -07001026 t.Errorf("freeConns = %d; want 0", got)
1027 }
1028}
Brad Fitzpatrick209f6b12013-03-25 16:50:27 -07001029
Tad Glines41c5d8d2013-08-30 09:27:33 -07001030func TestMaxOpenConns(t *testing.T) {
1031 if testing.Short() {
1032 t.Skip("skipping in short mode")
1033 }
1034 defer setHookpostCloseConn(nil)
1035 setHookpostCloseConn(func(_ *fakeConn, err error) {
1036 if err != nil {
1037 t.Errorf("Error closing fakeConn: %v", err)
1038 }
1039 })
1040
1041 db := newTestDB(t, "magicquery")
1042 defer closeDB(t, db)
1043
1044 driver := db.driver.(*fakeDriver)
1045
1046 // Force the number of open connections to 0 so we can get an accurate
1047 // count for the test
INADA Naoki0c516c12015-03-03 21:27:07 +09001048 db.clearAllConns(t)
Tad Glines41c5d8d2013-08-30 09:27:33 -07001049
1050 driver.mu.Lock()
1051 opens0 := driver.openCount
1052 closes0 := driver.closeCount
1053 driver.mu.Unlock()
1054
1055 db.SetMaxIdleConns(10)
1056 db.SetMaxOpenConns(10)
1057
1058 stmt, err := db.Prepare("SELECT|magicquery|op|op=?,millis=?")
1059 if err != nil {
1060 t.Fatal(err)
1061 }
1062
1063 // Start 50 parallel slow queries.
1064 const (
1065 nquery = 50
1066 sleepMillis = 25
1067 nbatch = 2
1068 )
1069 var wg sync.WaitGroup
1070 for batch := 0; batch < nbatch; batch++ {
1071 for i := 0; i < nquery; i++ {
1072 wg.Add(1)
1073 go func() {
1074 defer wg.Done()
1075 var op string
1076 if err := stmt.QueryRow("sleep", sleepMillis).Scan(&op); err != nil && err != ErrNoRows {
1077 t.Error(err)
1078 }
1079 }()
1080 }
1081 // Sleep for twice the expected length of time for the
1082 // batch of 50 queries above to finish before starting
1083 // the next round.
1084 time.Sleep(2 * sleepMillis * time.Millisecond)
1085 }
1086 wg.Wait()
1087
1088 if g, w := db.numFreeConns(), 10; g != w {
1089 t.Errorf("free conns = %d; want %d", g, w)
1090 }
1091
1092 if n := db.numDepsPollUntil(20, time.Second); n > 20 {
1093 t.Errorf("number of dependencies = %d; expected <= 20", n)
1094 db.dumpDeps(t)
1095 }
1096
1097 driver.mu.Lock()
1098 opens := driver.openCount - opens0
1099 closes := driver.closeCount - closes0
1100 driver.mu.Unlock()
1101
1102 if opens > 10 {
1103 t.Logf("open calls = %d", opens)
1104 t.Logf("close calls = %d", closes)
1105 t.Errorf("db connections opened = %d; want <= 10", opens)
1106 db.dumpDeps(t)
1107 }
1108
1109 if err := stmt.Close(); err != nil {
1110 t.Fatal(err)
1111 }
1112
1113 if g, w := db.numFreeConns(), 10; g != w {
1114 t.Errorf("free conns = %d; want %d", g, w)
1115 }
1116
1117 if n := db.numDepsPollUntil(10, time.Second); n > 10 {
1118 t.Errorf("number of dependencies = %d; expected <= 10", n)
1119 db.dumpDeps(t)
1120 }
1121
1122 db.SetMaxOpenConns(5)
1123
1124 if g, w := db.numFreeConns(), 5; g != w {
1125 t.Errorf("free conns = %d; want %d", g, w)
1126 }
1127
1128 if n := db.numDepsPollUntil(5, time.Second); n > 5 {
1129 t.Errorf("number of dependencies = %d; expected 0", n)
1130 db.dumpDeps(t)
1131 }
1132
1133 db.SetMaxOpenConns(0)
1134
1135 if g, w := db.numFreeConns(), 5; g != w {
1136 t.Errorf("free conns = %d; want %d", g, w)
1137 }
1138
1139 if n := db.numDepsPollUntil(5, time.Second); n > 5 {
1140 t.Errorf("number of dependencies = %d; expected 0", n)
1141 db.dumpDeps(t)
1142 }
1143
INADA Naoki0c516c12015-03-03 21:27:07 +09001144 db.clearAllConns(t)
Tad Glines41c5d8d2013-08-30 09:27:33 -07001145}
1146
Jiong Ducce127a2014-12-30 16:12:50 +08001147// Issue 9453: tests that SetMaxOpenConns can be lowered at runtime
1148// and affects the subsequent release of connections.
1149func TestMaxOpenConnsOnBusy(t *testing.T) {
1150 defer setHookpostCloseConn(nil)
1151 setHookpostCloseConn(func(_ *fakeConn, err error) {
1152 if err != nil {
1153 t.Errorf("Error closing fakeConn: %v", err)
1154 }
1155 })
1156
1157 db := newTestDB(t, "magicquery")
1158 defer closeDB(t, db)
1159
1160 db.SetMaxOpenConns(3)
1161
Marko Tiikkajac468f9462015-03-27 19:45:12 +01001162 conn0, err := db.conn(cachedOrNewConn)
Jiong Ducce127a2014-12-30 16:12:50 +08001163 if err != nil {
1164 t.Fatalf("db open conn fail: %v", err)
1165 }
1166
Marko Tiikkajac468f9462015-03-27 19:45:12 +01001167 conn1, err := db.conn(cachedOrNewConn)
Jiong Ducce127a2014-12-30 16:12:50 +08001168 if err != nil {
1169 t.Fatalf("db open conn fail: %v", err)
1170 }
1171
Marko Tiikkajac468f9462015-03-27 19:45:12 +01001172 conn2, err := db.conn(cachedOrNewConn)
Jiong Ducce127a2014-12-30 16:12:50 +08001173 if err != nil {
1174 t.Fatalf("db open conn fail: %v", err)
1175 }
1176
1177 if g, w := db.numOpen, 3; g != w {
1178 t.Errorf("free conns = %d; want %d", g, w)
1179 }
1180
1181 db.SetMaxOpenConns(2)
1182 if g, w := db.numOpen, 3; g != w {
1183 t.Errorf("free conns = %d; want %d", g, w)
1184 }
1185
1186 conn0.releaseConn(nil)
1187 conn1.releaseConn(nil)
1188 if g, w := db.numOpen, 2; g != w {
1189 t.Errorf("free conns = %d; want %d", g, w)
1190 }
1191
1192 conn2.releaseConn(nil)
1193 if g, w := db.numOpen, 2; g != w {
1194 t.Errorf("free conns = %d; want %d", g, w)
1195 }
1196}
1197
Chris Hines6de40092015-09-14 03:44:56 -04001198// Issue 10886: tests that all connection attempts return when more than
1199// DB.maxOpen connections are in flight and the first DB.maxOpen fail.
1200func TestPendingConnsAfterErr(t *testing.T) {
1201 const (
1202 maxOpen = 2
1203 tryOpen = maxOpen*2 + 2
1204 )
1205
1206 db := newTestDB(t, "people")
1207 defer closeDB(t, db)
1208 defer func() {
1209 for k, v := range db.lastPut {
1210 t.Logf("%p: %v", k, v)
1211 }
1212 }()
1213
1214 db.SetMaxOpenConns(maxOpen)
1215 db.SetMaxIdleConns(0)
1216
1217 errOffline := errors.New("db offline")
1218 defer func() { setHookOpenErr(nil) }()
1219
1220 errs := make(chan error, tryOpen)
1221
1222 unblock := make(chan struct{})
1223 setHookOpenErr(func() error {
1224 <-unblock // block until all connections are in flight
1225 return errOffline
1226 })
1227
1228 var opening sync.WaitGroup
1229 opening.Add(tryOpen)
1230 for i := 0; i < tryOpen; i++ {
1231 go func() {
1232 opening.Done() // signal one connection is in flight
1233 _, err := db.Exec("INSERT|people|name=Julia,age=19")
1234 errs <- err
1235 }()
1236 }
1237
1238 opening.Wait() // wait for all workers to begin running
1239 time.Sleep(10 * time.Millisecond) // make extra sure all workers are blocked
1240 close(unblock) // let all workers proceed
1241
1242 const timeout = 100 * time.Millisecond
1243 to := time.NewTimer(timeout)
1244 defer to.Stop()
1245
1246 // check that all connections fail without deadlock
1247 for i := 0; i < tryOpen; i++ {
1248 select {
1249 case err := <-errs:
1250 if got, want := err, errOffline; got != want {
1251 t.Errorf("unexpected err: got %v, want %v", got, want)
1252 }
1253 case <-to.C:
1254 t.Fatalf("orphaned connection request(s), still waiting after %v", timeout)
1255 }
1256 }
1257}
1258
Marko Tiikkaja0d12e242013-12-26 11:27:18 -08001259func TestSingleOpenConn(t *testing.T) {
1260 db := newTestDB(t, "people")
1261 defer closeDB(t, db)
1262
1263 db.SetMaxOpenConns(1)
1264
1265 rows, err := db.Query("SELECT|people|name|")
1266 if err != nil {
1267 t.Fatal(err)
1268 }
1269 if err = rows.Close(); err != nil {
1270 t.Fatal(err)
1271 }
1272 // shouldn't deadlock
1273 rows, err = db.Query("SELECT|people|name|")
1274 if err != nil {
1275 t.Fatal(err)
1276 }
1277 if err = rows.Close(); err != nil {
1278 t.Fatal(err)
1279 }
1280}
1281
Andrei Korzhevskii297c1d22015-03-23 18:23:53 +03001282func TestStats(t *testing.T) {
1283 db := newTestDB(t, "people")
1284 stats := db.Stats()
1285 if got := stats.OpenConnections; got != 1 {
1286 t.Errorf("stats.OpenConnections = %d; want 1", got)
1287 }
1288
1289 tx, err := db.Begin()
1290 if err != nil {
1291 t.Fatal(err)
1292 }
1293 tx.Commit()
1294
1295 closeDB(t, db)
1296 stats = db.Stats()
1297 if got := stats.OpenConnections; got != 0 {
1298 t.Errorf("stats.OpenConnections = %d; want 0", got)
1299 }
1300}
1301
INADA Naoki0c516c12015-03-03 21:27:07 +09001302func TestConnMaxLifetime(t *testing.T) {
1303 t0 := time.Unix(1000000, 0)
1304 offset := time.Duration(0)
1305
1306 nowFunc = func() time.Time { return t0.Add(offset) }
1307 defer func() { nowFunc = time.Now }()
1308
1309 db := newTestDB(t, "magicquery")
1310 defer closeDB(t, db)
1311
1312 driver := db.driver.(*fakeDriver)
1313
1314 // Force the number of open connections to 0 so we can get an accurate
1315 // count for the test
1316 db.clearAllConns(t)
1317
1318 driver.mu.Lock()
1319 opens0 := driver.openCount
1320 closes0 := driver.closeCount
1321 driver.mu.Unlock()
1322
1323 db.SetMaxIdleConns(10)
1324 db.SetMaxOpenConns(10)
1325
1326 tx, err := db.Begin()
1327 if err != nil {
1328 t.Fatal(err)
1329 }
1330
1331 offset = time.Second
1332 tx2, err := db.Begin()
1333 if err != nil {
1334 t.Fatal(err)
1335 }
1336
1337 tx.Commit()
1338 tx2.Commit()
1339
1340 driver.mu.Lock()
1341 opens := driver.openCount - opens0
1342 closes := driver.closeCount - closes0
1343 driver.mu.Unlock()
1344
1345 if opens != 2 {
1346 t.Errorf("opens = %d; want 2", opens)
1347 }
1348 if closes != 0 {
1349 t.Errorf("closes = %d; want 0", closes)
1350 }
1351 if g, w := db.numFreeConns(), 2; g != w {
1352 t.Errorf("free conns = %d; want %d", g, w)
1353 }
1354
1355 // Expire first conn
1356 offset = time.Second * 11
1357 db.SetConnMaxLifetime(time.Second * 10)
1358 if err != nil {
1359 t.Fatal(err)
1360 }
1361
1362 tx, err = db.Begin()
1363 if err != nil {
1364 t.Fatal(err)
1365 }
1366 tx2, err = db.Begin()
1367 if err != nil {
1368 t.Fatal(err)
1369 }
1370 tx.Commit()
1371 tx2.Commit()
1372
1373 driver.mu.Lock()
1374 opens = driver.openCount - opens0
1375 closes = driver.closeCount - closes0
1376 driver.mu.Unlock()
1377
1378 if opens != 3 {
1379 t.Errorf("opens = %d; want 3", opens)
1380 }
1381 if closes != 1 {
1382 t.Errorf("closes = %d; want 1", closes)
1383 }
1384}
1385
Brad Fitzpatrick277047f2013-04-25 14:45:56 -07001386// golang.org/issue/5323
1387func TestStmtCloseDeps(t *testing.T) {
1388 if testing.Short() {
1389 t.Skip("skipping in short mode")
1390 }
Brad Fitzpatrick209f6b12013-03-25 16:50:27 -07001391 defer setHookpostCloseConn(nil)
1392 setHookpostCloseConn(func(_ *fakeConn, err error) {
1393 if err != nil {
1394 t.Errorf("Error closing fakeConn: %v", err)
1395 }
1396 })
1397
Brad Fitzpatrick277047f2013-04-25 14:45:56 -07001398 db := newTestDB(t, "magicquery")
1399 defer closeDB(t, db)
1400
1401 driver := db.driver.(*fakeDriver)
1402
1403 driver.mu.Lock()
1404 opens0 := driver.openCount
1405 closes0 := driver.closeCount
1406 driver.mu.Unlock()
1407 openDelta0 := opens0 - closes0
1408
1409 stmt, err := db.Prepare("SELECT|magicquery|op|op=?,millis=?")
1410 if err != nil {
1411 t.Fatal(err)
1412 }
1413
1414 // Start 50 parallel slow queries.
1415 const (
1416 nquery = 50
1417 sleepMillis = 25
1418 nbatch = 2
1419 )
1420 var wg sync.WaitGroup
1421 for batch := 0; batch < nbatch; batch++ {
1422 for i := 0; i < nquery; i++ {
1423 wg.Add(1)
1424 go func() {
1425 defer wg.Done()
1426 var op string
1427 if err := stmt.QueryRow("sleep", sleepMillis).Scan(&op); err != nil && err != ErrNoRows {
1428 t.Error(err)
1429 }
1430 }()
1431 }
1432 // Sleep for twice the expected length of time for the
1433 // batch of 50 queries above to finish before starting
1434 // the next round.
1435 time.Sleep(2 * sleepMillis * time.Millisecond)
1436 }
1437 wg.Wait()
1438
1439 if g, w := db.numFreeConns(), 2; g != w {
1440 t.Errorf("free conns = %d; want %d", g, w)
1441 }
1442
1443 if n := db.numDepsPollUntil(4, time.Second); n > 4 {
1444 t.Errorf("number of dependencies = %d; expected <= 4", n)
1445 db.dumpDeps(t)
1446 }
1447
1448 driver.mu.Lock()
1449 opens := driver.openCount - opens0
1450 closes := driver.closeCount - closes0
Brad Fitzpatrick9456adb2013-08-29 17:26:00 -07001451 openDelta := (driver.openCount - driver.closeCount) - openDelta0
Tad Glines41c5d8d2013-08-30 09:27:33 -07001452 driver.mu.Unlock()
Brad Fitzpatrick277047f2013-04-25 14:45:56 -07001453
1454 if openDelta > 2 {
1455 t.Logf("open calls = %d", opens)
1456 t.Logf("close calls = %d", closes)
1457 t.Logf("open delta = %d", openDelta)
1458 t.Errorf("db connections opened = %d; want <= 2", openDelta)
1459 db.dumpDeps(t)
1460 }
1461
1462 if len(stmt.css) > nquery {
1463 t.Errorf("len(stmt.css) = %d; want <= %d", len(stmt.css), nquery)
1464 }
1465
1466 if err := stmt.Close(); err != nil {
1467 t.Fatal(err)
1468 }
1469
1470 if g, w := db.numFreeConns(), 2; g != w {
1471 t.Errorf("free conns = %d; want %d", g, w)
1472 }
1473
1474 if n := db.numDepsPollUntil(2, time.Second); n > 2 {
1475 t.Errorf("number of dependencies = %d; expected <= 2", n)
1476 db.dumpDeps(t)
1477 }
1478
INADA Naoki0c516c12015-03-03 21:27:07 +09001479 db.clearAllConns(t)
Brad Fitzpatrick277047f2013-04-25 14:45:56 -07001480}
1481
1482// golang.org/issue/5046
1483func TestCloseConnBeforeStmts(t *testing.T) {
Brad Fitzpatrick209f6b12013-03-25 16:50:27 -07001484 db := newTestDB(t, "people")
Brad Fitzpatrick277047f2013-04-25 14:45:56 -07001485 defer closeDB(t, db)
1486
1487 defer setHookpostCloseConn(nil)
1488 setHookpostCloseConn(func(_ *fakeConn, err error) {
1489 if err != nil {
1490 t.Errorf("Error closing fakeConn: %v; from %s", err, stack())
1491 db.dumpDeps(t)
1492 t.Errorf("DB = %#v", db)
1493 }
1494 })
Brad Fitzpatrick209f6b12013-03-25 16:50:27 -07001495
1496 stmt, err := db.Prepare("SELECT|people|name|")
1497 if err != nil {
1498 t.Fatal(err)
1499 }
1500
Alberto García Hierro6fb6f4e2014-08-28 08:49:56 -07001501 if len(db.freeConn) != 1 {
1502 t.Fatalf("expected 1 freeConn; got %d", len(db.freeConn))
Brad Fitzpatrick209f6b12013-03-25 16:50:27 -07001503 }
Alberto García Hierro6fb6f4e2014-08-28 08:49:56 -07001504 dc := db.freeConn[0]
Brad Fitzpatrick209f6b12013-03-25 16:50:27 -07001505 if dc.closed {
1506 t.Errorf("conn shouldn't be closed")
1507 }
1508
Brad Fitzpatrick277047f2013-04-25 14:45:56 -07001509 if n := len(dc.openStmt); n != 1 {
1510 t.Errorf("driverConn num openStmt = %d; want 1", n)
1511 }
Brad Fitzpatrick209f6b12013-03-25 16:50:27 -07001512 err = db.Close()
1513 if err != nil {
1514 t.Errorf("db Close = %v", err)
1515 }
1516 if !dc.closed {
1517 t.Errorf("after db.Close, driverConn should be closed")
1518 }
Brad Fitzpatrick277047f2013-04-25 14:45:56 -07001519 if n := len(dc.openStmt); n != 0 {
1520 t.Errorf("driverConn num openStmt = %d; want 0", n)
Brad Fitzpatrick209f6b12013-03-25 16:50:27 -07001521 }
1522
1523 err = stmt.Close()
1524 if err != nil {
1525 t.Errorf("Stmt close = %v", err)
1526 }
1527
1528 if !dc.closed {
1529 t.Errorf("conn should be closed")
1530 }
1531 if dc.ci != nil {
1532 t.Errorf("after Stmt Close, driverConn's Conn interface should be nil")
1533 }
1534}
James Tucker4f1ef562013-04-03 11:13:40 -07001535
Brad Fitzpatrick36d3bef2013-04-15 14:06:41 -07001536// golang.org/issue/5283: don't release the Rows' connection in Close
1537// before calling Stmt.Close.
1538func TestRowsCloseOrder(t *testing.T) {
1539 db := newTestDB(t, "people")
1540 defer closeDB(t, db)
1541
1542 db.SetMaxIdleConns(0)
1543 setStrictFakeConnClose(t)
1544 defer setStrictFakeConnClose(nil)
1545
1546 rows, err := db.Query("SELECT|people|age,name|")
1547 if err != nil {
1548 t.Fatal(err)
1549 }
1550 err = rows.Close()
1551 if err != nil {
1552 t.Fatal(err)
1553 }
1554}
1555
Nigel Taobc212652013-08-16 11:23:35 +10001556func TestRowsImplicitClose(t *testing.T) {
1557 db := newTestDB(t, "people")
1558 defer closeDB(t, db)
1559
1560 rows, err := db.Query("SELECT|people|age,name|")
1561 if err != nil {
1562 t.Fatal(err)
1563 }
1564
1565 want, fail := 2, errors.New("fail")
1566 r := rows.rowsi.(*rowsCursor)
1567 r.errPos, r.err = want, fail
1568
1569 got := 0
1570 for rows.Next() {
1571 got++
1572 }
1573 if got != want {
1574 t.Errorf("got %d rows, want %d", got, want)
1575 }
1576 if err := rows.Err(); err != fail {
1577 t.Errorf("got error %v, want %v", err, fail)
1578 }
1579 if !r.closed {
1580 t.Errorf("r.closed is false, want true")
1581 }
1582}
1583
Alex Brainmana2930652013-07-23 14:09:53 +10001584func TestStmtCloseOrder(t *testing.T) {
1585 db := newTestDB(t, "people")
1586 defer closeDB(t, db)
1587
1588 db.SetMaxIdleConns(0)
1589 setStrictFakeConnClose(t)
1590 defer setStrictFakeConnClose(nil)
1591
1592 _, err := db.Query("SELECT|non_existent|name|")
1593 if err == nil {
Martin Möhrmannfdd01792016-02-24 11:55:20 +01001594 t.Fatal("Querying non-existent table should fail")
Alex Brainmana2930652013-07-23 14:09:53 +10001595 }
1596}
1597
Marko Tiikkajac468f9462015-03-27 19:45:12 +01001598// Test cases where there's more than maxBadConnRetries bad connections in the
1599// pool (issue 8834)
1600func TestManyErrBadConn(t *testing.T) {
1601 manyErrBadConnSetup := func() *DB {
1602 db := newTestDB(t, "people")
1603
1604 nconn := maxBadConnRetries + 1
1605 db.SetMaxIdleConns(nconn)
1606 db.SetMaxOpenConns(nconn)
1607 // open enough connections
1608 func() {
1609 for i := 0; i < nconn; i++ {
1610 rows, err := db.Query("SELECT|people|age,name|")
1611 if err != nil {
1612 t.Fatal(err)
1613 }
1614 defer rows.Close()
1615 }
1616 }()
1617
1618 if db.numOpen != nconn {
1619 t.Fatalf("unexpected numOpen %d (was expecting %d)", db.numOpen, nconn)
1620 } else if len(db.freeConn) != nconn {
1621 t.Fatalf("unexpected len(db.freeConn) %d (was expecting %d)", len(db.freeConn), nconn)
1622 }
1623 for _, conn := range db.freeConn {
1624 conn.ci.(*fakeConn).stickyBad = true
1625 }
1626 return db
1627 }
1628
1629 // Query
1630 db := manyErrBadConnSetup()
1631 defer closeDB(t, db)
1632 rows, err := db.Query("SELECT|people|age,name|")
1633 if err != nil {
1634 t.Fatal(err)
1635 }
1636 if err = rows.Close(); err != nil {
1637 t.Fatal(err)
1638 }
1639
1640 // Exec
1641 db = manyErrBadConnSetup()
1642 defer closeDB(t, db)
1643 _, err = db.Exec("INSERT|people|name=Julia,age=19")
1644 if err != nil {
1645 t.Fatal(err)
1646 }
1647
1648 // Begin
1649 db = manyErrBadConnSetup()
1650 defer closeDB(t, db)
1651 tx, err := db.Begin()
1652 if err != nil {
1653 t.Fatal(err)
1654 }
1655 if err = tx.Rollback(); err != nil {
1656 t.Fatal(err)
1657 }
1658
1659 // Prepare
1660 db = manyErrBadConnSetup()
1661 defer closeDB(t, db)
1662 stmt, err := db.Prepare("SELECT|people|age,name|")
1663 if err != nil {
1664 t.Fatal(err)
1665 }
1666 if err = stmt.Close(); err != nil {
1667 t.Fatal(err)
1668 }
1669}
1670
Alex Brainman5dbe0712015-06-05 17:02:09 +10001671// golang.org/issue/5718
Julien Schmidt762a9d92013-12-17 11:57:30 -08001672func TestErrBadConnReconnect(t *testing.T) {
1673 db := newTestDB(t, "foo")
1674 defer closeDB(t, db)
1675 exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool")
1676
1677 simulateBadConn := func(name string, hook *func() bool, op func() error) {
1678 broken, retried := false, false
1679 numOpen := db.numOpen
1680
1681 // simulate a broken connection on the first try
1682 *hook = func() bool {
1683 if !broken {
1684 broken = true
1685 return true
1686 }
1687 retried = true
1688 return false
1689 }
1690
1691 if err := op(); err != nil {
1692 t.Errorf(name+": %v", err)
1693 return
1694 }
1695
1696 if !broken || !retried {
1697 t.Error(name + ": Failed to simulate broken connection")
1698 }
1699 *hook = nil
1700
1701 if numOpen != db.numOpen {
1702 t.Errorf(name+": leaked %d connection(s)!", db.numOpen-numOpen)
1703 numOpen = db.numOpen
1704 }
1705 }
1706
1707 // db.Exec
1708 dbExec := func() error {
1709 _, err := db.Exec("INSERT|t1|name=?,age=?,dead=?", "Gordon", 3, true)
1710 return err
1711 }
1712 simulateBadConn("db.Exec prepare", &hookPrepareBadConn, dbExec)
1713 simulateBadConn("db.Exec exec", &hookExecBadConn, dbExec)
1714
1715 // db.Query
1716 dbQuery := func() error {
1717 rows, err := db.Query("SELECT|t1|age,name|")
1718 if err == nil {
1719 err = rows.Close()
1720 }
1721 return err
1722 }
1723 simulateBadConn("db.Query prepare", &hookPrepareBadConn, dbQuery)
1724 simulateBadConn("db.Query query", &hookQueryBadConn, dbQuery)
1725
1726 // db.Prepare
1727 simulateBadConn("db.Prepare", &hookPrepareBadConn, func() error {
1728 stmt, err := db.Prepare("INSERT|t1|name=?,age=?,dead=?")
1729 if err != nil {
1730 return err
1731 }
1732 stmt.Close()
1733 return nil
1734 })
1735
Marko Tiikkaja90e2e2b2014-09-02 09:08:41 -07001736 // Provide a way to force a re-prepare of a statement on next execution
1737 forcePrepare := func(stmt *Stmt) {
1738 stmt.css = nil
1739 }
1740
Julien Schmidt762a9d92013-12-17 11:57:30 -08001741 // stmt.Exec
1742 stmt1, err := db.Prepare("INSERT|t1|name=?,age=?,dead=?")
1743 if err != nil {
1744 t.Fatalf("prepare: %v", err)
1745 }
1746 defer stmt1.Close()
1747 // make sure we must prepare the stmt first
Marko Tiikkaja90e2e2b2014-09-02 09:08:41 -07001748 forcePrepare(stmt1)
Julien Schmidt762a9d92013-12-17 11:57:30 -08001749
1750 stmtExec := func() error {
1751 _, err := stmt1.Exec("Gopher", 3, false)
1752 return err
1753 }
1754 simulateBadConn("stmt.Exec prepare", &hookPrepareBadConn, stmtExec)
1755 simulateBadConn("stmt.Exec exec", &hookExecBadConn, stmtExec)
1756
1757 // stmt.Query
1758 stmt2, err := db.Prepare("SELECT|t1|age,name|")
1759 if err != nil {
1760 t.Fatalf("prepare: %v", err)
1761 }
1762 defer stmt2.Close()
1763 // make sure we must prepare the stmt first
Marko Tiikkaja90e2e2b2014-09-02 09:08:41 -07001764 forcePrepare(stmt2)
Julien Schmidt762a9d92013-12-17 11:57:30 -08001765
1766 stmtQuery := func() error {
1767 rows, err := stmt2.Query()
1768 if err == nil {
1769 err = rows.Close()
1770 }
1771 return err
1772 }
1773 simulateBadConn("stmt.Query prepare", &hookPrepareBadConn, stmtQuery)
1774 simulateBadConn("stmt.Query exec", &hookQueryBadConn, stmtQuery)
1775}
1776
Chris Hinesd7376392015-08-24 21:48:39 -04001777// golang.org/issue/11264
1778func TestTxEndBadConn(t *testing.T) {
1779 db := newTestDB(t, "foo")
1780 defer closeDB(t, db)
1781 db.SetMaxIdleConns(0)
1782 exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool")
1783 db.SetMaxIdleConns(1)
1784
1785 simulateBadConn := func(name string, hook *func() bool, op func() error) {
1786 broken := false
1787 numOpen := db.numOpen
1788
1789 *hook = func() bool {
1790 if !broken {
1791 broken = true
1792 }
1793 return broken
1794 }
1795
1796 if err := op(); err != driver.ErrBadConn {
1797 t.Errorf(name+": %v", err)
1798 return
1799 }
1800
1801 if !broken {
1802 t.Error(name + ": Failed to simulate broken connection")
1803 }
1804 *hook = nil
1805
1806 if numOpen != db.numOpen {
1807 t.Errorf(name+": leaked %d connection(s)!", db.numOpen-numOpen)
1808 }
1809 }
1810
1811 // db.Exec
1812 dbExec := func(endTx func(tx *Tx) error) func() error {
1813 return func() error {
1814 tx, err := db.Begin()
1815 if err != nil {
1816 return err
1817 }
1818 _, err = tx.Exec("INSERT|t1|name=?,age=?,dead=?", "Gordon", 3, true)
1819 if err != nil {
1820 return err
1821 }
1822 return endTx(tx)
1823 }
1824 }
1825 simulateBadConn("db.Tx.Exec commit", &hookCommitBadConn, dbExec((*Tx).Commit))
1826 simulateBadConn("db.Tx.Exec rollback", &hookRollbackBadConn, dbExec((*Tx).Rollback))
1827
1828 // db.Query
1829 dbQuery := func(endTx func(tx *Tx) error) func() error {
1830 return func() error {
1831 tx, err := db.Begin()
1832 if err != nil {
1833 return err
1834 }
1835 rows, err := tx.Query("SELECT|t1|age,name|")
1836 if err == nil {
1837 err = rows.Close()
1838 } else {
1839 return err
1840 }
1841 return endTx(tx)
1842 }
1843 }
1844 simulateBadConn("db.Tx.Query commit", &hookCommitBadConn, dbQuery((*Tx).Commit))
1845 simulateBadConn("db.Tx.Query rollback", &hookRollbackBadConn, dbQuery((*Tx).Rollback))
1846}
1847
Tad Glines41c5d8d2013-08-30 09:27:33 -07001848type concurrentTest interface {
1849 init(t testing.TB, db *DB)
1850 finish(t testing.TB)
1851 test(t testing.TB) error
1852}
1853
1854type concurrentDBQueryTest struct {
1855 db *DB
1856}
1857
1858func (c *concurrentDBQueryTest) init(t testing.TB, db *DB) {
1859 c.db = db
1860}
1861
1862func (c *concurrentDBQueryTest) finish(t testing.TB) {
1863 c.db = nil
1864}
1865
1866func (c *concurrentDBQueryTest) test(t testing.TB) error {
1867 rows, err := c.db.Query("SELECT|people|name|")
1868 if err != nil {
1869 t.Error(err)
1870 return err
1871 }
1872 var name string
1873 for rows.Next() {
1874 rows.Scan(&name)
1875 }
1876 rows.Close()
1877 return nil
1878}
1879
1880type concurrentDBExecTest struct {
1881 db *DB
1882}
1883
1884func (c *concurrentDBExecTest) init(t testing.TB, db *DB) {
1885 c.db = db
1886}
1887
1888func (c *concurrentDBExecTest) finish(t testing.TB) {
1889 c.db = nil
1890}
1891
1892func (c *concurrentDBExecTest) test(t testing.TB) error {
1893 _, err := c.db.Exec("NOSERT|people|name=Chris,age=?,photo=CPHOTO,bdate=?", 3, chrisBirthday)
1894 if err != nil {
1895 t.Error(err)
1896 return err
1897 }
1898 return nil
1899}
1900
1901type concurrentStmtQueryTest struct {
1902 db *DB
1903 stmt *Stmt
1904}
1905
1906func (c *concurrentStmtQueryTest) init(t testing.TB, db *DB) {
1907 c.db = db
1908 var err error
1909 c.stmt, err = db.Prepare("SELECT|people|name|")
1910 if err != nil {
1911 t.Fatal(err)
1912 }
1913}
1914
1915func (c *concurrentStmtQueryTest) finish(t testing.TB) {
1916 if c.stmt != nil {
1917 c.stmt.Close()
1918 c.stmt = nil
1919 }
1920 c.db = nil
1921}
1922
1923func (c *concurrentStmtQueryTest) test(t testing.TB) error {
1924 rows, err := c.stmt.Query()
1925 if err != nil {
1926 t.Errorf("error on query: %v", err)
1927 return err
1928 }
1929
1930 var name string
1931 for rows.Next() {
1932 rows.Scan(&name)
1933 }
1934 rows.Close()
1935 return nil
1936}
1937
1938type concurrentStmtExecTest struct {
1939 db *DB
1940 stmt *Stmt
1941}
1942
1943func (c *concurrentStmtExecTest) init(t testing.TB, db *DB) {
1944 c.db = db
1945 var err error
1946 c.stmt, err = db.Prepare("NOSERT|people|name=Chris,age=?,photo=CPHOTO,bdate=?")
1947 if err != nil {
1948 t.Fatal(err)
1949 }
1950}
1951
1952func (c *concurrentStmtExecTest) finish(t testing.TB) {
1953 if c.stmt != nil {
1954 c.stmt.Close()
1955 c.stmt = nil
1956 }
1957 c.db = nil
1958}
1959
1960func (c *concurrentStmtExecTest) test(t testing.TB) error {
1961 _, err := c.stmt.Exec(3, chrisBirthday)
1962 if err != nil {
1963 t.Errorf("error on exec: %v", err)
1964 return err
1965 }
1966 return nil
1967}
1968
1969type concurrentTxQueryTest struct {
1970 db *DB
1971 tx *Tx
1972}
1973
1974func (c *concurrentTxQueryTest) init(t testing.TB, db *DB) {
1975 c.db = db
1976 var err error
1977 c.tx, err = c.db.Begin()
1978 if err != nil {
1979 t.Fatal(err)
1980 }
1981}
1982
1983func (c *concurrentTxQueryTest) finish(t testing.TB) {
1984 if c.tx != nil {
1985 c.tx.Rollback()
1986 c.tx = nil
1987 }
1988 c.db = nil
1989}
1990
1991func (c *concurrentTxQueryTest) test(t testing.TB) error {
1992 rows, err := c.db.Query("SELECT|people|name|")
1993 if err != nil {
1994 t.Error(err)
1995 return err
1996 }
1997 var name string
1998 for rows.Next() {
1999 rows.Scan(&name)
2000 }
2001 rows.Close()
2002 return nil
2003}
2004
2005type concurrentTxExecTest struct {
2006 db *DB
2007 tx *Tx
2008}
2009
2010func (c *concurrentTxExecTest) init(t testing.TB, db *DB) {
2011 c.db = db
2012 var err error
2013 c.tx, err = c.db.Begin()
2014 if err != nil {
2015 t.Fatal(err)
2016 }
2017}
2018
2019func (c *concurrentTxExecTest) finish(t testing.TB) {
2020 if c.tx != nil {
2021 c.tx.Rollback()
2022 c.tx = nil
2023 }
2024 c.db = nil
2025}
2026
2027func (c *concurrentTxExecTest) test(t testing.TB) error {
2028 _, err := c.tx.Exec("NOSERT|people|name=Chris,age=?,photo=CPHOTO,bdate=?", 3, chrisBirthday)
2029 if err != nil {
2030 t.Error(err)
2031 return err
2032 }
2033 return nil
2034}
2035
2036type concurrentTxStmtQueryTest struct {
2037 db *DB
2038 tx *Tx
2039 stmt *Stmt
2040}
2041
2042func (c *concurrentTxStmtQueryTest) init(t testing.TB, db *DB) {
2043 c.db = db
2044 var err error
2045 c.tx, err = c.db.Begin()
2046 if err != nil {
2047 t.Fatal(err)
2048 }
2049 c.stmt, err = c.tx.Prepare("SELECT|people|name|")
2050 if err != nil {
2051 t.Fatal(err)
2052 }
2053}
2054
2055func (c *concurrentTxStmtQueryTest) finish(t testing.TB) {
2056 if c.stmt != nil {
2057 c.stmt.Close()
2058 c.stmt = nil
2059 }
2060 if c.tx != nil {
2061 c.tx.Rollback()
2062 c.tx = nil
2063 }
2064 c.db = nil
2065}
2066
2067func (c *concurrentTxStmtQueryTest) test(t testing.TB) error {
2068 rows, err := c.stmt.Query()
2069 if err != nil {
2070 t.Errorf("error on query: %v", err)
2071 return err
2072 }
2073
2074 var name string
2075 for rows.Next() {
2076 rows.Scan(&name)
2077 }
2078 rows.Close()
2079 return nil
2080}
2081
2082type concurrentTxStmtExecTest struct {
2083 db *DB
2084 tx *Tx
2085 stmt *Stmt
2086}
2087
2088func (c *concurrentTxStmtExecTest) init(t testing.TB, db *DB) {
2089 c.db = db
2090 var err error
2091 c.tx, err = c.db.Begin()
2092 if err != nil {
2093 t.Fatal(err)
2094 }
2095 c.stmt, err = c.tx.Prepare("NOSERT|people|name=Chris,age=?,photo=CPHOTO,bdate=?")
2096 if err != nil {
2097 t.Fatal(err)
2098 }
2099}
2100
2101func (c *concurrentTxStmtExecTest) finish(t testing.TB) {
2102 if c.stmt != nil {
2103 c.stmt.Close()
2104 c.stmt = nil
2105 }
2106 if c.tx != nil {
2107 c.tx.Rollback()
2108 c.tx = nil
2109 }
2110 c.db = nil
2111}
2112
2113func (c *concurrentTxStmtExecTest) test(t testing.TB) error {
2114 _, err := c.stmt.Exec(3, chrisBirthday)
2115 if err != nil {
2116 t.Errorf("error on exec: %v", err)
2117 return err
2118 }
2119 return nil
2120}
2121
2122type concurrentRandomTest struct {
2123 tests []concurrentTest
2124}
2125
2126func (c *concurrentRandomTest) init(t testing.TB, db *DB) {
2127 c.tests = []concurrentTest{
2128 new(concurrentDBQueryTest),
2129 new(concurrentDBExecTest),
2130 new(concurrentStmtQueryTest),
2131 new(concurrentStmtExecTest),
2132 new(concurrentTxQueryTest),
2133 new(concurrentTxExecTest),
2134 new(concurrentTxStmtQueryTest),
2135 new(concurrentTxStmtExecTest),
2136 }
2137 for _, ct := range c.tests {
2138 ct.init(t, db)
2139 }
2140}
2141
2142func (c *concurrentRandomTest) finish(t testing.TB) {
2143 for _, ct := range c.tests {
2144 ct.finish(t)
2145 }
2146}
2147
2148func (c *concurrentRandomTest) test(t testing.TB) error {
2149 ct := c.tests[rand.Intn(len(c.tests))]
2150 return ct.test(t)
2151}
2152
2153func doConcurrentTest(t testing.TB, ct concurrentTest) {
2154 maxProcs, numReqs := 1, 500
2155 if testing.Short() {
2156 maxProcs, numReqs = 4, 50
2157 }
2158 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(maxProcs))
2159
2160 db := newTestDB(t, "people")
2161 defer closeDB(t, db)
2162
2163 ct.init(t, db)
2164 defer ct.finish(t)
2165
2166 var wg sync.WaitGroup
2167 wg.Add(numReqs)
2168
2169 reqs := make(chan bool)
2170 defer close(reqs)
2171
2172 for i := 0; i < maxProcs*2; i++ {
2173 go func() {
Robert Griesemer8a23c002014-07-16 16:29:51 -07002174 for range reqs {
Tad Glines41c5d8d2013-08-30 09:27:33 -07002175 err := ct.test(t)
2176 if err != nil {
2177 wg.Done()
2178 continue
2179 }
2180 wg.Done()
2181 }
2182 }()
2183 }
2184
2185 for i := 0; i < numReqs; i++ {
2186 reqs <- true
2187 }
2188
2189 wg.Wait()
2190}
2191
Brad Fitzpatrickca3ed9f2013-08-13 14:56:40 -07002192func TestIssue6081(t *testing.T) {
Brad Fitzpatrickca3ed9f2013-08-13 14:56:40 -07002193 db := newTestDB(t, "people")
2194 defer closeDB(t, db)
2195
2196 drv := db.driver.(*fakeDriver)
2197 drv.mu.Lock()
2198 opens0 := drv.openCount
2199 closes0 := drv.closeCount
2200 drv.mu.Unlock()
2201
2202 stmt, err := db.Prepare("SELECT|people|name|")
2203 if err != nil {
2204 t.Fatal(err)
2205 }
2206 rowsCloseHook = func(rows *Rows, err *error) {
2207 *err = driver.ErrBadConn
2208 }
2209 defer func() { rowsCloseHook = nil }()
2210 for i := 0; i < 10; i++ {
2211 rows, err := stmt.Query()
2212 if err != nil {
2213 t.Fatal(err)
2214 }
2215 rows.Close()
2216 }
2217 if n := len(stmt.css); n > 1 {
2218 t.Errorf("len(css slice) = %d; want <= 1", n)
2219 }
2220 stmt.Close()
2221 if n := len(stmt.css); n != 0 {
2222 t.Errorf("len(css slice) after Close = %d; want 0", n)
2223 }
2224
2225 drv.mu.Lock()
2226 opens := drv.openCount - opens0
2227 closes := drv.closeCount - closes0
2228 drv.mu.Unlock()
2229 if opens < 9 {
2230 t.Errorf("opens = %d; want >= 9", opens)
2231 }
2232 if closes < 9 {
2233 t.Errorf("closes = %d; want >= 9", closes)
2234 }
2235}
2236
James Tucker4f1ef562013-04-03 11:13:40 -07002237func TestConcurrency(t *testing.T) {
Tad Glines41c5d8d2013-08-30 09:27:33 -07002238 doConcurrentTest(t, new(concurrentDBQueryTest))
2239 doConcurrentTest(t, new(concurrentDBExecTest))
2240 doConcurrentTest(t, new(concurrentStmtQueryTest))
2241 doConcurrentTest(t, new(concurrentStmtExecTest))
2242 doConcurrentTest(t, new(concurrentTxQueryTest))
2243 doConcurrentTest(t, new(concurrentTxExecTest))
2244 doConcurrentTest(t, new(concurrentTxStmtQueryTest))
2245 doConcurrentTest(t, new(concurrentTxStmtExecTest))
2246 doConcurrentTest(t, new(concurrentRandomTest))
James Tucker4f1ef562013-04-03 11:13:40 -07002247}
2248
Alberto García Hierro37db8802013-10-16 09:22:57 -07002249func TestConnectionLeak(t *testing.T) {
2250 db := newTestDB(t, "people")
2251 defer closeDB(t, db)
2252 // Start by opening defaultMaxIdleConns
2253 rows := make([]*Rows, defaultMaxIdleConns)
2254 // We need to SetMaxOpenConns > MaxIdleConns, so the DB can open
2255 // a new connection and we can fill the idle queue with the released
2256 // connections.
2257 db.SetMaxOpenConns(len(rows) + 1)
2258 for ii := range rows {
2259 r, err := db.Query("SELECT|people|name|")
2260 if err != nil {
2261 t.Fatal(err)
2262 }
2263 r.Next()
2264 if err := r.Err(); err != nil {
2265 t.Fatal(err)
2266 }
2267 rows[ii] = r
2268 }
2269 // Now we have defaultMaxIdleConns busy connections. Open
2270 // a new one, but wait until the busy connections are released
2271 // before returning control to DB.
2272 drv := db.driver.(*fakeDriver)
2273 drv.waitCh = make(chan struct{}, 1)
2274 drv.waitingCh = make(chan struct{}, 1)
2275 var wg sync.WaitGroup
2276 wg.Add(1)
2277 go func() {
2278 r, err := db.Query("SELECT|people|name|")
2279 if err != nil {
2280 t.Fatal(err)
2281 }
2282 r.Close()
2283 wg.Done()
2284 }()
2285 // Wait until the goroutine we've just created has started waiting.
2286 <-drv.waitingCh
2287 // Now close the busy connections. This provides a connection for
2288 // the blocked goroutine and then fills up the idle queue.
2289 for _, v := range rows {
2290 v.Close()
2291 }
2292 // At this point we give the new connection to DB. This connection is
2293 // now useless, since the idle queue is full and there are no pending
2294 // requests. DB should deal with this situation without leaking the
2295 // connection.
2296 drv.waitCh <- struct{}{}
2297 wg.Wait()
2298}
2299
Tad Glines41c5d8d2013-08-30 09:27:33 -07002300func BenchmarkConcurrentDBExec(b *testing.B) {
James Tucker4f1ef562013-04-03 11:13:40 -07002301 b.ReportAllocs()
Tad Glines41c5d8d2013-08-30 09:27:33 -07002302 ct := new(concurrentDBExecTest)
James Tucker4f1ef562013-04-03 11:13:40 -07002303 for i := 0; i < b.N; i++ {
Tad Glines41c5d8d2013-08-30 09:27:33 -07002304 doConcurrentTest(b, ct)
2305 }
2306}
2307
2308func BenchmarkConcurrentStmtQuery(b *testing.B) {
2309 b.ReportAllocs()
2310 ct := new(concurrentStmtQueryTest)
2311 for i := 0; i < b.N; i++ {
2312 doConcurrentTest(b, ct)
2313 }
2314}
2315
2316func BenchmarkConcurrentStmtExec(b *testing.B) {
2317 b.ReportAllocs()
2318 ct := new(concurrentStmtExecTest)
2319 for i := 0; i < b.N; i++ {
2320 doConcurrentTest(b, ct)
2321 }
2322}
2323
2324func BenchmarkConcurrentTxQuery(b *testing.B) {
2325 b.ReportAllocs()
2326 ct := new(concurrentTxQueryTest)
2327 for i := 0; i < b.N; i++ {
2328 doConcurrentTest(b, ct)
2329 }
2330}
2331
2332func BenchmarkConcurrentTxExec(b *testing.B) {
2333 b.ReportAllocs()
2334 ct := new(concurrentTxExecTest)
2335 for i := 0; i < b.N; i++ {
2336 doConcurrentTest(b, ct)
2337 }
2338}
2339
2340func BenchmarkConcurrentTxStmtQuery(b *testing.B) {
2341 b.ReportAllocs()
2342 ct := new(concurrentTxStmtQueryTest)
2343 for i := 0; i < b.N; i++ {
2344 doConcurrentTest(b, ct)
2345 }
2346}
2347
2348func BenchmarkConcurrentTxStmtExec(b *testing.B) {
2349 b.ReportAllocs()
2350 ct := new(concurrentTxStmtExecTest)
2351 for i := 0; i < b.N; i++ {
2352 doConcurrentTest(b, ct)
2353 }
2354}
2355
2356func BenchmarkConcurrentRandom(b *testing.B) {
2357 b.ReportAllocs()
2358 ct := new(concurrentRandomTest)
2359 for i := 0; i < b.N; i++ {
2360 doConcurrentTest(b, ct)
James Tucker4f1ef562013-04-03 11:13:40 -07002361 }
2362}
INADA Naoki1b61a972015-01-23 20:02:37 +09002363
2364func BenchmarkManyConcurrentQueries(b *testing.B) {
2365 b.ReportAllocs()
2366 // To see lock contention in Go 1.4, 16~ cores and 128~ goroutines are required.
2367 const parallelism = 16
2368
2369 db := newTestDB(b, "magicquery")
2370 defer closeDB(b, db)
2371 db.SetMaxIdleConns(runtime.GOMAXPROCS(0) * parallelism)
2372
2373 stmt, err := db.Prepare("SELECT|magicquery|op|op=?,millis=?")
2374 if err != nil {
2375 b.Fatal(err)
2376 }
2377 defer stmt.Close()
2378
2379 b.SetParallelism(parallelism)
2380 b.RunParallel(func(pb *testing.PB) {
2381 for pb.Next() {
2382 rows, err := stmt.Query("sleep", 1)
2383 if err != nil {
2384 b.Error(err)
2385 return
2386 }
2387 rows.Close()
2388 }
2389 })
2390}