driver_test.go 17 KB

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