github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/go-sql-driver/mysql/driver_test.go (about) 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 9 package mysql 10 11 import ( 12 "bytes" 13 "crypto/tls" 14 "database/sql" 15 "database/sql/driver" 16 "fmt" 17 "io" 18 "io/ioutil" 19 "log" 20 "net" 21 "net/url" 22 "os" 23 "strings" 24 "sync" 25 "sync/atomic" 26 "testing" 27 "time" 28 ) 29 30 var ( 31 user string 32 pass string 33 prot string 34 addr string 35 dbname string 36 dsn string 37 netAddr string 38 available bool 39 ) 40 41 var ( 42 tDate = time.Date(2012, 6, 14, 0, 0, 0, 0, time.UTC) 43 sDate = "2012-06-14" 44 tDateTime = time.Date(2011, 11, 20, 21, 27, 37, 0, time.UTC) 45 sDateTime = "2011-11-20 21:27:37" 46 tDate0 = time.Time{} 47 sDate0 = "0000-00-00" 48 sDateTime0 = "0000-00-00 00:00:00" 49 ) 50 51 // See https://yougam/libraries/go-sql-driver/mysql/wiki/Testing 52 func init() { 53 // get environment variables 54 env := func(key, defaultValue string) string { 55 if value := os.Getenv(key); value != "" { 56 return value 57 } 58 return defaultValue 59 } 60 user = env("MYSQL_TEST_USER", "root") 61 pass = env("MYSQL_TEST_PASS", "") 62 prot = env("MYSQL_TEST_PROT", "tcp") 63 addr = env("MYSQL_TEST_ADDR", "localhost:3306") 64 dbname = env("MYSQL_TEST_DBNAME", "gotest") 65 netAddr = fmt.Sprintf("%s(%s)", prot, addr) 66 dsn = fmt.Sprintf("%s:%s@%s/%s?timeout=30s&strict=true", user, pass, netAddr, dbname) 67 c, err := net.Dial(prot, addr) 68 if err == nil { 69 available = true 70 c.Close() 71 } 72 } 73 74 type DBTest struct { 75 *testing.T 76 db *sql.DB 77 } 78 79 func runTestsWithMultiStatement(t *testing.T, dsn string, tests ...func(dbt *DBTest)) { 80 if !available { 81 t.Skipf("MySQL server not running on %s", netAddr) 82 } 83 84 dsn += "&multiStatements=true" 85 var db *sql.DB 86 if _, err := ParseDSN(dsn); err != errInvalidDSNUnsafeCollation { 87 db, err = sql.Open("mysql", dsn) 88 if err != nil { 89 t.Fatalf("error connecting: %s", err.Error()) 90 } 91 defer db.Close() 92 } 93 94 dbt := &DBTest{t, db} 95 for _, test := range tests { 96 test(dbt) 97 dbt.db.Exec("DROP TABLE IF EXISTS test") 98 } 99 } 100 101 func runTests(t *testing.T, dsn string, tests ...func(dbt *DBTest)) { 102 if !available { 103 t.Skipf("MySQL server not running on %s", netAddr) 104 } 105 106 db, err := sql.Open("mysql", dsn) 107 if err != nil { 108 t.Fatalf("error connecting: %s", err.Error()) 109 } 110 defer db.Close() 111 112 db.Exec("DROP TABLE IF EXISTS test") 113 114 dsn2 := dsn + "&interpolateParams=true" 115 var db2 *sql.DB 116 if _, err := ParseDSN(dsn2); err != errInvalidDSNUnsafeCollation { 117 db2, err = sql.Open("mysql", dsn2) 118 if err != nil { 119 t.Fatalf("error connecting: %s", err.Error()) 120 } 121 defer db2.Close() 122 } 123 124 dsn3 := dsn + "&multiStatements=true" 125 var db3 *sql.DB 126 if _, err := ParseDSN(dsn3); err != errInvalidDSNUnsafeCollation { 127 db3, err = sql.Open("mysql", dsn3) 128 if err != nil { 129 t.Fatalf("error connecting: %s", err.Error()) 130 } 131 defer db3.Close() 132 } 133 134 dbt := &DBTest{t, db} 135 dbt2 := &DBTest{t, db2} 136 dbt3 := &DBTest{t, db3} 137 for _, test := range tests { 138 test(dbt) 139 dbt.db.Exec("DROP TABLE IF EXISTS test") 140 if db2 != nil { 141 test(dbt2) 142 dbt2.db.Exec("DROP TABLE IF EXISTS test") 143 } 144 if db3 != nil { 145 test(dbt3) 146 dbt3.db.Exec("DROP TABLE IF EXISTS test") 147 } 148 } 149 } 150 151 func (dbt *DBTest) fail(method, query string, err error) { 152 if len(query) > 300 { 153 query = "[query too large to print]" 154 } 155 dbt.Fatalf("error on %s %s: %s", method, query, err.Error()) 156 } 157 158 func (dbt *DBTest) mustExec(query string, args ...interface{}) (res sql.Result) { 159 res, err := dbt.db.Exec(query, args...) 160 if err != nil { 161 dbt.fail("exec", query, err) 162 } 163 return res 164 } 165 166 func (dbt *DBTest) mustQuery(query string, args ...interface{}) (rows *sql.Rows) { 167 rows, err := dbt.db.Query(query, args...) 168 if err != nil { 169 dbt.fail("query", query, err) 170 } 171 return rows 172 } 173 174 func TestEmptyQuery(t *testing.T) { 175 runTests(t, dsn, func(dbt *DBTest) { 176 // just a comment, no query 177 rows := dbt.mustQuery("--") 178 // will hang before #255 179 if rows.Next() { 180 dbt.Errorf("next on rows must be false") 181 } 182 }) 183 } 184 185 func TestCRUD(t *testing.T) { 186 runTests(t, dsn, func(dbt *DBTest) { 187 // Create Table 188 dbt.mustExec("CREATE TABLE test (value BOOL)") 189 190 // Test for unexpected data 191 var out bool 192 rows := dbt.mustQuery("SELECT * FROM test") 193 if rows.Next() { 194 dbt.Error("unexpected data in empty table") 195 } 196 197 // Create Data 198 res := dbt.mustExec("INSERT INTO test VALUES (1)") 199 count, err := res.RowsAffected() 200 if err != nil { 201 dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error()) 202 } 203 if count != 1 { 204 dbt.Fatalf("expected 1 affected row, got %d", count) 205 } 206 207 id, err := res.LastInsertId() 208 if err != nil { 209 dbt.Fatalf("res.LastInsertId() returned error: %s", err.Error()) 210 } 211 if id != 0 { 212 dbt.Fatalf("expected InsertId 0, got %d", id) 213 } 214 215 // Read 216 rows = dbt.mustQuery("SELECT value FROM test") 217 if rows.Next() { 218 rows.Scan(&out) 219 if true != out { 220 dbt.Errorf("true != %t", out) 221 } 222 223 if rows.Next() { 224 dbt.Error("unexpected data") 225 } 226 } else { 227 dbt.Error("no data") 228 } 229 230 // Update 231 res = dbt.mustExec("UPDATE test SET value = ? WHERE value = ?", false, true) 232 count, err = res.RowsAffected() 233 if err != nil { 234 dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error()) 235 } 236 if count != 1 { 237 dbt.Fatalf("expected 1 affected row, got %d", count) 238 } 239 240 // Check Update 241 rows = dbt.mustQuery("SELECT value FROM test") 242 if rows.Next() { 243 rows.Scan(&out) 244 if false != out { 245 dbt.Errorf("false != %t", out) 246 } 247 248 if rows.Next() { 249 dbt.Error("unexpected data") 250 } 251 } else { 252 dbt.Error("no data") 253 } 254 255 // Delete 256 res = dbt.mustExec("DELETE FROM test WHERE value = ?", false) 257 count, err = res.RowsAffected() 258 if err != nil { 259 dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error()) 260 } 261 if count != 1 { 262 dbt.Fatalf("expected 1 affected row, got %d", count) 263 } 264 265 // Check for unexpected rows 266 res = dbt.mustExec("DELETE FROM test") 267 count, err = res.RowsAffected() 268 if err != nil { 269 dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error()) 270 } 271 if count != 0 { 272 dbt.Fatalf("expected 0 affected row, got %d", count) 273 } 274 }) 275 } 276 277 func TestMultiQuery(t *testing.T) { 278 runTestsWithMultiStatement(t, dsn, func(dbt *DBTest) { 279 // Create Table 280 dbt.mustExec("CREATE TABLE `test` (`id` int(11) NOT NULL, `value` int(11) NOT NULL) ") 281 282 // Create Data 283 res := dbt.mustExec("INSERT INTO test VALUES (1, 1)") 284 count, err := res.RowsAffected() 285 if err != nil { 286 dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error()) 287 } 288 if count != 1 { 289 dbt.Fatalf("expected 1 affected row, got %d", count) 290 } 291 292 // Update 293 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;") 294 count, err = res.RowsAffected() 295 if err != nil { 296 dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error()) 297 } 298 if count != 1 { 299 dbt.Fatalf("expected 1 affected row, got %d", count) 300 } 301 302 // Read 303 var out int 304 rows := dbt.mustQuery("SELECT value FROM test WHERE id=1;") 305 if rows.Next() { 306 rows.Scan(&out) 307 if 5 != out { 308 dbt.Errorf("5 != %d", out) 309 } 310 311 if rows.Next() { 312 dbt.Error("unexpected data") 313 } 314 } else { 315 dbt.Error("no data") 316 } 317 318 }) 319 } 320 321 func TestInt(t *testing.T) { 322 runTests(t, dsn, func(dbt *DBTest) { 323 types := [5]string{"TINYINT", "SMALLINT", "MEDIUMINT", "INT", "BIGINT"} 324 in := int64(42) 325 var out int64 326 var rows *sql.Rows 327 328 // SIGNED 329 for _, v := range types { 330 dbt.mustExec("CREATE TABLE test (value " + v + ")") 331 332 dbt.mustExec("INSERT INTO test VALUES (?)", in) 333 334 rows = dbt.mustQuery("SELECT value FROM test") 335 if rows.Next() { 336 rows.Scan(&out) 337 if in != out { 338 dbt.Errorf("%s: %d != %d", v, in, out) 339 } 340 } else { 341 dbt.Errorf("%s: no data", v) 342 } 343 344 dbt.mustExec("DROP TABLE IF EXISTS test") 345 } 346 347 // UNSIGNED ZEROFILL 348 for _, v := range types { 349 dbt.mustExec("CREATE TABLE test (value " + v + " ZEROFILL)") 350 351 dbt.mustExec("INSERT INTO test VALUES (?)", in) 352 353 rows = dbt.mustQuery("SELECT value FROM test") 354 if rows.Next() { 355 rows.Scan(&out) 356 if in != out { 357 dbt.Errorf("%s ZEROFILL: %d != %d", v, in, out) 358 } 359 } else { 360 dbt.Errorf("%s ZEROFILL: no data", v) 361 } 362 363 dbt.mustExec("DROP TABLE IF EXISTS test") 364 } 365 }) 366 } 367 368 func TestFloat(t *testing.T) { 369 runTests(t, dsn, func(dbt *DBTest) { 370 types := [2]string{"FLOAT", "DOUBLE"} 371 in := float32(42.23) 372 var out float32 373 var rows *sql.Rows 374 for _, v := range types { 375 dbt.mustExec("CREATE TABLE test (value " + v + ")") 376 dbt.mustExec("INSERT INTO test VALUES (?)", in) 377 rows = dbt.mustQuery("SELECT value FROM test") 378 if rows.Next() { 379 rows.Scan(&out) 380 if in != out { 381 dbt.Errorf("%s: %g != %g", v, in, out) 382 } 383 } else { 384 dbt.Errorf("%s: no data", v) 385 } 386 dbt.mustExec("DROP TABLE IF EXISTS test") 387 } 388 }) 389 } 390 391 func TestString(t *testing.T) { 392 runTests(t, dsn, func(dbt *DBTest) { 393 types := [6]string{"CHAR(255)", "VARCHAR(255)", "TINYTEXT", "TEXT", "MEDIUMTEXT", "LONGTEXT"} 394 in := "κόσμε üöäßñóùéàâÿœ'îë Árvíztűrő いろはにほへとちりぬるを イロハニホヘト דג סקרן чащах น่าฟังเอย" 395 var out string 396 var rows *sql.Rows 397 398 for _, v := range types { 399 dbt.mustExec("CREATE TABLE test (value " + v + ") CHARACTER SET utf8") 400 401 dbt.mustExec("INSERT INTO test VALUES (?)", in) 402 403 rows = dbt.mustQuery("SELECT value FROM test") 404 if rows.Next() { 405 rows.Scan(&out) 406 if in != out { 407 dbt.Errorf("%s: %s != %s", v, in, out) 408 } 409 } else { 410 dbt.Errorf("%s: no data", v) 411 } 412 413 dbt.mustExec("DROP TABLE IF EXISTS test") 414 } 415 416 // BLOB 417 dbt.mustExec("CREATE TABLE test (id int, value BLOB) CHARACTER SET utf8") 418 419 id := 2 420 in = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, " + 421 "sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, " + 422 "sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. " + 423 "Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. " + 424 "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, " + 425 "sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, " + 426 "sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. " + 427 "Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet." 428 dbt.mustExec("INSERT INTO test VALUES (?, ?)", id, in) 429 430 err := dbt.db.QueryRow("SELECT value FROM test WHERE id = ?", id).Scan(&out) 431 if err != nil { 432 dbt.Fatalf("Error on BLOB-Query: %s", err.Error()) 433 } else if out != in { 434 dbt.Errorf("BLOB: %s != %s", in, out) 435 } 436 }) 437 } 438 439 type timeTests struct { 440 dbtype string 441 tlayout string 442 tests []timeTest 443 } 444 445 type timeTest struct { 446 s string // leading "!": do not use t as value in queries 447 t time.Time 448 } 449 450 type timeMode byte 451 452 func (t timeMode) String() string { 453 switch t { 454 case binaryString: 455 return "binary:string" 456 case binaryTime: 457 return "binary:time.Time" 458 case textString: 459 return "text:string" 460 } 461 panic("unsupported timeMode") 462 } 463 464 func (t timeMode) Binary() bool { 465 switch t { 466 case binaryString, binaryTime: 467 return true 468 } 469 return false 470 } 471 472 const ( 473 binaryString timeMode = iota 474 binaryTime 475 textString 476 ) 477 478 func (t timeTest) genQuery(dbtype string, mode timeMode) string { 479 var inner string 480 if mode.Binary() { 481 inner = "?" 482 } else { 483 inner = `"%s"` 484 } 485 return `SELECT cast(` + inner + ` as ` + dbtype + `)` 486 } 487 488 func (t timeTest) run(dbt *DBTest, dbtype, tlayout string, mode timeMode) { 489 var rows *sql.Rows 490 query := t.genQuery(dbtype, mode) 491 switch mode { 492 case binaryString: 493 rows = dbt.mustQuery(query, t.s) 494 case binaryTime: 495 rows = dbt.mustQuery(query, t.t) 496 case textString: 497 query = fmt.Sprintf(query, t.s) 498 rows = dbt.mustQuery(query) 499 default: 500 panic("unsupported mode") 501 } 502 defer rows.Close() 503 var err error 504 if !rows.Next() { 505 err = rows.Err() 506 if err == nil { 507 err = fmt.Errorf("no data") 508 } 509 dbt.Errorf("%s [%s]: %s", dbtype, mode, err) 510 return 511 } 512 var dst interface{} 513 err = rows.Scan(&dst) 514 if err != nil { 515 dbt.Errorf("%s [%s]: %s", dbtype, mode, err) 516 return 517 } 518 switch val := dst.(type) { 519 case []uint8: 520 str := string(val) 521 if str == t.s { 522 return 523 } 524 if mode.Binary() && dbtype == "DATETIME" && len(str) == 26 && str[:19] == t.s { 525 // a fix mainly for TravisCI: 526 // accept full microsecond resolution in result for DATETIME columns 527 // where the binary protocol was used 528 return 529 } 530 dbt.Errorf("%s [%s] to string: expected %q, got %q", 531 dbtype, mode, 532 t.s, str, 533 ) 534 case time.Time: 535 if val == t.t { 536 return 537 } 538 dbt.Errorf("%s [%s] to string: expected %q, got %q", 539 dbtype, mode, 540 t.s, val.Format(tlayout), 541 ) 542 default: 543 fmt.Printf("%#v\n", []interface{}{dbtype, tlayout, mode, t.s, t.t}) 544 dbt.Errorf("%s [%s]: unhandled type %T (is '%v')", 545 dbtype, mode, 546 val, val, 547 ) 548 } 549 } 550 551 func TestDateTime(t *testing.T) { 552 afterTime := func(t time.Time, d string) time.Time { 553 dur, err := time.ParseDuration(d) 554 if err != nil { 555 panic(err) 556 } 557 return t.Add(dur) 558 } 559 // NOTE: MySQL rounds DATETIME(x) up - but that's not included in the tests 560 format := "2006-01-02 15:04:05.999999" 561 t0 := time.Time{} 562 tstr0 := "0000-00-00 00:00:00.000000" 563 testcases := []timeTests{ 564 {"DATE", format[:10], []timeTest{ 565 {t: time.Date(2011, 11, 20, 0, 0, 0, 0, time.UTC)}, 566 {t: t0, s: tstr0[:10]}, 567 }}, 568 {"DATETIME", format[:19], []timeTest{ 569 {t: time.Date(2011, 11, 20, 21, 27, 37, 0, time.UTC)}, 570 {t: t0, s: tstr0[:19]}, 571 }}, 572 {"DATETIME(0)", format[:21], []timeTest{ 573 {t: time.Date(2011, 11, 20, 21, 27, 37, 0, time.UTC)}, 574 {t: t0, s: tstr0[:19]}, 575 }}, 576 {"DATETIME(1)", format[:21], []timeTest{ 577 {t: time.Date(2011, 11, 20, 21, 27, 37, 100000000, time.UTC)}, 578 {t: t0, s: tstr0[:21]}, 579 }}, 580 {"DATETIME(6)", format, []timeTest{ 581 {t: time.Date(2011, 11, 20, 21, 27, 37, 123456000, time.UTC)}, 582 {t: t0, s: tstr0}, 583 }}, 584 {"TIME", format[11:19], []timeTest{ 585 {t: afterTime(t0, "12345s")}, 586 {s: "!-12:34:56"}, 587 {s: "!-838:59:59"}, 588 {s: "!838:59:59"}, 589 {t: t0, s: tstr0[11:19]}, 590 }}, 591 {"TIME(0)", format[11:19], []timeTest{ 592 {t: afterTime(t0, "12345s")}, 593 {s: "!-12:34:56"}, 594 {s: "!-838:59:59"}, 595 {s: "!838:59:59"}, 596 {t: t0, s: tstr0[11:19]}, 597 }}, 598 {"TIME(1)", format[11:21], []timeTest{ 599 {t: afterTime(t0, "12345600ms")}, 600 {s: "!-12:34:56.7"}, 601 {s: "!-838:59:58.9"}, 602 {s: "!838:59:58.9"}, 603 {t: t0, s: tstr0[11:21]}, 604 }}, 605 {"TIME(6)", format[11:], []timeTest{ 606 {t: afterTime(t0, "1234567890123000ns")}, 607 {s: "!-12:34:56.789012"}, 608 {s: "!-838:59:58.999999"}, 609 {s: "!838:59:58.999999"}, 610 {t: t0, s: tstr0[11:]}, 611 }}, 612 } 613 dsns := []string{ 614 dsn + "&parseTime=true", 615 dsn + "&parseTime=false", 616 } 617 for _, testdsn := range dsns { 618 runTests(t, testdsn, func(dbt *DBTest) { 619 microsecsSupported := false 620 zeroDateSupported := false 621 var rows *sql.Rows 622 var err error 623 rows, err = dbt.db.Query(`SELECT cast("00:00:00.1" as TIME(1)) = "00:00:00.1"`) 624 if err == nil { 625 rows.Scan(µsecsSupported) 626 rows.Close() 627 } 628 rows, err = dbt.db.Query(`SELECT cast("0000-00-00" as DATE) = "0000-00-00"`) 629 if err == nil { 630 rows.Scan(&zeroDateSupported) 631 rows.Close() 632 } 633 for _, setups := range testcases { 634 if t := setups.dbtype; !microsecsSupported && t[len(t)-1:] == ")" { 635 // skip fractional second tests if unsupported by server 636 continue 637 } 638 for _, setup := range setups.tests { 639 allowBinTime := true 640 if setup.s == "" { 641 // fill time string whereever Go can reliable produce it 642 setup.s = setup.t.Format(setups.tlayout) 643 } else if setup.s[0] == '!' { 644 // skip tests using setup.t as source in queries 645 allowBinTime = false 646 // fix setup.s - remove the "!" 647 setup.s = setup.s[1:] 648 } 649 if !zeroDateSupported && setup.s == tstr0[:len(setup.s)] { 650 // skip disallowed 0000-00-00 date 651 continue 652 } 653 setup.run(dbt, setups.dbtype, setups.tlayout, textString) 654 setup.run(dbt, setups.dbtype, setups.tlayout, binaryString) 655 if allowBinTime { 656 setup.run(dbt, setups.dbtype, setups.tlayout, binaryTime) 657 } 658 } 659 } 660 }) 661 } 662 } 663 664 func TestTimestampMicros(t *testing.T) { 665 format := "2006-01-02 15:04:05.999999" 666 f0 := format[:19] 667 f1 := format[:21] 668 f6 := format[:26] 669 runTests(t, dsn, func(dbt *DBTest) { 670 // check if microseconds are supported. 671 // Do not use timestamp(x) for that check - before 5.5.6, x would mean display width 672 // and not precision. 673 // Se last paragraph at http://dev.mysql.com/doc/refman/5.6/en/fractional-seconds.html 674 microsecsSupported := false 675 if rows, err := dbt.db.Query(`SELECT cast("00:00:00.1" as TIME(1)) = "00:00:00.1"`); err == nil { 676 rows.Scan(µsecsSupported) 677 rows.Close() 678 } 679 if !microsecsSupported { 680 // skip test 681 return 682 } 683 _, err := dbt.db.Exec(` 684 CREATE TABLE test ( 685 value0 TIMESTAMP NOT NULL DEFAULT '` + f0 + `', 686 value1 TIMESTAMP(1) NOT NULL DEFAULT '` + f1 + `', 687 value6 TIMESTAMP(6) NOT NULL DEFAULT '` + f6 + `' 688 )`, 689 ) 690 if err != nil { 691 dbt.Error(err) 692 } 693 defer dbt.mustExec("DROP TABLE IF EXISTS test") 694 dbt.mustExec("INSERT INTO test SET value0=?, value1=?, value6=?", f0, f1, f6) 695 var res0, res1, res6 string 696 rows := dbt.mustQuery("SELECT * FROM test") 697 if !rows.Next() { 698 dbt.Errorf("test contained no selectable values") 699 } 700 err = rows.Scan(&res0, &res1, &res6) 701 if err != nil { 702 dbt.Error(err) 703 } 704 if res0 != f0 { 705 dbt.Errorf("expected %q, got %q", f0, res0) 706 } 707 if res1 != f1 { 708 dbt.Errorf("expected %q, got %q", f1, res1) 709 } 710 if res6 != f6 { 711 dbt.Errorf("expected %q, got %q", f6, res6) 712 } 713 }) 714 } 715 716 func TestNULL(t *testing.T) { 717 runTests(t, dsn, func(dbt *DBTest) { 718 nullStmt, err := dbt.db.Prepare("SELECT NULL") 719 if err != nil { 720 dbt.Fatal(err) 721 } 722 defer nullStmt.Close() 723 724 nonNullStmt, err := dbt.db.Prepare("SELECT 1") 725 if err != nil { 726 dbt.Fatal(err) 727 } 728 defer nonNullStmt.Close() 729 730 // NullBool 731 var nb sql.NullBool 732 // Invalid 733 if err = nullStmt.QueryRow().Scan(&nb); err != nil { 734 dbt.Fatal(err) 735 } 736 if nb.Valid { 737 dbt.Error("valid NullBool which should be invalid") 738 } 739 // Valid 740 if err = nonNullStmt.QueryRow().Scan(&nb); err != nil { 741 dbt.Fatal(err) 742 } 743 if !nb.Valid { 744 dbt.Error("invalid NullBool which should be valid") 745 } else if nb.Bool != true { 746 dbt.Errorf("Unexpected NullBool value: %t (should be true)", nb.Bool) 747 } 748 749 // NullFloat64 750 var nf sql.NullFloat64 751 // Invalid 752 if err = nullStmt.QueryRow().Scan(&nf); err != nil { 753 dbt.Fatal(err) 754 } 755 if nf.Valid { 756 dbt.Error("valid NullFloat64 which should be invalid") 757 } 758 // Valid 759 if err = nonNullStmt.QueryRow().Scan(&nf); err != nil { 760 dbt.Fatal(err) 761 } 762 if !nf.Valid { 763 dbt.Error("invalid NullFloat64 which should be valid") 764 } else if nf.Float64 != float64(1) { 765 dbt.Errorf("unexpected NullFloat64 value: %f (should be 1.0)", nf.Float64) 766 } 767 768 // NullInt64 769 var ni sql.NullInt64 770 // Invalid 771 if err = nullStmt.QueryRow().Scan(&ni); err != nil { 772 dbt.Fatal(err) 773 } 774 if ni.Valid { 775 dbt.Error("valid NullInt64 which should be invalid") 776 } 777 // Valid 778 if err = nonNullStmt.QueryRow().Scan(&ni); err != nil { 779 dbt.Fatal(err) 780 } 781 if !ni.Valid { 782 dbt.Error("invalid NullInt64 which should be valid") 783 } else if ni.Int64 != int64(1) { 784 dbt.Errorf("unexpected NullInt64 value: %d (should be 1)", ni.Int64) 785 } 786 787 // NullString 788 var ns sql.NullString 789 // Invalid 790 if err = nullStmt.QueryRow().Scan(&ns); err != nil { 791 dbt.Fatal(err) 792 } 793 if ns.Valid { 794 dbt.Error("valid NullString which should be invalid") 795 } 796 // Valid 797 if err = nonNullStmt.QueryRow().Scan(&ns); err != nil { 798 dbt.Fatal(err) 799 } 800 if !ns.Valid { 801 dbt.Error("invalid NullString which should be valid") 802 } else if ns.String != `1` { 803 dbt.Error("unexpected NullString value:" + ns.String + " (should be `1`)") 804 } 805 806 // nil-bytes 807 var b []byte 808 // Read nil 809 if err = nullStmt.QueryRow().Scan(&b); err != nil { 810 dbt.Fatal(err) 811 } 812 if b != nil { 813 dbt.Error("non-nil []byte wich should be nil") 814 } 815 // Read non-nil 816 if err = nonNullStmt.QueryRow().Scan(&b); err != nil { 817 dbt.Fatal(err) 818 } 819 if b == nil { 820 dbt.Error("nil []byte wich should be non-nil") 821 } 822 // Insert nil 823 b = nil 824 success := false 825 if err = dbt.db.QueryRow("SELECT ? IS NULL", b).Scan(&success); err != nil { 826 dbt.Fatal(err) 827 } 828 if !success { 829 dbt.Error("inserting []byte(nil) as NULL failed") 830 } 831 // Check input==output with input==nil 832 b = nil 833 if err = dbt.db.QueryRow("SELECT ?", b).Scan(&b); err != nil { 834 dbt.Fatal(err) 835 } 836 if b != nil { 837 dbt.Error("non-nil echo from nil input") 838 } 839 // Check input==output with input!=nil 840 b = []byte("") 841 if err = dbt.db.QueryRow("SELECT ?", b).Scan(&b); err != nil { 842 dbt.Fatal(err) 843 } 844 if b == nil { 845 dbt.Error("nil echo from non-nil input") 846 } 847 848 // Insert NULL 849 dbt.mustExec("CREATE TABLE test (dummmy1 int, value int, dummy2 int)") 850 851 dbt.mustExec("INSERT INTO test VALUES (?, ?, ?)", 1, nil, 2) 852 853 var out interface{} 854 rows := dbt.mustQuery("SELECT * FROM test") 855 if rows.Next() { 856 rows.Scan(&out) 857 if out != nil { 858 dbt.Errorf("%v != nil", out) 859 } 860 } else { 861 dbt.Error("no data") 862 } 863 }) 864 } 865 866 func TestUint64(t *testing.T) { 867 const ( 868 u0 = uint64(0) 869 uall = ^u0 870 uhigh = uall >> 1 871 utop = ^uhigh 872 s0 = int64(0) 873 sall = ^s0 874 shigh = int64(uhigh) 875 stop = ^shigh 876 ) 877 runTests(t, dsn, func(dbt *DBTest) { 878 stmt, err := dbt.db.Prepare(`SELECT ?, ?, ? ,?, ?, ?, ?, ?`) 879 if err != nil { 880 dbt.Fatal(err) 881 } 882 defer stmt.Close() 883 row := stmt.QueryRow( 884 u0, uhigh, utop, uall, 885 s0, shigh, stop, sall, 886 ) 887 888 var ua, ub, uc, ud uint64 889 var sa, sb, sc, sd int64 890 891 err = row.Scan(&ua, &ub, &uc, &ud, &sa, &sb, &sc, &sd) 892 if err != nil { 893 dbt.Fatal(err) 894 } 895 switch { 896 case ua != u0, 897 ub != uhigh, 898 uc != utop, 899 ud != uall, 900 sa != s0, 901 sb != shigh, 902 sc != stop, 903 sd != sall: 904 dbt.Fatal("unexpected result value") 905 } 906 }) 907 } 908 909 func TestLongData(t *testing.T) { 910 runTests(t, dsn, func(dbt *DBTest) { 911 var maxAllowedPacketSize int 912 err := dbt.db.QueryRow("select @@max_allowed_packet").Scan(&maxAllowedPacketSize) 913 if err != nil { 914 dbt.Fatal(err) 915 } 916 maxAllowedPacketSize-- 917 918 // don't get too ambitious 919 if maxAllowedPacketSize > 1<<25 { 920 maxAllowedPacketSize = 1 << 25 921 } 922 923 dbt.mustExec("CREATE TABLE test (value LONGBLOB)") 924 925 in := strings.Repeat(`a`, maxAllowedPacketSize+1) 926 var out string 927 var rows *sql.Rows 928 929 // Long text data 930 const nonDataQueryLen = 28 // length query w/o value 931 inS := in[:maxAllowedPacketSize-nonDataQueryLen] 932 dbt.mustExec("INSERT INTO test VALUES('" + inS + "')") 933 rows = dbt.mustQuery("SELECT value FROM test") 934 if rows.Next() { 935 rows.Scan(&out) 936 if inS != out { 937 dbt.Fatalf("LONGBLOB: length in: %d, length out: %d", len(inS), len(out)) 938 } 939 if rows.Next() { 940 dbt.Error("LONGBLOB: unexpexted row") 941 } 942 } else { 943 dbt.Fatalf("LONGBLOB: no data") 944 } 945 946 // Empty table 947 dbt.mustExec("TRUNCATE TABLE test") 948 949 // Long binary data 950 dbt.mustExec("INSERT INTO test VALUES(?)", in) 951 rows = dbt.mustQuery("SELECT value FROM test WHERE 1=?", 1) 952 if rows.Next() { 953 rows.Scan(&out) 954 if in != out { 955 dbt.Fatalf("LONGBLOB: length in: %d, length out: %d", len(in), len(out)) 956 } 957 if rows.Next() { 958 dbt.Error("LONGBLOB: unexpexted row") 959 } 960 } else { 961 if err = rows.Err(); err != nil { 962 dbt.Fatalf("LONGBLOB: no data (err: %s)", err.Error()) 963 } else { 964 dbt.Fatal("LONGBLOB: no data (err: <nil>)") 965 } 966 } 967 }) 968 } 969 970 func TestLoadData(t *testing.T) { 971 runTests(t, dsn, func(dbt *DBTest) { 972 verifyLoadDataResult := func() { 973 rows, err := dbt.db.Query("SELECT * FROM test") 974 if err != nil { 975 dbt.Fatal(err.Error()) 976 } 977 978 i := 0 979 values := [4]string{ 980 "a string", 981 "a string containing a \t", 982 "a string containing a \n", 983 "a string containing both \t\n", 984 } 985 986 var id int 987 var value string 988 989 for rows.Next() { 990 i++ 991 err = rows.Scan(&id, &value) 992 if err != nil { 993 dbt.Fatal(err.Error()) 994 } 995 if i != id { 996 dbt.Fatalf("%d != %d", i, id) 997 } 998 if values[i-1] != value { 999 dbt.Fatalf("%q != %q", values[i-1], value) 1000 } 1001 } 1002 err = rows.Err() 1003 if err != nil { 1004 dbt.Fatal(err.Error()) 1005 } 1006 1007 if i != 4 { 1008 dbt.Fatalf("rows count mismatch. Got %d, want 4", i) 1009 } 1010 } 1011 file, err := ioutil.TempFile("", "gotest") 1012 defer os.Remove(file.Name()) 1013 if err != nil { 1014 dbt.Fatal(err) 1015 } 1016 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") 1017 file.Close() 1018 1019 dbt.db.Exec("DROP TABLE IF EXISTS test") 1020 dbt.mustExec("CREATE TABLE test (id INT NOT NULL PRIMARY KEY, value TEXT NOT NULL) CHARACTER SET utf8") 1021 1022 // Local File 1023 RegisterLocalFile(file.Name()) 1024 dbt.mustExec(fmt.Sprintf("LOAD DATA LOCAL INFILE %q INTO TABLE test", file.Name())) 1025 verifyLoadDataResult() 1026 // negative test 1027 _, err = dbt.db.Exec("LOAD DATA LOCAL INFILE 'doesnotexist' INTO TABLE test") 1028 if err == nil { 1029 dbt.Fatal("load non-existent file didn't fail") 1030 } else if err.Error() != "local file 'doesnotexist' is not registered" { 1031 dbt.Fatal(err.Error()) 1032 } 1033 1034 // Empty table 1035 dbt.mustExec("TRUNCATE TABLE test") 1036 1037 // Reader 1038 RegisterReaderHandler("test", func() io.Reader { 1039 file, err = os.Open(file.Name()) 1040 if err != nil { 1041 dbt.Fatal(err) 1042 } 1043 return file 1044 }) 1045 dbt.mustExec("LOAD DATA LOCAL INFILE 'Reader::test' INTO TABLE test") 1046 verifyLoadDataResult() 1047 // negative test 1048 _, err = dbt.db.Exec("LOAD DATA LOCAL INFILE 'Reader::doesnotexist' INTO TABLE test") 1049 if err == nil { 1050 dbt.Fatal("load non-existent Reader didn't fail") 1051 } else if err.Error() != "Reader 'doesnotexist' is not registered" { 1052 dbt.Fatal(err.Error()) 1053 } 1054 }) 1055 } 1056 1057 func TestFoundRows(t *testing.T) { 1058 runTests(t, dsn, func(dbt *DBTest) { 1059 dbt.mustExec("CREATE TABLE test (id INT NOT NULL ,data INT NOT NULL)") 1060 dbt.mustExec("INSERT INTO test (id, data) VALUES (0, 0),(0, 0),(1, 0),(1, 0),(1, 1)") 1061 1062 res := dbt.mustExec("UPDATE test SET data = 1 WHERE id = 0") 1063 count, err := res.RowsAffected() 1064 if err != nil { 1065 dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error()) 1066 } 1067 if count != 2 { 1068 dbt.Fatalf("Expected 2 affected rows, got %d", count) 1069 } 1070 res = dbt.mustExec("UPDATE test SET data = 1 WHERE id = 1") 1071 count, err = res.RowsAffected() 1072 if err != nil { 1073 dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error()) 1074 } 1075 if count != 2 { 1076 dbt.Fatalf("Expected 2 affected rows, got %d", count) 1077 } 1078 }) 1079 runTests(t, dsn+"&clientFoundRows=true", func(dbt *DBTest) { 1080 dbt.mustExec("CREATE TABLE test (id INT NOT NULL ,data INT NOT NULL)") 1081 dbt.mustExec("INSERT INTO test (id, data) VALUES (0, 0),(0, 0),(1, 0),(1, 0),(1, 1)") 1082 1083 res := dbt.mustExec("UPDATE test SET data = 1 WHERE id = 0") 1084 count, err := res.RowsAffected() 1085 if err != nil { 1086 dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error()) 1087 } 1088 if count != 2 { 1089 dbt.Fatalf("Expected 2 matched rows, got %d", count) 1090 } 1091 res = dbt.mustExec("UPDATE test SET data = 1 WHERE id = 1") 1092 count, err = res.RowsAffected() 1093 if err != nil { 1094 dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error()) 1095 } 1096 if count != 3 { 1097 dbt.Fatalf("Expected 3 matched rows, got %d", count) 1098 } 1099 }) 1100 } 1101 1102 func TestStrict(t *testing.T) { 1103 // ALLOW_INVALID_DATES to get rid of stricter modes - we want to test for warnings, not errors 1104 relaxedDsn := dsn + "&sql_mode='ALLOW_INVALID_DATES,NO_AUTO_CREATE_USER'" 1105 // make sure the MySQL version is recent enough with a separate connection 1106 // before running the test 1107 conn, err := MySQLDriver{}.Open(relaxedDsn) 1108 if conn != nil { 1109 conn.Close() 1110 } 1111 if me, ok := err.(*MySQLError); ok && me.Number == 1231 { 1112 // Error 1231: Variable 'sql_mode' can't be set to the value of 'ALLOW_INVALID_DATES' 1113 // => skip test, MySQL server version is too old 1114 return 1115 } 1116 runTests(t, relaxedDsn, func(dbt *DBTest) { 1117 dbt.mustExec("CREATE TABLE test (a TINYINT NOT NULL, b CHAR(4))") 1118 1119 var queries = [...]struct { 1120 in string 1121 codes []string 1122 }{ 1123 {"DROP TABLE IF EXISTS no_such_table", []string{"1051"}}, 1124 {"INSERT INTO test VALUES(10,'mysql'),(NULL,'test'),(300,'Open Source')", []string{"1265", "1048", "1264", "1265"}}, 1125 } 1126 var err error 1127 1128 var checkWarnings = func(err error, mode string, idx int) { 1129 if err == nil { 1130 dbt.Errorf("expected STRICT error on query [%s] %s", mode, queries[idx].in) 1131 } 1132 1133 if warnings, ok := err.(MySQLWarnings); ok { 1134 var codes = make([]string, len(warnings)) 1135 for i := range warnings { 1136 codes[i] = warnings[i].Code 1137 } 1138 if len(codes) != len(queries[idx].codes) { 1139 dbt.Errorf("unexpected STRICT error count on query [%s] %s: Wanted %v, Got %v", mode, queries[idx].in, queries[idx].codes, codes) 1140 } 1141 1142 for i := range warnings { 1143 if codes[i] != queries[idx].codes[i] { 1144 dbt.Errorf("unexpected STRICT error codes on query [%s] %s: Wanted %v, Got %v", mode, queries[idx].in, queries[idx].codes, codes) 1145 return 1146 } 1147 } 1148 1149 } else { 1150 dbt.Errorf("unexpected error on query [%s] %s: %s", mode, queries[idx].in, err.Error()) 1151 } 1152 } 1153 1154 // text protocol 1155 for i := range queries { 1156 _, err = dbt.db.Exec(queries[i].in) 1157 checkWarnings(err, "text", i) 1158 } 1159 1160 var stmt *sql.Stmt 1161 1162 // binary protocol 1163 for i := range queries { 1164 stmt, err = dbt.db.Prepare(queries[i].in) 1165 if err != nil { 1166 dbt.Errorf("error on preparing query %s: %s", queries[i].in, err.Error()) 1167 } 1168 1169 _, err = stmt.Exec() 1170 checkWarnings(err, "binary", i) 1171 1172 err = stmt.Close() 1173 if err != nil { 1174 dbt.Errorf("error on closing stmt for query %s: %s", queries[i].in, err.Error()) 1175 } 1176 } 1177 }) 1178 } 1179 1180 func TestTLS(t *testing.T) { 1181 tlsTest := func(dbt *DBTest) { 1182 if err := dbt.db.Ping(); err != nil { 1183 if err == ErrNoTLS { 1184 dbt.Skip("server does not support TLS") 1185 } else { 1186 dbt.Fatalf("error on Ping: %s", err.Error()) 1187 } 1188 } 1189 1190 rows := dbt.mustQuery("SHOW STATUS LIKE 'Ssl_cipher'") 1191 1192 var variable, value *sql.RawBytes 1193 for rows.Next() { 1194 if err := rows.Scan(&variable, &value); err != nil { 1195 dbt.Fatal(err.Error()) 1196 } 1197 1198 if value == nil { 1199 dbt.Fatal("no Cipher") 1200 } 1201 } 1202 } 1203 1204 runTests(t, dsn+"&tls=skip-verify", tlsTest) 1205 1206 // Verify that registering / using a custom cfg works 1207 RegisterTLSConfig("custom-skip-verify", &tls.Config{ 1208 InsecureSkipVerify: true, 1209 }) 1210 runTests(t, dsn+"&tls=custom-skip-verify", tlsTest) 1211 } 1212 1213 func TestReuseClosedConnection(t *testing.T) { 1214 // this test does not use sql.database, it uses the driver directly 1215 if !available { 1216 t.Skipf("MySQL server not running on %s", netAddr) 1217 } 1218 1219 md := &MySQLDriver{} 1220 conn, err := md.Open(dsn) 1221 if err != nil { 1222 t.Fatalf("error connecting: %s", err.Error()) 1223 } 1224 stmt, err := conn.Prepare("DO 1") 1225 if err != nil { 1226 t.Fatalf("error preparing statement: %s", err.Error()) 1227 } 1228 _, err = stmt.Exec(nil) 1229 if err != nil { 1230 t.Fatalf("error executing statement: %s", err.Error()) 1231 } 1232 err = conn.Close() 1233 if err != nil { 1234 t.Fatalf("error closing connection: %s", err.Error()) 1235 } 1236 1237 defer func() { 1238 if err := recover(); err != nil { 1239 t.Errorf("panic after reusing a closed connection: %v", err) 1240 } 1241 }() 1242 _, err = stmt.Exec(nil) 1243 if err != nil && err != driver.ErrBadConn { 1244 t.Errorf("unexpected error '%s', expected '%s'", 1245 err.Error(), driver.ErrBadConn.Error()) 1246 } 1247 } 1248 1249 func TestCharset(t *testing.T) { 1250 if !available { 1251 t.Skipf("MySQL server not running on %s", netAddr) 1252 } 1253 1254 mustSetCharset := func(charsetParam, expected string) { 1255 runTests(t, dsn+"&"+charsetParam, func(dbt *DBTest) { 1256 rows := dbt.mustQuery("SELECT @@character_set_connection") 1257 defer rows.Close() 1258 1259 if !rows.Next() { 1260 dbt.Fatalf("error getting connection charset: %s", rows.Err()) 1261 } 1262 1263 var got string 1264 rows.Scan(&got) 1265 1266 if got != expected { 1267 dbt.Fatalf("expected connection charset %s but got %s", expected, got) 1268 } 1269 }) 1270 } 1271 1272 // non utf8 test 1273 mustSetCharset("charset=ascii", "ascii") 1274 1275 // when the first charset is invalid, use the second 1276 mustSetCharset("charset=none,utf8", "utf8") 1277 1278 // when the first charset is valid, use it 1279 mustSetCharset("charset=ascii,utf8", "ascii") 1280 mustSetCharset("charset=utf8,ascii", "utf8") 1281 } 1282 1283 func TestFailingCharset(t *testing.T) { 1284 runTests(t, dsn+"&charset=none", func(dbt *DBTest) { 1285 // run query to really establish connection... 1286 _, err := dbt.db.Exec("SELECT 1") 1287 if err == nil { 1288 dbt.db.Close() 1289 t.Fatalf("connection must not succeed without a valid charset") 1290 } 1291 }) 1292 } 1293 1294 func TestCollation(t *testing.T) { 1295 if !available { 1296 t.Skipf("MySQL server not running on %s", netAddr) 1297 } 1298 1299 defaultCollation := "utf8_general_ci" 1300 testCollations := []string{ 1301 "", // do not set 1302 defaultCollation, // driver default 1303 "latin1_general_ci", 1304 "binary", 1305 "utf8_unicode_ci", 1306 "cp1257_bin", 1307 } 1308 1309 for _, collation := range testCollations { 1310 var expected, tdsn string 1311 if collation != "" { 1312 tdsn = dsn + "&collation=" + collation 1313 expected = collation 1314 } else { 1315 tdsn = dsn 1316 expected = defaultCollation 1317 } 1318 1319 runTests(t, tdsn, func(dbt *DBTest) { 1320 var got string 1321 if err := dbt.db.QueryRow("SELECT @@collation_connection").Scan(&got); err != nil { 1322 dbt.Fatal(err) 1323 } 1324 1325 if got != expected { 1326 dbt.Fatalf("expected connection collation %s but got %s", expected, got) 1327 } 1328 }) 1329 } 1330 } 1331 1332 func TestColumnsWithAlias(t *testing.T) { 1333 runTests(t, dsn+"&columnsWithAlias=true", func(dbt *DBTest) { 1334 rows := dbt.mustQuery("SELECT 1 AS A") 1335 defer rows.Close() 1336 cols, _ := rows.Columns() 1337 if len(cols) != 1 { 1338 t.Fatalf("expected 1 column, got %d", len(cols)) 1339 } 1340 if cols[0] != "A" { 1341 t.Fatalf("expected column name \"A\", got \"%s\"", cols[0]) 1342 } 1343 rows.Close() 1344 1345 rows = dbt.mustQuery("SELECT * FROM (SELECT 1 AS one) AS A") 1346 cols, _ = rows.Columns() 1347 if len(cols) != 1 { 1348 t.Fatalf("expected 1 column, got %d", len(cols)) 1349 } 1350 if cols[0] != "A.one" { 1351 t.Fatalf("expected column name \"A.one\", got \"%s\"", cols[0]) 1352 } 1353 }) 1354 } 1355 1356 func TestRawBytesResultExceedsBuffer(t *testing.T) { 1357 runTests(t, dsn, func(dbt *DBTest) { 1358 // defaultBufSize from buffer.go 1359 expected := strings.Repeat("abc", defaultBufSize) 1360 1361 rows := dbt.mustQuery("SELECT '" + expected + "'") 1362 defer rows.Close() 1363 if !rows.Next() { 1364 dbt.Error("expected result, got none") 1365 } 1366 var result sql.RawBytes 1367 rows.Scan(&result) 1368 if expected != string(result) { 1369 dbt.Error("result did not match expected value") 1370 } 1371 }) 1372 } 1373 1374 func TestTimezoneConversion(t *testing.T) { 1375 zones := []string{"UTC", "US/Central", "US/Pacific", "Local"} 1376 1377 // Regression test for timezone handling 1378 tzTest := func(dbt *DBTest) { 1379 1380 // Create table 1381 dbt.mustExec("CREATE TABLE test (ts TIMESTAMP)") 1382 1383 // Insert local time into database (should be converted) 1384 usCentral, _ := time.LoadLocation("US/Central") 1385 reftime := time.Date(2014, 05, 30, 18, 03, 17, 0, time.UTC).In(usCentral) 1386 dbt.mustExec("INSERT INTO test VALUE (?)", reftime) 1387 1388 // Retrieve time from DB 1389 rows := dbt.mustQuery("SELECT ts FROM test") 1390 if !rows.Next() { 1391 dbt.Fatal("did not get any rows out") 1392 } 1393 1394 var dbTime time.Time 1395 err := rows.Scan(&dbTime) 1396 if err != nil { 1397 dbt.Fatal("Err", err) 1398 } 1399 1400 // Check that dates match 1401 if reftime.Unix() != dbTime.Unix() { 1402 dbt.Errorf("times do not match.\n") 1403 dbt.Errorf(" Now(%v)=%v\n", usCentral, reftime) 1404 dbt.Errorf(" Now(UTC)=%v\n", dbTime) 1405 } 1406 } 1407 1408 for _, tz := range zones { 1409 runTests(t, dsn+"&parseTime=true&loc="+url.QueryEscape(tz), tzTest) 1410 } 1411 } 1412 1413 // Special cases 1414 1415 func TestRowsClose(t *testing.T) { 1416 runTests(t, dsn, func(dbt *DBTest) { 1417 rows, err := dbt.db.Query("SELECT 1") 1418 if err != nil { 1419 dbt.Fatal(err) 1420 } 1421 1422 err = rows.Close() 1423 if err != nil { 1424 dbt.Fatal(err) 1425 } 1426 1427 if rows.Next() { 1428 dbt.Fatal("unexpected row after rows.Close()") 1429 } 1430 1431 err = rows.Err() 1432 if err != nil { 1433 dbt.Fatal(err) 1434 } 1435 }) 1436 } 1437 1438 // dangling statements 1439 // http://code.google.com/p/go/issues/detail?id=3865 1440 func TestCloseStmtBeforeRows(t *testing.T) { 1441 runTests(t, dsn, func(dbt *DBTest) { 1442 stmt, err := dbt.db.Prepare("SELECT 1") 1443 if err != nil { 1444 dbt.Fatal(err) 1445 } 1446 1447 rows, err := stmt.Query() 1448 if err != nil { 1449 stmt.Close() 1450 dbt.Fatal(err) 1451 } 1452 defer rows.Close() 1453 1454 err = stmt.Close() 1455 if err != nil { 1456 dbt.Fatal(err) 1457 } 1458 1459 if !rows.Next() { 1460 dbt.Fatal("getting row failed") 1461 } else { 1462 err = rows.Err() 1463 if err != nil { 1464 dbt.Fatal(err) 1465 } 1466 1467 var out bool 1468 err = rows.Scan(&out) 1469 if err != nil { 1470 dbt.Fatalf("error on rows.Scan(): %s", err.Error()) 1471 } 1472 if out != true { 1473 dbt.Errorf("true != %t", out) 1474 } 1475 } 1476 }) 1477 } 1478 1479 // It is valid to have multiple Rows for the same Stmt 1480 // http://code.google.com/p/go/issues/detail?id=3734 1481 func TestStmtMultiRows(t *testing.T) { 1482 runTests(t, dsn, func(dbt *DBTest) { 1483 stmt, err := dbt.db.Prepare("SELECT 1 UNION SELECT 0") 1484 if err != nil { 1485 dbt.Fatal(err) 1486 } 1487 1488 rows1, err := stmt.Query() 1489 if err != nil { 1490 stmt.Close() 1491 dbt.Fatal(err) 1492 } 1493 defer rows1.Close() 1494 1495 rows2, err := stmt.Query() 1496 if err != nil { 1497 stmt.Close() 1498 dbt.Fatal(err) 1499 } 1500 defer rows2.Close() 1501 1502 var out bool 1503 1504 // 1 1505 if !rows1.Next() { 1506 dbt.Fatal("first rows1.Next failed") 1507 } else { 1508 err = rows1.Err() 1509 if err != nil { 1510 dbt.Fatal(err) 1511 } 1512 1513 err = rows1.Scan(&out) 1514 if err != nil { 1515 dbt.Fatalf("error on rows.Scan(): %s", err.Error()) 1516 } 1517 if out != true { 1518 dbt.Errorf("true != %t", out) 1519 } 1520 } 1521 1522 if !rows2.Next() { 1523 dbt.Fatal("first rows2.Next failed") 1524 } else { 1525 err = rows2.Err() 1526 if err != nil { 1527 dbt.Fatal(err) 1528 } 1529 1530 err = rows2.Scan(&out) 1531 if err != nil { 1532 dbt.Fatalf("error on rows.Scan(): %s", err.Error()) 1533 } 1534 if out != true { 1535 dbt.Errorf("true != %t", out) 1536 } 1537 } 1538 1539 // 2 1540 if !rows1.Next() { 1541 dbt.Fatal("second rows1.Next failed") 1542 } else { 1543 err = rows1.Err() 1544 if err != nil { 1545 dbt.Fatal(err) 1546 } 1547 1548 err = rows1.Scan(&out) 1549 if err != nil { 1550 dbt.Fatalf("error on rows.Scan(): %s", err.Error()) 1551 } 1552 if out != false { 1553 dbt.Errorf("false != %t", out) 1554 } 1555 1556 if rows1.Next() { 1557 dbt.Fatal("unexpected row on rows1") 1558 } 1559 err = rows1.Close() 1560 if err != nil { 1561 dbt.Fatal(err) 1562 } 1563 } 1564 1565 if !rows2.Next() { 1566 dbt.Fatal("second rows2.Next failed") 1567 } else { 1568 err = rows2.Err() 1569 if err != nil { 1570 dbt.Fatal(err) 1571 } 1572 1573 err = rows2.Scan(&out) 1574 if err != nil { 1575 dbt.Fatalf("error on rows.Scan(): %s", err.Error()) 1576 } 1577 if out != false { 1578 dbt.Errorf("false != %t", out) 1579 } 1580 1581 if rows2.Next() { 1582 dbt.Fatal("unexpected row on rows2") 1583 } 1584 err = rows2.Close() 1585 if err != nil { 1586 dbt.Fatal(err) 1587 } 1588 } 1589 }) 1590 } 1591 1592 // Regression test for 1593 // * more than 32 NULL parameters (issue 209) 1594 // * more parameters than fit into the buffer (issue 201) 1595 func TestPreparedManyCols(t *testing.T) { 1596 const numParams = defaultBufSize 1597 runTests(t, dsn, func(dbt *DBTest) { 1598 query := "SELECT ?" + strings.Repeat(",?", numParams-1) 1599 stmt, err := dbt.db.Prepare(query) 1600 if err != nil { 1601 dbt.Fatal(err) 1602 } 1603 defer stmt.Close() 1604 // create more parameters than fit into the buffer 1605 // which will take nil-values 1606 params := make([]interface{}, numParams) 1607 rows, err := stmt.Query(params...) 1608 if err != nil { 1609 stmt.Close() 1610 dbt.Fatal(err) 1611 } 1612 defer rows.Close() 1613 }) 1614 } 1615 1616 func TestConcurrent(t *testing.T) { 1617 if enabled, _ := readBool(os.Getenv("MYSQL_TEST_CONCURRENT")); !enabled { 1618 t.Skip("MYSQL_TEST_CONCURRENT env var not set") 1619 } 1620 1621 runTests(t, dsn, func(dbt *DBTest) { 1622 var max int 1623 err := dbt.db.QueryRow("SELECT @@max_connections").Scan(&max) 1624 if err != nil { 1625 dbt.Fatalf("%s", err.Error()) 1626 } 1627 dbt.Logf("testing up to %d concurrent connections \r\n", max) 1628 1629 var remaining, succeeded int32 = int32(max), 0 1630 1631 var wg sync.WaitGroup 1632 wg.Add(max) 1633 1634 var fatalError string 1635 var once sync.Once 1636 fatalf := func(s string, vals ...interface{}) { 1637 once.Do(func() { 1638 fatalError = fmt.Sprintf(s, vals...) 1639 }) 1640 } 1641 1642 for i := 0; i < max; i++ { 1643 go func(id int) { 1644 defer wg.Done() 1645 1646 tx, err := dbt.db.Begin() 1647 atomic.AddInt32(&remaining, -1) 1648 1649 if err != nil { 1650 if err.Error() != "Error 1040: Too many connections" { 1651 fatalf("error on conn %d: %s", id, err.Error()) 1652 } 1653 return 1654 } 1655 1656 // keep the connection busy until all connections are open 1657 for remaining > 0 { 1658 if _, err = tx.Exec("DO 1"); err != nil { 1659 fatalf("error on conn %d: %s", id, err.Error()) 1660 return 1661 } 1662 } 1663 1664 if err = tx.Commit(); err != nil { 1665 fatalf("error on conn %d: %s", id, err.Error()) 1666 return 1667 } 1668 1669 // everything went fine with this connection 1670 atomic.AddInt32(&succeeded, 1) 1671 }(i) 1672 } 1673 1674 // wait until all conections are open 1675 wg.Wait() 1676 1677 if fatalError != "" { 1678 dbt.Fatal(fatalError) 1679 } 1680 1681 dbt.Logf("reached %d concurrent connections\r\n", succeeded) 1682 }) 1683 } 1684 1685 // Tests custom dial functions 1686 func TestCustomDial(t *testing.T) { 1687 if !available { 1688 t.Skipf("MySQL server not running on %s", netAddr) 1689 } 1690 1691 // our custom dial function which justs wraps net.Dial here 1692 RegisterDial("mydial", func(addr string) (net.Conn, error) { 1693 return net.Dial(prot, addr) 1694 }) 1695 1696 db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@mydial(%s)/%s?timeout=30s&strict=true", user, pass, addr, dbname)) 1697 if err != nil { 1698 t.Fatalf("error connecting: %s", err.Error()) 1699 } 1700 defer db.Close() 1701 1702 if _, err = db.Exec("DO 1"); err != nil { 1703 t.Fatalf("connection failed: %s", err.Error()) 1704 } 1705 } 1706 1707 func TestSQLInjection(t *testing.T) { 1708 createTest := func(arg string) func(dbt *DBTest) { 1709 return func(dbt *DBTest) { 1710 dbt.mustExec("CREATE TABLE test (v INTEGER)") 1711 dbt.mustExec("INSERT INTO test VALUES (?)", 1) 1712 1713 var v int 1714 // NULL can't be equal to anything, the idea here is to inject query so it returns row 1715 // This test verifies that escapeQuotes and escapeBackslash are working properly 1716 err := dbt.db.QueryRow("SELECT v FROM test WHERE NULL = ?", arg).Scan(&v) 1717 if err == sql.ErrNoRows { 1718 return // success, sql injection failed 1719 } else if err == nil { 1720 dbt.Errorf("sql injection successful with arg: %s", arg) 1721 } else { 1722 dbt.Errorf("error running query with arg: %s; err: %s", arg, err.Error()) 1723 } 1724 } 1725 } 1726 1727 dsns := []string{ 1728 dsn, 1729 dsn + "&sql_mode='NO_BACKSLASH_ESCAPES,NO_AUTO_CREATE_USER'", 1730 } 1731 for _, testdsn := range dsns { 1732 runTests(t, testdsn, createTest("1 OR 1=1")) 1733 runTests(t, testdsn, createTest("' OR '1'='1")) 1734 } 1735 } 1736 1737 // Test if inserted data is correctly retrieved after being escaped 1738 func TestInsertRetrieveEscapedData(t *testing.T) { 1739 testData := func(dbt *DBTest) { 1740 dbt.mustExec("CREATE TABLE test (v VARCHAR(255))") 1741 1742 // All sequences that are escaped by escapeQuotes and escapeBackslash 1743 v := "foo \x00\n\r\x1a\"'\\" 1744 dbt.mustExec("INSERT INTO test VALUES (?)", v) 1745 1746 var out string 1747 err := dbt.db.QueryRow("SELECT v FROM test").Scan(&out) 1748 if err != nil { 1749 dbt.Fatalf("%s", err.Error()) 1750 } 1751 1752 if out != v { 1753 dbt.Errorf("%q != %q", out, v) 1754 } 1755 } 1756 1757 dsns := []string{ 1758 dsn, 1759 dsn + "&sql_mode='NO_BACKSLASH_ESCAPES,NO_AUTO_CREATE_USER'", 1760 } 1761 for _, testdsn := range dsns { 1762 runTests(t, testdsn, testData) 1763 } 1764 } 1765 1766 func TestUnixSocketAuthFail(t *testing.T) { 1767 runTests(t, dsn, func(dbt *DBTest) { 1768 // Save the current logger so we can restore it. 1769 oldLogger := errLog 1770 1771 // Set a new logger so we can capture its output. 1772 buffer := bytes.NewBuffer(make([]byte, 0, 64)) 1773 newLogger := log.New(buffer, "prefix: ", 0) 1774 SetLogger(newLogger) 1775 1776 // Restore the logger. 1777 defer SetLogger(oldLogger) 1778 1779 // Make a new DSN that uses the MySQL socket file and a bad password, which 1780 // we can make by simply appending any character to the real password. 1781 badPass := pass + "x" 1782 socket := "" 1783 if prot == "unix" { 1784 socket = addr 1785 } else { 1786 // Get socket file from MySQL. 1787 err := dbt.db.QueryRow("SELECT @@socket").Scan(&socket) 1788 if err != nil { 1789 t.Fatalf("error on SELECT @@socket: %s", err.Error()) 1790 } 1791 } 1792 t.Logf("socket: %s", socket) 1793 badDSN := fmt.Sprintf("%s:%s@unix(%s)/%s?timeout=30s&strict=true", user, badPass, socket, dbname) 1794 db, err := sql.Open("mysql", badDSN) 1795 if err != nil { 1796 t.Fatalf("error connecting: %s", err.Error()) 1797 } 1798 defer db.Close() 1799 1800 // Connect to MySQL for real. This will cause an auth failure. 1801 err = db.Ping() 1802 if err == nil { 1803 t.Error("expected Ping() to return an error") 1804 } 1805 1806 // The driver should not log anything. 1807 if actual := buffer.String(); actual != "" { 1808 t.Errorf("expected no output, got %q", actual) 1809 } 1810 }) 1811 }