123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317 |
- package xugu
- import (
- "C"
- "database/sql/driver"
- "errors"
- "fmt"
- "strconv"
- "strings"
- "time"
- )
- // Auxiliary Struct
- type __Value struct {
- // Boolean value, if the value is true, it means that the data
- // type of the current field is a large object data type
- islob bool
- // A pointer of * C.char data type, usually
- // pointing to the address of the parameter value to be bound
- value *C.char
- plob *XuguLob
- // length usually specifies the true length of the parameter
- // data to be bound
- length C.int
- // buff usually specifies the memory buffer
- // size of the parameter data to be bound
- buff C.int
- // When parameter binding, specify the data type of the field in the table
- types int
- // Return code
- rcode C.int
- }
- type parse struct {
- // bind_type is used to identify the type of parameter binding.
- // Parameter binding types include binding by parameter name
- // and binding by parameter placeholder
- bind_type int
- // param_count is used to specify the number
- // of parameters that need to be bound in the SQL statement
- param_count int
- // When the parameter binding type is binding
- // by parameter name, param_names is a collection of parameter names
- param_names []*C.char
- Val []__Value
- // When the parameter binding type is binding
- // by parameter placeholder, position identifies the parameter position
- position int
- }
- type ParseParam interface {
- // Conversion parameter data type
- assertParamType(driver.Value, int) error
- // Number of parsing parameters
- assertParamCount(string) int
- // Parse parameter binding type (binding type by parameter name
- // and binding type by parameter position)
- assertBindType(string) int
- // Parse parameter name
- assertParamName(string) error
- }
- func namedValueToValue(named []driver.NamedValue) ([]driver.Value, error) {
- __Par := make([]driver.Value, len(named))
- for pos, Param := range named {
- if len(Param.Name) > 0 {
- return nil, errors.New("Driver does not support the use of Named Parameters")
- }
- __Par[pos] = Param.Value
- }
- return __Par, nil
- }
- func (self *parse) assertParamType(dV driver.Value, pos int) error {
- var dest __Value
- switch dV.(type) {
- case int64:
- srcv, ok := dV.(int64)
- if !ok {
- news := errorNews("int64")
- return errors.New(news)
- }
- S := strconv.FormatInt(srcv, 10)
- dest.value = C.CString(S)
- dest.length = C.int(strings.Count(S, "") - 1)
- dest.buff = dest.length + 1
- dest.islob = false
- dest.types = SQL_XG_C_CHAR
- case float32:
- srcv, ok := dV.(float64)
- if !ok {
- news := errorNews("float32")
- return errors.New(news)
- }
- S := strconv.FormatFloat(srcv, 'f', 6, 64)
- dest.value = C.CString(S)
- dest.length = C.int(strings.Count(S, "") - 1)
- dest.buff = dest.length + 1
- dest.islob = false
- dest.types = SQL_XG_C_CHAR
- case float64:
- srcv, ok := dV.(float64)
- if !ok {
- news := errorNews("float64")
- return errors.New(news)
- }
- S := strconv.FormatFloat(srcv, 'f', 15, 64)
- dest.value = C.CString(S)
- dest.length = C.int(strings.Count(S, "") - 1)
- dest.buff = dest.length + 1
- dest.islob = false
- dest.types = SQL_XG_C_CHAR
- case bool:
- srcv, ok := dV.(bool)
- if !ok {
- news := errorNews("bool")
- return errors.New(news)
- }
- S := strconv.FormatBool(srcv)
- dest.value = C.CString(S)
- dest.length = C.int(strings.Count(S, "") - 1)
- dest.buff = dest.length + 1
- dest.islob = false
- dest.types = SQL_XG_C_CHAR
- case string:
- srcv, ok := dV.(string)
- if !ok {
- news := errorNews("string")
- return errors.New(news)
- }
- dest.value = C.CString(srcv)
- dest.length = C.int(strings.Count(srcv, "") - 1)
- dest.buff = dest.length + 1
- dest.islob = false
- dest.types = SQL_XG_C_CHAR
- if dest.length == 0 {
- dest.length = 1
- }
- case time.Time:
- srcv, ok := dV.(time.Time)
- if !ok {
- news := errorNews("time.Time")
- return errors.New(news)
- }
- tm := fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d",
- srcv.Year(), int(srcv.Month()), srcv.Day(),
- srcv.Hour(), srcv.Minute(), srcv.Second())
- dest.value = C.CString(tm)
- dest.length = C.int(strings.Count(tm, "") - 1)
- dest.buff = dest.length + 1
- dest.islob = false
- dest.types = SQL_XG_C_CHAR
- case []byte:
- re := CreateLob()
- dest.plob = &re
- srcv, ok := dV.([]byte)
- if !ok {
- news := errorNews("[]byte")
- return errors.New(news)
- }
- dest.plob.putLobData(srcv, len(srcv))
- dest.plob.putLobData(nil, -1)
- dest.value = nil
- dest.length = C.int(8)
- dest.buff = C.int(8)
- dest.islob = true
- dest.types = SQL_XG_C_BLOB
- case nil:
- dest.value = C.CString("xugusql")
- dest.length = 0
- dest.buff = C.int(strings.Count("xugusql", ""))
- dest.islob = false
- dest.types = SQL_XG_C_CHAR
- default:
- /* OTHER DATA TYPE */
- return errors.New("Unknown data type")
- }
- self.position = pos
- self.Val = append(self.Val, dest)
- return nil
- }
- func errorNews(str string) string {
- return fmt.Sprintf("[%s] asserting data type failed.", str)
- }
- func (self *parse) assertParamCount(query string) int {
- if self.bind_type == 0 {
- self.bind_type = self.assertBindType(query)
- }
- switch self.bind_type {
- case BIND_PARAM_BY_POS:
- self.param_count = strings.Count(query, "?")
- case BIND_PARAM_BY_NAME:
- self.param_count = 0
- pos := 0
- phead := -1
- for true {
- pos = strings.IndexByte(query[phead+1:], ':')
- if pos == -1 {
- break
- }
- pos += phead + 1
- tmp := pos
- for tmp > phead {
- tmp--
- if query[tmp] == ' ' {
- continue
- }
- if query[tmp] == ',' || query[tmp] == '(' {
- self.param_count++
- }
- break
- }
- phead = pos
- }
- }
- return self.param_count
- }
- func (self *parse) assertBindType(query string) int {
- self.bind_type = strings.IndexByte(query, '?')
- if self.bind_type != -1 {
- return BIND_PARAM_BY_POS
- }
- return BIND_PARAM_BY_NAME
- }
- func (self *parse) assertParamName(query string) error {
- if self.param_count <= 0 {
- self.assertParamCount(query)
- }
- pos := 0
- phead := -1
- for true {
- pos = strings.IndexByte(query[phead+1:], ':')
- if pos == -1 {
- break
- }
- pos += phead + 1
- tmp := pos
- for tmp > phead {
- tmp--
- if query[tmp] == ' ' {
- continue
- }
- // Parse parameter positions bound by parameter name
- if query[tmp] == ',' || query[tmp] == '(' {
- parg := pos
- for true {
- parg++
- if query[parg] == ',' || query[parg] == ')' || query[parg] == ' ' {
- self.param_names = append(self.param_names, C.CString(query[pos+1:parg]))
- break
- }
- }
- }
- break
- }
- phead = pos
- }
- return nil
- }
|