result.go 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. package native
  2. import (
  3. "errors"
  4. "github.com/ziutek/mymysql/mysql"
  5. "log"
  6. "math"
  7. "strconv"
  8. )
  9. type Result struct {
  10. my *Conn
  11. status_only bool // true if result doesn't contain result set
  12. binary bool // Binary result expected
  13. field_count int
  14. fields []*mysql.Field // Fields table
  15. fc_map map[string]int // Maps field name to column number
  16. message []byte
  17. affected_rows uint64
  18. // Primary key value (useful for AUTO_INCREMENT primary keys)
  19. insert_id uint64
  20. // Number of warinigs during command execution
  21. // You can use the SHOW WARNINGS query for details.
  22. warning_count int
  23. // MySQL server status immediately after the query execution
  24. status mysql.ConnStatus
  25. // Seted by GetRow if it returns nil row
  26. eor_returned bool
  27. }
  28. // Returns true if this is status result that includes no result set
  29. func (res *Result) StatusOnly() bool {
  30. return res.status_only
  31. }
  32. // Returns a table containing descriptions of the columns
  33. func (res *Result) Fields() []*mysql.Field {
  34. return res.fields
  35. }
  36. // Returns index for given name or -1 if field of that name doesn't exist
  37. func (res *Result) Map(field_name string) int {
  38. if fi, ok := res.fc_map[field_name]; ok {
  39. return fi
  40. }
  41. return -1
  42. }
  43. func (res *Result) Message() string {
  44. return string(res.message)
  45. }
  46. func (res *Result) AffectedRows() uint64 {
  47. return res.affected_rows
  48. }
  49. func (res *Result) InsertId() uint64 {
  50. return res.insert_id
  51. }
  52. func (res *Result) WarnCount() int {
  53. return res.warning_count
  54. }
  55. func (res *Result) MakeRow() mysql.Row {
  56. return make(mysql.Row, res.field_count)
  57. }
  58. func (my *Conn) getResult(res *Result, row mysql.Row) *Result {
  59. loop:
  60. pr := my.newPktReader() // New reader for next packet
  61. pkt0 := pr.readByte()
  62. if pkt0 == 255 {
  63. // Error packet
  64. my.getErrorPacket(pr)
  65. }
  66. if res == nil {
  67. switch {
  68. case pkt0 == 0:
  69. // OK packet
  70. return my.getOkPacket(pr)
  71. case pkt0 > 0 && pkt0 < 251:
  72. // Result set header packet
  73. res = my.getResSetHeadPacket(pr)
  74. // Read next packet
  75. goto loop
  76. case pkt0 == 251:
  77. // Load infile response
  78. // Handle response
  79. goto loop
  80. case pkt0 == 254:
  81. // EOF packet (without body)
  82. return nil
  83. }
  84. } else {
  85. switch {
  86. case pkt0 == 254:
  87. // EOF packet
  88. res.warning_count, res.status = my.getEofPacket(pr)
  89. my.status = res.status
  90. return res
  91. case pkt0 > 0 && pkt0 < 251 && res.field_count < len(res.fields):
  92. // Field packet
  93. field := my.getFieldPacket(pr)
  94. res.fields[res.field_count] = field
  95. res.fc_map[field.Name] = res.field_count
  96. // Increment field count
  97. res.field_count++
  98. // Read next packet
  99. goto loop
  100. case pkt0 < 254 && res.field_count == len(res.fields):
  101. // Row Data Packet
  102. if len(row) != res.field_count {
  103. panic(mysql.ErrRowLength)
  104. }
  105. if res.binary {
  106. my.getBinRowPacket(pr, res, row)
  107. } else {
  108. my.getTextRowPacket(pr, res, row)
  109. }
  110. return nil
  111. }
  112. }
  113. panic(mysql.ErrUnkResultPkt)
  114. }
  115. func (my *Conn) getOkPacket(pr *pktReader) (res *Result) {
  116. if my.Debug {
  117. log.Printf("[%2d ->] OK packet:", my.seq-1)
  118. }
  119. res = new(Result)
  120. res.status_only = true
  121. res.my = my
  122. // First byte was readed by getResult
  123. res.affected_rows = pr.readLCB()
  124. res.insert_id = pr.readLCB()
  125. res.status = mysql.ConnStatus(pr.readU16())
  126. my.status = res.status
  127. res.warning_count = int(pr.readU16())
  128. res.message = pr.readAll()
  129. pr.checkEof()
  130. if my.Debug {
  131. log.Printf(tab8s+"AffectedRows=%d InsertId=0x%x Status=0x%x "+
  132. "WarningCount=%d Message=\"%s\"", res.affected_rows, res.insert_id,
  133. res.status, res.warning_count, res.message,
  134. )
  135. }
  136. return
  137. }
  138. func (my *Conn) getErrorPacket(pr *pktReader) {
  139. if my.Debug {
  140. log.Printf("[%2d ->] Error packet:", my.seq-1)
  141. }
  142. var err mysql.Error
  143. err.Code = pr.readU16()
  144. if pr.readByte() != '#' {
  145. panic(mysql.ErrPkt)
  146. }
  147. pr.skipN(5)
  148. err.Msg = pr.readAll()
  149. pr.checkEof()
  150. if my.Debug {
  151. log.Printf(tab8s+"code=0x%x msg=\"%s\"", err.Code, err.Msg)
  152. }
  153. panic(&err)
  154. }
  155. func (my *Conn) getEofPacket(pr *pktReader) (warn_count int, status mysql.ConnStatus) {
  156. if my.Debug {
  157. if pr.eof() {
  158. log.Printf("[%2d ->] EOF packet without body", my.seq-1)
  159. } else {
  160. log.Printf("[%2d ->] EOF packet:", my.seq-1)
  161. }
  162. }
  163. if pr.eof() {
  164. return
  165. }
  166. warn_count = int(pr.readU16())
  167. if pr.eof() {
  168. return
  169. }
  170. status = mysql.ConnStatus(pr.readU16())
  171. pr.checkEof()
  172. if my.Debug {
  173. log.Printf(tab8s+"WarningCount=%d Status=0x%x", warn_count, status)
  174. }
  175. return
  176. }
  177. func (my *Conn) getResSetHeadPacket(pr *pktReader) (res *Result) {
  178. if my.Debug {
  179. log.Printf("[%2d ->] Result set header packet:", my.seq-1)
  180. }
  181. pr.unreadByte()
  182. field_count := int(pr.readLCB())
  183. pr.checkEof()
  184. res = &Result{
  185. my: my,
  186. fields: make([]*mysql.Field, field_count),
  187. fc_map: make(map[string]int),
  188. }
  189. if my.Debug {
  190. log.Printf(tab8s+"FieldCount=%d", field_count)
  191. }
  192. return
  193. }
  194. func (my *Conn) getFieldPacket(pr *pktReader) (field *mysql.Field) {
  195. if my.Debug {
  196. log.Printf("[%2d ->] Field packet:", my.seq-1)
  197. }
  198. pr.unreadByte()
  199. field = new(mysql.Field)
  200. if my.fullFieldInfo {
  201. field.Catalog = string(pr.readBin())
  202. field.Db = string(pr.readBin())
  203. field.Table = string(pr.readBin())
  204. field.OrgTable = string(pr.readBin())
  205. } else {
  206. pr.skipBin()
  207. pr.skipBin()
  208. pr.skipBin()
  209. pr.skipBin()
  210. }
  211. field.Name = string(pr.readBin())
  212. if my.fullFieldInfo {
  213. field.OrgName = string(pr.readBin())
  214. } else {
  215. pr.skipBin()
  216. }
  217. pr.skipN(1 + 2)
  218. //field.Charset= pr.readU16()
  219. field.DispLen = pr.readU32()
  220. field.Type = pr.readByte()
  221. field.Flags = pr.readU16()
  222. field.Scale = pr.readByte()
  223. pr.skipN(2)
  224. pr.checkEof()
  225. if my.Debug {
  226. log.Printf(tab8s+"Name=\"%s\" Type=0x%x", field.Name, field.Type)
  227. }
  228. return
  229. }
  230. func (my *Conn) getTextRowPacket(pr *pktReader, res *Result, row mysql.Row) {
  231. if my.Debug {
  232. log.Printf("[%2d ->] Text row data packet", my.seq-1)
  233. }
  234. pr.unreadByte()
  235. for ii := 0; ii < res.field_count; ii++ {
  236. bin, null := pr.readNullBin()
  237. if null {
  238. row[ii] = nil
  239. } else {
  240. row[ii] = bin
  241. }
  242. }
  243. pr.checkEof()
  244. }
  245. func (my *Conn) getBinRowPacket(pr *pktReader, res *Result, row mysql.Row) {
  246. if my.Debug {
  247. log.Printf("[%2d ->] Binary row data packet", my.seq-1)
  248. }
  249. // First byte was readed by getResult
  250. null_bitmap := make([]byte, (res.field_count+7+2)>>3)
  251. pr.readFull(null_bitmap)
  252. for ii, field := range res.fields {
  253. null_byte := (ii + 2) >> 3
  254. null_mask := byte(1) << uint(2+ii-(null_byte<<3))
  255. if null_bitmap[null_byte]&null_mask != 0 {
  256. // Null field
  257. row[ii] = nil
  258. continue
  259. }
  260. unsigned := (field.Flags & _FLAG_UNSIGNED) != 0
  261. if my.narrowTypeSet {
  262. row[ii] = readValueNarrow(pr, field.Type, unsigned)
  263. } else {
  264. row[ii] = readValue(pr, field.Type, unsigned)
  265. }
  266. }
  267. }
  268. func readValue(pr *pktReader, typ byte, unsigned bool) interface{} {
  269. switch typ {
  270. case MYSQL_TYPE_STRING, MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VARCHAR,
  271. MYSQL_TYPE_BIT, MYSQL_TYPE_BLOB, MYSQL_TYPE_TINY_BLOB,
  272. MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB, MYSQL_TYPE_SET,
  273. MYSQL_TYPE_ENUM, MYSQL_TYPE_GEOMETRY:
  274. return pr.readBin()
  275. case MYSQL_TYPE_TINY:
  276. if unsigned {
  277. return pr.readByte()
  278. } else {
  279. return int8(pr.readByte())
  280. }
  281. case MYSQL_TYPE_SHORT, MYSQL_TYPE_YEAR:
  282. if unsigned {
  283. return pr.readU16()
  284. } else {
  285. return int16(pr.readU16())
  286. }
  287. case MYSQL_TYPE_LONG, MYSQL_TYPE_INT24:
  288. if unsigned {
  289. return pr.readU32()
  290. } else {
  291. return int32(pr.readU32())
  292. }
  293. case MYSQL_TYPE_LONGLONG:
  294. if unsigned {
  295. return pr.readU64()
  296. } else {
  297. return int64(pr.readU64())
  298. }
  299. case MYSQL_TYPE_FLOAT:
  300. return math.Float32frombits(pr.readU32())
  301. case MYSQL_TYPE_DOUBLE:
  302. return math.Float64frombits(pr.readU64())
  303. case MYSQL_TYPE_DECIMAL, MYSQL_TYPE_NEWDECIMAL:
  304. dec := string(pr.readBin())
  305. r, err := strconv.ParseFloat(dec, 64)
  306. if err != nil {
  307. panic(errors.New("MySQL server returned wrong decimal value: " + dec))
  308. }
  309. return r
  310. case MYSQL_TYPE_DATE, MYSQL_TYPE_NEWDATE:
  311. return pr.readDate()
  312. case MYSQL_TYPE_DATETIME, MYSQL_TYPE_TIMESTAMP:
  313. return pr.readTime()
  314. case MYSQL_TYPE_TIME:
  315. return pr.readDuration()
  316. }
  317. panic(mysql.ErrUnkMySQLType)
  318. }
  319. func readValueNarrow(pr *pktReader, typ byte, unsigned bool) interface{} {
  320. switch typ {
  321. case MYSQL_TYPE_STRING, MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VARCHAR,
  322. MYSQL_TYPE_BIT, MYSQL_TYPE_BLOB, MYSQL_TYPE_TINY_BLOB,
  323. MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB, MYSQL_TYPE_SET,
  324. MYSQL_TYPE_ENUM, MYSQL_TYPE_GEOMETRY:
  325. return pr.readBin()
  326. case MYSQL_TYPE_TINY:
  327. if unsigned {
  328. return int64(pr.readByte())
  329. }
  330. return int64(int8(pr.readByte()))
  331. case MYSQL_TYPE_SHORT, MYSQL_TYPE_YEAR:
  332. if unsigned {
  333. return int64(pr.readU16())
  334. }
  335. return int64(int16(pr.readU16()))
  336. case MYSQL_TYPE_LONG, MYSQL_TYPE_INT24:
  337. if unsigned {
  338. return int64(pr.readU32())
  339. }
  340. return int64(int32(pr.readU32()))
  341. case MYSQL_TYPE_LONGLONG:
  342. v := pr.readU64()
  343. if unsigned && v > math.MaxInt64 {
  344. panic(errors.New("Value to large for int64 type"))
  345. }
  346. return int64(v)
  347. case MYSQL_TYPE_FLOAT:
  348. return float64(math.Float32frombits(pr.readU32()))
  349. case MYSQL_TYPE_DOUBLE:
  350. return math.Float64frombits(pr.readU64())
  351. case MYSQL_TYPE_DECIMAL, MYSQL_TYPE_NEWDECIMAL:
  352. dec := string(pr.readBin())
  353. r, err := strconv.ParseFloat(dec, 64)
  354. if err != nil {
  355. panic("MySQL server returned wrong decimal value: " + dec)
  356. }
  357. return r
  358. case MYSQL_TYPE_DATETIME, MYSQL_TYPE_TIMESTAMP, MYSQL_TYPE_DATE, MYSQL_TYPE_NEWDATE:
  359. return pr.readTime()
  360. case MYSQL_TYPE_TIME:
  361. return int64(pr.readDuration())
  362. }
  363. panic(mysql.ErrUnkMySQLType)
  364. }