connection.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  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 _, charset := range charsets {
  46. err = mc.exec("SET NAMES " + charset)
  47. if err != nil {
  48. return
  49. }
  50. }
  51. // Timeout - already handled on connecting
  52. case "timeout":
  53. continue
  54. // TLS-Encryption
  55. case "tls":
  56. err = errors.New("TLS-Encryption not implemented yet")
  57. return
  58. // Compression
  59. case "compress":
  60. err = errors.New("Compression not implemented yet")
  61. // System Vars
  62. default:
  63. err = mc.exec("SET " + param + "=" + val + "")
  64. if err != nil {
  65. return
  66. }
  67. }
  68. }
  69. return
  70. }
  71. func (mc *mysqlConn) Begin() (driver.Tx, error) {
  72. err := mc.exec("START TRANSACTION")
  73. if err == nil {
  74. return &mysqlTx{mc}, err
  75. }
  76. return nil, err
  77. }
  78. func (mc *mysqlConn) Close() (err error) {
  79. mc.writeCommandPacket(comQuit)
  80. mc.cfg = nil
  81. mc.buf = nil
  82. mc.netConn.Close()
  83. mc.netConn = nil
  84. return
  85. }
  86. func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) {
  87. // Send command
  88. err := mc.writeCommandPacketStr(comStmtPrepare, query)
  89. if err != nil {
  90. return nil, err
  91. }
  92. stmt := &mysqlStmt{
  93. mc: mc,
  94. }
  95. // Read Result
  96. columnCount, err := stmt.readPrepareResultPacket()
  97. if err == nil {
  98. if stmt.paramCount > 0 {
  99. stmt.params, err = stmt.mc.readColumns(stmt.paramCount)
  100. if err != nil {
  101. return nil, err
  102. }
  103. }
  104. if columnCount > 0 {
  105. err = stmt.mc.readUntilEOF()
  106. }
  107. }
  108. return stmt, err
  109. }
  110. func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, error) {
  111. if len(args) == 0 { // no args, fastpath
  112. mc.affectedRows = 0
  113. mc.insertId = 0
  114. err := mc.exec(query)
  115. if err == nil {
  116. return &mysqlResult{
  117. affectedRows: int64(mc.affectedRows),
  118. insertId: int64(mc.insertId),
  119. }, err
  120. }
  121. return nil, err
  122. }
  123. // with args, must use prepared stmt
  124. return nil, driver.ErrSkip
  125. }
  126. // Internal function to execute commands
  127. func (mc *mysqlConn) exec(query string) (err error) {
  128. // Send command
  129. err = mc.writeCommandPacketStr(comQuery, query)
  130. if err != nil {
  131. return
  132. }
  133. // Read Result
  134. var resLen int
  135. resLen, err = mc.readResultSetHeaderPacket()
  136. if err == nil && resLen > 0 {
  137. err = mc.readUntilEOF()
  138. if err != nil {
  139. return
  140. }
  141. err = mc.readUntilEOF()
  142. }
  143. return
  144. }
  145. func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, error) {
  146. if len(args) == 0 { // no args, fastpath
  147. // Send command
  148. err := mc.writeCommandPacketStr(comQuery, query)
  149. if err == nil {
  150. // Read Result
  151. var resLen int
  152. resLen, err = mc.readResultSetHeaderPacket()
  153. if err == nil {
  154. rows := &mysqlRows{mc, false, nil, false}
  155. if resLen > 0 {
  156. // Columns
  157. rows.columns, err = mc.readColumns(resLen)
  158. }
  159. return rows, err
  160. }
  161. }
  162. return nil, err
  163. }
  164. // with args, must use prepared stmt
  165. return nil, driver.ErrSkip
  166. }
  167. // Gets the value of the given MySQL System Variable
  168. func (mc *mysqlConn) getSystemVar(name string) (val []byte, err error) {
  169. // Send command
  170. err = mc.writeCommandPacketStr(comQuery, "SELECT @@"+name)
  171. if err == nil {
  172. // Read Result
  173. var resLen int
  174. resLen, err = mc.readResultSetHeaderPacket()
  175. if err == nil {
  176. rows := &mysqlRows{mc, false, nil, false}
  177. if resLen > 0 {
  178. // Columns
  179. rows.columns, err = mc.readColumns(resLen)
  180. }
  181. dest := make([]driver.Value, resLen)
  182. err = rows.readRow(dest)
  183. if err == nil {
  184. val = dest[0].([]byte)
  185. err = mc.readUntilEOF()
  186. }
  187. }
  188. }
  189. return
  190. }