xugusql_auxi.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. package xugu
  2. import (
  3. "C"
  4. "database/sql/driver"
  5. "errors"
  6. "fmt"
  7. "strconv"
  8. "strings"
  9. "time"
  10. )
  11. // Auxiliary Struct
  12. type __Value struct {
  13. // Boolean value, if the value is true, it means that the data
  14. // type of the current field is a large object data type
  15. islob bool
  16. // A pointer of * C.char data type, usually
  17. // pointing to the address of the parameter value to be bound
  18. value *C.char
  19. plob *XuguLob
  20. // length usually specifies the true length of the parameter
  21. // data to be bound
  22. length C.int
  23. // buff usually specifies the memory buffer
  24. // size of the parameter data to be bound
  25. buff C.int
  26. // When parameter binding, specify the data type of the field in the table
  27. types int
  28. // Return code
  29. rcode C.int
  30. }
  31. type parse struct {
  32. // bind_type is used to identify the type of parameter binding.
  33. // Parameter binding types include binding by parameter name
  34. // and binding by parameter placeholder
  35. bind_type int
  36. // param_count is used to specify the number
  37. // of parameters that need to be bound in the SQL statement
  38. param_count int
  39. // When the parameter binding type is binding
  40. // by parameter name, param_names is a collection of parameter names
  41. param_names []*C.char
  42. Val []__Value
  43. // When the parameter binding type is binding
  44. // by parameter placeholder, position identifies the parameter position
  45. position int
  46. }
  47. type ParseParam interface {
  48. // Conversion parameter data type
  49. assertParamType(driver.Value, int) error
  50. // Number of parsing parameters
  51. assertParamCount(string) int
  52. // Parse parameter binding type (binding type by parameter name
  53. // and binding type by parameter position)
  54. assertBindType(string) int
  55. // Parse parameter name
  56. assertParamName(string) error
  57. }
  58. func namedValueToValue(named []driver.NamedValue) ([]driver.Value, error) {
  59. __Par := make([]driver.Value, len(named))
  60. for pos, Param := range named {
  61. if len(Param.Name) > 0 {
  62. return nil, errors.New("Driver does not support the use of Named Parameters")
  63. }
  64. __Par[pos] = Param.Value
  65. }
  66. return __Par, nil
  67. }
  68. func (self *parse) assertParamType(dV driver.Value, pos int) error {
  69. var dest __Value
  70. switch dV.(type) {
  71. case int64:
  72. srcv, ok := dV.(int64)
  73. if !ok {
  74. news := errorNews("int64")
  75. return errors.New(news)
  76. }
  77. S := strconv.FormatInt(srcv, 10)
  78. dest.value = C.CString(S)
  79. dest.length = C.int(strings.Count(S, "") - 1)
  80. dest.buff = dest.length + 1
  81. dest.islob = false
  82. dest.types = SQL_XG_C_CHAR
  83. case float32:
  84. srcv, ok := dV.(float64)
  85. if !ok {
  86. news := errorNews("float32")
  87. return errors.New(news)
  88. }
  89. S := strconv.FormatFloat(srcv, 'f', 6, 64)
  90. dest.value = C.CString(S)
  91. dest.length = C.int(strings.Count(S, "") - 1)
  92. dest.buff = dest.length + 1
  93. dest.islob = false
  94. dest.types = SQL_XG_C_CHAR
  95. case float64:
  96. srcv, ok := dV.(float64)
  97. if !ok {
  98. news := errorNews("float64")
  99. return errors.New(news)
  100. }
  101. S := strconv.FormatFloat(srcv, 'f', 15, 64)
  102. dest.value = C.CString(S)
  103. dest.length = C.int(strings.Count(S, "") - 1)
  104. dest.buff = dest.length + 1
  105. dest.islob = false
  106. dest.types = SQL_XG_C_CHAR
  107. case bool:
  108. srcv, ok := dV.(bool)
  109. if !ok {
  110. news := errorNews("bool")
  111. return errors.New(news)
  112. }
  113. S := strconv.FormatBool(srcv)
  114. dest.value = C.CString(S)
  115. dest.length = C.int(strings.Count(S, "") - 1)
  116. dest.buff = dest.length + 1
  117. dest.islob = false
  118. dest.types = SQL_XG_C_CHAR
  119. case string:
  120. srcv, ok := dV.(string)
  121. if !ok {
  122. news := errorNews("string")
  123. return errors.New(news)
  124. }
  125. dest.value = C.CString(srcv)
  126. dest.length = C.int(strings.Count(srcv, "") - 1)
  127. dest.buff = dest.length + 1
  128. dest.islob = false
  129. dest.types = SQL_XG_C_CHAR
  130. if dest.length == 0 {
  131. dest.length = 1
  132. }
  133. case time.Time:
  134. srcv, ok := dV.(time.Time)
  135. if !ok {
  136. news := errorNews("time.Time")
  137. return errors.New(news)
  138. }
  139. tm := fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d",
  140. srcv.Year(), int(srcv.Month()), srcv.Day(),
  141. srcv.Hour(), srcv.Minute(), srcv.Second())
  142. dest.value = C.CString(tm)
  143. dest.length = C.int(strings.Count(tm, "") - 1)
  144. dest.buff = dest.length + 1
  145. dest.islob = false
  146. dest.types = SQL_XG_C_CHAR
  147. case []byte:
  148. re := CreateLob()
  149. dest.plob = &re
  150. srcv, ok := dV.([]byte)
  151. if !ok {
  152. news := errorNews("[]byte")
  153. return errors.New(news)
  154. }
  155. dest.plob.putLobData(srcv, len(srcv))
  156. dest.plob.putLobData(nil, -1)
  157. dest.value = nil
  158. dest.length = C.int(8)
  159. dest.buff = C.int(8)
  160. dest.islob = true
  161. dest.types = SQL_XG_C_BLOB
  162. case nil:
  163. dest.value = C.CString("xugusql")
  164. dest.length = 0
  165. dest.buff = C.int(strings.Count("xugusql", ""))
  166. dest.islob = false
  167. dest.types = SQL_XG_C_CHAR
  168. default:
  169. /* OTHER DATA TYPE */
  170. return errors.New("Unknown data type")
  171. }
  172. self.position = pos
  173. self.Val = append(self.Val, dest)
  174. return nil
  175. }
  176. func errorNews(str string) string {
  177. return fmt.Sprintf("[%s] asserting data type failed.", str)
  178. }
  179. func (self *parse) assertParamCount(query string) int {
  180. if self.bind_type == 0 {
  181. self.bind_type = self.assertBindType(query)
  182. }
  183. switch self.bind_type {
  184. case BIND_PARAM_BY_POS:
  185. self.param_count = strings.Count(query, "?")
  186. case BIND_PARAM_BY_NAME:
  187. self.param_count = 0
  188. pos := 0
  189. phead := -1
  190. for true {
  191. pos = strings.IndexByte(query[phead+1:], ':')
  192. if pos == -1 {
  193. break
  194. }
  195. pos += phead + 1
  196. tmp := pos
  197. for tmp > phead {
  198. tmp--
  199. if query[tmp] == ' ' {
  200. continue
  201. }
  202. if query[tmp] == ',' || query[tmp] == '(' {
  203. self.param_count++
  204. }
  205. break
  206. }
  207. phead = pos
  208. }
  209. }
  210. return self.param_count
  211. }
  212. func (self *parse) assertBindType(query string) int {
  213. self.bind_type = strings.IndexByte(query, '?')
  214. if self.bind_type != -1 {
  215. return BIND_PARAM_BY_POS
  216. }
  217. return BIND_PARAM_BY_NAME
  218. }
  219. func (self *parse) assertParamName(query string) error {
  220. if self.param_count <= 0 {
  221. self.assertParamCount(query)
  222. }
  223. pos := 0
  224. phead := -1
  225. for true {
  226. pos = strings.IndexByte(query[phead+1:], ':')
  227. if pos == -1 {
  228. break
  229. }
  230. pos += phead + 1
  231. tmp := pos
  232. for tmp > phead {
  233. tmp--
  234. if query[tmp] == ' ' {
  235. continue
  236. }
  237. // Parse parameter positions bound by parameter name
  238. if query[tmp] == ',' || query[tmp] == '(' {
  239. parg := pos
  240. for true {
  241. parg++
  242. if query[parg] == ',' || query[parg] == ')' || query[parg] == ' ' {
  243. self.param_names = append(self.param_names, C.CString(query[pos+1:parg]))
  244. break
  245. }
  246. }
  247. }
  248. break
  249. }
  250. phead = pos
  251. }
  252. return nil
  253. }