xugusql_stmt.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. package xugusql
  2. import (
  3. "C"
  4. "database/sql/driver"
  5. "errors"
  6. "unsafe"
  7. )
  8. type xugusqlStmt struct {
  9. // Context connection handle pointer
  10. stmt_conn unsafe.Pointer
  11. // Boolean value, used to identify whether
  12. // the executed SQL statement has been prepared
  13. prepared bool
  14. // Accept the prepared code for
  15. // the prepared SQL statement
  16. prename *C.char
  17. // Boolean value used to identify
  18. // whether the cursor is enabled
  19. curopend bool
  20. // Cursor name
  21. curname *C.char
  22. // The number of parameters
  23. // in the executed SQL statement
  24. param_count int
  25. mysql string
  26. // Context result set handle pointer
  27. result unsafe.Pointer
  28. }
  29. /* Collect error information from the database server */
  30. func (self *xugusqlStmt) get_error() error {
  31. message := cgo_c_calloc(ERROR_BUFF_SIZE)
  32. defer func() {
  33. cgo_c_free(unsafe.Pointer(message))
  34. }()
  35. var length C.int
  36. cgo_xgc_error(&self.stmt_conn, message, &length)
  37. return errors.New(C.GoString(message))
  38. }
  39. /* {{ */
  40. func (self *xugusqlStmt) Close() error {
  41. if self.curopend {
  42. re := cgo_xgc_close_cursor(&self.stmt_conn, self.curname)
  43. if re < 0 {
  44. return self.get_error()
  45. }
  46. cgo_c_free(unsafe.Pointer(self.curname))
  47. self.curname = nil
  48. self.curopend = false
  49. }
  50. if self.prepared {
  51. re := cgo_xgc_unprepare(&self.stmt_conn, self.prename)
  52. if re < 0 {
  53. return self.get_error()
  54. }
  55. cgo_c_free(unsafe.Pointer(self.prename))
  56. self.prename = nil
  57. self.prepared = false
  58. }
  59. return nil
  60. }
  61. /* {{ */
  62. func (self *xugusqlStmt) NumInput() int {
  63. parser := &parse{
  64. bind_type: 0,
  65. param_count: 0,
  66. position: 0,
  67. }
  68. return parser.assertParamCount(self.mysql)
  69. }
  70. // Exec executes a prepared statement with the given arguments and
  71. // returns a Result summarizing the effect of the statement.
  72. func (self *xugusqlStmt) Exec(args []driver.Value) (driver.Result, error) {
  73. sql := C.CString(self.mysql)
  74. switch cgo_xgc_sql_type(sql) {
  75. case SQL_SELECT:
  76. return nil, errors.New("Exec does not support queries")
  77. }
  78. if !self.prepared {
  79. return nil, errors.New("SQL statement is not Prepared")
  80. }
  81. parser := &parse{
  82. bind_type: 0,
  83. param_count: 0,
  84. position: 0,
  85. }
  86. if len(args) != 0 {
  87. for pos, param := range args {
  88. err := parser.assertParamType(param, pos)
  89. if err != nil {
  90. return nil, err
  91. }
  92. }
  93. if len(parser.Val) != parser.assertParamCount(self.mysql) {
  94. return nil, errors.New("The number of parameters does not match")
  95. }
  96. switch parser.assertBindType(self.mysql) {
  97. case BIND_PARAM_BY_POS:
  98. for pos, param := range parser.Val {
  99. if !param.islob {
  100. re := cgo_xgc_bindparambypos(&self.stmt_conn, pos+1,
  101. SQL_PARAM_INPUT, param.types,
  102. unsafe.Pointer(param.value), param.buff, &param.length)
  103. if re < 0 {
  104. return nil, self.get_error()
  105. }
  106. } else {
  107. re := cgo_xgc_bindparambypos(&self.stmt_conn, pos+1,
  108. SQL_PARAM_INPUT, param.types,
  109. unsafe.Pointer(&param.plob), param.buff, &param.length)
  110. if re < 0 {
  111. return nil, self.get_error()
  112. }
  113. }
  114. }
  115. case BIND_PARAM_BY_NAME:
  116. parser.assertParamName(self.mysql)
  117. for pos, param := range parser.Val {
  118. if !param.islob {
  119. re := cgo_xgc_bindparambyname(&self.stmt_conn, parser.param_names[pos],
  120. SQL_PARAM_INPUT, param.types, unsafe.Pointer(param.value),
  121. param.buff, &param.rcode, &param.length)
  122. if re < 0 {
  123. return nil, self.get_error()
  124. }
  125. } else {
  126. re := cgo_xgc_bindparambyname(&self.stmt_conn, parser.param_names[pos],
  127. SQL_PARAM_INPUT, param.types, unsafe.Pointer(&param.plob),
  128. param.buff, &param.rcode, &param.length)
  129. if re < 0 {
  130. return nil, self.get_error()
  131. }
  132. }
  133. }
  134. }
  135. }
  136. defer func() {
  137. cgo_c_free(unsafe.Pointer(sql))
  138. for pos, param := range parser.Val {
  139. if parser.bind_type == BIND_PARAM_BY_NAME {
  140. cgo_c_free(unsafe.Pointer(parser.param_names[pos]))
  141. }
  142. if !param.islob {
  143. cgo_c_free(unsafe.Pointer(param.value))
  144. } else {
  145. cgo_xgc_lob_distroy(&param.plob)
  146. }
  147. }
  148. }()
  149. result := &xugusqlResult{
  150. affectedRows: 0,
  151. insertId: 0,
  152. }
  153. re := cgo_xgc_execute(&self.stmt_conn, self.prename, self.curname, &self.result)
  154. if re < 0 {
  155. return nil, self.get_error()
  156. }
  157. var pCT, pCC, pRC, pEC C.int
  158. var pID = cgo_c_calloc(ROWID_BUFF_SIZE)
  159. re = cgo_xgc_get_result_set(&self.result, &pCT, &pCC, &pRC, &pEC, pID)
  160. if re < 0 {
  161. return nil, self.get_error()
  162. }
  163. cgo_c_free(unsafe.Pointer(pID))
  164. result.affectedRows = int64(pEC)
  165. return result, nil
  166. }
  167. // QueryContext executes a prepared query statement with the given arguments
  168. // and returns the query results as a *Rows.
  169. func (self *xugusqlStmt) Query(args []driver.Value) (driver.Rows, error) {
  170. sql := C.CString(self.mysql)
  171. if cgo_xgc_sql_type(sql) != SQL_SELECT {
  172. return nil, errors.New("The executed SQL statement is not a SELECT")
  173. }
  174. if !self.prepared {
  175. return nil, errors.New("SQL statement is not Prepared")
  176. }
  177. parser := &parse{
  178. bind_type: 0,
  179. param_count: 0,
  180. position: 0,
  181. }
  182. if len(args) != 0 {
  183. for pos, param := range args {
  184. err := parser.assertParamType(param, pos)
  185. if err != nil {
  186. return nil, err
  187. }
  188. }
  189. if len(parser.Val) != parser.assertParamCount(self.mysql) {
  190. return nil, errors.New("The number of parameters does not match")
  191. }
  192. switch parser.assertBindType(self.mysql) {
  193. case BIND_PARAM_BY_POS:
  194. for pos, param := range parser.Val {
  195. if !param.islob {
  196. re := cgo_xgc_bindparambypos(&self.stmt_conn, pos+1,
  197. SQL_PARAM_INPUT, param.types,
  198. unsafe.Pointer(param.value), param.buff, &param.length)
  199. if re < 0 {
  200. return nil, self.get_error()
  201. }
  202. } else {
  203. re := cgo_xgc_bindparambypos(&self.stmt_conn, pos+1,
  204. SQL_PARAM_INPUT, param.types,
  205. unsafe.Pointer(&param.plob), param.buff, &param.length)
  206. if re < 0 {
  207. return nil, self.get_error()
  208. }
  209. }
  210. }
  211. case BIND_PARAM_BY_NAME:
  212. parser.assertParamName(self.mysql)
  213. for pos, param := range parser.Val {
  214. if !param.islob {
  215. re := cgo_xgc_bindparambyname(&self.stmt_conn,
  216. parser.param_names[pos],
  217. SQL_PARAM_INPUT, param.types, unsafe.Pointer(param.value),
  218. param.buff, &param.rcode, &param.length)
  219. if re < 0 {
  220. return nil, self.get_error()
  221. }
  222. } else {
  223. re := cgo_xgc_bindparambyname(&self.stmt_conn,
  224. parser.param_names[pos],
  225. SQL_PARAM_INPUT, param.types, unsafe.Pointer(&param.plob),
  226. param.buff, &param.rcode, &param.length)
  227. if re < 0 {
  228. return nil, self.get_error()
  229. }
  230. }
  231. }
  232. }
  233. }
  234. defer func() {
  235. cgo_c_free(unsafe.Pointer(sql))
  236. for pos, param := range parser.Val {
  237. if parser.bind_type == BIND_PARAM_BY_NAME {
  238. cgo_c_free(unsafe.Pointer(parser.param_names[pos]))
  239. }
  240. if !param.islob {
  241. cgo_c_free(unsafe.Pointer(param.value))
  242. } else {
  243. cgo_xgc_lob_distroy(&param.plob)
  244. }
  245. }
  246. }()
  247. //if self.curname == nil {
  248. // self.curname = cgo_c_calloc(CURSOR_NAME_BUFF_SIZE)
  249. //}
  250. re := cgo_xgc_execute(&self.stmt_conn, self.prename, self.curname, &self.result)
  251. if re < 0 {
  252. return nil, self.get_error()
  253. }
  254. //re = cgo_xgc_fetch_with_cursor(&self.stmt_conn, self.curname, &self.result)
  255. //if re < 0 {
  256. // return nil, self.get_error()
  257. //}
  258. //self.curopend = true
  259. return &xugusqlRows{
  260. result: self.result,
  261. prepared: self.prepared,
  262. rows_conn: self.stmt_conn,
  263. }, nil
  264. }