driver_test.go 21 KB

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