driver_test.go 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  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. func getEnv() bool {
  17. once.Do(func() {
  18. user := os.Getenv("MYSQL_TEST_USER")
  19. if user == "" {
  20. user = "root"
  21. }
  22. pass := os.Getenv("MYSQL_TEST_PASS")
  23. if pass == "" {
  24. pass = "root"
  25. }
  26. prot := os.Getenv("MYSQL_TEST_PROT")
  27. if prot == "" {
  28. prot = "tcp"
  29. }
  30. addr := os.Getenv("MYSQL_TEST_ADDR")
  31. if addr == "" {
  32. addr = "localhost:3306"
  33. }
  34. dbname := os.Getenv("MYSQL_TEST_DBNAME")
  35. if dbname == "" {
  36. dbname = "gotest"
  37. }
  38. netAddr = fmt.Sprintf("%s(%s)", prot, addr)
  39. dsn = fmt.Sprintf("%s:%s@%s/%s?charset=utf8", user, pass, netAddr, dbname)
  40. c, err := net.Dial(prot, addr)
  41. if err == nil {
  42. run = true
  43. c.Close()
  44. }
  45. })
  46. return run
  47. }
  48. func mustExec(t *testing.T, db *sql.DB, query string, args ...interface{}) (res sql.Result) {
  49. res, err := db.Exec(query, args...)
  50. if err != nil {
  51. t.Fatalf("Error on Exec %q: %v", query, err)
  52. }
  53. return
  54. }
  55. func mustQuery(t *testing.T, db *sql.DB, query string, args ...interface{}) (rows *sql.Rows) {
  56. rows, err := db.Query(query, args...)
  57. if err != nil {
  58. t.Fatalf("Error on Query %q: %v", query, err)
  59. }
  60. return
  61. }
  62. func TestCRUD(t *testing.T) {
  63. if !getEnv() {
  64. t.Logf("MySQL-Server not running on %s. Skipping TestCRUD", netAddr)
  65. return
  66. }
  67. db, err := sql.Open("mysql", dsn)
  68. if err != nil {
  69. t.Fatalf("Error connecting: %v", err)
  70. }
  71. defer db.Close()
  72. mustExec(t, db, "DROP TABLE IF EXISTS test")
  73. // Create Table
  74. mustExec(t, db, "CREATE TABLE test (value BOOL)")
  75. // Test for unexpected data
  76. var out bool
  77. rows := mustQuery(t, db, ("SELECT * FROM test"))
  78. if rows.Next() {
  79. t.Error("unexpected data in empty table")
  80. }
  81. // Create Data
  82. res := mustExec(t, db, ("INSERT INTO test VALUES (1)"))
  83. count, err := res.RowsAffected()
  84. if err != nil {
  85. t.Fatalf("res.RowsAffected() returned error: %v", err)
  86. }
  87. if count != 1 {
  88. t.Fatalf("Expected 1 affected row, got %d", count)
  89. }
  90. id, err := res.LastInsertId()
  91. if err != nil {
  92. t.Fatalf("res.LastInsertId() returned error: %v", err)
  93. }
  94. if id != 0 {
  95. t.Fatalf("Expected InsertID 0, got %d", id)
  96. }
  97. // Read
  98. rows = mustQuery(t, db, ("SELECT value FROM test"))
  99. if rows.Next() {
  100. rows.Scan(&out)
  101. if true != out {
  102. t.Errorf("true != %d", out)
  103. }
  104. if rows.Next() {
  105. t.Error("unexpected data")
  106. }
  107. } else {
  108. t.Error("no data")
  109. }
  110. // Update
  111. mustExec(t, db, "UPDATE test SET value = ? WHERE value = ?", false, true)
  112. count, err = res.RowsAffected()
  113. if err != nil {
  114. t.Fatalf("res.RowsAffected() returned error: %v", err)
  115. }
  116. if count != 1 {
  117. t.Fatalf("Expected 1 affected row, got %d", count)
  118. }
  119. // Check Update
  120. rows = mustQuery(t, db, ("SELECT value FROM test"))
  121. if rows.Next() {
  122. rows.Scan(&out)
  123. if false != out {
  124. t.Errorf("false != %d", out)
  125. }
  126. if rows.Next() {
  127. t.Error("unexpected data")
  128. }
  129. } else {
  130. t.Error("no data")
  131. }
  132. // Delete
  133. mustExec(t, db, "DELETE FROM test WHERE value = ?", false)
  134. count, err = res.RowsAffected()
  135. if err != nil {
  136. t.Fatalf("res.RowsAffected() returned error: %v", err)
  137. }
  138. if count != 1 {
  139. t.Fatalf("Expected 1 affected row, got %d", count)
  140. }
  141. }
  142. func TestInt(t *testing.T) {
  143. if !getEnv() {
  144. t.Logf("MySQL-Server not running on %s. Skipping TestInt", netAddr)
  145. return
  146. }
  147. db, err := sql.Open("mysql", dsn)
  148. if err != nil {
  149. t.Fatalf("Error connecting: %v", err)
  150. }
  151. defer db.Close()
  152. mustExec(t, db, "DROP TABLE IF EXISTS test")
  153. types := [5]string{"TINYINT", "SMALLINT", "MEDIUMINT", "INT", "BIGINT"}
  154. in := int64(42)
  155. var out int64
  156. var rows *sql.Rows
  157. // SIGNED
  158. for _, v := range types {
  159. mustExec(t, db, "CREATE TABLE test (value "+v+")")
  160. mustExec(t, db, ("INSERT INTO test VALUES (?)"), in)
  161. rows = mustQuery(t, db, ("SELECT value FROM test"))
  162. if rows.Next() {
  163. rows.Scan(&out)
  164. if in != out {
  165. t.Errorf("%s: %d != %d", v, in, out)
  166. }
  167. } else {
  168. t.Errorf("%s: no data", v)
  169. }
  170. mustExec(t, db, "DROP TABLE IF EXISTS test")
  171. }
  172. // UNSIGNED ZEROFILL
  173. for _, v := range types {
  174. mustExec(t, db, "CREATE TABLE test (value "+v+" ZEROFILL)")
  175. mustExec(t, db, ("INSERT INTO test VALUES (?)"), in)
  176. rows = mustQuery(t, db, ("SELECT value FROM test"))
  177. if rows.Next() {
  178. rows.Scan(&out)
  179. if in != out {
  180. t.Errorf("%s ZEROFILL: %d != %d", v, in, out)
  181. }
  182. } else {
  183. t.Errorf("%s ZEROFILL: no data", v)
  184. }
  185. mustExec(t, db, "DROP TABLE IF EXISTS test")
  186. }
  187. }
  188. func TestFloat(t *testing.T) {
  189. if !getEnv() {
  190. t.Logf("MySQL-Server not running on %s. Skipping TestFloat", netAddr)
  191. return
  192. }
  193. db, err := sql.Open("mysql", dsn)
  194. if err != nil {
  195. t.Fatalf("Error connecting: %v", err)
  196. }
  197. defer db.Close()
  198. mustExec(t, db, "DROP TABLE IF EXISTS test")
  199. types := [2]string{"FLOAT", "DOUBLE"}
  200. in := float64(42.23)
  201. var out float64
  202. var rows *sql.Rows
  203. for _, v := range types {
  204. mustExec(t, db, "CREATE TABLE test (value "+v+")")
  205. mustExec(t, db, ("INSERT INTO test VALUES (?)"), in)
  206. rows = mustQuery(t, db, ("SELECT value FROM test"))
  207. if rows.Next() {
  208. rows.Scan(&out)
  209. if in != out {
  210. t.Errorf("%s: %d != %d", v, in, out)
  211. }
  212. } else {
  213. t.Errorf("%s: no data", v)
  214. }
  215. mustExec(t, db, "DROP TABLE IF EXISTS test")
  216. }
  217. }
  218. func TestString(t *testing.T) {
  219. if !getEnv() {
  220. t.Logf("MySQL-Server not running on %s. Skipping TestString", netAddr)
  221. return
  222. }
  223. db, err := sql.Open("mysql", dsn)
  224. if err != nil {
  225. t.Fatalf("Error connecting: %v", err)
  226. }
  227. defer db.Close()
  228. mustExec(t, db, "DROP TABLE IF EXISTS test")
  229. types := [6]string{"CHAR(255)", "VARCHAR(255)", "TINYTEXT", "TEXT", "MEDIUMTEXT", "LONGTEXT"}
  230. in := "κόσμε üöäßñóùéàâÿœ'îë Árvíztűrő いろはにほへとちりぬるを イロハニホヘト דג סקרן чащах น่าฟังเอย"
  231. var out string
  232. var rows *sql.Rows
  233. for _, v := range types {
  234. mustExec(t, db, "CREATE TABLE test (value "+v+") CHARACTER SET utf8 COLLATE utf8_unicode_ci")
  235. mustExec(t, db, ("INSERT INTO test VALUES (?)"), in)
  236. rows = mustQuery(t, db, ("SELECT value FROM test"))
  237. if rows.Next() {
  238. rows.Scan(&out)
  239. if in != out {
  240. t.Errorf("%s: %d != %d", v, in, out)
  241. }
  242. } else {
  243. t.Errorf("%s: no data", v)
  244. }
  245. mustExec(t, db, "DROP TABLE IF EXISTS test")
  246. }
  247. }
  248. func TestNULL(t *testing.T) {
  249. if !getEnv() {
  250. t.Logf("MySQL-Server not running on %s. Skipping TestNULL", netAddr)
  251. return
  252. }
  253. db, err := sql.Open("mysql", dsn)
  254. if err != nil {
  255. t.Fatalf("Error connecting: %v", err)
  256. }
  257. defer db.Close()
  258. stmt, err := db.Prepare("SELECT NULL")
  259. if err != nil {
  260. t.Fatal(err)
  261. }
  262. defer stmt.Close()
  263. var ns sql.NullString
  264. err = stmt.QueryRow().Scan(&ns)
  265. if err != nil {
  266. t.Fatal(err)
  267. }
  268. if ns.Valid {
  269. t.Error("Valid NullString which should be invalid")
  270. }
  271. }
  272. // Special cases
  273. func TestRowsClose(t *testing.T) {
  274. if !getEnv() {
  275. t.Logf("MySQL-Server not running on %s. Skipping TestRowsClose", netAddr)
  276. return
  277. }
  278. db, err := sql.Open("mysql", dsn)
  279. if err != nil {
  280. t.Fatalf("Error connecting: %v", err)
  281. }
  282. defer db.Close()
  283. rows, err := db.Query("SELECT 1")
  284. if err != nil {
  285. t.Fatal(err)
  286. }
  287. err = rows.Close()
  288. if err != nil {
  289. t.Fatal(err)
  290. }
  291. if rows.Next() {
  292. t.Fatal("Unexpected row after rows.Close()")
  293. }
  294. err = rows.Err()
  295. if err != nil {
  296. t.Fatal(err)
  297. }
  298. }
  299. // dangling statements
  300. // http://code.google.com/p/go/issues/detail?id=3865
  301. func TestCloseStmtBeforeRows(t *testing.T) {
  302. if !getEnv() {
  303. t.Logf("MySQL-Server not running on %s. Skipping TestCloseStmtBeforeRows", netAddr)
  304. return
  305. }
  306. db, err := sql.Open("mysql", dsn)
  307. if err != nil {
  308. t.Fatalf("Error connecting: %v", err)
  309. }
  310. defer db.Close()
  311. stmt, err := db.Prepare("SELECT 1")
  312. if err != nil {
  313. t.Fatal(err)
  314. }
  315. rows, err := stmt.Query()
  316. if err != nil {
  317. stmt.Close()
  318. t.Fatal(err)
  319. }
  320. defer rows.Close()
  321. err = stmt.Close()
  322. if err != nil {
  323. t.Fatal(err)
  324. }
  325. if !rows.Next() {
  326. t.Fatal("Getting row failed")
  327. } else {
  328. err = rows.Err()
  329. if err != nil {
  330. t.Fatal(err)
  331. }
  332. var out bool
  333. err = rows.Scan(&out)
  334. if err != nil {
  335. t.Fatalf("Error on rows.Scan(): %v", err)
  336. }
  337. if out != true {
  338. t.Errorf("true != %d", out)
  339. }
  340. }
  341. }
  342. // It is valid to have multiple Rows for the same Stmt
  343. // http://code.google.com/p/go/issues/detail?id=3734
  344. func TestStmtMultiRows(t *testing.T) {
  345. if !getEnv() {
  346. t.Logf("MySQL-Server not running on %s. Skipping TestStmtMultiRows", netAddr)
  347. return
  348. }
  349. db, err := sql.Open("mysql", dsn)
  350. if err != nil {
  351. t.Fatalf("Error connecting: %v", err)
  352. }
  353. defer db.Close()
  354. stmt, err := db.Prepare("SELECT 1 UNION SELECT 0")
  355. if err != nil {
  356. t.Fatal(err)
  357. }
  358. rows1, err := stmt.Query()
  359. if err != nil {
  360. stmt.Close()
  361. t.Fatal(err)
  362. }
  363. defer rows1.Close()
  364. rows2, err := stmt.Query()
  365. if err != nil {
  366. stmt.Close()
  367. t.Fatal(err)
  368. }
  369. defer rows2.Close()
  370. var out bool
  371. // 1
  372. if !rows1.Next() {
  373. t.Fatal("1st rows1.Next failed")
  374. } else {
  375. err = rows1.Err()
  376. if err != nil {
  377. t.Fatal(err)
  378. }
  379. err = rows1.Scan(&out)
  380. if err != nil {
  381. t.Fatalf("Error on rows.Scan(): %v", err)
  382. }
  383. if out != true {
  384. t.Errorf("true != %d", out)
  385. }
  386. }
  387. if !rows2.Next() {
  388. t.Fatal("1st rows2.Next failed")
  389. } else {
  390. err = rows2.Err()
  391. if err != nil {
  392. t.Fatal(err)
  393. }
  394. err = rows2.Scan(&out)
  395. if err != nil {
  396. t.Fatalf("Error on rows.Scan(): %v", err)
  397. }
  398. if out != true {
  399. t.Errorf("true != %d", out)
  400. }
  401. }
  402. // 2
  403. if !rows1.Next() {
  404. t.Fatal("2nd rows1.Next failed")
  405. } else {
  406. err = rows1.Err()
  407. if err != nil {
  408. t.Fatal(err)
  409. }
  410. err = rows1.Scan(&out)
  411. if err != nil {
  412. t.Fatalf("Error on rows.Scan(): %v", err)
  413. }
  414. if out != false {
  415. t.Errorf("false != %d", out)
  416. }
  417. if rows1.Next() {
  418. t.Fatal("Unexpected row on rows1")
  419. }
  420. err = rows1.Close()
  421. if err != nil {
  422. t.Fatal(err)
  423. }
  424. }
  425. if !rows2.Next() {
  426. t.Fatal("2nd rows2.Next failed")
  427. } else {
  428. err = rows2.Err()
  429. if err != nil {
  430. t.Fatal(err)
  431. }
  432. err = rows2.Scan(&out)
  433. if err != nil {
  434. t.Fatalf("Error on rows.Scan(): %v", err)
  435. }
  436. if out != false {
  437. t.Errorf("false != %d", out)
  438. }
  439. if rows2.Next() {
  440. t.Fatal("Unexpected row on rows2")
  441. }
  442. err = rows2.Close()
  443. if err != nil {
  444. t.Fatal(err)
  445. }
  446. }
  447. }