driver_test.go 10.0 KB

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