package xugu import ( "database/sql/driver" "encoding/binary" "fmt" "strings" ) type ParseParam interface { // 转换参数数据类型 assertParamType(driver.Value, int) error // 解析参数数量 assertParamCount(string) int // 解析参数绑定类型(按参数名称绑定类型和按参数位置绑定类型) assertBindType(string) int // 解析参数名称 assertParamName(string) error } // 辅助结构体 // type xuguValue struct { // // 布尔值,如果值为 true,表示当前字段的数据类型是大对象数据类型 // islob bool // // 一个 *C.char 类型的指针,通常指向要绑定的参数值的地址 // value []byte // plob []byte // // length 通常指定要绑定的参数数据的实际长度 // length []int // // buff 通常指定要绑定的参数数据的内存缓冲区大小 // buffSize int // // 在参数绑定时,指定表中字段的数据类型 // types int // // 返回代码 // rcode int // } type xuguParse struct { // bind_type 用于标识参数绑定的类型。 // 参数绑定类型包括按参数名称绑定和按参数占位符绑定 bind_type int // param_count 用于指定在 SQL 语句中需要绑定的参数数量 param_count int // 当参数绑定类型为按参数名称绑定时,param_names 是参数名称的集合 param_names []byte //Val []xuguValue // 当参数绑定类型为按参数占位符绑定时,position 标识参数的位置 position int } func (Parse *xuguParse) assertParamCount(query string) int { fmt.Println("----assertParamCount func 判断参数个数") if Parse.bind_type == 0 { Parse.bind_type = Parse.assertBindType(query) } fmt.Println("**Parse.bind_type is", Parse.bind_type) switch Parse.bind_type { case BIND_PARAM_BY_POS: Parse.param_count = strings.Count(query, "?") case BIND_PARAM_BY_NAME: fmt.Println(">case BIND_PARAM_BY_NAME") Parse.param_count = 0 pos := 0 phead := -1 for { 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] == '(' { Parse.param_count++ } break } phead = pos } } fmt.Println("**Parse.param_count", Parse.param_count) return Parse.param_count } func (Parse *xuguParse) assertBindType(query string) int { fmt.Println("-----(param *xuguParse) assertBindType 判断绑定类型") Parse.bind_type = strings.IndexByte(query, '?') if Parse.bind_type != -1 { fmt.Println("** 是大对象语句") return BIND_PARAM_BY_POS } fmt.Println("** 不是大对象语句") return BIND_PARAM_BY_NAME } func (param *xuguParse) assertParamType(dV driver.Value, pos int) error { fmt.Println("-----(param *xuguParse) assertParamType 判断参数类型") // var dest xuguValue // 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 := cgo_xgc_new_lob(&dest.plob) // if re < 0 { // return errors.New("Cannot create new large object") // } // srcv, ok := dV.([]byte) // if !ok { // news := errorNews("[]byte") // return errors.New(news) // } // cgo_xgc_put_lob_data( // &dest.plob, // unsafe.Pointer((*C.char)(unsafe.Pointer(&srcv[0]))), // len(srcv)) // cgo_xgc_put_lob_data(&dest.plob, 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") // } // param.position = pos // param.Val = append(param.Val, dest) return nil } func (param *xuguParse) assertParamName(query string) error { fmt.Println("----(param *xuguParse) assertParamName 判断参数名") if param.param_count <= 0 { param.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] == ' ' { param.param_names = append(param.param_names, query[pos+1:parg]...) break } } } break } phead = pos } return nil } type SelectResult struct { Field_Num uint32 Fields []FieldDescri Values [][]ValueData //[字段][字段所有值] } type FieldDescri struct { FieldNameLen int FieldName string FieldType fieldType FieldPreciScale int FieldFlag int } type ValueData struct { Col_len uint32 Col_Data []byte } func parseSelectResult(readBuf buffer) (*SelectResult, error) { data := &SelectResult{} char := readBuf.peekChar() fmt.Println("--=char: ", string(char)) switch char { case 'A': readBuf.idx++ //Field_Num Field_Num := binary.BigEndian.Uint32(readBuf.readNext(4)) data.Field_Num = Field_Num fmt.Println("Field_Num: ", data.Field_Num) //获取字段信息 for i := 0; i < int(Field_Num); i++ { field := FieldDescri{} //Field_Name_Len field.FieldNameLen = int(binary.BigEndian.Uint32(readBuf.readNext(4))) fmt.Println("FieldNameLen: ", field.FieldNameLen) //Field_Name: field.FieldName = string(readBuf.readNext(field.FieldNameLen)) fmt.Println("FieldName: ", field.FieldName) //Field_DType: field.FieldType = fieldType(binary.BigEndian.Uint32(readBuf.readNext(4))) fmt.Println("FieldType: ", field.FieldType) //Field_Preci_Scale: field.FieldPreciScale = int(binary.BigEndian.Uint32(readBuf.readNext(4))) fmt.Println("FieldPreciScale: ", field.FieldPreciScale) //Field_Flag: field.FieldFlag = int(binary.BigEndian.Uint32(readBuf.readNext(4))) fmt.Println("FieldFlag: ", field.FieldFlag) data.Fields = append(data.Fields, field) } fmt.Println("data的字段总数: ", data.Field_Num) for i, v := range data.Fields { fmt.Println("data的内容: ", i, v.FieldName) } data.Values = make([][]ValueData, data.Field_Num) //获取字段的行值 // 使用 Peek 方法检查下一个字节是否为'R'或'K' char := readBuf.peekChar() fmt.Println("是否为R: ", string(char)) readBuf.idx++ if char == 'K' { break } else if char == 'R' { colIdx := 0 for { col := ValueData{} col.Col_len = binary.BigEndian.Uint32(readBuf.readNext(4)) // fmt.Println("Col_len: ", col.Col_len) col.Col_Data = readBuf.readNext(int(col.Col_len)) fmt.Println("Col_Data: ", string(col.Col_Data)) data.Values[colIdx] = append(data.Values[colIdx], col) colIdx++ char := readBuf.peekChar() if char == 'R' { fmt.Println("--=char3: ", string(readBuf.peekChar())) readBuf.idx++ colIdx = 0 continue } else if char == 'K' { fmt.Println("--=char4: ", string(readBuf.peekChar())) break } } } else { break } } fmt.Println("data的内容: ", data) for i := 0; i < int(data.Field_Num); i++ { for j := 0; j < len(data.Values[i]); j++ { fmt.Printf("data.Values[%d]: %v\n", i, (data.Values[i][j].Col_Data)) } } return data, nil } func parseInsertResult(readBuf buffer) (*SelectResult, error) { }