connection.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  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. "bufio"
  12. "database/sql/driver"
  13. "net"
  14. "strings"
  15. )
  16. type mysqlConn struct {
  17. cfg *config
  18. server *serverSettings
  19. netConn net.Conn
  20. bufReader *bufio.Reader
  21. protocol uint8
  22. sequence uint8
  23. affectedRows uint64
  24. insertId uint64
  25. }
  26. type config struct {
  27. user string
  28. passwd string
  29. net string
  30. addr string
  31. dbname string
  32. params map[string]string
  33. }
  34. type serverSettings struct {
  35. protocol byte
  36. version string
  37. flags ClientFlag
  38. charset uint8
  39. scrambleBuff []byte
  40. threadID uint32
  41. }
  42. // Handles parameters set in DSN
  43. func (mc *mysqlConn) handleParams() (err error) {
  44. for param, val := range mc.cfg.params {
  45. switch param {
  46. // Charset
  47. case "charset":
  48. charsets := strings.Split(val, ",")
  49. for _, charset := range charsets {
  50. err = mc.exec("SET NAMES " + charset)
  51. if err == nil {
  52. break
  53. }
  54. }
  55. if err != nil {
  56. return
  57. }
  58. // TLS-Encryption
  59. case "tls":
  60. dbgLog.Print("TLS-Encryption not implemented yet")
  61. // Compression
  62. case "compress":
  63. dbgLog.Print("Compression not implemented yet")
  64. // System Vars
  65. default:
  66. err = mc.exec("SET " + param + "=" + val + "")
  67. if err != nil {
  68. return
  69. }
  70. }
  71. }
  72. return
  73. }
  74. func (mc *mysqlConn) Begin() (driver.Tx, error) {
  75. err := mc.exec("START TRANSACTION")
  76. if err != nil {
  77. return nil, err
  78. }
  79. return &mysqlTx{mc}, err
  80. }
  81. func (mc *mysqlConn) Close() (err error) {
  82. mc.writeCommandPacket(COM_QUIT)
  83. mc.bufReader = nil
  84. mc.netConn.Close()
  85. mc.netConn = nil
  86. return
  87. }
  88. func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) {
  89. // Send command
  90. err := mc.writeCommandPacket(COM_STMT_PREPARE, query)
  91. if err != nil {
  92. return nil, err
  93. }
  94. stmt := mysqlStmt{new(stmtContent)}
  95. stmt.mc = mc
  96. // Read Result
  97. var columnCount uint16
  98. columnCount, err = stmt.readPrepareResultPacket()
  99. if err != nil {
  100. return nil, err
  101. }
  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. if err != nil {
  111. return nil, err
  112. }
  113. }
  114. return stmt, err
  115. }
  116. func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, error) {
  117. if len(args) > 0 {
  118. return nil, driver.ErrSkip
  119. }
  120. mc.affectedRows = 0
  121. mc.insertId = 0
  122. err := mc.exec(query)
  123. if err != nil {
  124. return nil, err
  125. }
  126. return &mysqlResult{
  127. affectedRows: int64(mc.affectedRows),
  128. insertId: int64(mc.insertId)},
  129. err
  130. }
  131. // Internal function to execute commands
  132. func (mc *mysqlConn) exec(query string) (err error) {
  133. // Send command
  134. err = mc.writeCommandPacket(COM_QUERY, query)
  135. if err != nil {
  136. return
  137. }
  138. // Read Result
  139. var resLen int
  140. resLen, err = mc.readResultSetHeaderPacket()
  141. if err != nil {
  142. return
  143. }
  144. if resLen > 0 {
  145. _, err = mc.readUntilEOF()
  146. if err != nil {
  147. return
  148. }
  149. mc.affectedRows, err = mc.readUntilEOF()
  150. if err != nil {
  151. return
  152. }
  153. }
  154. return
  155. }
  156. func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, error) {
  157. if len(args) > 0 {
  158. return nil, driver.ErrSkip
  159. }
  160. // Send command
  161. err := mc.writeCommandPacket(COM_QUERY, query)
  162. if err != nil {
  163. return nil, err
  164. }
  165. // Read Result
  166. var resLen int
  167. resLen, err = mc.readResultSetHeaderPacket()
  168. if err != nil {
  169. return nil, err
  170. }
  171. rows := mysqlRows{&rowsContent{mc, false, nil, false}}
  172. if resLen > 0 {
  173. // Columns
  174. rows.content.columns, err = mc.readColumns(resLen)
  175. if err != nil {
  176. return nil, err
  177. }
  178. }
  179. return rows, err
  180. }