statement.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  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. "fmt"
  13. "reflect"
  14. "time"
  15. )
  16. type stmtContent struct {
  17. mc *mysqlConn
  18. id uint32
  19. query string
  20. paramCount int
  21. params []*mysqlField
  22. args *[]driver.Value
  23. newParamsBound bool
  24. }
  25. type mysqlStmt struct {
  26. *stmtContent
  27. }
  28. func (stmt mysqlStmt) Close() error {
  29. e := stmt.mc.writeCommandPacket(COM_STMT_CLOSE, stmt.id)
  30. stmt.params = nil
  31. stmt.mc = nil
  32. return e
  33. }
  34. func (stmt mysqlStmt) NumInput() int {
  35. return stmt.paramCount
  36. }
  37. func (stmt mysqlStmt) Exec(args []driver.Value) (driver.Result, error) {
  38. stmt.mc.affectedRows = 0
  39. stmt.mc.insertId = 0
  40. // Send command
  41. e := stmt.buildExecutePacket(&args)
  42. if e != nil {
  43. return nil, e
  44. }
  45. // Read Result
  46. var resLen int
  47. resLen, e = stmt.mc.readResultSetHeaderPacket()
  48. if e != nil {
  49. return nil, e
  50. }
  51. if resLen > 0 {
  52. _, e = stmt.mc.readUntilEOF()
  53. if e != nil {
  54. return nil, e
  55. }
  56. stmt.mc.affectedRows, e = stmt.mc.readUntilEOF()
  57. if e != nil {
  58. return nil, e
  59. }
  60. }
  61. if e != nil {
  62. return nil, e
  63. }
  64. if stmt.mc.affectedRows == 0 {
  65. return driver.ResultNoRows, nil
  66. }
  67. return &mysqlResult{
  68. affectedRows: int64(stmt.mc.affectedRows),
  69. insertId: int64(stmt.mc.insertId)},
  70. nil
  71. }
  72. func (stmt mysqlStmt) Query(args []driver.Value) (dr driver.Rows, e error) {
  73. // Send command
  74. e = stmt.buildExecutePacket(&args)
  75. if e != nil {
  76. return nil, e
  77. }
  78. // Get Result
  79. var resLen int
  80. rows := new(mysqlRows)
  81. rows.content = new(rowsContent)
  82. resLen, e = stmt.mc.readResultSetHeaderPacket()
  83. if e != nil {
  84. return nil, e
  85. }
  86. if resLen > 0 {
  87. // Columns
  88. rows.content.columns, e = stmt.mc.readColumns(resLen)
  89. if e != nil {
  90. return
  91. }
  92. // Rows
  93. e = stmt.mc.readBinaryRows(rows.content)
  94. if e != nil {
  95. return
  96. }
  97. }
  98. dr = rows
  99. return
  100. }
  101. /* Command Packet
  102. Bytes Name
  103. ----- ----
  104. 1 code
  105. 4 statement_id
  106. 1 flags
  107. 4 iteration_count
  108. if param_count > 0:
  109. (param_count+7)/8 null_bit_map
  110. 1 new_parameter_bound_flag
  111. if new_params_bound == 1:
  112. n*2 type of parameters
  113. n values for the parameters
  114. */
  115. func (stmt mysqlStmt) buildExecutePacket(args *[]driver.Value) (e error) {
  116. if len(*args) < stmt.paramCount {
  117. return fmt.Errorf(
  118. "Not enough Arguments to call STMT_EXEC (Got: %d Has: %d",
  119. len(*args),
  120. stmt.paramCount)
  121. }
  122. // Reset packet-sequence
  123. stmt.mc.sequence = 0
  124. data := make([]byte, 0, 10)
  125. // code [1 byte]
  126. data = append(data, byte(COM_STMT_EXECUTE))
  127. // statement_id [4 bytes]
  128. data = append(data, uint32ToBytes(stmt.id)...)
  129. // flags (0: CURSOR_TYPE_NO_CURSOR) [1 byte]
  130. data = append(data, byte(0))
  131. // iteration_count [4 bytes]
  132. data = append(data, uint32ToBytes(1)...)
  133. if stmt.paramCount > 0 {
  134. var i int
  135. // build nullBitMap
  136. nullBitMap := make([]byte, (stmt.paramCount+7)/8)
  137. bitMask := uint64(0)
  138. // Check for NULL fields
  139. for i = 0; i < stmt.paramCount; i++ {
  140. if (*args)[i] == nil {
  141. fmt.Println("nil", i, (*args)[i])
  142. bitMask += 1 << uint(i)
  143. }
  144. }
  145. // Convert bitMask to bytes
  146. for i = 0; i < len(nullBitMap); i++ {
  147. nullBitMap[i] = byte(bitMask >> uint(i*8))
  148. }
  149. // append nullBitMap [(param_count+7)/8 bytes]
  150. data = append(data, nullBitMap...)
  151. // Check for changed Params
  152. newParamsBound := true
  153. if stmt.args != nil {
  154. for i := 0; i < len(*args); i++ {
  155. if (*args)[i] != (*stmt.args)[i] {
  156. fmt.Println((*args)[i], "!=", (*stmt.args)[i])
  157. newParamsBound = false
  158. break
  159. }
  160. }
  161. }
  162. // No (new) Parameters bound or rebound
  163. if !newParamsBound {
  164. //newParameterBoundFlag 0 [1 byte]
  165. data = append(data, byte(0))
  166. } else {
  167. // newParameterBoundFlag 1 [1 byte]
  168. data = append(data, byte(1))
  169. // append types and cache values
  170. paramValues := make([]byte, 0)
  171. var pv reflect.Value
  172. for i = 0; i < stmt.paramCount; i++ {
  173. switch (*args)[i].(type) {
  174. case nil:
  175. data = append(data, []byte{
  176. byte(FIELD_TYPE_NULL),
  177. 0x0}...)
  178. continue
  179. case []byte:
  180. fmt.Println("[]byte", (*args)[i])
  181. case time.Time:
  182. fmt.Println("time.Time", (*args)[i])
  183. }
  184. pv = reflect.ValueOf((*args)[i])
  185. switch pv.Kind() {
  186. case reflect.Int64:
  187. data = append(data, []byte{
  188. byte(FIELD_TYPE_LONGLONG),
  189. 0x0}...)
  190. paramValues = append(paramValues, int64ToBytes(pv.Int())...)
  191. fmt.Println("int64", (*args)[i])
  192. case reflect.Float64:
  193. fmt.Println("float64", (*args)[i])
  194. case reflect.Bool:
  195. data = append(data, []byte{
  196. byte(FIELD_TYPE_TINY),
  197. 0x0}...)
  198. val := pv.Bool()
  199. if val {
  200. paramValues = append(paramValues, byte(1))
  201. } else {
  202. paramValues = append(paramValues, byte(0))
  203. }
  204. fmt.Println("bool", (*args)[i])
  205. case reflect.String:
  206. data = append(data, []byte{
  207. byte(FIELD_TYPE_STRING),
  208. 0x0}...)
  209. val := pv.String()
  210. paramValues = append(paramValues, lengthCodedBinaryToBytes(uint64(len(val)))...)
  211. paramValues = append(paramValues, []byte(val)...)
  212. fmt.Println("string", string([]byte(val)))
  213. default:
  214. return fmt.Errorf("Invalid Value: %s", pv.Kind().String())
  215. }
  216. }
  217. // append cached values
  218. data = append(data, paramValues...)
  219. fmt.Println("data", string(data))
  220. }
  221. // Save args
  222. stmt.args = args
  223. }
  224. return stmt.mc.writePacket(data)
  225. }
  226. // ColumnConverter returns a ValueConverter for the provided
  227. // column index. If the type of a specific column isn't known
  228. // or shouldn't be handled specially, DefaultValueConverter
  229. // can be returned.
  230. func (stmt mysqlStmt) ColumnConverter(idx int) driver.ValueConverter {
  231. debug(fmt.Sprintf("ColumnConverter(%d)", idx))
  232. return driver.DefaultParameterConverter
  233. }