binding.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. package native
  2. import (
  3. "github.com/ziutek/mymysql/mysql"
  4. "reflect"
  5. "time"
  6. )
  7. var (
  8. timeType = reflect.TypeOf(time.Time{})
  9. timestampType = reflect.TypeOf(mysql.Timestamp{})
  10. dateType = reflect.TypeOf(mysql.Date{})
  11. durationType = reflect.TypeOf(time.Duration(0))
  12. blobType = reflect.TypeOf(mysql.Blob{})
  13. rawType = reflect.TypeOf(mysql.Raw{})
  14. )
  15. // val should be an addressable value
  16. func bindValue(val reflect.Value) (out paramValue) {
  17. if !val.IsValid() {
  18. out.typ = MYSQL_TYPE_NULL
  19. return
  20. }
  21. typ := val.Type()
  22. if typ.Kind() == reflect.Ptr {
  23. // We have addressable pointer
  24. out.addr = val.Addr()
  25. // Dereference pointer for next operation on its value
  26. typ = typ.Elem()
  27. val = val.Elem()
  28. } else {
  29. // We have addressable value. Create a pointer to it
  30. pv := val.Addr()
  31. // This pointer is unaddressable so copy it and return an address
  32. out.addr = reflect.New(pv.Type())
  33. out.addr.Elem().Set(pv)
  34. }
  35. // Obtain value type
  36. switch typ.Kind() {
  37. case reflect.String:
  38. out.typ = MYSQL_TYPE_STRING
  39. out.length = -1
  40. return
  41. case reflect.Int:
  42. out.typ = _INT_TYPE
  43. out.length = _SIZE_OF_INT
  44. return
  45. case reflect.Int8:
  46. out.typ = MYSQL_TYPE_TINY
  47. out.length = 1
  48. return
  49. case reflect.Int16:
  50. out.typ = MYSQL_TYPE_SHORT
  51. out.length = 2
  52. return
  53. case reflect.Int32:
  54. out.typ = MYSQL_TYPE_LONG
  55. out.length = 4
  56. return
  57. case reflect.Int64:
  58. if typ == durationType {
  59. out.typ = MYSQL_TYPE_TIME
  60. out.length = -1
  61. return
  62. }
  63. out.typ = MYSQL_TYPE_LONGLONG
  64. out.length = 8
  65. return
  66. case reflect.Uint:
  67. out.typ = _INT_TYPE | MYSQL_UNSIGNED_MASK
  68. out.length = _SIZE_OF_INT
  69. return
  70. case reflect.Uint8:
  71. out.typ = MYSQL_TYPE_TINY | MYSQL_UNSIGNED_MASK
  72. out.length = 1
  73. return
  74. case reflect.Uint16:
  75. out.typ = MYSQL_TYPE_SHORT | MYSQL_UNSIGNED_MASK
  76. out.length = 2
  77. return
  78. case reflect.Uint32:
  79. out.typ = MYSQL_TYPE_LONG | MYSQL_UNSIGNED_MASK
  80. out.length = 4
  81. return
  82. case reflect.Uint64:
  83. out.typ = MYSQL_TYPE_LONGLONG | MYSQL_UNSIGNED_MASK
  84. out.length = 8
  85. return
  86. case reflect.Float32:
  87. out.typ = MYSQL_TYPE_FLOAT
  88. out.length = 4
  89. return
  90. case reflect.Float64:
  91. out.typ = MYSQL_TYPE_DOUBLE
  92. out.length = 8
  93. return
  94. case reflect.Slice:
  95. out.length = -1
  96. if typ == blobType {
  97. out.typ = MYSQL_TYPE_BLOB
  98. return
  99. }
  100. if typ.Elem().Kind() == reflect.Uint8 {
  101. out.typ = MYSQL_TYPE_VAR_STRING
  102. return
  103. }
  104. case reflect.Struct:
  105. out.length = -1
  106. if typ == timeType {
  107. out.typ = MYSQL_TYPE_DATETIME
  108. return
  109. }
  110. if typ == dateType {
  111. out.typ = MYSQL_TYPE_DATE
  112. return
  113. }
  114. if typ == timestampType {
  115. out.typ = MYSQL_TYPE_TIMESTAMP
  116. return
  117. }
  118. if typ == rawType {
  119. out.typ = val.FieldByName("Typ").Interface().(uint16)
  120. out.addr = val.FieldByName("Val").Addr()
  121. out.raw = true
  122. return
  123. }
  124. case reflect.Bool:
  125. out.typ = MYSQL_TYPE_TINY
  126. // bool implementation isn't documented so we treat it in special way
  127. out.length = -1
  128. return
  129. }
  130. panic(mysql.ErrBindUnkType)
  131. }