value.go 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. package sqltypes
  2. import (
  3. "fmt"
  4. "strconv"
  5. "time"
  6. )
  7. var (
  8. // NULL represents the NULL value.
  9. NULL = Value{}
  10. // DontEscape tells you if a character should not be escaped.
  11. DontEscape = byte(255)
  12. nullstr = []byte("null")
  13. )
  14. type Value struct {
  15. typ Type
  16. val []byte
  17. }
  18. // NewValue builds a Value using typ and val. If the value and typ
  19. // don't match, it returns an error.
  20. func NewValue(typ Type, val []byte) (v Value, err error) {
  21. switch {
  22. case IsSigned(typ):
  23. if _, err := strconv.ParseInt(string(val), 0, 64); err != nil {
  24. return NULL, err
  25. }
  26. return MakeTrusted(typ, val), nil
  27. case IsUnsigned(typ):
  28. if _, err := strconv.ParseUint(string(val), 0, 64); err != nil {
  29. return NULL, err
  30. }
  31. return MakeTrusted(typ, val), nil
  32. case IsFloat(typ) || typ == Decimal:
  33. if _, err := strconv.ParseFloat(string(val), 64); err != nil {
  34. return NULL, err
  35. }
  36. return MakeTrusted(typ, val), nil
  37. case IsQuoted(typ) || typ == Bit || typ == Null:
  38. return MakeTrusted(typ, val), nil
  39. }
  40. // All other types are unsafe or invalid.
  41. return NULL, fmt.Errorf("invalid type specified for MakeValue: %v", typ)
  42. }
  43. // MakeTrusted makes a new Value based on the type.
  44. // This function should only be used if you know the value
  45. // and type conform to the rules. Every place this function is
  46. // called, a comment is needed that explains why it's justified.
  47. // Exceptions: The current package and mysql package do not need
  48. // comments. Other packages can also use the function to create
  49. // VarBinary or VarChar values.
  50. func MakeTrusted(typ Type, val []byte) Value {
  51. if typ == Null {
  52. return NULL
  53. }
  54. return Value{typ: typ, val: val}
  55. }
  56. // NewInt64 builds an Int64 Value.
  57. func NewInt64(v int64) Value {
  58. return MakeTrusted(Int64, strconv.AppendInt(nil, v, 10))
  59. }
  60. // NewInt32 builds an Int64 Value.
  61. func NewInt32(v int32) Value {
  62. return MakeTrusted(Int32, strconv.AppendInt(nil, int64(v), 10))
  63. }
  64. // NewUint64 builds an Uint64 Value.
  65. func NewUint64(v uint64) Value {
  66. return MakeTrusted(Uint64, strconv.AppendUint(nil, v, 10))
  67. }
  68. // NewFloat32 builds an Float64 Value.
  69. func NewFloat32(v float32) Value {
  70. return MakeTrusted(Float32, strconv.AppendFloat(nil, float64(v), 'f', -1, 64))
  71. }
  72. // NewFloat64 builds an Float64 Value.
  73. func NewFloat64(v float64) Value {
  74. return MakeTrusted(Float64, strconv.AppendFloat(nil, v, 'g', -1, 64))
  75. }
  76. // NewVarChar builds a VarChar Value.
  77. func NewVarChar(v string) Value {
  78. return MakeTrusted(VarChar, []byte(v))
  79. }
  80. // NewVarBinary builds a VarBinary Value.
  81. // The input is a string because it's the most common use case.
  82. func NewVarBinary(v string) Value {
  83. return MakeTrusted(VarBinary, []byte(v))
  84. }
  85. // NewIntegral builds an integral type from a string representation.
  86. // The type will be Int64 or Uint64. Int64 will be preferred where possible.
  87. func NewIntegral(val string) (n Value, err error) {
  88. signed, err := strconv.ParseInt(val, 0, 64)
  89. if err == nil {
  90. return MakeTrusted(Int64, strconv.AppendInt(nil, signed, 10)), nil
  91. }
  92. unsigned, err := strconv.ParseUint(val, 0, 64)
  93. if err != nil {
  94. return Value{}, err
  95. }
  96. return MakeTrusted(Uint64, strconv.AppendUint(nil, unsigned, 10)), nil
  97. }
  98. // MakeString makes a VarBinary Value.
  99. func MakeString(val []byte) Value {
  100. return MakeTrusted(VarBinary, val)
  101. }
  102. // BuildValue builds a value from any go type. sqltype.Value is
  103. // also allowed.
  104. func BuildValue(goval interface{}) (v Value, err error) {
  105. // Look for the most common types first.
  106. switch goval := goval.(type) {
  107. case nil:
  108. // no op
  109. case []byte:
  110. v = MakeTrusted(VarBinary, goval)
  111. case int64:
  112. v = MakeTrusted(Int64, strconv.AppendInt(nil, int64(goval), 10))
  113. case uint64:
  114. v = MakeTrusted(Uint64, strconv.AppendUint(nil, uint64(goval), 10))
  115. case float64:
  116. v = MakeTrusted(Float64, strconv.AppendFloat(nil, goval, 'f', -1, 64))
  117. case int:
  118. v = MakeTrusted(Int64, strconv.AppendInt(nil, int64(goval), 10))
  119. case int8:
  120. v = MakeTrusted(Int8, strconv.AppendInt(nil, int64(goval), 10))
  121. case int16:
  122. v = MakeTrusted(Int16, strconv.AppendInt(nil, int64(goval), 10))
  123. case int32:
  124. v = MakeTrusted(Int32, strconv.AppendInt(nil, int64(goval), 10))
  125. case uint:
  126. v = MakeTrusted(Uint64, strconv.AppendUint(nil, uint64(goval), 10))
  127. case uint8:
  128. v = MakeTrusted(Uint8, strconv.AppendUint(nil, uint64(goval), 10))
  129. case uint16:
  130. v = MakeTrusted(Uint16, strconv.AppendUint(nil, uint64(goval), 10))
  131. case uint32:
  132. v = MakeTrusted(Uint32, strconv.AppendUint(nil, uint64(goval), 10))
  133. case float32:
  134. v = MakeTrusted(Float32, strconv.AppendFloat(nil, float64(goval), 'f', -1, 64))
  135. case string:
  136. v = MakeTrusted(VarBinary, []byte(goval))
  137. case time.Time:
  138. v = MakeTrusted(Datetime, []byte(goval.Format("2006-01-02 15:04:05")))
  139. case Value:
  140. v = goval
  141. case *BindVariable:
  142. return ValueFromBytes(goval.Type, goval.Value)
  143. default:
  144. return v, fmt.Errorf("unexpected type %T: %v", goval, goval)
  145. }
  146. return v, nil
  147. }
  148. // BuildConverted is like BuildValue except that it tries to
  149. // convert a string or []byte to an integral if the target type
  150. // is an integral. We don't perform other implicit conversions
  151. // because they're unsafe.
  152. func BuildConverted(typ Type, goval interface{}) (v Value, err error) {
  153. if IsIntegral(typ) {
  154. switch goval := goval.(type) {
  155. case []byte:
  156. return ValueFromBytes(typ, goval)
  157. case string:
  158. return ValueFromBytes(typ, []byte(goval))
  159. case Value:
  160. if goval.IsQuoted() {
  161. return ValueFromBytes(typ, goval.Raw())
  162. }
  163. }
  164. }
  165. return BuildValue(goval)
  166. }
  167. // ValueFromBytes builds a Value using typ and val. It ensures that val
  168. // matches the requested type. If type is an integral it's converted to
  169. // a canonical form. Otherwise, the original representation is preserved.
  170. func ValueFromBytes(typ Type, val []byte) (v Value, err error) {
  171. switch {
  172. case IsSigned(typ):
  173. signed, err := strconv.ParseInt(string(val), 0, 64)
  174. if err != nil {
  175. return NULL, err
  176. }
  177. v = MakeTrusted(typ, strconv.AppendInt(nil, signed, 10))
  178. case IsUnsigned(typ):
  179. unsigned, err := strconv.ParseUint(string(val), 0, 64)
  180. if err != nil {
  181. return NULL, err
  182. }
  183. v = MakeTrusted(typ, strconv.AppendUint(nil, unsigned, 10))
  184. case IsFloat(typ) || typ == Decimal:
  185. _, err := strconv.ParseFloat(string(val), 64)
  186. if err != nil {
  187. return NULL, err
  188. }
  189. // After verification, we preserve the original representation.
  190. fallthrough
  191. default:
  192. v = MakeTrusted(typ, val)
  193. }
  194. return v, nil
  195. }
  196. // BuildIntegral builds an integral type from a string representation.
  197. // The type will be Int64 or Uint64. Int64 will be preferred where possible.
  198. func BuildIntegral(val string) (n Value, err error) {
  199. signed, err := strconv.ParseInt(val, 0, 64)
  200. if err == nil {
  201. return MakeTrusted(Int64, strconv.AppendInt(nil, signed, 10)), nil
  202. }
  203. unsigned, err := strconv.ParseUint(val, 0, 64)
  204. if err != nil {
  205. return Value{}, err
  206. }
  207. return MakeTrusted(Uint64, strconv.AppendUint(nil, unsigned, 10)), nil
  208. }
  209. // Type returns the type of Value.
  210. func (v Value) Type() Type {
  211. return v.typ
  212. }
  213. // Raw returns the raw bytes. All types are currently implemented as []byte.
  214. // You should avoid using this function. If you do, you should treat the
  215. // bytes as read-only.
  216. func (v Value) Raw() []byte {
  217. return v.val
  218. }
  219. // Len returns the length.
  220. func (v Value) Len() int {
  221. return len(v.val)
  222. }
  223. // Values represents the array of Value.
  224. type Values []Value
  225. // Len implements the interface.
  226. func (vs Values) Len() int {
  227. len := 0
  228. for _, v := range vs {
  229. len += v.Len()
  230. }
  231. return len
  232. }
  233. // String returns the raw value as a string.
  234. func (v Value) String() string {
  235. return BytesToString(v.val)
  236. }
  237. // ToNative converts Value to a native go type.
  238. // This does not work for sqltypes.Tuple. The function
  239. // panics if there are inconsistencies.
  240. func (v Value) ToNative() interface{} {
  241. var out interface{}
  242. var err error
  243. switch {
  244. case v.typ == Null:
  245. // no-op
  246. case IsSigned(v.typ):
  247. out, err = v.ParseInt64()
  248. case IsUnsigned(v.typ):
  249. out, err = v.ParseUint64()
  250. case IsFloat(v.typ):
  251. out, err = v.ParseFloat64()
  252. default:
  253. out = v.val
  254. }
  255. if err != nil {
  256. panic(err)
  257. }
  258. return out
  259. }
  260. // ParseInt64 will parse a Value into an int64. It does
  261. // not check the type.
  262. func (v Value) ParseInt64() (val int64, err error) {
  263. return strconv.ParseInt(v.String(), 10, 64)
  264. }
  265. // ParseUint64 will parse a Value into a uint64. It does
  266. // not check the type.
  267. func (v Value) ParseUint64() (val uint64, err error) {
  268. return strconv.ParseUint(v.String(), 10, 64)
  269. }
  270. // ParseFloat64 will parse a Value into an float64. It does
  271. // not check the type.
  272. func (v Value) ParseFloat64() (val float64, err error) {
  273. return strconv.ParseFloat(v.String(), 64)
  274. }
  275. // IsNull returns true if Value is null.
  276. func (v Value) IsNull() bool {
  277. return v.typ == Null
  278. }
  279. // IsIntegral returns true if Value is an integral.
  280. func (v Value) IsIntegral() bool {
  281. return IsIntegral(v.typ)
  282. }
  283. // IsSigned returns true if Value is a signed integral.
  284. func (v Value) IsSigned() bool {
  285. return IsSigned(v.typ)
  286. }
  287. // IsUnsigned returns true if Value is an unsigned integral.
  288. func (v Value) IsUnsigned() bool {
  289. return IsUnsigned(v.typ)
  290. }
  291. // IsFloat returns true if Value is a float.
  292. func (v Value) IsFloat() bool {
  293. return IsFloat(v.typ)
  294. }
  295. // IsQuoted returns true if Value must be SQL-quoted.
  296. func (v Value) IsQuoted() bool {
  297. return IsQuoted(v.typ)
  298. }
  299. // IsText returns true if Value is a collatable text.
  300. func (v Value) IsText() bool {
  301. return IsText(v.typ)
  302. }
  303. // IsBinary returns true if Value is binary.
  304. func (v Value) IsBinary() bool {
  305. return IsBinary(v.typ)
  306. }
  307. // IsTemporal returns true if Value is time type.
  308. func (v Value) IsTemporal() bool {
  309. return IsTemporal(v.typ)
  310. }
  311. // ToString returns the value as MySQL would return it as string.
  312. // If the value is not convertible like in the case of Expression, it returns nil.
  313. func (v Value) ToString() string {
  314. return BytesToString(v.val)
  315. }