1// Go MySQL Driver - A MySQL-Driver for Go's database/sql package 2// 3// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. 4// 5// This Source Code Form is subject to the terms of the Mozilla Public 6// License, v. 2.0. If a copy of the MPL was not distributed with this file, 7// You can obtain one at http://mozilla.org/MPL/2.0/. 8 9package mysql 10 11import ( 12 "bytes" 13 "context" 14 "crypto/tls" 15 "database/sql" 16 "database/sql/driver" 17 "encoding/json" 18 "fmt" 19 "io" 20 "io/ioutil" 21 "log" 22 "math" 23 "net" 24 "net/url" 25 "os" 26 "reflect" 27 "runtime" 28 "strings" 29 "sync" 30 "sync/atomic" 31 "testing" 32 "time" 33) 34 35// Ensure that all the driver interfaces are implemented 36var ( 37 _ driver.Rows = &binaryRows{} 38 _ driver.Rows = &textRows{} 39) 40 41var ( 42 user string 43 pass string 44 prot string 45 addr string 46 dbname string 47 dsn string 48 netAddr string 49 available bool 50) 51 52var ( 53 tDate = time.Date(2012, 6, 14, 0, 0, 0, 0, time.UTC) 54 sDate = "2012-06-14" 55 tDateTime = time.Date(2011, 11, 20, 21, 27, 37, 0, time.UTC) 56 sDateTime = "2011-11-20 21:27:37" 57 tDate0 = time.Time{} 58 sDate0 = "0000-00-00" 59 sDateTime0 = "0000-00-00 00:00:00" 60) 61 62// See https://github.com/go-sql-driver/mysql/wiki/Testing 63func init() { 64 // get environment variables 65 env := func(key, defaultValue string) string { 66 if value := os.Getenv(key); value != "" { 67 return value 68 } 69 return defaultValue 70 } 71 user = env("MYSQL_TEST_USER", "root") 72 pass = env("MYSQL_TEST_PASS", "") 73 prot = env("MYSQL_TEST_PROT", "tcp") 74 addr = env("MYSQL_TEST_ADDR", "localhost:3306") 75 dbname = env("MYSQL_TEST_DBNAME", "gotest") 76 netAddr = fmt.Sprintf("%s(%s)", prot, addr) 77 dsn = fmt.Sprintf("%s:%s@%s/%s?timeout=30s", user, pass, netAddr, dbname) 78 c, err := net.Dial(prot, addr) 79 if err == nil { 80 available = true 81 c.Close() 82 } 83} 84 85type DBTest struct { 86 *testing.T 87 db *sql.DB 88} 89 90type netErrorMock struct { 91 temporary bool 92 timeout bool 93} 94 95func (e netErrorMock) Temporary() bool { 96 return e.temporary 97} 98 99func (e netErrorMock) Timeout() bool { 100 return e.timeout 101} 102 103func (e netErrorMock) Error() string { 104 return fmt.Sprintf("mock net error. Temporary: %v, Timeout %v", e.temporary, e.timeout) 105} 106 107func runTestsWithMultiStatement(t *testing.T, dsn string, tests ...func(dbt *DBTest)) { 108 if !available { 109 t.Skipf("MySQL server not running on %s", netAddr) 110 } 111 112 dsn += "&multiStatements=true" 113 var db *sql.DB 114 if _, err := ParseDSN(dsn); err != errInvalidDSNUnsafeCollation { 115 db, err = sql.Open("mysql", dsn) 116 if err != nil { 117 t.Fatalf("error connecting: %s", err.Error()) 118 } 119 defer db.Close() 120 } 121 122 dbt := &DBTest{t, db} 123 for _, test := range tests { 124 test(dbt) 125 dbt.db.Exec("DROP TABLE IF EXISTS test") 126 } 127} 128 129func runTests(t *testing.T, dsn string, tests ...func(dbt *DBTest)) { 130 if !available { 131 t.Skipf("MySQL server not running on %s", netAddr) 132 } 133 134 db, err := sql.Open("mysql", dsn) 135 if err != nil { 136 t.Fatalf("error connecting: %s", err.Error()) 137 } 138 defer db.Close() 139 140 db.Exec("DROP TABLE IF EXISTS test") 141 142 dsn2 := dsn + "&interpolateParams=true" 143 var db2 *sql.DB 144 if _, err := ParseDSN(dsn2); err != errInvalidDSNUnsafeCollation { 145 db2, err = sql.Open("mysql", dsn2) 146 if err != nil { 147 t.Fatalf("error connecting: %s", err.Error()) 148 } 149 defer db2.Close() 150 } 151 152 dsn3 := dsn + "&multiStatements=true" 153 var db3 *sql.DB 154 if _, err := ParseDSN(dsn3); err != errInvalidDSNUnsafeCollation { 155 db3, err = sql.Open("mysql", dsn3) 156 if err != nil { 157 t.Fatalf("error connecting: %s", err.Error()) 158 } 159 defer db3.Close() 160 } 161 162 dbt := &DBTest{t, db} 163 dbt2 := &DBTest{t, db2} 164 dbt3 := &DBTest{t, db3} 165 for _, test := range tests { 166 test(dbt) 167 dbt.db.Exec("DROP TABLE IF EXISTS test") 168 if db2 != nil { 169 test(dbt2) 170 dbt2.db.Exec("DROP TABLE IF EXISTS test") 171 } 172 if db3 != nil { 173 test(dbt3) 174 dbt3.db.Exec("DROP TABLE IF EXISTS test") 175 } 176 } 177} 178 179func (dbt *DBTest) fail(method, query string, err error) { 180 if len(query) > 300 { 181 query = "[query too large to print]" 182 } 183 dbt.Fatalf("error on %s %s: %s", method, query, err.Error()) 184} 185 186func (dbt *DBTest) mustExec(query string, args ...interface{}) (res sql.Result) { 187 res, err := dbt.db.Exec(query, args...) 188 if err != nil { 189 dbt.fail("exec", query, err) 190 } 191 return res 192} 193 194func (dbt *DBTest) mustQuery(query string, args ...interface{}) (rows *sql.Rows) { 195 rows, err := dbt.db.Query(query, args...) 196 if err != nil { 197 dbt.fail("query", query, err) 198 } 199 return rows 200} 201 202func maybeSkip(t *testing.T, err error, skipErrno uint16) { 203 mySQLErr, ok := err.(*MySQLError) 204 if !ok { 205 return 206 } 207 208 if mySQLErr.Number == skipErrno { 209 t.Skipf("skipping test for error: %v", err) 210 } 211} 212 213func TestEmptyQuery(t *testing.T) { 214 runTests(t, dsn, func(dbt *DBTest) { 215 // just a comment, no query 216 rows := dbt.mustQuery("--") 217 defer rows.Close() 218 // will hang before #255 219 if rows.Next() { 220 dbt.Errorf("next on rows must be false") 221 } 222 }) 223} 224 225func TestCRUD(t *testing.T) { 226 runTests(t, dsn, func(dbt *DBTest) { 227 // Create Table 228 dbt.mustExec("CREATE TABLE test (value BOOL)") 229 230 // Test for unexpected data 231 var out bool 232 rows := dbt.mustQuery("SELECT * FROM test") 233 if rows.Next() { 234 dbt.Error("unexpected data in empty table") 235 } 236 rows.Close() 237 238 // Create Data 239 res := dbt.mustExec("INSERT INTO test VALUES (1)") 240 count, err := res.RowsAffected() 241 if err != nil { 242 dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error()) 243 } 244 if count != 1 { 245 dbt.Fatalf("expected 1 affected row, got %d", count) 246 } 247 248 id, err := res.LastInsertId() 249 if err != nil { 250 dbt.Fatalf("res.LastInsertId() returned error: %s", err.Error()) 251 } 252 if id != 0 { 253 dbt.Fatalf("expected InsertId 0, got %d", id) 254 } 255 256 // Read 257 rows = dbt.mustQuery("SELECT value FROM test") 258 if rows.Next() { 259 rows.Scan(&out) 260 if true != out { 261 dbt.Errorf("true != %t", out) 262 } 263 264 if rows.Next() { 265 dbt.Error("unexpected data") 266 } 267 } else { 268 dbt.Error("no data") 269 } 270 rows.Close() 271 272 // Update 273 res = dbt.mustExec("UPDATE test SET value = ? WHERE value = ?", false, true) 274 count, err = res.RowsAffected() 275 if err != nil { 276 dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error()) 277 } 278 if count != 1 { 279 dbt.Fatalf("expected 1 affected row, got %d", count) 280 } 281 282 // Check Update 283 rows = dbt.mustQuery("SELECT value FROM test") 284 if rows.Next() { 285 rows.Scan(&out) 286 if false != out { 287 dbt.Errorf("false != %t", out) 288 } 289 290 if rows.Next() { 291 dbt.Error("unexpected data") 292 } 293 } else { 294 dbt.Error("no data") 295 } 296 rows.Close() 297 298 // Delete 299 res = dbt.mustExec("DELETE FROM test WHERE value = ?", false) 300 count, err = res.RowsAffected() 301 if err != nil { 302 dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error()) 303 } 304 if count != 1 { 305 dbt.Fatalf("expected 1 affected row, got %d", count) 306 } 307 308 // Check for unexpected rows 309 res = dbt.mustExec("DELETE FROM test") 310 count, err = res.RowsAffected() 311 if err != nil { 312 dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error()) 313 } 314 if count != 0 { 315 dbt.Fatalf("expected 0 affected row, got %d", count) 316 } 317 }) 318} 319 320func TestMultiQuery(t *testing.T) { 321 runTestsWithMultiStatement(t, dsn, func(dbt *DBTest) { 322 // Create Table 323 dbt.mustExec("CREATE TABLE `test` (`id` int(11) NOT NULL, `value` int(11) NOT NULL) ") 324 325 // Create Data 326 res := dbt.mustExec("INSERT INTO test VALUES (1, 1)") 327 count, err := res.RowsAffected() 328 if err != nil { 329 dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error()) 330 } 331 if count != 1 { 332 dbt.Fatalf("expected 1 affected row, got %d", count) 333 } 334 335 // Update 336 res = dbt.mustExec("UPDATE test SET value = 3 WHERE id = 1; UPDATE test SET value = 4 WHERE id = 1; UPDATE test SET value = 5 WHERE id = 1;") 337 count, err = res.RowsAffected() 338 if err != nil { 339 dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error()) 340 } 341 if count != 1 { 342 dbt.Fatalf("expected 1 affected row, got %d", count) 343 } 344 345 // Read 346 var out int 347 rows := dbt.mustQuery("SELECT value FROM test WHERE id=1;") 348 if rows.Next() { 349 rows.Scan(&out) 350 if 5 != out { 351 dbt.Errorf("5 != %d", out) 352 } 353 354 if rows.Next() { 355 dbt.Error("unexpected data") 356 } 357 } else { 358 dbt.Error("no data") 359 } 360 rows.Close() 361 362 }) 363} 364 365func TestInt(t *testing.T) { 366 runTests(t, dsn, func(dbt *DBTest) { 367 types := [5]string{"TINYINT", "SMALLINT", "MEDIUMINT", "INT", "BIGINT"} 368 in := int64(42) 369 var out int64 370 var rows *sql.Rows 371 372 // SIGNED 373 for _, v := range types { 374 dbt.mustExec("CREATE TABLE test (value " + v + ")") 375 376 dbt.mustExec("INSERT INTO test VALUES (?)", in) 377 378 rows = dbt.mustQuery("SELECT value FROM test") 379 if rows.Next() { 380 rows.Scan(&out) 381 if in != out { 382 dbt.Errorf("%s: %d != %d", v, in, out) 383 } 384 } else { 385 dbt.Errorf("%s: no data", v) 386 } 387 rows.Close() 388 389 dbt.mustExec("DROP TABLE IF EXISTS test") 390 } 391 392 // UNSIGNED ZEROFILL 393 for _, v := range types { 394 dbt.mustExec("CREATE TABLE test (value " + v + " ZEROFILL)") 395 396 dbt.mustExec("INSERT INTO test VALUES (?)", in) 397 398 rows = dbt.mustQuery("SELECT value FROM test") 399 if rows.Next() { 400 rows.Scan(&out) 401 if in != out { 402 dbt.Errorf("%s ZEROFILL: %d != %d", v, in, out) 403 } 404 } else { 405 dbt.Errorf("%s ZEROFILL: no data", v) 406 } 407 rows.Close() 408 409 dbt.mustExec("DROP TABLE IF EXISTS test") 410 } 411 }) 412} 413 414func TestFloat32(t *testing.T) { 415 runTests(t, dsn, func(dbt *DBTest) { 416 types := [2]string{"FLOAT", "DOUBLE"} 417 in := float32(42.23) 418 var out float32 419 var rows *sql.Rows 420 for _, v := range types { 421 dbt.mustExec("CREATE TABLE test (value " + v + ")") 422 dbt.mustExec("INSERT INTO test VALUES (?)", in) 423 rows = dbt.mustQuery("SELECT value FROM test") 424 if rows.Next() { 425 rows.Scan(&out) 426 if in != out { 427 dbt.Errorf("%s: %g != %g", v, in, out) 428 } 429 } else { 430 dbt.Errorf("%s: no data", v) 431 } 432 rows.Close() 433 dbt.mustExec("DROP TABLE IF EXISTS test") 434 } 435 }) 436} 437 438func TestFloat64(t *testing.T) { 439 runTests(t, dsn, func(dbt *DBTest) { 440 types := [2]string{"FLOAT", "DOUBLE"} 441 var expected float64 = 42.23 442 var out float64 443 var rows *sql.Rows 444 for _, v := range types { 445 dbt.mustExec("CREATE TABLE test (value " + v + ")") 446 dbt.mustExec("INSERT INTO test VALUES (42.23)") 447 rows = dbt.mustQuery("SELECT value FROM test") 448 if rows.Next() { 449 rows.Scan(&out) 450 if expected != out { 451 dbt.Errorf("%s: %g != %g", v, expected, out) 452 } 453 } else { 454 dbt.Errorf("%s: no data", v) 455 } 456 rows.Close() 457 dbt.mustExec("DROP TABLE IF EXISTS test") 458 } 459 }) 460} 461 462func TestFloat64Placeholder(t *testing.T) { 463 runTests(t, dsn, func(dbt *DBTest) { 464 types := [2]string{"FLOAT", "DOUBLE"} 465 var expected float64 = 42.23 466 var out float64 467 var rows *sql.Rows 468 for _, v := range types { 469 dbt.mustExec("CREATE TABLE test (id int, value " + v + ")") 470 dbt.mustExec("INSERT INTO test VALUES (1, 42.23)") 471 rows = dbt.mustQuery("SELECT value FROM test WHERE id = ?", 1) 472 if rows.Next() { 473 rows.Scan(&out) 474 if expected != out { 475 dbt.Errorf("%s: %g != %g", v, expected, out) 476 } 477 } else { 478 dbt.Errorf("%s: no data", v) 479 } 480 rows.Close() 481 dbt.mustExec("DROP TABLE IF EXISTS test") 482 } 483 }) 484} 485 486func TestString(t *testing.T) { 487 runTests(t, dsn, func(dbt *DBTest) { 488 types := [6]string{"CHAR(255)", "VARCHAR(255)", "TINYTEXT", "TEXT", "MEDIUMTEXT", "LONGTEXT"} 489 in := "κόσμε üöäßñóùéàâÿœ'îë Árvíztűrő いろはにほへとちりぬるを イロハニホヘト דג סקרן чащах น่าฟังเอย" 490 var out string 491 var rows *sql.Rows 492 493 for _, v := range types { 494 dbt.mustExec("CREATE TABLE test (value " + v + ") CHARACTER SET utf8") 495 496 dbt.mustExec("INSERT INTO test VALUES (?)", in) 497 498 rows = dbt.mustQuery("SELECT value FROM test") 499 if rows.Next() { 500 rows.Scan(&out) 501 if in != out { 502 dbt.Errorf("%s: %s != %s", v, in, out) 503 } 504 } else { 505 dbt.Errorf("%s: no data", v) 506 } 507 rows.Close() 508 509 dbt.mustExec("DROP TABLE IF EXISTS test") 510 } 511 512 // BLOB 513 dbt.mustExec("CREATE TABLE test (id int, value BLOB) CHARACTER SET utf8") 514 515 id := 2 516 in = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, " + 517 "sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, " + 518 "sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. " + 519 "Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. " + 520 "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, " + 521 "sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, " + 522 "sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. " + 523 "Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet." 524 dbt.mustExec("INSERT INTO test VALUES (?, ?)", id, in) 525 526 err := dbt.db.QueryRow("SELECT value FROM test WHERE id = ?", id).Scan(&out) 527 if err != nil { 528 dbt.Fatalf("Error on BLOB-Query: %s", err.Error()) 529 } else if out != in { 530 dbt.Errorf("BLOB: %s != %s", in, out) 531 } 532 }) 533} 534 535func TestRawBytes(t *testing.T) { 536 runTests(t, dsn, func(dbt *DBTest) { 537 v1 := []byte("aaa") 538 v2 := []byte("bbb") 539 rows := dbt.mustQuery("SELECT ?, ?", v1, v2) 540 defer rows.Close() 541 if rows.Next() { 542 var o1, o2 sql.RawBytes 543 if err := rows.Scan(&o1, &o2); err != nil { 544 dbt.Errorf("Got error: %v", err) 545 } 546 if !bytes.Equal(v1, o1) { 547 dbt.Errorf("expected %v, got %v", v1, o1) 548 } 549 if !bytes.Equal(v2, o2) { 550 dbt.Errorf("expected %v, got %v", v2, o2) 551 } 552 // https://github.com/go-sql-driver/mysql/issues/765 553 // Appending to RawBytes shouldn't overwrite next RawBytes. 554 o1 = append(o1, "xyzzy"...) 555 if !bytes.Equal(v2, o2) { 556 dbt.Errorf("expected %v, got %v", v2, o2) 557 } 558 } else { 559 dbt.Errorf("no data") 560 } 561 }) 562} 563 564func TestRawMessage(t *testing.T) { 565 runTests(t, dsn, func(dbt *DBTest) { 566 v1 := json.RawMessage("{}") 567 v2 := json.RawMessage("[]") 568 rows := dbt.mustQuery("SELECT ?, ?", v1, v2) 569 defer rows.Close() 570 if rows.Next() { 571 var o1, o2 json.RawMessage 572 if err := rows.Scan(&o1, &o2); err != nil { 573 dbt.Errorf("Got error: %v", err) 574 } 575 if !bytes.Equal(v1, o1) { 576 dbt.Errorf("expected %v, got %v", v1, o1) 577 } 578 if !bytes.Equal(v2, o2) { 579 dbt.Errorf("expected %v, got %v", v2, o2) 580 } 581 } else { 582 dbt.Errorf("no data") 583 } 584 }) 585} 586 587type testValuer struct { 588 value string 589} 590 591func (tv testValuer) Value() (driver.Value, error) { 592 return tv.value, nil 593} 594 595func TestValuer(t *testing.T) { 596 runTests(t, dsn, func(dbt *DBTest) { 597 in := testValuer{"a_value"} 598 var out string 599 var rows *sql.Rows 600 601 dbt.mustExec("CREATE TABLE test (value VARCHAR(255)) CHARACTER SET utf8") 602 dbt.mustExec("INSERT INTO test VALUES (?)", in) 603 rows = dbt.mustQuery("SELECT value FROM test") 604 if rows.Next() { 605 rows.Scan(&out) 606 if in.value != out { 607 dbt.Errorf("Valuer: %v != %s", in, out) 608 } 609 } else { 610 dbt.Errorf("Valuer: no data") 611 } 612 rows.Close() 613 614 dbt.mustExec("DROP TABLE IF EXISTS test") 615 }) 616} 617 618type testValuerWithValidation struct { 619 value string 620} 621 622func (tv testValuerWithValidation) Value() (driver.Value, error) { 623 if len(tv.value) == 0 { 624 return nil, fmt.Errorf("Invalid string valuer. Value must not be empty") 625 } 626 627 return tv.value, nil 628} 629 630func TestValuerWithValidation(t *testing.T) { 631 runTests(t, dsn, func(dbt *DBTest) { 632 in := testValuerWithValidation{"a_value"} 633 var out string 634 var rows *sql.Rows 635 636 dbt.mustExec("CREATE TABLE testValuer (value VARCHAR(255)) CHARACTER SET utf8") 637 dbt.mustExec("INSERT INTO testValuer VALUES (?)", in) 638 639 rows = dbt.mustQuery("SELECT value FROM testValuer") 640 defer rows.Close() 641 642 if rows.Next() { 643 rows.Scan(&out) 644 if in.value != out { 645 dbt.Errorf("Valuer: %v != %s", in, out) 646 } 647 } else { 648 dbt.Errorf("Valuer: no data") 649 } 650 651 if _, err := dbt.db.Exec("INSERT INTO testValuer VALUES (?)", testValuerWithValidation{""}); err == nil { 652 dbt.Errorf("Failed to check valuer error") 653 } 654 655 if _, err := dbt.db.Exec("INSERT INTO testValuer VALUES (?)", nil); err != nil { 656 dbt.Errorf("Failed to check nil") 657 } 658 659 if _, err := dbt.db.Exec("INSERT INTO testValuer VALUES (?)", map[string]bool{}); err == nil { 660 dbt.Errorf("Failed to check not valuer") 661 } 662 663 dbt.mustExec("DROP TABLE IF EXISTS testValuer") 664 }) 665} 666 667type timeTests struct { 668 dbtype string 669 tlayout string 670 tests []timeTest 671} 672 673type timeTest struct { 674 s string // leading "!": do not use t as value in queries 675 t time.Time 676} 677 678type timeMode byte 679 680func (t timeMode) String() string { 681 switch t { 682 case binaryString: 683 return "binary:string" 684 case binaryTime: 685 return "binary:time.Time" 686 case textString: 687 return "text:string" 688 } 689 panic("unsupported timeMode") 690} 691 692func (t timeMode) Binary() bool { 693 switch t { 694 case binaryString, binaryTime: 695 return true 696 } 697 return false 698} 699 700const ( 701 binaryString timeMode = iota 702 binaryTime 703 textString 704) 705 706func (t timeTest) genQuery(dbtype string, mode timeMode) string { 707 var inner string 708 if mode.Binary() { 709 inner = "?" 710 } else { 711 inner = `"%s"` 712 } 713 return `SELECT cast(` + inner + ` as ` + dbtype + `)` 714} 715 716func (t timeTest) run(dbt *DBTest, dbtype, tlayout string, mode timeMode) { 717 var rows *sql.Rows 718 query := t.genQuery(dbtype, mode) 719 switch mode { 720 case binaryString: 721 rows = dbt.mustQuery(query, t.s) 722 case binaryTime: 723 rows = dbt.mustQuery(query, t.t) 724 case textString: 725 query = fmt.Sprintf(query, t.s) 726 rows = dbt.mustQuery(query) 727 default: 728 panic("unsupported mode") 729 } 730 defer rows.Close() 731 var err error 732 if !rows.Next() { 733 err = rows.Err() 734 if err == nil { 735 err = fmt.Errorf("no data") 736 } 737 dbt.Errorf("%s [%s]: %s", dbtype, mode, err) 738 return 739 } 740 var dst interface{} 741 err = rows.Scan(&dst) 742 if err != nil { 743 dbt.Errorf("%s [%s]: %s", dbtype, mode, err) 744 return 745 } 746 switch val := dst.(type) { 747 case []uint8: 748 str := string(val) 749 if str == t.s { 750 return 751 } 752 if mode.Binary() && dbtype == "DATETIME" && len(str) == 26 && str[:19] == t.s { 753 // a fix mainly for TravisCI: 754 // accept full microsecond resolution in result for DATETIME columns 755 // where the binary protocol was used 756 return 757 } 758 dbt.Errorf("%s [%s] to string: expected %q, got %q", 759 dbtype, mode, 760 t.s, str, 761 ) 762 case time.Time: 763 if val == t.t { 764 return 765 } 766 dbt.Errorf("%s [%s] to string: expected %q, got %q", 767 dbtype, mode, 768 t.s, val.Format(tlayout), 769 ) 770 default: 771 fmt.Printf("%#v\n", []interface{}{dbtype, tlayout, mode, t.s, t.t}) 772 dbt.Errorf("%s [%s]: unhandled type %T (is '%v')", 773 dbtype, mode, 774 val, val, 775 ) 776 } 777} 778 779func TestDateTime(t *testing.T) { 780 afterTime := func(t time.Time, d string) time.Time { 781 dur, err := time.ParseDuration(d) 782 if err != nil { 783 panic(err) 784 } 785 return t.Add(dur) 786 } 787 // NOTE: MySQL rounds DATETIME(x) up - but that's not included in the tests 788 format := "2006-01-02 15:04:05.999999" 789 t0 := time.Time{} 790 tstr0 := "0000-00-00 00:00:00.000000" 791 testcases := []timeTests{ 792 {"DATE", format[:10], []timeTest{ 793 {t: time.Date(2011, 11, 20, 0, 0, 0, 0, time.UTC)}, 794 {t: t0, s: tstr0[:10]}, 795 }}, 796 {"DATETIME", format[:19], []timeTest{ 797 {t: time.Date(2011, 11, 20, 21, 27, 37, 0, time.UTC)}, 798 {t: t0, s: tstr0[:19]}, 799 }}, 800 {"DATETIME(0)", format[:21], []timeTest{ 801 {t: time.Date(2011, 11, 20, 21, 27, 37, 0, time.UTC)}, 802 {t: t0, s: tstr0[:19]}, 803 }}, 804 {"DATETIME(1)", format[:21], []timeTest{ 805 {t: time.Date(2011, 11, 20, 21, 27, 37, 100000000, time.UTC)}, 806 {t: t0, s: tstr0[:21]}, 807 }}, 808 {"DATETIME(6)", format, []timeTest{ 809 {t: time.Date(2011, 11, 20, 21, 27, 37, 123456000, time.UTC)}, 810 {t: t0, s: tstr0}, 811 }}, 812 {"TIME", format[11:19], []timeTest{ 813 {t: afterTime(t0, "12345s")}, 814 {s: "!-12:34:56"}, 815 {s: "!-838:59:59"}, 816 {s: "!838:59:59"}, 817 {t: t0, s: tstr0[11:19]}, 818 }}, 819 {"TIME(0)", format[11:19], []timeTest{ 820 {t: afterTime(t0, "12345s")}, 821 {s: "!-12:34:56"}, 822 {s: "!-838:59:59"}, 823 {s: "!838:59:59"}, 824 {t: t0, s: tstr0[11:19]}, 825 }}, 826 {"TIME(1)", format[11:21], []timeTest{ 827 {t: afterTime(t0, "12345600ms")}, 828 {s: "!-12:34:56.7"}, 829 {s: "!-838:59:58.9"}, 830 {s: "!838:59:58.9"}, 831 {t: t0, s: tstr0[11:21]}, 832 }}, 833 {"TIME(6)", format[11:], []timeTest{ 834 {t: afterTime(t0, "1234567890123000ns")}, 835 {s: "!-12:34:56.789012"}, 836 {s: "!-838:59:58.999999"}, 837 {s: "!838:59:58.999999"}, 838 {t: t0, s: tstr0[11:]}, 839 }}, 840 } 841 dsns := []string{ 842 dsn + "&parseTime=true", 843 dsn + "&parseTime=false", 844 } 845 for _, testdsn := range dsns { 846 runTests(t, testdsn, func(dbt *DBTest) { 847 microsecsSupported := false 848 zeroDateSupported := false 849 var rows *sql.Rows 850 var err error 851 rows, err = dbt.db.Query(`SELECT cast("00:00:00.1" as TIME(1)) = "00:00:00.1"`) 852 if err == nil { 853 rows.Scan(µsecsSupported) 854 rows.Close() 855 } 856 rows, err = dbt.db.Query(`SELECT cast("0000-00-00" as DATE) = "0000-00-00"`) 857 if err == nil { 858 rows.Scan(&zeroDateSupported) 859 rows.Close() 860 } 861 for _, setups := range testcases { 862 if t := setups.dbtype; !microsecsSupported && t[len(t)-1:] == ")" { 863 // skip fractional second tests if unsupported by server 864 continue 865 } 866 for _, setup := range setups.tests { 867 allowBinTime := true 868 if setup.s == "" { 869 // fill time string wherever Go can reliable produce it 870 setup.s = setup.t.Format(setups.tlayout) 871 } else if setup.s[0] == '!' { 872 // skip tests using setup.t as source in queries 873 allowBinTime = false 874 // fix setup.s - remove the "!" 875 setup.s = setup.s[1:] 876 } 877 if !zeroDateSupported && setup.s == tstr0[:len(setup.s)] { 878 // skip disallowed 0000-00-00 date 879 continue 880 } 881 setup.run(dbt, setups.dbtype, setups.tlayout, textString) 882 setup.run(dbt, setups.dbtype, setups.tlayout, binaryString) 883 if allowBinTime { 884 setup.run(dbt, setups.dbtype, setups.tlayout, binaryTime) 885 } 886 } 887 } 888 }) 889 } 890} 891 892func TestTimestampMicros(t *testing.T) { 893 format := "2006-01-02 15:04:05.999999" 894 f0 := format[:19] 895 f1 := format[:21] 896 f6 := format[:26] 897 runTests(t, dsn, func(dbt *DBTest) { 898 // check if microseconds are supported. 899 // Do not use timestamp(x) for that check - before 5.5.6, x would mean display width 900 // and not precision. 901 // Se last paragraph at http://dev.mysql.com/doc/refman/5.6/en/fractional-seconds.html 902 microsecsSupported := false 903 if rows, err := dbt.db.Query(`SELECT cast("00:00:00.1" as TIME(1)) = "00:00:00.1"`); err == nil { 904 rows.Scan(µsecsSupported) 905 rows.Close() 906 } 907 if !microsecsSupported { 908 // skip test 909 return 910 } 911 _, err := dbt.db.Exec(` 912 CREATE TABLE test ( 913 value0 TIMESTAMP NOT NULL DEFAULT '` + f0 + `', 914 value1 TIMESTAMP(1) NOT NULL DEFAULT '` + f1 + `', 915 value6 TIMESTAMP(6) NOT NULL DEFAULT '` + f6 + `' 916 )`, 917 ) 918 if err != nil { 919 dbt.Error(err) 920 } 921 defer dbt.mustExec("DROP TABLE IF EXISTS test") 922 dbt.mustExec("INSERT INTO test SET value0=?, value1=?, value6=?", f0, f1, f6) 923 var res0, res1, res6 string 924 rows := dbt.mustQuery("SELECT * FROM test") 925 defer rows.Close() 926 if !rows.Next() { 927 dbt.Errorf("test contained no selectable values") 928 } 929 err = rows.Scan(&res0, &res1, &res6) 930 if err != nil { 931 dbt.Error(err) 932 } 933 if res0 != f0 { 934 dbt.Errorf("expected %q, got %q", f0, res0) 935 } 936 if res1 != f1 { 937 dbt.Errorf("expected %q, got %q", f1, res1) 938 } 939 if res6 != f6 { 940 dbt.Errorf("expected %q, got %q", f6, res6) 941 } 942 }) 943} 944 945func TestNULL(t *testing.T) { 946 runTests(t, dsn, func(dbt *DBTest) { 947 nullStmt, err := dbt.db.Prepare("SELECT NULL") 948 if err != nil { 949 dbt.Fatal(err) 950 } 951 defer nullStmt.Close() 952 953 nonNullStmt, err := dbt.db.Prepare("SELECT 1") 954 if err != nil { 955 dbt.Fatal(err) 956 } 957 defer nonNullStmt.Close() 958 959 // NullBool 960 var nb sql.NullBool 961 // Invalid 962 if err = nullStmt.QueryRow().Scan(&nb); err != nil { 963 dbt.Fatal(err) 964 } 965 if nb.Valid { 966 dbt.Error("valid NullBool which should be invalid") 967 } 968 // Valid 969 if err = nonNullStmt.QueryRow().Scan(&nb); err != nil { 970 dbt.Fatal(err) 971 } 972 if !nb.Valid { 973 dbt.Error("invalid NullBool which should be valid") 974 } else if nb.Bool != true { 975 dbt.Errorf("Unexpected NullBool value: %t (should be true)", nb.Bool) 976 } 977 978 // NullFloat64 979 var nf sql.NullFloat64 980 // Invalid 981 if err = nullStmt.QueryRow().Scan(&nf); err != nil { 982 dbt.Fatal(err) 983 } 984 if nf.Valid { 985 dbt.Error("valid NullFloat64 which should be invalid") 986 } 987 // Valid 988 if err = nonNullStmt.QueryRow().Scan(&nf); err != nil { 989 dbt.Fatal(err) 990 } 991 if !nf.Valid { 992 dbt.Error("invalid NullFloat64 which should be valid") 993 } else if nf.Float64 != float64(1) { 994 dbt.Errorf("unexpected NullFloat64 value: %f (should be 1.0)", nf.Float64) 995 } 996 997 // NullInt64 998 var ni sql.NullInt64 999 // Invalid 1000 if err = nullStmt.QueryRow().Scan(&ni); err != nil { 1001 dbt.Fatal(err) 1002 } 1003 if ni.Valid { 1004 dbt.Error("valid NullInt64 which should be invalid") 1005 } 1006 // Valid 1007 if err = nonNullStmt.QueryRow().Scan(&ni); err != nil { 1008 dbt.Fatal(err) 1009 } 1010 if !ni.Valid { 1011 dbt.Error("invalid NullInt64 which should be valid") 1012 } else if ni.Int64 != int64(1) { 1013 dbt.Errorf("unexpected NullInt64 value: %d (should be 1)", ni.Int64) 1014 } 1015 1016 // NullString 1017 var ns sql.NullString 1018 // Invalid 1019 if err = nullStmt.QueryRow().Scan(&ns); err != nil { 1020 dbt.Fatal(err) 1021 } 1022 if ns.Valid { 1023 dbt.Error("valid NullString which should be invalid") 1024 } 1025 // Valid 1026 if err = nonNullStmt.QueryRow().Scan(&ns); err != nil { 1027 dbt.Fatal(err) 1028 } 1029 if !ns.Valid { 1030 dbt.Error("invalid NullString which should be valid") 1031 } else if ns.String != `1` { 1032 dbt.Error("unexpected NullString value:" + ns.String + " (should be `1`)") 1033 } 1034 1035 // nil-bytes 1036 var b []byte 1037 // Read nil 1038 if err = nullStmt.QueryRow().Scan(&b); err != nil { 1039 dbt.Fatal(err) 1040 } 1041 if b != nil { 1042 dbt.Error("non-nil []byte which should be nil") 1043 } 1044 // Read non-nil 1045 if err = nonNullStmt.QueryRow().Scan(&b); err != nil { 1046 dbt.Fatal(err) 1047 } 1048 if b == nil { 1049 dbt.Error("nil []byte which should be non-nil") 1050 } 1051 // Insert nil 1052 b = nil 1053 success := false 1054 if err = dbt.db.QueryRow("SELECT ? IS NULL", b).Scan(&success); err != nil { 1055 dbt.Fatal(err) 1056 } 1057 if !success { 1058 dbt.Error("inserting []byte(nil) as NULL failed") 1059 } 1060 // Check input==output with input==nil 1061 b = nil 1062 if err = dbt.db.QueryRow("SELECT ?", b).Scan(&b); err != nil { 1063 dbt.Fatal(err) 1064 } 1065 if b != nil { 1066 dbt.Error("non-nil echo from nil input") 1067 } 1068 // Check input==output with input!=nil 1069 b = []byte("") 1070 if err = dbt.db.QueryRow("SELECT ?", b).Scan(&b); err != nil { 1071 dbt.Fatal(err) 1072 } 1073 if b == nil { 1074 dbt.Error("nil echo from non-nil input") 1075 } 1076 1077 // Insert NULL 1078 dbt.mustExec("CREATE TABLE test (dummmy1 int, value int, dummy2 int)") 1079 1080 dbt.mustExec("INSERT INTO test VALUES (?, ?, ?)", 1, nil, 2) 1081 1082 var out interface{} 1083 rows := dbt.mustQuery("SELECT * FROM test") 1084 defer rows.Close() 1085 if rows.Next() { 1086 rows.Scan(&out) 1087 if out != nil { 1088 dbt.Errorf("%v != nil", out) 1089 } 1090 } else { 1091 dbt.Error("no data") 1092 } 1093 }) 1094} 1095 1096func TestUint64(t *testing.T) { 1097 const ( 1098 u0 = uint64(0) 1099 uall = ^u0 1100 uhigh = uall >> 1 1101 utop = ^uhigh 1102 s0 = int64(0) 1103 sall = ^s0 1104 shigh = int64(uhigh) 1105 stop = ^shigh 1106 ) 1107 runTests(t, dsn, func(dbt *DBTest) { 1108 stmt, err := dbt.db.Prepare(`SELECT ?, ?, ? ,?, ?, ?, ?, ?`) 1109 if err != nil { 1110 dbt.Fatal(err) 1111 } 1112 defer stmt.Close() 1113 row := stmt.QueryRow( 1114 u0, uhigh, utop, uall, 1115 s0, shigh, stop, sall, 1116 ) 1117 1118 var ua, ub, uc, ud uint64 1119 var sa, sb, sc, sd int64 1120 1121 err = row.Scan(&ua, &ub, &uc, &ud, &sa, &sb, &sc, &sd) 1122 if err != nil { 1123 dbt.Fatal(err) 1124 } 1125 switch { 1126 case ua != u0, 1127 ub != uhigh, 1128 uc != utop, 1129 ud != uall, 1130 sa != s0, 1131 sb != shigh, 1132 sc != stop, 1133 sd != sall: 1134 dbt.Fatal("unexpected result value") 1135 } 1136 }) 1137} 1138 1139func TestLongData(t *testing.T) { 1140 runTests(t, dsn+"&maxAllowedPacket=0", func(dbt *DBTest) { 1141 var maxAllowedPacketSize int 1142 err := dbt.db.QueryRow("select @@max_allowed_packet").Scan(&maxAllowedPacketSize) 1143 if err != nil { 1144 dbt.Fatal(err) 1145 } 1146 maxAllowedPacketSize-- 1147 1148 // don't get too ambitious 1149 if maxAllowedPacketSize > 1<<25 { 1150 maxAllowedPacketSize = 1 << 25 1151 } 1152 1153 dbt.mustExec("CREATE TABLE test (value LONGBLOB)") 1154 1155 in := strings.Repeat(`a`, maxAllowedPacketSize+1) 1156 var out string 1157 var rows *sql.Rows 1158 1159 // Long text data 1160 const nonDataQueryLen = 28 // length query w/o value 1161 inS := in[:maxAllowedPacketSize-nonDataQueryLen] 1162 dbt.mustExec("INSERT INTO test VALUES('" + inS + "')") 1163 rows = dbt.mustQuery("SELECT value FROM test") 1164 defer rows.Close() 1165 if rows.Next() { 1166 rows.Scan(&out) 1167 if inS != out { 1168 dbt.Fatalf("LONGBLOB: length in: %d, length out: %d", len(inS), len(out)) 1169 } 1170 if rows.Next() { 1171 dbt.Error("LONGBLOB: unexpexted row") 1172 } 1173 } else { 1174 dbt.Fatalf("LONGBLOB: no data") 1175 } 1176 1177 // Empty table 1178 dbt.mustExec("TRUNCATE TABLE test") 1179 1180 // Long binary data 1181 dbt.mustExec("INSERT INTO test VALUES(?)", in) 1182 rows = dbt.mustQuery("SELECT value FROM test WHERE 1=?", 1) 1183 defer rows.Close() 1184 if rows.Next() { 1185 rows.Scan(&out) 1186 if in != out { 1187 dbt.Fatalf("LONGBLOB: length in: %d, length out: %d", len(in), len(out)) 1188 } 1189 if rows.Next() { 1190 dbt.Error("LONGBLOB: unexpexted row") 1191 } 1192 } else { 1193 if err = rows.Err(); err != nil { 1194 dbt.Fatalf("LONGBLOB: no data (err: %s)", err.Error()) 1195 } else { 1196 dbt.Fatal("LONGBLOB: no data (err: <nil>)") 1197 } 1198 } 1199 }) 1200} 1201 1202func TestLoadData(t *testing.T) { 1203 runTests(t, dsn, func(dbt *DBTest) { 1204 verifyLoadDataResult := func() { 1205 rows, err := dbt.db.Query("SELECT * FROM test") 1206 if err != nil { 1207 dbt.Fatal(err.Error()) 1208 } 1209 1210 i := 0 1211 values := [4]string{ 1212 "a string", 1213 "a string containing a \t", 1214 "a string containing a \n", 1215 "a string containing both \t\n", 1216 } 1217 1218 var id int 1219 var value string 1220 1221 for rows.Next() { 1222 i++ 1223 err = rows.Scan(&id, &value) 1224 if err != nil { 1225 dbt.Fatal(err.Error()) 1226 } 1227 if i != id { 1228 dbt.Fatalf("%d != %d", i, id) 1229 } 1230 if values[i-1] != value { 1231 dbt.Fatalf("%q != %q", values[i-1], value) 1232 } 1233 } 1234 err = rows.Err() 1235 if err != nil { 1236 dbt.Fatal(err.Error()) 1237 } 1238 1239 if i != 4 { 1240 dbt.Fatalf("rows count mismatch. Got %d, want 4", i) 1241 } 1242 } 1243 1244 dbt.db.Exec("DROP TABLE IF EXISTS test") 1245 dbt.mustExec("CREATE TABLE test (id INT NOT NULL PRIMARY KEY, value TEXT NOT NULL) CHARACTER SET utf8") 1246 1247 // Local File 1248 file, err := ioutil.TempFile("", "gotest") 1249 defer os.Remove(file.Name()) 1250 if err != nil { 1251 dbt.Fatal(err) 1252 } 1253 RegisterLocalFile(file.Name()) 1254 1255 // Try first with empty file 1256 dbt.mustExec(fmt.Sprintf("LOAD DATA LOCAL INFILE %q INTO TABLE test", file.Name())) 1257 var count int 1258 err = dbt.db.QueryRow("SELECT COUNT(*) FROM test").Scan(&count) 1259 if err != nil { 1260 dbt.Fatal(err.Error()) 1261 } 1262 if count != 0 { 1263 dbt.Fatalf("unexpected row count: got %d, want 0", count) 1264 } 1265 1266 // Then fille File with data and try to load it 1267 file.WriteString("1\ta string\n2\ta string containing a \\t\n3\ta string containing a \\n\n4\ta string containing both \\t\\n\n") 1268 file.Close() 1269 dbt.mustExec(fmt.Sprintf("LOAD DATA LOCAL INFILE %q INTO TABLE test", file.Name())) 1270 verifyLoadDataResult() 1271 1272 // Try with non-existing file 1273 _, err = dbt.db.Exec("LOAD DATA LOCAL INFILE 'doesnotexist' INTO TABLE test") 1274 if err == nil { 1275 dbt.Fatal("load non-existent file didn't fail") 1276 } else if err.Error() != "local file 'doesnotexist' is not registered" { 1277 dbt.Fatal(err.Error()) 1278 } 1279 1280 // Empty table 1281 dbt.mustExec("TRUNCATE TABLE test") 1282 1283 // Reader 1284 RegisterReaderHandler("test", func() io.Reader { 1285 file, err = os.Open(file.Name()) 1286 if err != nil { 1287 dbt.Fatal(err) 1288 } 1289 return file 1290 }) 1291 dbt.mustExec("LOAD DATA LOCAL INFILE 'Reader::test' INTO TABLE test") 1292 verifyLoadDataResult() 1293 // negative test 1294 _, err = dbt.db.Exec("LOAD DATA LOCAL INFILE 'Reader::doesnotexist' INTO TABLE test") 1295 if err == nil { 1296 dbt.Fatal("load non-existent Reader didn't fail") 1297 } else if err.Error() != "Reader 'doesnotexist' is not registered" { 1298 dbt.Fatal(err.Error()) 1299 } 1300 }) 1301} 1302 1303func TestFoundRows(t *testing.T) { 1304 runTests(t, dsn, func(dbt *DBTest) { 1305 dbt.mustExec("CREATE TABLE test (id INT NOT NULL ,data INT NOT NULL)") 1306 dbt.mustExec("INSERT INTO test (id, data) VALUES (0, 0),(0, 0),(1, 0),(1, 0),(1, 1)") 1307 1308 res := dbt.mustExec("UPDATE test SET data = 1 WHERE id = 0") 1309 count, err := res.RowsAffected() 1310 if err != nil { 1311 dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error()) 1312 } 1313 if count != 2 { 1314 dbt.Fatalf("Expected 2 affected rows, got %d", count) 1315 } 1316 res = dbt.mustExec("UPDATE test SET data = 1 WHERE id = 1") 1317 count, err = res.RowsAffected() 1318 if err != nil { 1319 dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error()) 1320 } 1321 if count != 2 { 1322 dbt.Fatalf("Expected 2 affected rows, got %d", count) 1323 } 1324 }) 1325 runTests(t, dsn+"&clientFoundRows=true", func(dbt *DBTest) { 1326 dbt.mustExec("CREATE TABLE test (id INT NOT NULL ,data INT NOT NULL)") 1327 dbt.mustExec("INSERT INTO test (id, data) VALUES (0, 0),(0, 0),(1, 0),(1, 0),(1, 1)") 1328 1329 res := dbt.mustExec("UPDATE test SET data = 1 WHERE id = 0") 1330 count, err := res.RowsAffected() 1331 if err != nil { 1332 dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error()) 1333 } 1334 if count != 2 { 1335 dbt.Fatalf("Expected 2 matched rows, got %d", count) 1336 } 1337 res = dbt.mustExec("UPDATE test SET data = 1 WHERE id = 1") 1338 count, err = res.RowsAffected() 1339 if err != nil { 1340 dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error()) 1341 } 1342 if count != 3 { 1343 dbt.Fatalf("Expected 3 matched rows, got %d", count) 1344 } 1345 }) 1346} 1347 1348func TestTLS(t *testing.T) { 1349 tlsTestReq := func(dbt *DBTest) { 1350 if err := dbt.db.Ping(); err != nil { 1351 if err == ErrNoTLS { 1352 dbt.Skip("server does not support TLS") 1353 } else { 1354 dbt.Fatalf("error on Ping: %s", err.Error()) 1355 } 1356 } 1357 1358 rows := dbt.mustQuery("SHOW STATUS LIKE 'Ssl_cipher'") 1359 defer rows.Close() 1360 1361 var variable, value *sql.RawBytes 1362 for rows.Next() { 1363 if err := rows.Scan(&variable, &value); err != nil { 1364 dbt.Fatal(err.Error()) 1365 } 1366 1367 if (*value == nil) || (len(*value) == 0) { 1368 dbt.Fatalf("no Cipher") 1369 } else { 1370 dbt.Logf("Cipher: %s", *value) 1371 } 1372 } 1373 } 1374 tlsTestOpt := func(dbt *DBTest) { 1375 if err := dbt.db.Ping(); err != nil { 1376 dbt.Fatalf("error on Ping: %s", err.Error()) 1377 } 1378 } 1379 1380 runTests(t, dsn+"&tls=preferred", tlsTestOpt) 1381 runTests(t, dsn+"&tls=skip-verify", tlsTestReq) 1382 1383 // Verify that registering / using a custom cfg works 1384 RegisterTLSConfig("custom-skip-verify", &tls.Config{ 1385 InsecureSkipVerify: true, 1386 }) 1387 runTests(t, dsn+"&tls=custom-skip-verify", tlsTestReq) 1388} 1389 1390func TestReuseClosedConnection(t *testing.T) { 1391 // this test does not use sql.database, it uses the driver directly 1392 if !available { 1393 t.Skipf("MySQL server not running on %s", netAddr) 1394 } 1395 1396 md := &MySQLDriver{} 1397 conn, err := md.Open(dsn) 1398 if err != nil { 1399 t.Fatalf("error connecting: %s", err.Error()) 1400 } 1401 stmt, err := conn.Prepare("DO 1") 1402 if err != nil { 1403 t.Fatalf("error preparing statement: %s", err.Error()) 1404 } 1405 _, err = stmt.Exec(nil) 1406 if err != nil { 1407 t.Fatalf("error executing statement: %s", err.Error()) 1408 } 1409 err = conn.Close() 1410 if err != nil { 1411 t.Fatalf("error closing connection: %s", err.Error()) 1412 } 1413 1414 defer func() { 1415 if err := recover(); err != nil { 1416 t.Errorf("panic after reusing a closed connection: %v", err) 1417 } 1418 }() 1419 _, err = stmt.Exec(nil) 1420 if err != nil && err != driver.ErrBadConn { 1421 t.Errorf("unexpected error '%s', expected '%s'", 1422 err.Error(), driver.ErrBadConn.Error()) 1423 } 1424} 1425 1426func TestCharset(t *testing.T) { 1427 if !available { 1428 t.Skipf("MySQL server not running on %s", netAddr) 1429 } 1430 1431 mustSetCharset := func(charsetParam, expected string) { 1432 runTests(t, dsn+"&"+charsetParam, func(dbt *DBTest) { 1433 rows := dbt.mustQuery("SELECT @@character_set_connection") 1434 defer rows.Close() 1435 1436 if !rows.Next() { 1437 dbt.Fatalf("error getting connection charset: %s", rows.Err()) 1438 } 1439 1440 var got string 1441 rows.Scan(&got) 1442 1443 if got != expected { 1444 dbt.Fatalf("expected connection charset %s but got %s", expected, got) 1445 } 1446 }) 1447 } 1448 1449 // non utf8 test 1450 mustSetCharset("charset=ascii", "ascii") 1451 1452 // when the first charset is invalid, use the second 1453 mustSetCharset("charset=none,utf8", "utf8") 1454 1455 // when the first charset is valid, use it 1456 mustSetCharset("charset=ascii,utf8", "ascii") 1457 mustSetCharset("charset=utf8,ascii", "utf8") 1458} 1459 1460func TestFailingCharset(t *testing.T) { 1461 runTests(t, dsn+"&charset=none", func(dbt *DBTest) { 1462 // run query to really establish connection... 1463 _, err := dbt.db.Exec("SELECT 1") 1464 if err == nil { 1465 dbt.db.Close() 1466 t.Fatalf("connection must not succeed without a valid charset") 1467 } 1468 }) 1469} 1470 1471func TestCollation(t *testing.T) { 1472 if !available { 1473 t.Skipf("MySQL server not running on %s", netAddr) 1474 } 1475 1476 defaultCollation := "utf8mb4_general_ci" 1477 testCollations := []string{ 1478 "", // do not set 1479 defaultCollation, // driver default 1480 "latin1_general_ci", 1481 "binary", 1482 "utf8_unicode_ci", 1483 "cp1257_bin", 1484 } 1485 1486 for _, collation := range testCollations { 1487 var expected, tdsn string 1488 if collation != "" { 1489 tdsn = dsn + "&collation=" + collation 1490 expected = collation 1491 } else { 1492 tdsn = dsn 1493 expected = defaultCollation 1494 } 1495 1496 runTests(t, tdsn, func(dbt *DBTest) { 1497 var got string 1498 if err := dbt.db.QueryRow("SELECT @@collation_connection").Scan(&got); err != nil { 1499 dbt.Fatal(err) 1500 } 1501 1502 if got != expected { 1503 dbt.Fatalf("expected connection collation %s but got %s", expected, got) 1504 } 1505 }) 1506 } 1507} 1508 1509func TestColumnsWithAlias(t *testing.T) { 1510 runTests(t, dsn+"&columnsWithAlias=true", func(dbt *DBTest) { 1511 rows := dbt.mustQuery("SELECT 1 AS A") 1512 defer rows.Close() 1513 cols, _ := rows.Columns() 1514 if len(cols) != 1 { 1515 t.Fatalf("expected 1 column, got %d", len(cols)) 1516 } 1517 if cols[0] != "A" { 1518 t.Fatalf("expected column name \"A\", got \"%s\"", cols[0]) 1519 } 1520 1521 rows = dbt.mustQuery("SELECT * FROM (SELECT 1 AS one) AS A") 1522 defer rows.Close() 1523 cols, _ = rows.Columns() 1524 if len(cols) != 1 { 1525 t.Fatalf("expected 1 column, got %d", len(cols)) 1526 } 1527 if cols[0] != "A.one" { 1528 t.Fatalf("expected column name \"A.one\", got \"%s\"", cols[0]) 1529 } 1530 }) 1531} 1532 1533func TestRawBytesResultExceedsBuffer(t *testing.T) { 1534 runTests(t, dsn, func(dbt *DBTest) { 1535 // defaultBufSize from buffer.go 1536 expected := strings.Repeat("abc", defaultBufSize) 1537 1538 rows := dbt.mustQuery("SELECT '" + expected + "'") 1539 defer rows.Close() 1540 if !rows.Next() { 1541 dbt.Error("expected result, got none") 1542 } 1543 var result sql.RawBytes 1544 rows.Scan(&result) 1545 if expected != string(result) { 1546 dbt.Error("result did not match expected value") 1547 } 1548 }) 1549} 1550 1551func TestTimezoneConversion(t *testing.T) { 1552 zones := []string{"UTC", "US/Central", "US/Pacific", "Local"} 1553 1554 // Regression test for timezone handling 1555 tzTest := func(dbt *DBTest) { 1556 // Create table 1557 dbt.mustExec("CREATE TABLE test (ts TIMESTAMP)") 1558 1559 // Insert local time into database (should be converted) 1560 usCentral, _ := time.LoadLocation("US/Central") 1561 reftime := time.Date(2014, 05, 30, 18, 03, 17, 0, time.UTC).In(usCentral) 1562 dbt.mustExec("INSERT INTO test VALUE (?)", reftime) 1563 1564 // Retrieve time from DB 1565 rows := dbt.mustQuery("SELECT ts FROM test") 1566 defer rows.Close() 1567 if !rows.Next() { 1568 dbt.Fatal("did not get any rows out") 1569 } 1570 1571 var dbTime time.Time 1572 err := rows.Scan(&dbTime) 1573 if err != nil { 1574 dbt.Fatal("Err", err) 1575 } 1576 1577 // Check that dates match 1578 if reftime.Unix() != dbTime.Unix() { 1579 dbt.Errorf("times do not match.\n") 1580 dbt.Errorf(" Now(%v)=%v\n", usCentral, reftime) 1581 dbt.Errorf(" Now(UTC)=%v\n", dbTime) 1582 } 1583 } 1584 1585 for _, tz := range zones { 1586 runTests(t, dsn+"&parseTime=true&loc="+url.QueryEscape(tz), tzTest) 1587 } 1588} 1589 1590// Special cases 1591 1592func TestRowsClose(t *testing.T) { 1593 runTests(t, dsn, func(dbt *DBTest) { 1594 rows, err := dbt.db.Query("SELECT 1") 1595 if err != nil { 1596 dbt.Fatal(err) 1597 } 1598 1599 err = rows.Close() 1600 if err != nil { 1601 dbt.Fatal(err) 1602 } 1603 1604 if rows.Next() { 1605 dbt.Fatal("unexpected row after rows.Close()") 1606 } 1607 1608 err = rows.Err() 1609 if err != nil { 1610 dbt.Fatal(err) 1611 } 1612 }) 1613} 1614 1615// dangling statements 1616// http://code.google.com/p/go/issues/detail?id=3865 1617func TestCloseStmtBeforeRows(t *testing.T) { 1618 runTests(t, dsn, func(dbt *DBTest) { 1619 stmt, err := dbt.db.Prepare("SELECT 1") 1620 if err != nil { 1621 dbt.Fatal(err) 1622 } 1623 1624 rows, err := stmt.Query() 1625 if err != nil { 1626 stmt.Close() 1627 dbt.Fatal(err) 1628 } 1629 defer rows.Close() 1630 1631 err = stmt.Close() 1632 if err != nil { 1633 dbt.Fatal(err) 1634 } 1635 1636 if !rows.Next() { 1637 dbt.Fatal("getting row failed") 1638 } else { 1639 err = rows.Err() 1640 if err != nil { 1641 dbt.Fatal(err) 1642 } 1643 1644 var out bool 1645 err = rows.Scan(&out) 1646 if err != nil { 1647 dbt.Fatalf("error on rows.Scan(): %s", err.Error()) 1648 } 1649 if out != true { 1650 dbt.Errorf("true != %t", out) 1651 } 1652 } 1653 }) 1654} 1655 1656// It is valid to have multiple Rows for the same Stmt 1657// http://code.google.com/p/go/issues/detail?id=3734 1658func TestStmtMultiRows(t *testing.T) { 1659 runTests(t, dsn, func(dbt *DBTest) { 1660 stmt, err := dbt.db.Prepare("SELECT 1 UNION SELECT 0") 1661 if err != nil { 1662 dbt.Fatal(err) 1663 } 1664 1665 rows1, err := stmt.Query() 1666 if err != nil { 1667 stmt.Close() 1668 dbt.Fatal(err) 1669 } 1670 defer rows1.Close() 1671 1672 rows2, err := stmt.Query() 1673 if err != nil { 1674 stmt.Close() 1675 dbt.Fatal(err) 1676 } 1677 defer rows2.Close() 1678 1679 var out bool 1680 1681 // 1 1682 if !rows1.Next() { 1683 dbt.Fatal("first rows1.Next failed") 1684 } else { 1685 err = rows1.Err() 1686 if err != nil { 1687 dbt.Fatal(err) 1688 } 1689 1690 err = rows1.Scan(&out) 1691 if err != nil { 1692 dbt.Fatalf("error on rows.Scan(): %s", err.Error()) 1693 } 1694 if out != true { 1695 dbt.Errorf("true != %t", out) 1696 } 1697 } 1698 1699 if !rows2.Next() { 1700 dbt.Fatal("first rows2.Next failed") 1701 } else { 1702 err = rows2.Err() 1703 if err != nil { 1704 dbt.Fatal(err) 1705 } 1706 1707 err = rows2.Scan(&out) 1708 if err != nil { 1709 dbt.Fatalf("error on rows.Scan(): %s", err.Error()) 1710 } 1711 if out != true { 1712 dbt.Errorf("true != %t", out) 1713 } 1714 } 1715 1716 // 2 1717 if !rows1.Next() { 1718 dbt.Fatal("second rows1.Next failed") 1719 } else { 1720 err = rows1.Err() 1721 if err != nil { 1722 dbt.Fatal(err) 1723 } 1724 1725 err = rows1.Scan(&out) 1726 if err != nil { 1727 dbt.Fatalf("error on rows.Scan(): %s", err.Error()) 1728 } 1729 if out != false { 1730 dbt.Errorf("false != %t", out) 1731 } 1732 1733 if rows1.Next() { 1734 dbt.Fatal("unexpected row on rows1") 1735 } 1736 err = rows1.Close() 1737 if err != nil { 1738 dbt.Fatal(err) 1739 } 1740 } 1741 1742 if !rows2.Next() { 1743 dbt.Fatal("second rows2.Next failed") 1744 } else { 1745 err = rows2.Err() 1746 if err != nil { 1747 dbt.Fatal(err) 1748 } 1749 1750 err = rows2.Scan(&out) 1751 if err != nil { 1752 dbt.Fatalf("error on rows.Scan(): %s", err.Error()) 1753 } 1754 if out != false { 1755 dbt.Errorf("false != %t", out) 1756 } 1757 1758 if rows2.Next() { 1759 dbt.Fatal("unexpected row on rows2") 1760 } 1761 err = rows2.Close() 1762 if err != nil { 1763 dbt.Fatal(err) 1764 } 1765 } 1766 }) 1767} 1768 1769// Regression test for 1770// * more than 32 NULL parameters (issue 209) 1771// * more parameters than fit into the buffer (issue 201) 1772// * parameters * 64 > max_allowed_packet (issue 734) 1773func TestPreparedManyCols(t *testing.T) { 1774 numParams := 65535 1775 runTests(t, dsn, func(dbt *DBTest) { 1776 query := "SELECT ?" + strings.Repeat(",?", numParams-1) 1777 stmt, err := dbt.db.Prepare(query) 1778 if err != nil { 1779 dbt.Fatal(err) 1780 } 1781 defer stmt.Close() 1782 1783 // create more parameters than fit into the buffer 1784 // which will take nil-values 1785 params := make([]interface{}, numParams) 1786 rows, err := stmt.Query(params...) 1787 if err != nil { 1788 dbt.Fatal(err) 1789 } 1790 rows.Close() 1791 1792 // Create 0byte string which we can't send via STMT_LONG_DATA. 1793 for i := 0; i < numParams; i++ { 1794 params[i] = "" 1795 } 1796 rows, err = stmt.Query(params...) 1797 if err != nil { 1798 dbt.Fatal(err) 1799 } 1800 rows.Close() 1801 }) 1802} 1803 1804func TestConcurrent(t *testing.T) { 1805 if enabled, _ := readBool(os.Getenv("MYSQL_TEST_CONCURRENT")); !enabled { 1806 t.Skip("MYSQL_TEST_CONCURRENT env var not set") 1807 } 1808 1809 runTests(t, dsn, func(dbt *DBTest) { 1810 var version string 1811 if err := dbt.db.QueryRow("SELECT @@version").Scan(&version); err != nil { 1812 dbt.Fatalf("%s", err.Error()) 1813 } 1814 if strings.Contains(strings.ToLower(version), "mariadb") { 1815 t.Skip(`TODO: "fix commands out of sync. Did you run multiple statements at once?" on MariaDB`) 1816 } 1817 1818 var max int 1819 err := dbt.db.QueryRow("SELECT @@max_connections").Scan(&max) 1820 if err != nil { 1821 dbt.Fatalf("%s", err.Error()) 1822 } 1823 dbt.Logf("testing up to %d concurrent connections \r\n", max) 1824 1825 var remaining, succeeded int32 = int32(max), 0 1826 1827 var wg sync.WaitGroup 1828 wg.Add(max) 1829 1830 var fatalError string 1831 var once sync.Once 1832 fatalf := func(s string, vals ...interface{}) { 1833 once.Do(func() { 1834 fatalError = fmt.Sprintf(s, vals...) 1835 }) 1836 } 1837 1838 for i := 0; i < max; i++ { 1839 go func(id int) { 1840 defer wg.Done() 1841 1842 tx, err := dbt.db.Begin() 1843 atomic.AddInt32(&remaining, -1) 1844 1845 if err != nil { 1846 if err.Error() != "Error 1040: Too many connections" { 1847 fatalf("error on conn %d: %s", id, err.Error()) 1848 } 1849 return 1850 } 1851 1852 // keep the connection busy until all connections are open 1853 for remaining > 0 { 1854 if _, err = tx.Exec("DO 1"); err != nil { 1855 fatalf("error on conn %d: %s", id, err.Error()) 1856 return 1857 } 1858 } 1859 1860 if err = tx.Commit(); err != nil { 1861 fatalf("error on conn %d: %s", id, err.Error()) 1862 return 1863 } 1864 1865 // everything went fine with this connection 1866 atomic.AddInt32(&succeeded, 1) 1867 }(i) 1868 } 1869 1870 // wait until all conections are open 1871 wg.Wait() 1872 1873 if fatalError != "" { 1874 dbt.Fatal(fatalError) 1875 } 1876 1877 dbt.Logf("reached %d concurrent connections\r\n", succeeded) 1878 }) 1879} 1880 1881func testDialError(t *testing.T, dialErr error, expectErr error) { 1882 RegisterDialContext("mydial", func(ctx context.Context, addr string) (net.Conn, error) { 1883 return nil, dialErr 1884 }) 1885 1886 db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@mydial(%s)/%s?timeout=30s", user, pass, addr, dbname)) 1887 if err != nil { 1888 t.Fatalf("error connecting: %s", err.Error()) 1889 } 1890 defer db.Close() 1891 1892 _, err = db.Exec("DO 1") 1893 if err != expectErr { 1894 t.Fatalf("was expecting %s. Got: %s", dialErr, err) 1895 } 1896} 1897 1898func TestDialUnknownError(t *testing.T) { 1899 testErr := fmt.Errorf("test") 1900 testDialError(t, testErr, testErr) 1901} 1902 1903func TestDialNonRetryableNetErr(t *testing.T) { 1904 testErr := netErrorMock{} 1905 testDialError(t, testErr, testErr) 1906} 1907 1908func TestDialTemporaryNetErr(t *testing.T) { 1909 testErr := netErrorMock{temporary: true} 1910 testDialError(t, testErr, testErr) 1911} 1912 1913// Tests custom dial functions 1914func TestCustomDial(t *testing.T) { 1915 if !available { 1916 t.Skipf("MySQL server not running on %s", netAddr) 1917 } 1918 1919 // our custom dial function which justs wraps net.Dial here 1920 RegisterDialContext("mydial", func(ctx context.Context, addr string) (net.Conn, error) { 1921 var d net.Dialer 1922 return d.DialContext(ctx, prot, addr) 1923 }) 1924 1925 db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@mydial(%s)/%s?timeout=30s", user, pass, addr, dbname)) 1926 if err != nil { 1927 t.Fatalf("error connecting: %s", err.Error()) 1928 } 1929 defer db.Close() 1930 1931 if _, err = db.Exec("DO 1"); err != nil { 1932 t.Fatalf("connection failed: %s", err.Error()) 1933 } 1934} 1935 1936func TestSQLInjection(t *testing.T) { 1937 createTest := func(arg string) func(dbt *DBTest) { 1938 return func(dbt *DBTest) { 1939 dbt.mustExec("CREATE TABLE test (v INTEGER)") 1940 dbt.mustExec("INSERT INTO test VALUES (?)", 1) 1941 1942 var v int 1943 // NULL can't be equal to anything, the idea here is to inject query so it returns row 1944 // This test verifies that escapeQuotes and escapeBackslash are working properly 1945 err := dbt.db.QueryRow("SELECT v FROM test WHERE NULL = ?", arg).Scan(&v) 1946 if err == sql.ErrNoRows { 1947 return // success, sql injection failed 1948 } else if err == nil { 1949 dbt.Errorf("sql injection successful with arg: %s", arg) 1950 } else { 1951 dbt.Errorf("error running query with arg: %s; err: %s", arg, err.Error()) 1952 } 1953 } 1954 } 1955 1956 dsns := []string{ 1957 dsn, 1958 dsn + "&sql_mode='NO_BACKSLASH_ESCAPES'", 1959 } 1960 for _, testdsn := range dsns { 1961 runTests(t, testdsn, createTest("1 OR 1=1")) 1962 runTests(t, testdsn, createTest("' OR '1'='1")) 1963 } 1964} 1965 1966// Test if inserted data is correctly retrieved after being escaped 1967func TestInsertRetrieveEscapedData(t *testing.T) { 1968 testData := func(dbt *DBTest) { 1969 dbt.mustExec("CREATE TABLE test (v VARCHAR(255))") 1970 1971 // All sequences that are escaped by escapeQuotes and escapeBackslash 1972 v := "foo \x00\n\r\x1a\"'\\" 1973 dbt.mustExec("INSERT INTO test VALUES (?)", v) 1974 1975 var out string 1976 err := dbt.db.QueryRow("SELECT v FROM test").Scan(&out) 1977 if err != nil { 1978 dbt.Fatalf("%s", err.Error()) 1979 } 1980 1981 if out != v { 1982 dbt.Errorf("%q != %q", out, v) 1983 } 1984 } 1985 1986 dsns := []string{ 1987 dsn, 1988 dsn + "&sql_mode='NO_BACKSLASH_ESCAPES'", 1989 } 1990 for _, testdsn := range dsns { 1991 runTests(t, testdsn, testData) 1992 } 1993} 1994 1995func TestUnixSocketAuthFail(t *testing.T) { 1996 runTests(t, dsn, func(dbt *DBTest) { 1997 // Save the current logger so we can restore it. 1998 oldLogger := errLog 1999 2000 // Set a new logger so we can capture its output. 2001 buffer := bytes.NewBuffer(make([]byte, 0, 64)) 2002 newLogger := log.New(buffer, "prefix: ", 0) 2003 SetLogger(newLogger) 2004 2005 // Restore the logger. 2006 defer SetLogger(oldLogger) 2007 2008 // Make a new DSN that uses the MySQL socket file and a bad password, which 2009 // we can make by simply appending any character to the real password. 2010 badPass := pass + "x" 2011 socket := "" 2012 if prot == "unix" { 2013 socket = addr 2014 } else { 2015 // Get socket file from MySQL. 2016 err := dbt.db.QueryRow("SELECT @@socket").Scan(&socket) 2017 if err != nil { 2018 t.Fatalf("error on SELECT @@socket: %s", err.Error()) 2019 } 2020 } 2021 t.Logf("socket: %s", socket) 2022 badDSN := fmt.Sprintf("%s:%s@unix(%s)/%s?timeout=30s", user, badPass, socket, dbname) 2023 db, err := sql.Open("mysql", badDSN) 2024 if err != nil { 2025 t.Fatalf("error connecting: %s", err.Error()) 2026 } 2027 defer db.Close() 2028 2029 // Connect to MySQL for real. This will cause an auth failure. 2030 err = db.Ping() 2031 if err == nil { 2032 t.Error("expected Ping() to return an error") 2033 } 2034 2035 // The driver should not log anything. 2036 if actual := buffer.String(); actual != "" { 2037 t.Errorf("expected no output, got %q", actual) 2038 } 2039 }) 2040} 2041 2042// See Issue #422 2043func TestInterruptBySignal(t *testing.T) { 2044 runTestsWithMultiStatement(t, dsn, func(dbt *DBTest) { 2045 dbt.mustExec(` 2046 DROP PROCEDURE IF EXISTS test_signal; 2047 CREATE PROCEDURE test_signal(ret INT) 2048 BEGIN 2049 SELECT ret; 2050 SIGNAL SQLSTATE 2051 '45001' 2052 SET 2053 MESSAGE_TEXT = "an error", 2054 MYSQL_ERRNO = 45001; 2055 END 2056 `) 2057 defer dbt.mustExec("DROP PROCEDURE test_signal") 2058 2059 var val int 2060 2061 // text protocol 2062 rows, err := dbt.db.Query("CALL test_signal(42)") 2063 if err != nil { 2064 dbt.Fatalf("error on text query: %s", err.Error()) 2065 } 2066 for rows.Next() { 2067 if err := rows.Scan(&val); err != nil { 2068 dbt.Error(err) 2069 } else if val != 42 { 2070 dbt.Errorf("expected val to be 42") 2071 } 2072 } 2073 rows.Close() 2074 2075 // binary protocol 2076 rows, err = dbt.db.Query("CALL test_signal(?)", 42) 2077 if err != nil { 2078 dbt.Fatalf("error on binary query: %s", err.Error()) 2079 } 2080 for rows.Next() { 2081 if err := rows.Scan(&val); err != nil { 2082 dbt.Error(err) 2083 } else if val != 42 { 2084 dbt.Errorf("expected val to be 42") 2085 } 2086 } 2087 rows.Close() 2088 }) 2089} 2090 2091func TestColumnsReusesSlice(t *testing.T) { 2092 rows := mysqlRows{ 2093 rs: resultSet{ 2094 columns: []mysqlField{ 2095 { 2096 tableName: "test", 2097 name: "A", 2098 }, 2099 { 2100 tableName: "test", 2101 name: "B", 2102 }, 2103 }, 2104 }, 2105 } 2106 2107 allocs := testing.AllocsPerRun(1, func() { 2108 cols := rows.Columns() 2109 2110 if len(cols) != 2 { 2111 t.Fatalf("expected 2 columns, got %d", len(cols)) 2112 } 2113 }) 2114 2115 if allocs != 0 { 2116 t.Fatalf("expected 0 allocations, got %d", int(allocs)) 2117 } 2118 2119 if rows.rs.columnNames == nil { 2120 t.Fatalf("expected columnNames to be set, got nil") 2121 } 2122} 2123 2124func TestRejectReadOnly(t *testing.T) { 2125 runTests(t, dsn, func(dbt *DBTest) { 2126 // Create Table 2127 dbt.mustExec("CREATE TABLE test (value BOOL)") 2128 // Set the session to read-only. We didn't set the `rejectReadOnly` 2129 // option, so any writes after this should fail. 2130 _, err := dbt.db.Exec("SET SESSION TRANSACTION READ ONLY") 2131 // Error 1193: Unknown system variable 'TRANSACTION' => skip test, 2132 // MySQL server version is too old 2133 maybeSkip(t, err, 1193) 2134 if _, err := dbt.db.Exec("DROP TABLE test"); err == nil { 2135 t.Fatalf("writing to DB in read-only session without " + 2136 "rejectReadOnly did not error") 2137 } 2138 // Set the session back to read-write so runTests() can properly clean 2139 // up the table `test`. 2140 dbt.mustExec("SET SESSION TRANSACTION READ WRITE") 2141 }) 2142 2143 // Enable the `rejectReadOnly` option. 2144 runTests(t, dsn+"&rejectReadOnly=true", func(dbt *DBTest) { 2145 // Create Table 2146 dbt.mustExec("CREATE TABLE test (value BOOL)") 2147 // Set the session to read only. Any writes after this should error on 2148 // a driver.ErrBadConn, and cause `database/sql` to initiate a new 2149 // connection. 2150 dbt.mustExec("SET SESSION TRANSACTION READ ONLY") 2151 // This would error, but `database/sql` should automatically retry on a 2152 // new connection which is not read-only, and eventually succeed. 2153 dbt.mustExec("DROP TABLE test") 2154 }) 2155} 2156 2157func TestPing(t *testing.T) { 2158 runTests(t, dsn, func(dbt *DBTest) { 2159 if err := dbt.db.Ping(); err != nil { 2160 dbt.fail("Ping", "Ping", err) 2161 } 2162 }) 2163} 2164 2165// See Issue #799 2166func TestEmptyPassword(t *testing.T) { 2167 if !available { 2168 t.Skipf("MySQL server not running on %s", netAddr) 2169 } 2170 2171 dsn := fmt.Sprintf("%s:%s@%s/%s?timeout=30s", user, "", netAddr, dbname) 2172 db, err := sql.Open("mysql", dsn) 2173 if err == nil { 2174 defer db.Close() 2175 err = db.Ping() 2176 } 2177 2178 if pass == "" { 2179 if err != nil { 2180 t.Fatal(err.Error()) 2181 } 2182 } else { 2183 if err == nil { 2184 t.Fatal("expected authentication error") 2185 } 2186 if !strings.HasPrefix(err.Error(), "Error 1045") { 2187 t.Fatal(err.Error()) 2188 } 2189 } 2190} 2191 2192// static interface implementation checks of mysqlConn 2193var ( 2194 _ driver.ConnBeginTx = &mysqlConn{} 2195 _ driver.ConnPrepareContext = &mysqlConn{} 2196 _ driver.ExecerContext = &mysqlConn{} 2197 _ driver.Pinger = &mysqlConn{} 2198 _ driver.QueryerContext = &mysqlConn{} 2199) 2200 2201// static interface implementation checks of mysqlStmt 2202var ( 2203 _ driver.StmtExecContext = &mysqlStmt{} 2204 _ driver.StmtQueryContext = &mysqlStmt{} 2205) 2206 2207// Ensure that all the driver interfaces are implemented 2208var ( 2209 // _ driver.RowsColumnTypeLength = &binaryRows{} 2210 // _ driver.RowsColumnTypeLength = &textRows{} 2211 _ driver.RowsColumnTypeDatabaseTypeName = &binaryRows{} 2212 _ driver.RowsColumnTypeDatabaseTypeName = &textRows{} 2213 _ driver.RowsColumnTypeNullable = &binaryRows{} 2214 _ driver.RowsColumnTypeNullable = &textRows{} 2215 _ driver.RowsColumnTypePrecisionScale = &binaryRows{} 2216 _ driver.RowsColumnTypePrecisionScale = &textRows{} 2217 _ driver.RowsColumnTypeScanType = &binaryRows{} 2218 _ driver.RowsColumnTypeScanType = &textRows{} 2219 _ driver.RowsNextResultSet = &binaryRows{} 2220 _ driver.RowsNextResultSet = &textRows{} 2221) 2222 2223func TestMultiResultSet(t *testing.T) { 2224 type result struct { 2225 values [][]int 2226 columns []string 2227 } 2228 2229 // checkRows is a helper test function to validate rows containing 3 result 2230 // sets with specific values and columns. The basic query would look like this: 2231 // 2232 // SELECT 1 AS col1, 2 AS col2 UNION SELECT 3, 4; 2233 // SELECT 0 UNION SELECT 1; 2234 // SELECT 1 AS col1, 2 AS col2, 3 AS col3 UNION SELECT 4, 5, 6; 2235 // 2236 // to distinguish test cases the first string argument is put in front of 2237 // every error or fatal message. 2238 checkRows := func(desc string, rows *sql.Rows, dbt *DBTest) { 2239 expected := []result{ 2240 { 2241 values: [][]int{{1, 2}, {3, 4}}, 2242 columns: []string{"col1", "col2"}, 2243 }, 2244 { 2245 values: [][]int{{1, 2, 3}, {4, 5, 6}}, 2246 columns: []string{"col1", "col2", "col3"}, 2247 }, 2248 } 2249 2250 var res1 result 2251 for rows.Next() { 2252 var res [2]int 2253 if err := rows.Scan(&res[0], &res[1]); err != nil { 2254 dbt.Fatal(err) 2255 } 2256 res1.values = append(res1.values, res[:]) 2257 } 2258 2259 cols, err := rows.Columns() 2260 if err != nil { 2261 dbt.Fatal(desc, err) 2262 } 2263 res1.columns = cols 2264 2265 if !reflect.DeepEqual(expected[0], res1) { 2266 dbt.Error(desc, "want =", expected[0], "got =", res1) 2267 } 2268 2269 if !rows.NextResultSet() { 2270 dbt.Fatal(desc, "expected next result set") 2271 } 2272 2273 // ignoring one result set 2274 2275 if !rows.NextResultSet() { 2276 dbt.Fatal(desc, "expected next result set") 2277 } 2278 2279 var res2 result 2280 cols, err = rows.Columns() 2281 if err != nil { 2282 dbt.Fatal(desc, err) 2283 } 2284 res2.columns = cols 2285 2286 for rows.Next() { 2287 var res [3]int 2288 if err := rows.Scan(&res[0], &res[1], &res[2]); err != nil { 2289 dbt.Fatal(desc, err) 2290 } 2291 res2.values = append(res2.values, res[:]) 2292 } 2293 2294 if !reflect.DeepEqual(expected[1], res2) { 2295 dbt.Error(desc, "want =", expected[1], "got =", res2) 2296 } 2297 2298 if rows.NextResultSet() { 2299 dbt.Error(desc, "unexpected next result set") 2300 } 2301 2302 if err := rows.Err(); err != nil { 2303 dbt.Error(desc, err) 2304 } 2305 } 2306 2307 runTestsWithMultiStatement(t, dsn, func(dbt *DBTest) { 2308 rows := dbt.mustQuery(`DO 1; 2309 SELECT 1 AS col1, 2 AS col2 UNION SELECT 3, 4; 2310 DO 1; 2311 SELECT 0 UNION SELECT 1; 2312 SELECT 1 AS col1, 2 AS col2, 3 AS col3 UNION SELECT 4, 5, 6;`) 2313 defer rows.Close() 2314 checkRows("query: ", rows, dbt) 2315 }) 2316 2317 runTestsWithMultiStatement(t, dsn, func(dbt *DBTest) { 2318 queries := []string{ 2319 ` 2320 DROP PROCEDURE IF EXISTS test_mrss; 2321 CREATE PROCEDURE test_mrss() 2322 BEGIN 2323 DO 1; 2324 SELECT 1 AS col1, 2 AS col2 UNION SELECT 3, 4; 2325 DO 1; 2326 SELECT 0 UNION SELECT 1; 2327 SELECT 1 AS col1, 2 AS col2, 3 AS col3 UNION SELECT 4, 5, 6; 2328 END 2329 `, 2330 ` 2331 DROP PROCEDURE IF EXISTS test_mrss; 2332 CREATE PROCEDURE test_mrss() 2333 BEGIN 2334 SELECT 1 AS col1, 2 AS col2 UNION SELECT 3, 4; 2335 SELECT 0 UNION SELECT 1; 2336 SELECT 1 AS col1, 2 AS col2, 3 AS col3 UNION SELECT 4, 5, 6; 2337 END 2338 `, 2339 } 2340 2341 defer dbt.mustExec("DROP PROCEDURE IF EXISTS test_mrss") 2342 2343 for i, query := range queries { 2344 dbt.mustExec(query) 2345 2346 stmt, err := dbt.db.Prepare("CALL test_mrss()") 2347 if err != nil { 2348 dbt.Fatalf("%v (i=%d)", err, i) 2349 } 2350 defer stmt.Close() 2351 2352 for j := 0; j < 2; j++ { 2353 rows, err := stmt.Query() 2354 if err != nil { 2355 dbt.Fatalf("%v (i=%d) (j=%d)", err, i, j) 2356 } 2357 checkRows(fmt.Sprintf("prepared stmt query (i=%d) (j=%d): ", i, j), rows, dbt) 2358 } 2359 } 2360 }) 2361} 2362 2363func TestMultiResultSetNoSelect(t *testing.T) { 2364 runTestsWithMultiStatement(t, dsn, func(dbt *DBTest) { 2365 rows := dbt.mustQuery("DO 1; DO 2;") 2366 defer rows.Close() 2367 2368 if rows.Next() { 2369 dbt.Error("unexpected row") 2370 } 2371 2372 if rows.NextResultSet() { 2373 dbt.Error("unexpected next result set") 2374 } 2375 2376 if err := rows.Err(); err != nil { 2377 dbt.Error("expected nil; got ", err) 2378 } 2379 }) 2380} 2381 2382// tests if rows are set in a proper state if some results were ignored before 2383// calling rows.NextResultSet. 2384func TestSkipResults(t *testing.T) { 2385 runTests(t, dsn, func(dbt *DBTest) { 2386 rows := dbt.mustQuery("SELECT 1, 2") 2387 defer rows.Close() 2388 2389 if !rows.Next() { 2390 dbt.Error("expected row") 2391 } 2392 2393 if rows.NextResultSet() { 2394 dbt.Error("unexpected next result set") 2395 } 2396 2397 if err := rows.Err(); err != nil { 2398 dbt.Error("expected nil; got ", err) 2399 } 2400 }) 2401} 2402 2403func TestPingContext(t *testing.T) { 2404 runTests(t, dsn, func(dbt *DBTest) { 2405 ctx, cancel := context.WithCancel(context.Background()) 2406 cancel() 2407 if err := dbt.db.PingContext(ctx); err != context.Canceled { 2408 dbt.Errorf("expected context.Canceled, got %v", err) 2409 } 2410 }) 2411} 2412 2413func TestContextCancelExec(t *testing.T) { 2414 runTests(t, dsn, func(dbt *DBTest) { 2415 dbt.mustExec("CREATE TABLE test (v INTEGER)") 2416 ctx, cancel := context.WithCancel(context.Background()) 2417 2418 // Delay execution for just a bit until db.ExecContext has begun. 2419 defer time.AfterFunc(250*time.Millisecond, cancel).Stop() 2420 2421 // This query will be canceled. 2422 startTime := time.Now() 2423 if _, err := dbt.db.ExecContext(ctx, "INSERT INTO test VALUES (SLEEP(1))"); err != context.Canceled { 2424 dbt.Errorf("expected context.Canceled, got %v", err) 2425 } 2426 if d := time.Since(startTime); d > 500*time.Millisecond { 2427 dbt.Errorf("too long execution time: %s", d) 2428 } 2429 2430 // Wait for the INSERT query to be done. 2431 time.Sleep(time.Second) 2432 2433 // Check how many times the query is executed. 2434 var v int 2435 if err := dbt.db.QueryRow("SELECT COUNT(*) FROM test").Scan(&v); err != nil { 2436 dbt.Fatalf("%s", err.Error()) 2437 } 2438 if v != 1 { // TODO: need to kill the query, and v should be 0. 2439 dbt.Skipf("[WARN] expected val to be 1, got %d", v) 2440 } 2441 2442 // Context is already canceled, so error should come before execution. 2443 if _, err := dbt.db.ExecContext(ctx, "INSERT INTO test VALUES (1)"); err == nil { 2444 dbt.Error("expected error") 2445 } else if err.Error() != "context canceled" { 2446 dbt.Fatalf("unexpected error: %s", err) 2447 } 2448 2449 // The second insert query will fail, so the table has no changes. 2450 if err := dbt.db.QueryRow("SELECT COUNT(*) FROM test").Scan(&v); err != nil { 2451 dbt.Fatalf("%s", err.Error()) 2452 } 2453 if v != 1 { 2454 dbt.Skipf("[WARN] expected val to be 1, got %d", v) 2455 } 2456 }) 2457} 2458 2459func TestContextCancelQuery(t *testing.T) { 2460 runTests(t, dsn, func(dbt *DBTest) { 2461 dbt.mustExec("CREATE TABLE test (v INTEGER)") 2462 ctx, cancel := context.WithCancel(context.Background()) 2463 2464 // Delay execution for just a bit until db.ExecContext has begun. 2465 defer time.AfterFunc(250*time.Millisecond, cancel).Stop() 2466 2467 // This query will be canceled. 2468 startTime := time.Now() 2469 if _, err := dbt.db.QueryContext(ctx, "INSERT INTO test VALUES (SLEEP(1))"); err != context.Canceled { 2470 dbt.Errorf("expected context.Canceled, got %v", err) 2471 } 2472 if d := time.Since(startTime); d > 500*time.Millisecond { 2473 dbt.Errorf("too long execution time: %s", d) 2474 } 2475 2476 // Wait for the INSERT query to be done. 2477 time.Sleep(time.Second) 2478 2479 // Check how many times the query is executed. 2480 var v int 2481 if err := dbt.db.QueryRow("SELECT COUNT(*) FROM test").Scan(&v); err != nil { 2482 dbt.Fatalf("%s", err.Error()) 2483 } 2484 if v != 1 { // TODO: need to kill the query, and v should be 0. 2485 dbt.Skipf("[WARN] expected val to be 1, got %d", v) 2486 } 2487 2488 // Context is already canceled, so error should come before execution. 2489 if _, err := dbt.db.QueryContext(ctx, "INSERT INTO test VALUES (1)"); err != context.Canceled { 2490 dbt.Errorf("expected context.Canceled, got %v", err) 2491 } 2492 2493 // The second insert query will fail, so the table has no changes. 2494 if err := dbt.db.QueryRow("SELECT COUNT(*) FROM test").Scan(&v); err != nil { 2495 dbt.Fatalf("%s", err.Error()) 2496 } 2497 if v != 1 { 2498 dbt.Skipf("[WARN] expected val to be 1, got %d", v) 2499 } 2500 }) 2501} 2502 2503func TestContextCancelQueryRow(t *testing.T) { 2504 runTests(t, dsn, func(dbt *DBTest) { 2505 dbt.mustExec("CREATE TABLE test (v INTEGER)") 2506 dbt.mustExec("INSERT INTO test VALUES (1), (2), (3)") 2507 ctx, cancel := context.WithCancel(context.Background()) 2508 2509 rows, err := dbt.db.QueryContext(ctx, "SELECT v FROM test") 2510 if err != nil { 2511 dbt.Fatalf("%s", err.Error()) 2512 } 2513 2514 // the first row will be succeed. 2515 var v int 2516 if !rows.Next() { 2517 dbt.Fatalf("unexpected end") 2518 } 2519 if err := rows.Scan(&v); err != nil { 2520 dbt.Fatalf("%s", err.Error()) 2521 } 2522 2523 cancel() 2524 // make sure the driver receives the cancel request. 2525 time.Sleep(100 * time.Millisecond) 2526 2527 if rows.Next() { 2528 dbt.Errorf("expected end, but not") 2529 } 2530 if err := rows.Err(); err != context.Canceled { 2531 dbt.Errorf("expected context.Canceled, got %v", err) 2532 } 2533 }) 2534} 2535 2536func TestContextCancelPrepare(t *testing.T) { 2537 runTests(t, dsn, func(dbt *DBTest) { 2538 ctx, cancel := context.WithCancel(context.Background()) 2539 cancel() 2540 if _, err := dbt.db.PrepareContext(ctx, "SELECT 1"); err != context.Canceled { 2541 dbt.Errorf("expected context.Canceled, got %v", err) 2542 } 2543 }) 2544} 2545 2546func TestContextCancelStmtExec(t *testing.T) { 2547 runTests(t, dsn, func(dbt *DBTest) { 2548 dbt.mustExec("CREATE TABLE test (v INTEGER)") 2549 ctx, cancel := context.WithCancel(context.Background()) 2550 stmt, err := dbt.db.PrepareContext(ctx, "INSERT INTO test VALUES (SLEEP(1))") 2551 if err != nil { 2552 dbt.Fatalf("unexpected error: %v", err) 2553 } 2554 2555 // Delay execution for just a bit until db.ExecContext has begun. 2556 defer time.AfterFunc(250*time.Millisecond, cancel).Stop() 2557 2558 // This query will be canceled. 2559 startTime := time.Now() 2560 if _, err := stmt.ExecContext(ctx); err != context.Canceled { 2561 dbt.Errorf("expected context.Canceled, got %v", err) 2562 } 2563 if d := time.Since(startTime); d > 500*time.Millisecond { 2564 dbt.Errorf("too long execution time: %s", d) 2565 } 2566 2567 // Wait for the INSERT query to be done. 2568 time.Sleep(time.Second) 2569 2570 // Check how many times the query is executed. 2571 var v int 2572 if err := dbt.db.QueryRow("SELECT COUNT(*) FROM test").Scan(&v); err != nil { 2573 dbt.Fatalf("%s", err.Error()) 2574 } 2575 if v != 1 { // TODO: need to kill the query, and v should be 0. 2576 dbt.Skipf("[WARN] expected val to be 1, got %d", v) 2577 } 2578 }) 2579} 2580 2581func TestContextCancelStmtQuery(t *testing.T) { 2582 runTests(t, dsn, func(dbt *DBTest) { 2583 dbt.mustExec("CREATE TABLE test (v INTEGER)") 2584 ctx, cancel := context.WithCancel(context.Background()) 2585 stmt, err := dbt.db.PrepareContext(ctx, "INSERT INTO test VALUES (SLEEP(1))") 2586 if err != nil { 2587 dbt.Fatalf("unexpected error: %v", err) 2588 } 2589 2590 // Delay execution for just a bit until db.ExecContext has begun. 2591 defer time.AfterFunc(250*time.Millisecond, cancel).Stop() 2592 2593 // This query will be canceled. 2594 startTime := time.Now() 2595 if _, err := stmt.QueryContext(ctx); err != context.Canceled { 2596 dbt.Errorf("expected context.Canceled, got %v", err) 2597 } 2598 if d := time.Since(startTime); d > 500*time.Millisecond { 2599 dbt.Errorf("too long execution time: %s", d) 2600 } 2601 2602 // Wait for the INSERT query has done. 2603 time.Sleep(time.Second) 2604 2605 // Check how many times the query is executed. 2606 var v int 2607 if err := dbt.db.QueryRow("SELECT COUNT(*) FROM test").Scan(&v); err != nil { 2608 dbt.Fatalf("%s", err.Error()) 2609 } 2610 if v != 1 { // TODO: need to kill the query, and v should be 0. 2611 dbt.Skipf("[WARN] expected val to be 1, got %d", v) 2612 } 2613 }) 2614} 2615 2616func TestContextCancelBegin(t *testing.T) { 2617 if runtime.GOOS == "windows" || runtime.GOOS == "darwin" { 2618 t.Skip(`FIXME: it sometime fails with "expected driver.ErrBadConn, got sql: connection is already closed" on windows and macOS`) 2619 } 2620 2621 runTests(t, dsn, func(dbt *DBTest) { 2622 dbt.mustExec("CREATE TABLE test (v INTEGER)") 2623 ctx, cancel := context.WithCancel(context.Background()) 2624 conn, err := dbt.db.Conn(ctx) 2625 if err != nil { 2626 dbt.Fatal(err) 2627 } 2628 defer conn.Close() 2629 tx, err := conn.BeginTx(ctx, nil) 2630 if err != nil { 2631 dbt.Fatal(err) 2632 } 2633 2634 // Delay execution for just a bit until db.ExecContext has begun. 2635 defer time.AfterFunc(100*time.Millisecond, cancel).Stop() 2636 2637 // This query will be canceled. 2638 startTime := time.Now() 2639 if _, err := tx.ExecContext(ctx, "INSERT INTO test VALUES (SLEEP(1))"); err != context.Canceled { 2640 dbt.Errorf("expected context.Canceled, got %v", err) 2641 } 2642 if d := time.Since(startTime); d > 500*time.Millisecond { 2643 dbt.Errorf("too long execution time: %s", d) 2644 } 2645 2646 // Transaction is canceled, so expect an error. 2647 switch err := tx.Commit(); err { 2648 case sql.ErrTxDone: 2649 // because the transaction has already been rollbacked. 2650 // the database/sql package watches ctx 2651 // and rollbacks when ctx is canceled. 2652 case context.Canceled: 2653 // the database/sql package rollbacks on another goroutine, 2654 // so the transaction may not be rollbacked depending on goroutine scheduling. 2655 default: 2656 dbt.Errorf("expected sql.ErrTxDone or context.Canceled, got %v", err) 2657 } 2658 2659 // The connection is now in an inoperable state - so performing other 2660 // operations should fail with ErrBadConn 2661 // Important to exercise isolation level too - it runs SET TRANSACTION ISOLATION 2662 // LEVEL XXX first, which needs to return ErrBadConn if the connection's context 2663 // is cancelled 2664 _, err = conn.BeginTx(context.Background(), &sql.TxOptions{Isolation: sql.LevelReadCommitted}) 2665 if err != driver.ErrBadConn { 2666 dbt.Errorf("expected driver.ErrBadConn, got %v", err) 2667 } 2668 2669 // cannot begin a transaction (on a different conn) with a canceled context 2670 if _, err := dbt.db.BeginTx(ctx, nil); err != context.Canceled { 2671 dbt.Errorf("expected context.Canceled, got %v", err) 2672 } 2673 }) 2674} 2675 2676func TestContextBeginIsolationLevel(t *testing.T) { 2677 runTests(t, dsn, func(dbt *DBTest) { 2678 dbt.mustExec("CREATE TABLE test (v INTEGER)") 2679 ctx, cancel := context.WithCancel(context.Background()) 2680 defer cancel() 2681 2682 tx1, err := dbt.db.BeginTx(ctx, &sql.TxOptions{ 2683 Isolation: sql.LevelRepeatableRead, 2684 }) 2685 if err != nil { 2686 dbt.Fatal(err) 2687 } 2688 2689 tx2, err := dbt.db.BeginTx(ctx, &sql.TxOptions{ 2690 Isolation: sql.LevelReadCommitted, 2691 }) 2692 if err != nil { 2693 dbt.Fatal(err) 2694 } 2695 2696 _, err = tx1.ExecContext(ctx, "INSERT INTO test VALUES (1)") 2697 if err != nil { 2698 dbt.Fatal(err) 2699 } 2700 2701 var v int 2702 row := tx2.QueryRowContext(ctx, "SELECT COUNT(*) FROM test") 2703 if err := row.Scan(&v); err != nil { 2704 dbt.Fatal(err) 2705 } 2706 // Because writer transaction wasn't commited yet, it should be available 2707 if v != 0 { 2708 dbt.Errorf("expected val to be 0, got %d", v) 2709 } 2710 2711 err = tx1.Commit() 2712 if err != nil { 2713 dbt.Fatal(err) 2714 } 2715 2716 row = tx2.QueryRowContext(ctx, "SELECT COUNT(*) FROM test") 2717 if err := row.Scan(&v); err != nil { 2718 dbt.Fatal(err) 2719 } 2720 // Data written by writer transaction is already commited, it should be selectable 2721 if v != 1 { 2722 dbt.Errorf("expected val to be 1, got %d", v) 2723 } 2724 tx2.Commit() 2725 }) 2726} 2727 2728func TestContextBeginReadOnly(t *testing.T) { 2729 runTests(t, dsn, func(dbt *DBTest) { 2730 dbt.mustExec("CREATE TABLE test (v INTEGER)") 2731 ctx, cancel := context.WithCancel(context.Background()) 2732 defer cancel() 2733 2734 tx, err := dbt.db.BeginTx(ctx, &sql.TxOptions{ 2735 ReadOnly: true, 2736 }) 2737 if _, ok := err.(*MySQLError); ok { 2738 dbt.Skip("It seems that your MySQL does not support READ ONLY transactions") 2739 return 2740 } else if err != nil { 2741 dbt.Fatal(err) 2742 } 2743 2744 // INSERT queries fail in a READ ONLY transaction. 2745 _, err = tx.ExecContext(ctx, "INSERT INTO test VALUES (1)") 2746 if _, ok := err.(*MySQLError); !ok { 2747 dbt.Errorf("expected MySQLError, got %v", err) 2748 } 2749 2750 // SELECT queries can be executed. 2751 var v int 2752 row := tx.QueryRowContext(ctx, "SELECT COUNT(*) FROM test") 2753 if err := row.Scan(&v); err != nil { 2754 dbt.Fatal(err) 2755 } 2756 if v != 0 { 2757 dbt.Errorf("expected val to be 0, got %d", v) 2758 } 2759 2760 if err := tx.Commit(); err != nil { 2761 dbt.Fatal(err) 2762 } 2763 }) 2764} 2765 2766func TestRowsColumnTypes(t *testing.T) { 2767 niNULL := sql.NullInt64{Int64: 0, Valid: false} 2768 ni0 := sql.NullInt64{Int64: 0, Valid: true} 2769 ni1 := sql.NullInt64{Int64: 1, Valid: true} 2770 ni42 := sql.NullInt64{Int64: 42, Valid: true} 2771 nfNULL := sql.NullFloat64{Float64: 0.0, Valid: false} 2772 nf0 := sql.NullFloat64{Float64: 0.0, Valid: true} 2773 nf1337 := sql.NullFloat64{Float64: 13.37, Valid: true} 2774 nt0 := nullTime{Time: time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC), Valid: true} 2775 nt1 := nullTime{Time: time.Date(2006, 01, 02, 15, 04, 05, 100000000, time.UTC), Valid: true} 2776 nt2 := nullTime{Time: time.Date(2006, 01, 02, 15, 04, 05, 110000000, time.UTC), Valid: true} 2777 nt6 := nullTime{Time: time.Date(2006, 01, 02, 15, 04, 05, 111111000, time.UTC), Valid: true} 2778 nd1 := nullTime{Time: time.Date(2006, 01, 02, 0, 0, 0, 0, time.UTC), Valid: true} 2779 nd2 := nullTime{Time: time.Date(2006, 03, 04, 0, 0, 0, 0, time.UTC), Valid: true} 2780 ndNULL := nullTime{Time: time.Time{}, Valid: false} 2781 rbNULL := sql.RawBytes(nil) 2782 rb0 := sql.RawBytes("0") 2783 rb42 := sql.RawBytes("42") 2784 rbTest := sql.RawBytes("Test") 2785 rb0pad4 := sql.RawBytes("0\x00\x00\x00") // BINARY right-pads values with 0x00 2786 rbx0 := sql.RawBytes("\x00") 2787 rbx42 := sql.RawBytes("\x42") 2788 2789 var columns = []struct { 2790 name string 2791 fieldType string // type used when creating table schema 2792 databaseTypeName string // actual type used by MySQL 2793 scanType reflect.Type 2794 nullable bool 2795 precision int64 // 0 if not ok 2796 scale int64 2797 valuesIn [3]string 2798 valuesOut [3]interface{} 2799 }{ 2800 {"bit8null", "BIT(8)", "BIT", scanTypeRawBytes, true, 0, 0, [3]string{"0x0", "NULL", "0x42"}, [3]interface{}{rbx0, rbNULL, rbx42}}, 2801 {"boolnull", "BOOL", "TINYINT", scanTypeNullInt, true, 0, 0, [3]string{"NULL", "true", "0"}, [3]interface{}{niNULL, ni1, ni0}}, 2802 {"bool", "BOOL NOT NULL", "TINYINT", scanTypeInt8, false, 0, 0, [3]string{"1", "0", "FALSE"}, [3]interface{}{int8(1), int8(0), int8(0)}}, 2803 {"intnull", "INTEGER", "INT", scanTypeNullInt, true, 0, 0, [3]string{"0", "NULL", "42"}, [3]interface{}{ni0, niNULL, ni42}}, 2804 {"smallint", "SMALLINT NOT NULL", "SMALLINT", scanTypeInt16, false, 0, 0, [3]string{"0", "-32768", "32767"}, [3]interface{}{int16(0), int16(-32768), int16(32767)}}, 2805 {"smallintnull", "SMALLINT", "SMALLINT", scanTypeNullInt, true, 0, 0, [3]string{"0", "NULL", "42"}, [3]interface{}{ni0, niNULL, ni42}}, 2806 {"int3null", "INT(3)", "INT", scanTypeNullInt, true, 0, 0, [3]string{"0", "NULL", "42"}, [3]interface{}{ni0, niNULL, ni42}}, 2807 {"int7", "INT(7) NOT NULL", "INT", scanTypeInt32, false, 0, 0, [3]string{"0", "-1337", "42"}, [3]interface{}{int32(0), int32(-1337), int32(42)}}, 2808 {"mediumintnull", "MEDIUMINT", "MEDIUMINT", scanTypeNullInt, true, 0, 0, [3]string{"0", "42", "NULL"}, [3]interface{}{ni0, ni42, niNULL}}, 2809 {"bigint", "BIGINT NOT NULL", "BIGINT", scanTypeInt64, false, 0, 0, [3]string{"0", "65535", "-42"}, [3]interface{}{int64(0), int64(65535), int64(-42)}}, 2810 {"bigintnull", "BIGINT", "BIGINT", scanTypeNullInt, true, 0, 0, [3]string{"NULL", "1", "42"}, [3]interface{}{niNULL, ni1, ni42}}, 2811 {"tinyuint", "TINYINT UNSIGNED NOT NULL", "TINYINT", scanTypeUint8, false, 0, 0, [3]string{"0", "255", "42"}, [3]interface{}{uint8(0), uint8(255), uint8(42)}}, 2812 {"smalluint", "SMALLINT UNSIGNED NOT NULL", "SMALLINT", scanTypeUint16, false, 0, 0, [3]string{"0", "65535", "42"}, [3]interface{}{uint16(0), uint16(65535), uint16(42)}}, 2813 {"biguint", "BIGINT UNSIGNED NOT NULL", "BIGINT", scanTypeUint64, false, 0, 0, [3]string{"0", "65535", "42"}, [3]interface{}{uint64(0), uint64(65535), uint64(42)}}, 2814 {"uint13", "INT(13) UNSIGNED NOT NULL", "INT", scanTypeUint32, false, 0, 0, [3]string{"0", "1337", "42"}, [3]interface{}{uint32(0), uint32(1337), uint32(42)}}, 2815 {"float", "FLOAT NOT NULL", "FLOAT", scanTypeFloat32, false, math.MaxInt64, math.MaxInt64, [3]string{"0", "42", "13.37"}, [3]interface{}{float32(0), float32(42), float32(13.37)}}, 2816 {"floatnull", "FLOAT", "FLOAT", scanTypeNullFloat, true, math.MaxInt64, math.MaxInt64, [3]string{"0", "NULL", "13.37"}, [3]interface{}{nf0, nfNULL, nf1337}}, 2817 {"float74null", "FLOAT(7,4)", "FLOAT", scanTypeNullFloat, true, math.MaxInt64, 4, [3]string{"0", "NULL", "13.37"}, [3]interface{}{nf0, nfNULL, nf1337}}, 2818 {"double", "DOUBLE NOT NULL", "DOUBLE", scanTypeFloat64, false, math.MaxInt64, math.MaxInt64, [3]string{"0", "42", "13.37"}, [3]interface{}{float64(0), float64(42), float64(13.37)}}, 2819 {"doublenull", "DOUBLE", "DOUBLE", scanTypeNullFloat, true, math.MaxInt64, math.MaxInt64, [3]string{"0", "NULL", "13.37"}, [3]interface{}{nf0, nfNULL, nf1337}}, 2820 {"decimal1", "DECIMAL(10,6) NOT NULL", "DECIMAL", scanTypeRawBytes, false, 10, 6, [3]string{"0", "13.37", "1234.123456"}, [3]interface{}{sql.RawBytes("0.000000"), sql.RawBytes("13.370000"), sql.RawBytes("1234.123456")}}, 2821 {"decimal1null", "DECIMAL(10,6)", "DECIMAL", scanTypeRawBytes, true, 10, 6, [3]string{"0", "NULL", "1234.123456"}, [3]interface{}{sql.RawBytes("0.000000"), rbNULL, sql.RawBytes("1234.123456")}}, 2822 {"decimal2", "DECIMAL(8,4) NOT NULL", "DECIMAL", scanTypeRawBytes, false, 8, 4, [3]string{"0", "13.37", "1234.123456"}, [3]interface{}{sql.RawBytes("0.0000"), sql.RawBytes("13.3700"), sql.RawBytes("1234.1235")}}, 2823 {"decimal2null", "DECIMAL(8,4)", "DECIMAL", scanTypeRawBytes, true, 8, 4, [3]string{"0", "NULL", "1234.123456"}, [3]interface{}{sql.RawBytes("0.0000"), rbNULL, sql.RawBytes("1234.1235")}}, 2824 {"decimal3", "DECIMAL(5,0) NOT NULL", "DECIMAL", scanTypeRawBytes, false, 5, 0, [3]string{"0", "13.37", "-12345.123456"}, [3]interface{}{rb0, sql.RawBytes("13"), sql.RawBytes("-12345")}}, 2825 {"decimal3null", "DECIMAL(5,0)", "DECIMAL", scanTypeRawBytes, true, 5, 0, [3]string{"0", "NULL", "-12345.123456"}, [3]interface{}{rb0, rbNULL, sql.RawBytes("-12345")}}, 2826 {"char25null", "CHAR(25)", "CHAR", scanTypeRawBytes, true, 0, 0, [3]string{"0", "NULL", "'Test'"}, [3]interface{}{rb0, rbNULL, rbTest}}, 2827 {"varchar42", "VARCHAR(42) NOT NULL", "VARCHAR", scanTypeRawBytes, false, 0, 0, [3]string{"0", "'Test'", "42"}, [3]interface{}{rb0, rbTest, rb42}}, 2828 {"binary4null", "BINARY(4)", "BINARY", scanTypeRawBytes, true, 0, 0, [3]string{"0", "NULL", "'Test'"}, [3]interface{}{rb0pad4, rbNULL, rbTest}}, 2829 {"varbinary42", "VARBINARY(42) NOT NULL", "VARBINARY", scanTypeRawBytes, false, 0, 0, [3]string{"0", "'Test'", "42"}, [3]interface{}{rb0, rbTest, rb42}}, 2830 {"tinyblobnull", "TINYBLOB", "BLOB", scanTypeRawBytes, true, 0, 0, [3]string{"0", "NULL", "'Test'"}, [3]interface{}{rb0, rbNULL, rbTest}}, 2831 {"tinytextnull", "TINYTEXT", "TEXT", scanTypeRawBytes, true, 0, 0, [3]string{"0", "NULL", "'Test'"}, [3]interface{}{rb0, rbNULL, rbTest}}, 2832 {"blobnull", "BLOB", "BLOB", scanTypeRawBytes, true, 0, 0, [3]string{"0", "NULL", "'Test'"}, [3]interface{}{rb0, rbNULL, rbTest}}, 2833 {"textnull", "TEXT", "TEXT", scanTypeRawBytes, true, 0, 0, [3]string{"0", "NULL", "'Test'"}, [3]interface{}{rb0, rbNULL, rbTest}}, 2834 {"mediumblob", "MEDIUMBLOB NOT NULL", "BLOB", scanTypeRawBytes, false, 0, 0, [3]string{"0", "'Test'", "42"}, [3]interface{}{rb0, rbTest, rb42}}, 2835 {"mediumtext", "MEDIUMTEXT NOT NULL", "TEXT", scanTypeRawBytes, false, 0, 0, [3]string{"0", "'Test'", "42"}, [3]interface{}{rb0, rbTest, rb42}}, 2836 {"longblob", "LONGBLOB NOT NULL", "BLOB", scanTypeRawBytes, false, 0, 0, [3]string{"0", "'Test'", "42"}, [3]interface{}{rb0, rbTest, rb42}}, 2837 {"longtext", "LONGTEXT NOT NULL", "TEXT", scanTypeRawBytes, false, 0, 0, [3]string{"0", "'Test'", "42"}, [3]interface{}{rb0, rbTest, rb42}}, 2838 {"datetime", "DATETIME", "DATETIME", scanTypeNullTime, true, 0, 0, [3]string{"'2006-01-02 15:04:05'", "'2006-01-02 15:04:05.1'", "'2006-01-02 15:04:05.111111'"}, [3]interface{}{nt0, nt0, nt0}}, 2839 {"datetime2", "DATETIME(2)", "DATETIME", scanTypeNullTime, true, 2, 2, [3]string{"'2006-01-02 15:04:05'", "'2006-01-02 15:04:05.1'", "'2006-01-02 15:04:05.111111'"}, [3]interface{}{nt0, nt1, nt2}}, 2840 {"datetime6", "DATETIME(6)", "DATETIME", scanTypeNullTime, true, 6, 6, [3]string{"'2006-01-02 15:04:05'", "'2006-01-02 15:04:05.1'", "'2006-01-02 15:04:05.111111'"}, [3]interface{}{nt0, nt1, nt6}}, 2841 {"date", "DATE", "DATE", scanTypeNullTime, true, 0, 0, [3]string{"'2006-01-02'", "NULL", "'2006-03-04'"}, [3]interface{}{nd1, ndNULL, nd2}}, 2842 {"year", "YEAR NOT NULL", "YEAR", scanTypeUint16, false, 0, 0, [3]string{"2006", "2000", "1994"}, [3]interface{}{uint16(2006), uint16(2000), uint16(1994)}}, 2843 } 2844 2845 schema := "" 2846 values1 := "" 2847 values2 := "" 2848 values3 := "" 2849 for _, column := range columns { 2850 schema += fmt.Sprintf("`%s` %s, ", column.name, column.fieldType) 2851 values1 += column.valuesIn[0] + ", " 2852 values2 += column.valuesIn[1] + ", " 2853 values3 += column.valuesIn[2] + ", " 2854 } 2855 schema = schema[:len(schema)-2] 2856 values1 = values1[:len(values1)-2] 2857 values2 = values2[:len(values2)-2] 2858 values3 = values3[:len(values3)-2] 2859 2860 runTests(t, dsn+"&parseTime=true", func(dbt *DBTest) { 2861 dbt.mustExec("CREATE TABLE test (" + schema + ")") 2862 dbt.mustExec("INSERT INTO test VALUES (" + values1 + "), (" + values2 + "), (" + values3 + ")") 2863 2864 rows, err := dbt.db.Query("SELECT * FROM test") 2865 if err != nil { 2866 t.Fatalf("Query: %v", err) 2867 } 2868 2869 tt, err := rows.ColumnTypes() 2870 if err != nil { 2871 t.Fatalf("ColumnTypes: %v", err) 2872 } 2873 2874 if len(tt) != len(columns) { 2875 t.Fatalf("unexpected number of columns: expected %d, got %d", len(columns), len(tt)) 2876 } 2877 2878 types := make([]reflect.Type, len(tt)) 2879 for i, tp := range tt { 2880 column := columns[i] 2881 2882 // Name 2883 name := tp.Name() 2884 if name != column.name { 2885 t.Errorf("column name mismatch %s != %s", name, column.name) 2886 continue 2887 } 2888 2889 // DatabaseTypeName 2890 databaseTypeName := tp.DatabaseTypeName() 2891 if databaseTypeName != column.databaseTypeName { 2892 t.Errorf("databasetypename name mismatch for column %q: %s != %s", name, databaseTypeName, column.databaseTypeName) 2893 continue 2894 } 2895 2896 // ScanType 2897 scanType := tp.ScanType() 2898 if scanType != column.scanType { 2899 if scanType == nil { 2900 t.Errorf("scantype is null for column %q", name) 2901 } else { 2902 t.Errorf("scantype mismatch for column %q: %s != %s", name, scanType.Name(), column.scanType.Name()) 2903 } 2904 continue 2905 } 2906 types[i] = scanType 2907 2908 // Nullable 2909 nullable, ok := tp.Nullable() 2910 if !ok { 2911 t.Errorf("nullable not ok %q", name) 2912 continue 2913 } 2914 if nullable != column.nullable { 2915 t.Errorf("nullable mismatch for column %q: %t != %t", name, nullable, column.nullable) 2916 } 2917 2918 // Length 2919 // length, ok := tp.Length() 2920 // if length != column.length { 2921 // if !ok { 2922 // t.Errorf("length not ok for column %q", name) 2923 // } else { 2924 // t.Errorf("length mismatch for column %q: %d != %d", name, length, column.length) 2925 // } 2926 // continue 2927 // } 2928 2929 // Precision and Scale 2930 precision, scale, ok := tp.DecimalSize() 2931 if precision != column.precision { 2932 if !ok { 2933 t.Errorf("precision not ok for column %q", name) 2934 } else { 2935 t.Errorf("precision mismatch for column %q: %d != %d", name, precision, column.precision) 2936 } 2937 continue 2938 } 2939 if scale != column.scale { 2940 if !ok { 2941 t.Errorf("scale not ok for column %q", name) 2942 } else { 2943 t.Errorf("scale mismatch for column %q: %d != %d", name, scale, column.scale) 2944 } 2945 continue 2946 } 2947 } 2948 2949 values := make([]interface{}, len(tt)) 2950 for i := range values { 2951 values[i] = reflect.New(types[i]).Interface() 2952 } 2953 i := 0 2954 for rows.Next() { 2955 err = rows.Scan(values...) 2956 if err != nil { 2957 t.Fatalf("failed to scan values in %v", err) 2958 } 2959 for j := range values { 2960 value := reflect.ValueOf(values[j]).Elem().Interface() 2961 if !reflect.DeepEqual(value, columns[j].valuesOut[i]) { 2962 if columns[j].scanType == scanTypeRawBytes { 2963 t.Errorf("row %d, column %d: %v != %v", i, j, string(value.(sql.RawBytes)), string(columns[j].valuesOut[i].(sql.RawBytes))) 2964 } else { 2965 t.Errorf("row %d, column %d: %v != %v", i, j, value, columns[j].valuesOut[i]) 2966 } 2967 } 2968 } 2969 i++ 2970 } 2971 if i != 3 { 2972 t.Errorf("expected 3 rows, got %d", i) 2973 } 2974 2975 if err := rows.Close(); err != nil { 2976 t.Errorf("error closing rows: %s", err) 2977 } 2978 }) 2979} 2980 2981func TestValuerWithValueReceiverGivenNilValue(t *testing.T) { 2982 runTests(t, dsn, func(dbt *DBTest) { 2983 dbt.mustExec("CREATE TABLE test (value VARCHAR(255))") 2984 dbt.db.Exec("INSERT INTO test VALUES (?)", (*testValuer)(nil)) 2985 // This test will panic on the INSERT if ConvertValue() does not check for typed nil before calling Value() 2986 }) 2987} 2988 2989// TestRawBytesAreNotModified checks for a race condition that arises when a query context 2990// is canceled while a user is calling rows.Scan. This is a more stringent test than the one 2991// proposed in https://github.com/golang/go/issues/23519. Here we're explicitly using 2992// `sql.RawBytes` to check the contents of our internal buffers are not modified after an implicit 2993// call to `Rows.Close`, so Context cancellation should **not** invalidate the backing buffers. 2994func TestRawBytesAreNotModified(t *testing.T) { 2995 const blob = "abcdefghijklmnop" 2996 const contextRaceIterations = 20 2997 const blobSize = defaultBufSize * 3 / 4 // Second row overwrites first row. 2998 const insertRows = 4 2999 3000 var sqlBlobs = [2]string{ 3001 strings.Repeat(blob, blobSize/len(blob)), 3002 strings.Repeat(strings.ToUpper(blob), blobSize/len(blob)), 3003 } 3004 3005 runTests(t, dsn, func(dbt *DBTest) { 3006 dbt.mustExec("CREATE TABLE test (id int, value BLOB) CHARACTER SET utf8") 3007 for i := 0; i < insertRows; i++ { 3008 dbt.mustExec("INSERT INTO test VALUES (?, ?)", i+1, sqlBlobs[i&1]) 3009 } 3010 3011 for i := 0; i < contextRaceIterations; i++ { 3012 func() { 3013 ctx, cancel := context.WithCancel(context.Background()) 3014 defer cancel() 3015 3016 rows, err := dbt.db.QueryContext(ctx, `SELECT id, value FROM test`) 3017 if err != nil { 3018 t.Fatal(err) 3019 } 3020 3021 var b int 3022 var raw sql.RawBytes 3023 for rows.Next() { 3024 if err := rows.Scan(&b, &raw); err != nil { 3025 t.Fatal(err) 3026 } 3027 3028 before := string(raw) 3029 // Ensure cancelling the query does not corrupt the contents of `raw` 3030 cancel() 3031 time.Sleep(time.Microsecond * 100) 3032 after := string(raw) 3033 3034 if before != after { 3035 t.Fatalf("the backing storage for sql.RawBytes has been modified (i=%v)", i) 3036 } 3037 } 3038 rows.Close() 3039 }() 3040 } 3041 }) 3042} 3043 3044var _ driver.DriverContext = &MySQLDriver{} 3045 3046type dialCtxKey struct{} 3047 3048func TestConnectorObeysDialTimeouts(t *testing.T) { 3049 if !available { 3050 t.Skipf("MySQL server not running on %s", netAddr) 3051 } 3052 3053 RegisterDialContext("dialctxtest", func(ctx context.Context, addr string) (net.Conn, error) { 3054 var d net.Dialer 3055 if !ctx.Value(dialCtxKey{}).(bool) { 3056 return nil, fmt.Errorf("test error: query context is not propagated to our dialer") 3057 } 3058 return d.DialContext(ctx, prot, addr) 3059 }) 3060 3061 db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@dialctxtest(%s)/%s?timeout=30s", user, pass, addr, dbname)) 3062 if err != nil { 3063 t.Fatalf("error connecting: %s", err.Error()) 3064 } 3065 defer db.Close() 3066 3067 ctx := context.WithValue(context.Background(), dialCtxKey{}, true) 3068 3069 _, err = db.ExecContext(ctx, "DO 1") 3070 if err != nil { 3071 t.Fatal(err) 3072 } 3073} 3074 3075func configForTests(t *testing.T) *Config { 3076 if !available { 3077 t.Skipf("MySQL server not running on %s", netAddr) 3078 } 3079 3080 mycnf := NewConfig() 3081 mycnf.User = user 3082 mycnf.Passwd = pass 3083 mycnf.Addr = addr 3084 mycnf.Net = prot 3085 mycnf.DBName = dbname 3086 return mycnf 3087} 3088 3089func TestNewConnector(t *testing.T) { 3090 mycnf := configForTests(t) 3091 conn, err := NewConnector(mycnf) 3092 if err != nil { 3093 t.Fatal(err) 3094 } 3095 3096 db := sql.OpenDB(conn) 3097 defer db.Close() 3098 3099 if err := db.Ping(); err != nil { 3100 t.Fatal(err) 3101 } 3102} 3103 3104type slowConnection struct { 3105 net.Conn 3106 slowdown time.Duration 3107} 3108 3109func (sc *slowConnection) Read(b []byte) (int, error) { 3110 time.Sleep(sc.slowdown) 3111 return sc.Conn.Read(b) 3112} 3113 3114type connectorHijack struct { 3115 driver.Connector 3116 connErr error 3117} 3118 3119func (cw *connectorHijack) Connect(ctx context.Context) (driver.Conn, error) { 3120 var conn driver.Conn 3121 conn, cw.connErr = cw.Connector.Connect(ctx) 3122 return conn, cw.connErr 3123} 3124 3125func TestConnectorTimeoutsDuringOpen(t *testing.T) { 3126 RegisterDialContext("slowconn", func(ctx context.Context, addr string) (net.Conn, error) { 3127 var d net.Dialer 3128 conn, err := d.DialContext(ctx, prot, addr) 3129 if err != nil { 3130 return nil, err 3131 } 3132 return &slowConnection{Conn: conn, slowdown: 100 * time.Millisecond}, nil 3133 }) 3134 3135 mycnf := configForTests(t) 3136 mycnf.Net = "slowconn" 3137 3138 conn, err := NewConnector(mycnf) 3139 if err != nil { 3140 t.Fatal(err) 3141 } 3142 3143 hijack := &connectorHijack{Connector: conn} 3144 3145 db := sql.OpenDB(hijack) 3146 defer db.Close() 3147 3148 ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond) 3149 defer cancel() 3150 3151 _, err = db.ExecContext(ctx, "DO 1") 3152 if err != context.DeadlineExceeded { 3153 t.Fatalf("ExecContext should have timed out") 3154 } 3155 if hijack.connErr != context.DeadlineExceeded { 3156 t.Fatalf("(*Connector).Connect should have timed out") 3157 } 3158} 3159 3160// A connection which can only be closed. 3161type dummyConnection struct { 3162 net.Conn 3163 closed bool 3164} 3165 3166func (d *dummyConnection) Close() error { 3167 d.closed = true 3168 return nil 3169} 3170 3171func TestConnectorTimeoutsWatchCancel(t *testing.T) { 3172 var ( 3173 cancel func() // Used to cancel the context just after connecting. 3174 created *dummyConnection // The created connection. 3175 ) 3176 3177 RegisterDialContext("TestConnectorTimeoutsWatchCancel", func(ctx context.Context, addr string) (net.Conn, error) { 3178 // Canceling at this time triggers the watchCancel error branch in Connect(). 3179 cancel() 3180 created = &dummyConnection{} 3181 return created, nil 3182 }) 3183 3184 mycnf := NewConfig() 3185 mycnf.User = "root" 3186 mycnf.Addr = "foo" 3187 mycnf.Net = "TestConnectorTimeoutsWatchCancel" 3188 3189 conn, err := NewConnector(mycnf) 3190 if err != nil { 3191 t.Fatal(err) 3192 } 3193 3194 db := sql.OpenDB(conn) 3195 defer db.Close() 3196 3197 var ctx context.Context 3198 ctx, cancel = context.WithCancel(context.Background()) 3199 defer cancel() 3200 3201 if _, err := db.Conn(ctx); err != context.Canceled { 3202 t.Errorf("got %v, want context.Canceled", err) 3203 } 3204 3205 if created == nil { 3206 t.Fatal("no connection created") 3207 } 3208 if !created.closed { 3209 t.Errorf("connection not closed") 3210 } 3211} 3212