driver_test.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754
  1. package mysql
  2. import (
  3. "database/sql"
  4. "fmt"
  5. "net"
  6. "os"
  7. "sync"
  8. "testing"
  9. )
  10. var (
  11. dsn string
  12. netAddr string
  13. run bool
  14. once sync.Once
  15. )
  16. // See https://github.com/Go-SQL-Driver/MySQL/wiki/Testing
  17. func getEnv() bool {
  18. once.Do(func() {
  19. user := os.Getenv("MYSQL_TEST_USER")
  20. if user == "" {
  21. user = "root"
  22. }
  23. pass := os.Getenv("MYSQL_TEST_PASS")
  24. prot := os.Getenv("MYSQL_TEST_PROT")
  25. if prot == "" {
  26. prot = "tcp"
  27. }
  28. addr := os.Getenv("MYSQL_TEST_ADDR")
  29. if addr == "" {
  30. addr = "localhost:3306"
  31. }
  32. dbname := os.Getenv("MYSQL_TEST_DBNAME")
  33. if dbname == "" {
  34. dbname = "gotest"
  35. }
  36. netAddr = fmt.Sprintf("%s(%s)", prot, addr)
  37. dsn = fmt.Sprintf("%s:%s@%s/%s?timeout=30s&charset=utf8", user, pass, netAddr, dbname)
  38. c, err := net.Dial(prot, addr)
  39. if err == nil {
  40. run = true
  41. c.Close()
  42. }
  43. })
  44. return run
  45. }
  46. func mustExec(t *testing.T, db *sql.DB, query string, args ...interface{}) (res sql.Result) {
  47. res, err := db.Exec(query, args...)
  48. if err != nil {
  49. t.Fatalf("Error on Exec %q: %v", query, err)
  50. }
  51. return
  52. }
  53. func mustQuery(t *testing.T, db *sql.DB, query string, args ...interface{}) (rows *sql.Rows) {
  54. rows, err := db.Query(query, args...)
  55. if err != nil {
  56. t.Fatalf("Error on Query %q: %v", query, err)
  57. }
  58. return
  59. }
  60. func TestCRUD(t *testing.T) {
  61. if !getEnv() {
  62. t.Logf("MySQL-Server not running on %s. Skipping TestCRUD", netAddr)
  63. return
  64. }
  65. db, err := sql.Open("mysql", dsn)
  66. if err != nil {
  67. t.Fatalf("Error connecting: %v", err)
  68. }
  69. defer db.Close()
  70. mustExec(t, db, "DROP TABLE IF EXISTS test")
  71. // Create Table
  72. mustExec(t, db, "CREATE TABLE test (value BOOL)")
  73. // Test for unexpected data
  74. var out bool
  75. rows := mustQuery(t, db, ("SELECT * FROM test"))
  76. if rows.Next() {
  77. t.Error("unexpected data in empty table")
  78. }
  79. // Create Data
  80. res := mustExec(t, db, ("INSERT INTO test VALUES (1)"))
  81. count, err := res.RowsAffected()
  82. if err != nil {
  83. t.Fatalf("res.RowsAffected() returned error: %v", err)
  84. }
  85. if count != 1 {
  86. t.Fatalf("Expected 1 affected row, got %d", count)
  87. }
  88. id, err := res.LastInsertId()
  89. if err != nil {
  90. t.Fatalf("res.LastInsertId() returned error: %v", err)
  91. }
  92. if id != 0 {
  93. t.Fatalf("Expected InsertID 0, got %d", id)
  94. }
  95. // Read
  96. rows = mustQuery(t, db, ("SELECT value FROM test"))
  97. if rows.Next() {
  98. rows.Scan(&out)
  99. if true != out {
  100. t.Errorf("true != %t", out)
  101. }
  102. if rows.Next() {
  103. t.Error("unexpected data")
  104. }
  105. } else {
  106. t.Error("no data")
  107. }
  108. // Update
  109. res = mustExec(t, db, "UPDATE test SET value = ? WHERE value = ?", false, true)
  110. count, err = res.RowsAffected()
  111. if err != nil {
  112. t.Fatalf("res.RowsAffected() returned error: %v", err)
  113. }
  114. if count != 1 {
  115. t.Fatalf("Expected 1 affected row, got %d", count)
  116. }
  117. // Check Update
  118. rows = mustQuery(t, db, ("SELECT value FROM test"))
  119. if rows.Next() {
  120. rows.Scan(&out)
  121. if false != out {
  122. t.Errorf("false != %t", out)
  123. }
  124. if rows.Next() {
  125. t.Error("unexpected data")
  126. }
  127. } else {
  128. t.Error("no data")
  129. }
  130. // Delete
  131. res = mustExec(t, db, "DELETE FROM test WHERE value = ?", false)
  132. count, err = res.RowsAffected()
  133. if err != nil {
  134. t.Fatalf("res.RowsAffected() returned error: %v", err)
  135. }
  136. if count != 1 {
  137. t.Fatalf("Expected 1 affected row, got %d", count)
  138. }
  139. // Check for unexpected rows
  140. res = mustExec(t, db, "DELETE FROM test")
  141. count, err = res.RowsAffected()
  142. if err != nil {
  143. t.Fatalf("res.RowsAffected() returned error: %v", err)
  144. }
  145. if count != 0 {
  146. t.Fatalf("Expected 0 affected row, got %d", count)
  147. }
  148. }
  149. func TestInt(t *testing.T) {
  150. if !getEnv() {
  151. t.Logf("MySQL-Server not running on %s. Skipping TestInt", netAddr)
  152. return
  153. }
  154. db, err := sql.Open("mysql", dsn)
  155. if err != nil {
  156. t.Fatalf("Error connecting: %v", err)
  157. }
  158. defer db.Close()
  159. mustExec(t, db, "DROP TABLE IF EXISTS test")
  160. types := [5]string{"TINYINT", "SMALLINT", "MEDIUMINT", "INT", "BIGINT"}
  161. in := int64(42)
  162. var out int64
  163. var rows *sql.Rows
  164. // SIGNED
  165. for _, v := range types {
  166. mustExec(t, db, "CREATE TABLE test (value "+v+")")
  167. mustExec(t, db, ("INSERT INTO test VALUES (?)"), in)
  168. rows = mustQuery(t, db, ("SELECT value FROM test"))
  169. if rows.Next() {
  170. rows.Scan(&out)
  171. if in != out {
  172. t.Errorf("%s: %d != %d", v, in, out)
  173. }
  174. } else {
  175. t.Errorf("%s: no data", v)
  176. }
  177. mustExec(t, db, "DROP TABLE IF EXISTS test")
  178. }
  179. // UNSIGNED ZEROFILL
  180. for _, v := range types {
  181. mustExec(t, db, "CREATE TABLE test (value "+v+" ZEROFILL)")
  182. mustExec(t, db, ("INSERT INTO test VALUES (?)"), in)
  183. rows = mustQuery(t, db, ("SELECT value FROM test"))
  184. if rows.Next() {
  185. rows.Scan(&out)
  186. if in != out {
  187. t.Errorf("%s ZEROFILL: %d != %d", v, in, out)
  188. }
  189. } else {
  190. t.Errorf("%s ZEROFILL: no data", v)
  191. }
  192. mustExec(t, db, "DROP TABLE IF EXISTS test")
  193. }
  194. }
  195. func TestFloat(t *testing.T) {
  196. if !getEnv() {
  197. t.Logf("MySQL-Server not running on %s. Skipping TestFloat", netAddr)
  198. return
  199. }
  200. db, err := sql.Open("mysql", dsn)
  201. if err != nil {
  202. t.Fatalf("Error connecting: %v", err)
  203. }
  204. defer db.Close()
  205. mustExec(t, db, "DROP TABLE IF EXISTS test")
  206. types := [2]string{"FLOAT", "DOUBLE"}
  207. in := float32(42.23)
  208. var out float32
  209. var rows *sql.Rows
  210. for _, v := range types {
  211. mustExec(t, db, "CREATE TABLE test (value "+v+")")
  212. mustExec(t, db, ("INSERT INTO test VALUES (?)"), in)
  213. rows = mustQuery(t, db, ("SELECT value FROM test"))
  214. if rows.Next() {
  215. rows.Scan(&out)
  216. if in != out {
  217. t.Errorf("%s: %g != %g", v, in, out)
  218. }
  219. } else {
  220. t.Errorf("%s: no data", v)
  221. }
  222. mustExec(t, db, "DROP TABLE IF EXISTS test")
  223. }
  224. }
  225. func TestString(t *testing.T) {
  226. if !getEnv() {
  227. t.Logf("MySQL-Server not running on %s. Skipping TestString", netAddr)
  228. return
  229. }
  230. db, err := sql.Open("mysql", dsn)
  231. if err != nil {
  232. t.Fatalf("Error connecting: %v", err)
  233. }
  234. defer db.Close()
  235. mustExec(t, db, "DROP TABLE IF EXISTS test")
  236. types := [6]string{"CHAR(255)", "VARCHAR(255)", "TINYTEXT", "TEXT", "MEDIUMTEXT", "LONGTEXT"}
  237. in := "κόσμε üöäßñóùéàâÿœ'îë Árvíztűrő いろはにほへとちりぬるを イロハニホヘト דג סקרן чащах น่าฟังเอย"
  238. var out string
  239. var rows *sql.Rows
  240. for _, v := range types {
  241. mustExec(t, db, "CREATE TABLE test (value "+v+") CHARACTER SET utf8 COLLATE utf8_unicode_ci")
  242. mustExec(t, db, ("INSERT INTO test VALUES (?)"), in)
  243. rows = mustQuery(t, db, ("SELECT value FROM test"))
  244. if rows.Next() {
  245. rows.Scan(&out)
  246. if in != out {
  247. t.Errorf("%s: %s != %s", v, in, out)
  248. }
  249. } else {
  250. t.Errorf("%s: no data", v)
  251. }
  252. mustExec(t, db, "DROP TABLE IF EXISTS test")
  253. }
  254. // BLOB
  255. mustExec(t, db, "CREATE TABLE test (id int, value BLOB) CHARACTER SET utf8 COLLATE utf8_unicode_ci")
  256. id := 2
  257. in = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, " +
  258. "sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, " +
  259. "sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. " +
  260. "Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. " +
  261. "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, " +
  262. "sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, " +
  263. "sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. " +
  264. "Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."
  265. mustExec(t, db, ("INSERT INTO test VALUES (?, ?)"), id, in)
  266. err = db.QueryRow("SELECT value FROM test WHERE id = ?", id).Scan(&out)
  267. if err != nil {
  268. t.Fatalf("Error on BLOB-Query: %v", err)
  269. } else if out != in {
  270. t.Errorf("BLOB: %s != %s", in, out)
  271. }
  272. return
  273. }
  274. func TestDateTime(t *testing.T) {
  275. if !getEnv() {
  276. t.Logf("MySQL-Server not running on %s. Skipping TestString", netAddr)
  277. return
  278. }
  279. db, err := sql.Open("mysql", dsn)
  280. if err != nil {
  281. t.Fatalf("Error connecting: %v", err)
  282. }
  283. defer db.Close()
  284. mustExec(t, db, "DROP TABLE IF EXISTS test")
  285. types := [...]string{"DATE", "DATETIME"}
  286. in := [...]string{"2012-06-14", "2011-11-20 21:27:37"}
  287. var out string
  288. var rows *sql.Rows
  289. for i, v := range types {
  290. mustExec(t, db, "CREATE TABLE test (value "+v+") CHARACTER SET utf8 COLLATE utf8_unicode_ci")
  291. mustExec(t, db, ("INSERT INTO test VALUES (?)"), in[i])
  292. rows = mustQuery(t, db, ("SELECT value FROM test"))
  293. if rows.Next() {
  294. rows.Scan(&out)
  295. if in[i] != out {
  296. t.Errorf("%s: %s != %s", v, in[i], out)
  297. }
  298. } else {
  299. t.Errorf("%s: no data", v)
  300. }
  301. mustExec(t, db, "DROP TABLE IF EXISTS test")
  302. }
  303. }
  304. func TestNULL(t *testing.T) {
  305. if !getEnv() {
  306. t.Logf("MySQL-Server not running on %s. Skipping TestNULL", netAddr)
  307. return
  308. }
  309. db, err := sql.Open("mysql", dsn)
  310. if err != nil {
  311. t.Fatalf("Error connecting: %v", err)
  312. }
  313. defer db.Close()
  314. nullStmt, err := db.Prepare("SELECT NULL")
  315. if err != nil {
  316. t.Fatal(err)
  317. }
  318. defer nullStmt.Close()
  319. nonNullStmt, err := db.Prepare("SELECT 1")
  320. if err != nil {
  321. t.Fatal(err)
  322. }
  323. defer nonNullStmt.Close()
  324. // NullBool
  325. var nb sql.NullBool
  326. // Invalid
  327. err = nullStmt.QueryRow().Scan(&nb)
  328. if err != nil {
  329. t.Fatal(err)
  330. }
  331. if nb.Valid {
  332. t.Error("Valid NullBool which should be invalid")
  333. }
  334. // Valid
  335. err = nonNullStmt.QueryRow().Scan(&nb)
  336. if err != nil {
  337. t.Fatal(err)
  338. }
  339. if !nb.Valid {
  340. t.Error("Invalid NullBool which should be valid")
  341. } else if nb.Bool != true {
  342. t.Errorf("Unexpected NullBool value: %t (should be true)", nb.Bool)
  343. }
  344. // NullFloat64
  345. var nf sql.NullFloat64
  346. // Invalid
  347. err = nullStmt.QueryRow().Scan(&nf)
  348. if err != nil {
  349. t.Fatal(err)
  350. }
  351. if nf.Valid {
  352. t.Error("Valid NullFloat64 which should be invalid")
  353. }
  354. // Valid
  355. err = nonNullStmt.QueryRow().Scan(&nf)
  356. if err != nil {
  357. t.Fatal(err)
  358. }
  359. if !nf.Valid {
  360. t.Error("Invalid NullFloat64 which should be valid")
  361. } else if nf.Float64 != float64(1) {
  362. t.Errorf("Unexpected NullFloat64 value: %f (should be 1.0)", nf.Float64)
  363. }
  364. // NullInt64
  365. var ni sql.NullInt64
  366. // Invalid
  367. err = nullStmt.QueryRow().Scan(&ni)
  368. if err != nil {
  369. t.Fatal(err)
  370. }
  371. if ni.Valid {
  372. t.Error("Valid NullInt64 which should be invalid")
  373. }
  374. // Valid
  375. err = nonNullStmt.QueryRow().Scan(&ni)
  376. if err != nil {
  377. t.Fatal(err)
  378. }
  379. if !ni.Valid {
  380. t.Error("Invalid NullInt64 which should be valid")
  381. } else if ni.Int64 != int64(1) {
  382. t.Errorf("Unexpected NullInt64 value: %d (should be 1)", ni.Int64)
  383. }
  384. // NullString
  385. var ns sql.NullString
  386. // Invalid
  387. err = nullStmt.QueryRow().Scan(&ns)
  388. if err != nil {
  389. t.Fatal(err)
  390. }
  391. if ns.Valid {
  392. t.Error("Valid NullString which should be invalid")
  393. }
  394. // Valid
  395. err = nonNullStmt.QueryRow().Scan(&ns)
  396. if err != nil {
  397. t.Fatal(err)
  398. }
  399. if !ns.Valid {
  400. t.Error("Invalid NullString which should be valid")
  401. } else if ns.String != `1` {
  402. t.Error("Unexpected NullString value:" + ns.String + " (should be `1`)")
  403. }
  404. }
  405. // Special cases
  406. func TestRowsClose(t *testing.T) {
  407. if !getEnv() {
  408. t.Logf("MySQL-Server not running on %s. Skipping TestRowsClose", netAddr)
  409. return
  410. }
  411. db, err := sql.Open("mysql", dsn)
  412. if err != nil {
  413. t.Fatalf("Error connecting: %v", err)
  414. }
  415. defer db.Close()
  416. rows, err := db.Query("SELECT 1")
  417. if err != nil {
  418. t.Fatal(err)
  419. }
  420. err = rows.Close()
  421. if err != nil {
  422. t.Fatal(err)
  423. }
  424. if rows.Next() {
  425. t.Fatal("Unexpected row after rows.Close()")
  426. }
  427. err = rows.Err()
  428. if err != nil {
  429. t.Fatal(err)
  430. }
  431. }
  432. // dangling statements
  433. // http://code.google.com/p/go/issues/detail?id=3865
  434. func TestCloseStmtBeforeRows(t *testing.T) {
  435. if !getEnv() {
  436. t.Logf("MySQL-Server not running on %s. Skipping TestCloseStmtBeforeRows", netAddr)
  437. return
  438. }
  439. db, err := sql.Open("mysql", dsn)
  440. if err != nil {
  441. t.Fatalf("Error connecting: %v", err)
  442. }
  443. defer db.Close()
  444. stmt, err := db.Prepare("SELECT 1")
  445. if err != nil {
  446. t.Fatal(err)
  447. }
  448. rows, err := stmt.Query()
  449. if err != nil {
  450. stmt.Close()
  451. t.Fatal(err)
  452. }
  453. defer rows.Close()
  454. err = stmt.Close()
  455. if err != nil {
  456. t.Fatal(err)
  457. }
  458. if !rows.Next() {
  459. t.Fatal("Getting row failed")
  460. } else {
  461. err = rows.Err()
  462. if err != nil {
  463. t.Fatal(err)
  464. }
  465. var out bool
  466. err = rows.Scan(&out)
  467. if err != nil {
  468. t.Fatalf("Error on rows.Scan(): %v", err)
  469. }
  470. if out != true {
  471. t.Errorf("true != %t", out)
  472. }
  473. }
  474. }
  475. // It is valid to have multiple Rows for the same Stmt
  476. // http://code.google.com/p/go/issues/detail?id=3734
  477. func TestStmtMultiRows(t *testing.T) {
  478. if !getEnv() {
  479. t.Logf("MySQL-Server not running on %s. Skipping TestStmtMultiRows", netAddr)
  480. return
  481. }
  482. db, err := sql.Open("mysql", dsn)
  483. if err != nil {
  484. t.Fatalf("Error connecting: %v", err)
  485. }
  486. defer db.Close()
  487. stmt, err := db.Prepare("SELECT 1 UNION SELECT 0")
  488. if err != nil {
  489. t.Fatal(err)
  490. }
  491. rows1, err := stmt.Query()
  492. if err != nil {
  493. stmt.Close()
  494. t.Fatal(err)
  495. }
  496. defer rows1.Close()
  497. rows2, err := stmt.Query()
  498. if err != nil {
  499. stmt.Close()
  500. t.Fatal(err)
  501. }
  502. defer rows2.Close()
  503. var out bool
  504. // 1
  505. if !rows1.Next() {
  506. t.Fatal("1st rows1.Next failed")
  507. } else {
  508. err = rows1.Err()
  509. if err != nil {
  510. t.Fatal(err)
  511. }
  512. err = rows1.Scan(&out)
  513. if err != nil {
  514. t.Fatalf("Error on rows.Scan(): %v", err)
  515. }
  516. if out != true {
  517. t.Errorf("true != %t", out)
  518. }
  519. }
  520. if !rows2.Next() {
  521. t.Fatal("1st rows2.Next failed")
  522. } else {
  523. err = rows2.Err()
  524. if err != nil {
  525. t.Fatal(err)
  526. }
  527. err = rows2.Scan(&out)
  528. if err != nil {
  529. t.Fatalf("Error on rows.Scan(): %v", err)
  530. }
  531. if out != true {
  532. t.Errorf("true != %t", out)
  533. }
  534. }
  535. // 2
  536. if !rows1.Next() {
  537. t.Fatal("2nd rows1.Next failed")
  538. } else {
  539. err = rows1.Err()
  540. if err != nil {
  541. t.Fatal(err)
  542. }
  543. err = rows1.Scan(&out)
  544. if err != nil {
  545. t.Fatalf("Error on rows.Scan(): %v", err)
  546. }
  547. if out != false {
  548. t.Errorf("false != %t", out)
  549. }
  550. if rows1.Next() {
  551. t.Fatal("Unexpected row on rows1")
  552. }
  553. err = rows1.Close()
  554. if err != nil {
  555. t.Fatal(err)
  556. }
  557. }
  558. if !rows2.Next() {
  559. t.Fatal("2nd rows2.Next failed")
  560. } else {
  561. err = rows2.Err()
  562. if err != nil {
  563. t.Fatal(err)
  564. }
  565. err = rows2.Scan(&out)
  566. if err != nil {
  567. t.Fatalf("Error on rows.Scan(): %v", err)
  568. }
  569. if out != false {
  570. t.Errorf("false != %t", out)
  571. }
  572. if rows2.Next() {
  573. t.Fatal("Unexpected row on rows2")
  574. }
  575. err = rows2.Close()
  576. if err != nil {
  577. t.Fatal(err)
  578. }
  579. }
  580. }
  581. func TestConcurrent(t *testing.T) {
  582. if os.Getenv("MYSQL_TEST_CONCURRENT") != "1" {
  583. t.Log("CONCURRENT env var not set. Skipping TestConcurrent")
  584. return
  585. }
  586. if !getEnv() {
  587. t.Logf("MySQL-Server not running on %s. Skipping TestConcurrent", netAddr)
  588. return
  589. }
  590. db, err := sql.Open("mysql", dsn)
  591. if err != nil {
  592. t.Fatalf("Error connecting: %v", err)
  593. }
  594. defer db.Close()
  595. var max int
  596. err = db.QueryRow("SELECT @@max_connections").Scan(&max)
  597. if err != nil {
  598. t.Fatalf("%v", err)
  599. }
  600. t.Logf("Testing %d concurrent connections \r\n", max)
  601. canStop := false
  602. c := make(chan struct{}, max)
  603. for i := 0; i < max; i++ {
  604. go func() {
  605. tx, err := db.Begin()
  606. if err != nil {
  607. canStop = true
  608. t.Fatalf("Error on Con %d: %s", i, err.Error())
  609. }
  610. c <- struct{}{}
  611. for !canStop {
  612. _, err := tx.Exec("SELECT 1")
  613. if err != nil {
  614. canStop = true
  615. t.Fatalf("Error on Con %d: %s", i, err.Error())
  616. }
  617. }
  618. err = tx.Commit()
  619. if err != nil {
  620. canStop = true
  621. t.Fatalf("Error on Con %d: %s", i, err.Error())
  622. }
  623. }()
  624. }
  625. for i := 0; i < max; i++ {
  626. <-c
  627. }
  628. canStop = true
  629. }