resultset_helper.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. package mysql
  2. import (
  3. "math"
  4. "strconv"
  5. "github.com/juju/errors"
  6. "github.com/siddontang/go/hack"
  7. )
  8. func formatTextValue(value interface{}) ([]byte, error) {
  9. switch v := value.(type) {
  10. case int8:
  11. return strconv.AppendInt(nil, int64(v), 10), nil
  12. case int16:
  13. return strconv.AppendInt(nil, int64(v), 10), nil
  14. case int32:
  15. return strconv.AppendInt(nil, int64(v), 10), nil
  16. case int64:
  17. return strconv.AppendInt(nil, int64(v), 10), nil
  18. case int:
  19. return strconv.AppendInt(nil, int64(v), 10), nil
  20. case uint8:
  21. return strconv.AppendUint(nil, uint64(v), 10), nil
  22. case uint16:
  23. return strconv.AppendUint(nil, uint64(v), 10), nil
  24. case uint32:
  25. return strconv.AppendUint(nil, uint64(v), 10), nil
  26. case uint64:
  27. return strconv.AppendUint(nil, uint64(v), 10), nil
  28. case uint:
  29. return strconv.AppendUint(nil, uint64(v), 10), nil
  30. case float32:
  31. return strconv.AppendFloat(nil, float64(v), 'f', -1, 64), nil
  32. case float64:
  33. return strconv.AppendFloat(nil, float64(v), 'f', -1, 64), nil
  34. case []byte:
  35. return v, nil
  36. case string:
  37. return hack.Slice(v), nil
  38. default:
  39. return nil, errors.Errorf("invalid type %T", value)
  40. }
  41. }
  42. func formatBinaryValue(value interface{}) ([]byte, error) {
  43. switch v := value.(type) {
  44. case int8:
  45. return Uint64ToBytes(uint64(v)), nil
  46. case int16:
  47. return Uint64ToBytes(uint64(v)), nil
  48. case int32:
  49. return Uint64ToBytes(uint64(v)), nil
  50. case int64:
  51. return Uint64ToBytes(uint64(v)), nil
  52. case int:
  53. return Uint64ToBytes(uint64(v)), nil
  54. case uint8:
  55. return Uint64ToBytes(uint64(v)), nil
  56. case uint16:
  57. return Uint64ToBytes(uint64(v)), nil
  58. case uint32:
  59. return Uint64ToBytes(uint64(v)), nil
  60. case uint64:
  61. return Uint64ToBytes(uint64(v)), nil
  62. case uint:
  63. return Uint64ToBytes(uint64(v)), nil
  64. case float32:
  65. return Uint64ToBytes(math.Float64bits(float64(v))), nil
  66. case float64:
  67. return Uint64ToBytes(math.Float64bits(v)), nil
  68. case []byte:
  69. return v, nil
  70. case string:
  71. return hack.Slice(v), nil
  72. default:
  73. return nil, errors.Errorf("invalid type %T", value)
  74. }
  75. }
  76. func formatField(field *Field, value interface{}) error {
  77. switch value.(type) {
  78. case int8, int16, int32, int64, int:
  79. field.Charset = 63
  80. field.Type = MYSQL_TYPE_LONGLONG
  81. field.Flag = BINARY_FLAG | NOT_NULL_FLAG
  82. case uint8, uint16, uint32, uint64, uint:
  83. field.Charset = 63
  84. field.Type = MYSQL_TYPE_LONGLONG
  85. field.Flag = BINARY_FLAG | NOT_NULL_FLAG | UNSIGNED_FLAG
  86. case float32, float64:
  87. field.Charset = 63
  88. field.Type = MYSQL_TYPE_DOUBLE
  89. field.Flag = BINARY_FLAG | NOT_NULL_FLAG
  90. case string, []byte:
  91. field.Charset = 33
  92. field.Type = MYSQL_TYPE_VAR_STRING
  93. default:
  94. return errors.Errorf("unsupport type %T for resultset", value)
  95. }
  96. return nil
  97. }
  98. func BuildSimpleTextResultset(names []string, values [][]interface{}) (*Resultset, error) {
  99. r := new(Resultset)
  100. r.Fields = make([]*Field, len(names))
  101. var b []byte
  102. var err error
  103. for i, vs := range values {
  104. if len(vs) != len(r.Fields) {
  105. return nil, errors.Errorf("row %d has %d column not equal %d", i, len(vs), len(r.Fields))
  106. }
  107. var row []byte
  108. for j, value := range vs {
  109. if i == 0 {
  110. field := &Field{}
  111. r.Fields[j] = field
  112. field.Name = hack.Slice(names[j])
  113. if err = formatField(field, value); err != nil {
  114. return nil, errors.Trace(err)
  115. }
  116. }
  117. b, err = formatTextValue(value)
  118. if err != nil {
  119. return nil, errors.Trace(err)
  120. }
  121. row = append(row, PutLengthEncodedString(b)...)
  122. }
  123. r.RowDatas = append(r.RowDatas, row)
  124. }
  125. return r, nil
  126. }
  127. func BuildSimpleBinaryResultset(names []string, values [][]interface{}) (*Resultset, error) {
  128. r := new(Resultset)
  129. r.Fields = make([]*Field, len(names))
  130. var b []byte
  131. var err error
  132. bitmapLen := ((len(names) + 7 + 2) >> 3)
  133. for i, vs := range values {
  134. if len(vs) != len(r.Fields) {
  135. return nil, errors.Errorf("row %d has %d column not equal %d", i, len(vs), len(r.Fields))
  136. }
  137. var row []byte
  138. nullBitmap := make([]byte, bitmapLen)
  139. row = append(row, 0)
  140. row = append(row, nullBitmap...)
  141. for j, value := range vs {
  142. if i == 0 {
  143. field := &Field{}
  144. r.Fields[j] = field
  145. field.Name = hack.Slice(names[j])
  146. if err = formatField(field, value); err != nil {
  147. return nil, errors.Trace(err)
  148. }
  149. }
  150. if value == nil {
  151. nullBitmap[(i+2)/8] |= (1 << (uint(i+2) % 8))
  152. continue
  153. }
  154. b, err = formatBinaryValue(value)
  155. if err != nil {
  156. return nil, errors.Trace(err)
  157. }
  158. if r.Fields[j].Type == MYSQL_TYPE_VAR_STRING {
  159. row = append(row, PutLengthEncodedString(b)...)
  160. } else {
  161. row = append(row, b...)
  162. }
  163. }
  164. copy(row[1:], nullBitmap)
  165. r.RowDatas = append(r.RowDatas, row)
  166. }
  167. return r, nil
  168. }
  169. func BuildSimpleResultset(names []string, values [][]interface{}, binary bool) (*Resultset, error) {
  170. if binary {
  171. return BuildSimpleBinaryResultset(names, values)
  172. } else {
  173. return BuildSimpleTextResultset(names, values)
  174. }
  175. }