xugusql_rows.go 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. package xugusql
  2. import (
  3. "C"
  4. "database/sql/driver"
  5. "errors"
  6. "io"
  7. "reflect"
  8. "time"
  9. "unsafe"
  10. )
  11. type Row struct {
  12. // Data information storage carrier of each column in the result set
  13. columns []xugusqlField
  14. // The name of each column in the result set of the current query
  15. names []string
  16. done bool
  17. }
  18. type xugusqlRows struct {
  19. // A context handle pointer, which can be used to obtain
  20. // information about the result set
  21. result unsafe.Pointer
  22. // The return value of the function cgo_xgc_read_next()
  23. lastRowRelt int
  24. // The return value of the function cgo_xgc_next_result()
  25. lastRelt int
  26. // Boolean value, used to identify whether the executed
  27. // SQL statement has been prepared
  28. prepared bool
  29. // Context connection handle pointer
  30. rows_conn unsafe.Pointer
  31. rowset Row
  32. }
  33. func (self *xugusqlRows) get_error() error {
  34. conn := self.rows_conn
  35. message := cgo_c_calloc(ERROR_BUFF_SIZE)
  36. defer func() {
  37. cgo_c_free(unsafe.Pointer(message))
  38. }()
  39. var length C.int
  40. cgo_xgc_error(&conn, message, &length)
  41. return errors.New(C.GoString(message))
  42. }
  43. /*
  44. * Columns returns the column names.
  45. * Columns returns an error if the rows are closed.
  46. */
  47. func (self *xugusqlRows) Columns() []string {
  48. var FieldCount C.int
  49. result := self.result
  50. if self.rowset.names != nil {
  51. return self.rowset.names
  52. }
  53. re := cgo_xgc_get_fields_count(&result, &FieldCount)
  54. if re < 0 {
  55. return self.rowset.names
  56. }
  57. column_name := cgo_c_calloc(COLUMN_NAME_BUFF_SIZE)
  58. defer func() {
  59. cgo_c_free(unsafe.Pointer(column_name))
  60. }()
  61. columns := make([]string, int(FieldCount))
  62. fields := make([]xugusqlField, int(FieldCount))
  63. for j := range columns {
  64. cgo_c_memset(column_name, COLUMN_NAME_BUFF_SIZE)
  65. re = cgo_xgc_get_column_name(&result, j+1, column_name)
  66. if re < 0 {
  67. return columns
  68. }
  69. columns[j] = C.GoString(column_name)
  70. fields[j].name = C.GoString(column_name)
  71. var dtype C.int
  72. re = cgo_xgc_get_column_type(&result, j+1, &dtype)
  73. if re < 0 {
  74. return columns
  75. }
  76. fields[j].fieldType = fieldType(dtype)
  77. }
  78. self.rowset.columns = fields
  79. self.rowset.names = columns
  80. return columns
  81. }
  82. func (self *xugusqlRows) Close() error {
  83. result := self.result
  84. self.rowset.columns = nil
  85. self.rowset.names = nil
  86. if result != nil {
  87. re := cgo_xgc_free_rowset(&result)
  88. if re < 0 {
  89. return self.get_error()
  90. }
  91. self.result = nil
  92. }
  93. return nil
  94. }
  95. // TODO(bradfitz): for now we need to defensively clone all
  96. // []byte that the driver returned (not permitting
  97. // *RawBytes in Rows.Scan), since we're about to close
  98. // the Rows in our defer, when we return from this function.
  99. // the contract with the driver.Next(...) interface is that it
  100. // can return slices into read-only temporary memory that's
  101. // only valid until the next Scan/Close. But the TODO is that
  102. // for a lot of drivers, this copy will be unnecessary. We
  103. // should provide an optional interface for drivers to
  104. // implement to say, "don't worry, the []bytes that I return
  105. // from Next will not be modified again." (for instance, if
  106. // they were obtained from the network anyway) But for now we
  107. // don't care.
  108. func (self *xugusqlRows) Next(dest []driver.Value) error {
  109. if self.result == nil {
  110. return errors.New("The result set has been released")
  111. }
  112. result := self.result
  113. self.lastRowRelt = cgo_xgc_read_next(&result)
  114. if self.lastRowRelt < 0 {
  115. return self.get_error()
  116. }
  117. if self.lastRowRelt == RET_NO_DATA {
  118. return io.EOF
  119. }
  120. pVal := cgo_c_calloc(FIELD_BUFF_SIZE)
  121. defer func() {
  122. cgo_c_free(unsafe.Pointer(pVal))
  123. }()
  124. var FieldCount = len(self.rowset.names)
  125. var length C.int
  126. for j := 0; j < FieldCount; j++ {
  127. coluType := self.rowset.columns[j].fieldType
  128. switch coluType {
  129. case fieldTypeBinary, fieldTypeLob,
  130. fieldTypeClob, fieldTypeBlob:
  131. var pLob unsafe.Pointer
  132. cgo_xgc_new_lob(&pLob)
  133. re := cgo_xgc_get_lob(&result, j+1, int(coluType), &pLob, LOB_BUFF_SIZE, &length)
  134. if re < 0 && re != SQL_XG_C_NULL {
  135. return self.get_error()
  136. }
  137. dest[j] = make([]byte, int(length)+1)
  138. if re == SQL_XG_C_NULL {
  139. dest[j] = nil
  140. } else {
  141. data := make([]byte, int(length))
  142. cgo_xgc_get_lob_data(&pLob, unsafe.Pointer(&data[0]), length)
  143. dest[j] = data
  144. }
  145. cgo_xgc_lob_distroy(&pLob)
  146. case fieldTypeDate:
  147. cgo_c_memset(pVal, FIELD_BUFF_SIZE)
  148. re := cgo_xgc_get_data(&result, j+1, int(fieldTypeChar), pVal, FIELD_BUFF_SIZE, &length)
  149. if re < 0 && re != SQL_XG_C_NULL {
  150. return self.get_error()
  151. }
  152. if re == SQL_XG_C_NULL {
  153. dest[j] = nil
  154. } else {
  155. //tzone, _ := time.LoadLocation("Asia/Shanghai")
  156. //tv, _ := time.ParseInLocation("2006-01-02", C.GoString(pVal), tzone)
  157. tv, _ := time.Parse("2006-01-02", C.GoString(pVal))
  158. dest[j] = tv
  159. }
  160. case fieldTypeTime,
  161. fieldTypeTimeTZ:
  162. cgo_c_memset(pVal, FIELD_BUFF_SIZE)
  163. re := cgo_xgc_get_data(&result, j+1, int(fieldTypeChar), pVal, FIELD_BUFF_SIZE, &length)
  164. if re < 0 && re != SQL_XG_C_NULL {
  165. return self.get_error()
  166. }
  167. if re == SQL_XG_C_NULL {
  168. dest[j] = nil
  169. } else {
  170. //tzone, _ := time.LoadLocation("Asia/Shanghai")
  171. //tv, _ := time.ParseInLocation("15:04:05", C.GoString(pVal), tzone)
  172. tv, _ := time.Parse("15:04:05", C.GoString(pVal))
  173. dest[j] = tv
  174. }
  175. case fieldTypeDatetime,
  176. fieldTypeDatetimeTZ:
  177. cgo_c_memset(pVal, FIELD_BUFF_SIZE)
  178. re := cgo_xgc_get_data(&result, j+1, int(fieldTypeChar), pVal, FIELD_BUFF_SIZE, &length)
  179. if re < 0 && re != SQL_XG_C_NULL {
  180. return self.get_error()
  181. }
  182. if re == SQL_XG_C_NULL {
  183. dest[j] = nil
  184. } else {
  185. //tzone, _ := time.LoadLocation("Asia/Shanghai")
  186. //tv, _ := time.ParseInLocation("2006-01-02 15:04:05", C.GoString(pVal), tzone)
  187. tv, _ := time.Parse("2006-01-02 15:04:05", C.GoString(pVal))
  188. dest[j] = tv
  189. }
  190. default:
  191. cgo_c_memset(pVal, FIELD_BUFF_SIZE)
  192. re := cgo_xgc_get_data(&result, j+1, int(fieldTypeChar), pVal, FIELD_BUFF_SIZE, &length)
  193. if re < 0 && re != SQL_XG_C_NULL {
  194. return self.get_error()
  195. }
  196. dest[j] = make([]byte, int(length)+1)
  197. if re == SQL_XG_C_NULL {
  198. dest[j] = nil
  199. } else {
  200. dest[j] = []byte(C.GoString(pVal))
  201. }
  202. }
  203. }
  204. return nil
  205. }
  206. // The driver is at the end of the current result set.
  207. // Test to see if there is another result set after the current one.
  208. // Only close Rows if there is no further result sets to read.
  209. func (self *xugusqlRows) HasNextResultSet() bool {
  210. result := self.result
  211. if self.prepared {
  212. return false
  213. }
  214. if self.lastRowRelt == RET_NO_DATA {
  215. self.lastRelt = cgo_xgc_next_result(&result)
  216. if self.lastRelt == RET_NO_DATA {
  217. return false
  218. }
  219. self.rowset.columns = nil
  220. self.rowset.names = nil
  221. self.result = result
  222. return true
  223. }
  224. return false
  225. }
  226. // NextResultSet prepares the next result set for reading. It reports whether
  227. // there is further result sets, or false if there is no further result set
  228. // or if there is an error advancing to it. The Err method should be consulted
  229. // to distinguish between the two cases.
  230. //
  231. // After calling NextResultSet, the Next method should always be called before
  232. // scanning. If there are further result sets they may not have rows in the result
  233. // set.
  234. func (self *xugusqlRows) NextResultSet() error {
  235. if self.result == nil {
  236. return errors.New("The result set has been released")
  237. }
  238. result := self.result
  239. if self.prepared {
  240. return io.EOF
  241. }
  242. if self.lastRelt == RET_NO_DATA {
  243. return io.EOF
  244. }
  245. self.result = result
  246. return nil
  247. }
  248. /* {{ */
  249. /* {{ type ColumnTypeScanType interface }} */
  250. func (self *xugusqlRows) ColumnTypeScanType(index int) reflect.Type {
  251. return self.rowset.columns[index].scanType()
  252. }
  253. /* {{ */
  254. /* {{ RowsColumnTypeDatabaseTypeName }} */
  255. func (self *xugusqlRows) ColumnTypeDatabaseTypeName(index int) string {
  256. return self.rowset.columns[index].typeDatabaseName()
  257. }
  258. /* {{ */
  259. /* {{ RowsColumnTypeLength }} */
  260. func (self *xugusqlRows) ColumnTypeLength(index int) (int64, bool) {
  261. return 0, false
  262. }
  263. /* {{ */
  264. /* {{ RowsColumnTypeNullable */
  265. func (self *xugusqlRows) ColumnTypeNullable(index int) (nullable, ok bool) {
  266. /* not support */
  267. return false, false
  268. }
  269. /* {{ */
  270. /* {{ RowsColumnTypePrecisionScale */
  271. func (self *xugusqlRows) ColumnTypePrecisionScale(index int) (int64, int64, bool) {
  272. /* not support */
  273. return 0, 0, false
  274. }