xugusql_auxi.go 6.5 KB

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