connection.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. // Go MySQL Driver - A MySQL-Driver for Go's database/sql package
  2. //
  3. // Copyright 2012 Julien Schmidt. All rights reserved.
  4. // http://www.julienschmidt.com
  5. //
  6. // This Source Code Form is subject to the terms of the Mozilla Public
  7. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  8. // You can obtain one at http://mozilla.org/MPL/2.0/.
  9. package mysql
  10. import (
  11. "database/sql/driver"
  12. "errors"
  13. "net"
  14. "strings"
  15. )
  16. type mysqlConn struct {
  17. cfg *config
  18. flags clientFlag
  19. charset byte
  20. cipher []byte
  21. netConn net.Conn
  22. buf *buffer
  23. protocol uint8
  24. sequence uint8
  25. affectedRows uint64
  26. insertId uint64
  27. maxPacketAllowed int
  28. maxWriteSize int
  29. }
  30. type config struct {
  31. user string
  32. passwd string
  33. net string
  34. addr string
  35. dbname string
  36. params map[string]string
  37. }
  38. // Handles parameters set in DSN
  39. func (mc *mysqlConn) handleParams() (err error) {
  40. for param, val := range mc.cfg.params {
  41. switch param {
  42. // Charset
  43. case "charset":
  44. charsets := strings.Split(val, ",")
  45. for i := range charsets {
  46. // ignore errors here - a charset may not exist
  47. err = mc.exec("SET NAMES " + charsets[i])
  48. if err == nil {
  49. break
  50. }
  51. }
  52. if err != nil {
  53. return
  54. }
  55. // handled elsewhere
  56. case "timeout", "allowAllFiles":
  57. continue
  58. // TLS-Encryption
  59. case "tls":
  60. err = errors.New("TLS-Encryption not implemented yet")
  61. return
  62. // Compression
  63. case "compress":
  64. err = errors.New("Compression not implemented yet")
  65. // System Vars
  66. default:
  67. err = mc.exec("SET " + param + "=" + val + "")
  68. if err != nil {
  69. return
  70. }
  71. }
  72. }
  73. return
  74. }
  75. func (mc *mysqlConn) Begin() (driver.Tx, error) {
  76. err := mc.exec("START TRANSACTION")
  77. if err == nil {
  78. return &mysqlTx{mc}, err
  79. }
  80. return nil, err
  81. }
  82. func (mc *mysqlConn) Close() (err error) {
  83. mc.writeCommandPacket(comQuit)
  84. mc.cfg = nil
  85. mc.buf = nil
  86. mc.netConn.Close()
  87. mc.netConn = nil
  88. return
  89. }
  90. func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) {
  91. // Send command
  92. err := mc.writeCommandPacketStr(comStmtPrepare, query)
  93. if err != nil {
  94. return nil, err
  95. }
  96. stmt := &mysqlStmt{
  97. mc: mc,
  98. }
  99. // Read Result
  100. columnCount, err := stmt.readPrepareResultPacket()
  101. if err == nil {
  102. if stmt.paramCount > 0 {
  103. stmt.params, err = stmt.mc.readColumns(stmt.paramCount)
  104. if err != nil {
  105. return nil, err
  106. }
  107. }
  108. if columnCount > 0 {
  109. err = stmt.mc.readUntilEOF()
  110. }
  111. }
  112. return stmt, err
  113. }
  114. func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, error) {
  115. if len(args) == 0 { // no args, fastpath
  116. mc.affectedRows = 0
  117. mc.insertId = 0
  118. err := mc.exec(query)
  119. if err == nil {
  120. return &mysqlResult{
  121. affectedRows: int64(mc.affectedRows),
  122. insertId: int64(mc.insertId),
  123. }, err
  124. }
  125. return nil, err
  126. }
  127. // with args, must use prepared stmt
  128. return nil, driver.ErrSkip
  129. }
  130. // Internal function to execute commands
  131. func (mc *mysqlConn) exec(query string) (err error) {
  132. // Send command
  133. err = mc.writeCommandPacketStr(comQuery, query)
  134. if err != nil {
  135. return
  136. }
  137. // Read Result
  138. var resLen int
  139. resLen, err = mc.readResultSetHeaderPacket()
  140. if err == nil && resLen > 0 {
  141. err = mc.readUntilEOF()
  142. if err != nil {
  143. return
  144. }
  145. err = mc.readUntilEOF()
  146. }
  147. return
  148. }
  149. func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, error) {
  150. if len(args) == 0 { // no args, fastpath
  151. // Send command
  152. err := mc.writeCommandPacketStr(comQuery, query)
  153. if err == nil {
  154. // Read Result
  155. var resLen int
  156. resLen, err = mc.readResultSetHeaderPacket()
  157. if err == nil {
  158. rows := &mysqlRows{mc, false, nil, false}
  159. if resLen > 0 {
  160. // Columns
  161. rows.columns, err = mc.readColumns(resLen)
  162. }
  163. return rows, err
  164. }
  165. }
  166. return nil, err
  167. }
  168. // with args, must use prepared stmt
  169. return nil, driver.ErrSkip
  170. }
  171. // Gets the value of the given MySQL System Variable
  172. // The returned byte slice is only valid until the next read
  173. func (mc *mysqlConn) getSystemVar(name string) (val []byte, err error) {
  174. // Send command
  175. err = mc.writeCommandPacketStr(comQuery, "SELECT @@"+name)
  176. if err == nil {
  177. // Read Result
  178. var resLen int
  179. resLen, err = mc.readResultSetHeaderPacket()
  180. if err == nil {
  181. rows := &mysqlRows{mc, false, nil, false}
  182. if resLen > 0 {
  183. // Columns
  184. rows.columns, err = mc.readColumns(resLen)
  185. }
  186. dest := make([]driver.Value, resLen)
  187. err = rows.readRow(dest)
  188. if err == nil {
  189. val = dest[0].([]byte)
  190. err = mc.readUntilEOF()
  191. }
  192. }
  193. }
  194. return
  195. }