driver_test.go 24 KB

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