123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336 |
- package xugusql
- import (
- "C"
- "database/sql/driver"
- "errors"
- "io"
- "reflect"
- "time"
- "unsafe"
- )
- type Row struct {
- // Data information storage carrier of each column in the result set
- columns []xugusqlField
- // The name of each column in the result set of the current query
- names []string
- done bool
- }
- type xugusqlRows struct {
- // A context handle pointer, which can be used to obtain
- // information about the result set
- result unsafe.Pointer
- // The return value of the function cgo_xgc_read_next()
- lastRowRelt int
- // The return value of the function cgo_xgc_next_result()
- lastRelt int
- // Boolean value, used to identify whether the executed
- // SQL statement has been prepared
- prepared bool
- // Context connection handle pointer
- rows_conn unsafe.Pointer
- rowset Row
- }
- func (self *xugusqlRows) get_error() error {
- conn := self.rows_conn
- message := cgo_c_calloc(ERROR_BUFF_SIZE)
- defer func() {
- cgo_c_free(unsafe.Pointer(message))
- }()
- var length C.int
- cgo_xgc_error(&conn, message, &length)
- return errors.New(C.GoString(message))
- }
- /*
- * Columns returns the column names.
- * Columns returns an error if the rows are closed.
- */
- func (self *xugusqlRows) Columns() []string {
- var FieldCount C.int
- result := self.result
- if self.rowset.names != nil {
- return self.rowset.names
- }
- re := cgo_xgc_get_fields_count(&result, &FieldCount)
- if re < 0 {
- return self.rowset.names
- }
- column_name := cgo_c_calloc(COLUMN_NAME_BUFF_SIZE)
- defer func() {
- cgo_c_free(unsafe.Pointer(column_name))
- }()
- columns := make([]string, int(FieldCount))
- fields := make([]xugusqlField, int(FieldCount))
- for j := range columns {
- cgo_c_memset(column_name, COLUMN_NAME_BUFF_SIZE)
- re = cgo_xgc_get_column_name(&result, j+1, column_name)
- if re < 0 {
- return columns
- }
- columns[j] = C.GoString(column_name)
- fields[j].name = C.GoString(column_name)
- var dtype C.int
- re = cgo_xgc_get_column_type(&result, j+1, &dtype)
- if re < 0 {
- return columns
- }
- fields[j].fieldType = fieldType(dtype)
- }
- self.rowset.columns = fields
- self.rowset.names = columns
- return columns
- }
- func (self *xugusqlRows) Close() error {
- result := self.result
- self.rowset.columns = nil
- self.rowset.names = nil
- if result != nil {
- re := cgo_xgc_free_rowset(&result)
- if re < 0 {
- return self.get_error()
- }
- self.result = nil
- }
- return nil
- }
- // TODO(bradfitz): for now we need to defensively clone all
- // []byte that the driver returned (not permitting
- // *RawBytes in Rows.Scan), since we're about to close
- // the Rows in our defer, when we return from this function.
- // the contract with the driver.Next(...) interface is that it
- // can return slices into read-only temporary memory that's
- // only valid until the next Scan/Close. But the TODO is that
- // for a lot of drivers, this copy will be unnecessary. We
- // should provide an optional interface for drivers to
- // implement to say, "don't worry, the []bytes that I return
- // from Next will not be modified again." (for instance, if
- // they were obtained from the network anyway) But for now we
- // don't care.
- func (self *xugusqlRows) Next(dest []driver.Value) error {
- if self.result == nil {
- return errors.New("The result set has been released")
- }
- result := self.result
- self.lastRowRelt = cgo_xgc_read_next(&result)
- if self.lastRowRelt < 0 {
- return self.get_error()
- }
- if self.lastRowRelt == RET_NO_DATA {
- return io.EOF
- }
- pVal := cgo_c_calloc(FIELD_BUFF_SIZE)
- defer func() {
- cgo_c_free(unsafe.Pointer(pVal))
- }()
- var FieldCount = len(self.rowset.names)
- var length C.int
- for j := 0; j < FieldCount; j++ {
- coluType := self.rowset.columns[j].fieldType
- switch coluType {
- case fieldTypeBinary, fieldTypeLob,
- fieldTypeClob, fieldTypeBlob:
- var pLob unsafe.Pointer
- cgo_xgc_new_lob(&pLob)
- re := cgo_xgc_get_lob(&result, j+1, int(coluType), &pLob, LOB_BUFF_SIZE, &length)
- if re < 0 && re != SQL_XG_C_NULL {
- return self.get_error()
- }
- dest[j] = make([]byte, int(length)+1)
- if re == SQL_XG_C_NULL {
- dest[j] = nil
- } else {
- data := make([]byte, int(length))
- cgo_xgc_get_lob_data(&pLob, unsafe.Pointer(&data[0]), length)
- dest[j] = data
- }
- cgo_xgc_lob_distroy(&pLob)
- case fieldTypeDate:
- cgo_c_memset(pVal, FIELD_BUFF_SIZE)
- re := cgo_xgc_get_data(&result, j+1, int(fieldTypeChar), pVal, FIELD_BUFF_SIZE, &length)
- if re < 0 && re != SQL_XG_C_NULL {
- return self.get_error()
- }
- if re == SQL_XG_C_NULL {
- dest[j] = nil
- } else {
- //tzone, _ := time.LoadLocation("Asia/Shanghai")
- //tv, _ := time.ParseInLocation("2006-01-02", C.GoString(pVal), tzone)
- tv, _ := time.Parse("2006-01-02", C.GoString(pVal))
- dest[j] = tv
- }
- case fieldTypeTime,
- fieldTypeTimeTZ:
- cgo_c_memset(pVal, FIELD_BUFF_SIZE)
- re := cgo_xgc_get_data(&result, j+1, int(fieldTypeChar), pVal, FIELD_BUFF_SIZE, &length)
- if re < 0 && re != SQL_XG_C_NULL {
- return self.get_error()
- }
- if re == SQL_XG_C_NULL {
- dest[j] = nil
- } else {
- //tzone, _ := time.LoadLocation("Asia/Shanghai")
- //tv, _ := time.ParseInLocation("15:04:05", C.GoString(pVal), tzone)
- tv, _ := time.Parse("15:04:05", C.GoString(pVal))
- dest[j] = tv
- }
- case fieldTypeDatetime,
- fieldTypeDatetimeTZ:
- cgo_c_memset(pVal, FIELD_BUFF_SIZE)
- re := cgo_xgc_get_data(&result, j+1, int(fieldTypeChar), pVal, FIELD_BUFF_SIZE, &length)
- if re < 0 && re != SQL_XG_C_NULL {
- return self.get_error()
- }
- if re == SQL_XG_C_NULL {
- dest[j] = nil
- } else {
- //tzone, _ := time.LoadLocation("Asia/Shanghai")
- //tv, _ := time.ParseInLocation("2006-01-02 15:04:05", C.GoString(pVal), tzone)
- tv, _ := time.Parse("2006-01-02 15:04:05", C.GoString(pVal))
- dest[j] = tv
- }
- default:
- cgo_c_memset(pVal, FIELD_BUFF_SIZE)
- re := cgo_xgc_get_data(&result, j+1, int(fieldTypeChar), pVal, FIELD_BUFF_SIZE, &length)
- if re < 0 && re != SQL_XG_C_NULL {
- return self.get_error()
- }
- dest[j] = make([]byte, int(length)+1)
- if re == SQL_XG_C_NULL {
- dest[j] = nil
- } else {
- dest[j] = []byte(C.GoString(pVal))
- }
- }
- }
- return nil
- }
- // The driver is at the end of the current result set.
- // Test to see if there is another result set after the current one.
- // Only close Rows if there is no further result sets to read.
- func (self *xugusqlRows) HasNextResultSet() bool {
- result := self.result
- if self.prepared {
- return false
- }
- if self.lastRowRelt == RET_NO_DATA {
- self.lastRelt = cgo_xgc_next_result(&result)
- if self.lastRelt == RET_NO_DATA {
- return false
- }
- self.rowset.columns = nil
- self.rowset.names = nil
- self.result = result
- return true
- }
- return false
- }
- // NextResultSet prepares the next result set for reading. It reports whether
- // there is further result sets, or false if there is no further result set
- // or if there is an error advancing to it. The Err method should be consulted
- // to distinguish between the two cases.
- //
- // After calling NextResultSet, the Next method should always be called before
- // scanning. If there are further result sets they may not have rows in the result
- // set.
- func (self *xugusqlRows) NextResultSet() error {
- if self.result == nil {
- return errors.New("The result set has been released")
- }
- result := self.result
- if self.prepared {
- return io.EOF
- }
- if self.lastRelt == RET_NO_DATA {
- return io.EOF
- }
- self.result = result
- return nil
- }
- /* {{ */
- /* {{ type ColumnTypeScanType interface }} */
- func (self *xugusqlRows) ColumnTypeScanType(index int) reflect.Type {
- return self.rowset.columns[index].scanType()
- }
- /* {{ */
- /* {{ RowsColumnTypeDatabaseTypeName }} */
- func (self *xugusqlRows) ColumnTypeDatabaseTypeName(index int) string {
- return self.rowset.columns[index].typeDatabaseName()
- }
- /* {{ */
- /* {{ RowsColumnTypeLength }} */
- func (self *xugusqlRows) ColumnTypeLength(index int) (int64, bool) {
- return 0, false
- }
- /* {{ */
- /* {{ RowsColumnTypeNullable */
- func (self *xugusqlRows) ColumnTypeNullable(index int) (nullable, ok bool) {
- /* not support */
- return false, false
- }
- /* {{ */
- /* {{ RowsColumnTypePrecisionScale */
- func (self *xugusqlRows) ColumnTypePrecisionScale(index int) (int64, int64, bool) {
- /* not support */
- return 0, 0, false
- }
|