package xugu import ( "bufio" "database/sql/driver" "encoding/binary" "errors" "fmt" "strconv" "strings" ) type ParseParam interface { // 转换参数数据类型 assertParamType(driver.Value, int) error // 解析参数数量 assertParamCount(string) int // 解析参数绑定类型(按参数名称绑定类型和按参数位置绑定类型) assertBindType(string) int // 解析参数名称 assertParamName(string) error } // 辅助结构体 type xuguValue struct { // 布尔值,如果值为 true,表示当前字段的数据类型是大对象数据类型 islob bool plob []byte // 绑定参数变量的值 ? = aa value string // length 通常指定要绑定的参数变量值的实际长度 length int // buff 通常指定要绑定的参数数据的内存缓冲区大小 buff int // ?号在 sql 语句中的位置下标 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) } switch Parse.bind_type { case BIND_PARAM_BY_POS: Parse.param_count = strings.Count(query, "?") 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 } } return Parse.param_count } // 判断绑定类型 ? 或者 :name func (Parse *xuguParse) assertBindType(query string) int { fmt.Println("--assertBindType") Parse.bind_type = strings.IndexByte(query, '?') fmt.Println("Parse.bind_type", Parse.bind_type) if Parse.bind_type != -1 { return BIND_PARAM_BY_POS } 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 { return errors.New("assertParamType int64 error") } S := strconv.FormatInt(srcv, 10) dest.value = S dest.length = 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 { return errors.New("assertParamType string error") } dest.value = srcv dest.length = 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 = "xugusql" dest.length = 0 dest.buff = 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 { 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 } fmt.Printf("param: %#v", param) fmt.Println("----(param *xuguParse) assertParamName 判断参数名结束") return nil } func (param *xuguParse) bindParamByPos(query string) string { fmt.Printf("param: %#v \n", param) for i := 0; i < param.param_count; i++ { //sql语句里替换夫的下标, 替换为 query = strings.Replace(query, "?", param.Val[i].value, 1) } return query } type SelectResult struct { Field_Num uint32 Fields []FieldDescri Values [][]ValueData //[字段][字段所有值] rowIdx int } type FieldDescri struct { FieldNameLen int FieldName string FieldType fieldType FieldPreciScale int FieldFlag int } type ValueData struct { Col_len uint32 Col_Data []byte } type InsertResult struct { RowidLen uint32 RowidData []byte } type UpdateResult struct { UpdateNum uint32 } type DeleteResult struct { DeleteNum uint32 } type ProcRet struct { RetDType uint32 RetDataLen uint32 RetData []byte } type OutParamRet struct { OutParamNo uint32 OutParamDType uint32 OutParamLen uint32 OutParamData []byte } type ErrInfo struct { ErrStrLen uint32 ErrStr []byte } type WarnInfo struct { WarnStrLen uint32 WarnStr []byte } type Message struct { MsgStrLen uint32 MsgStr []byte } type FormArgDescri struct { ArgNum int Args []ArgDescri } type ArgDescri struct { ArgNameLen int ArgName string ArgNo int ArgDType int ArgPreciScale int } func parseSelectResult(readBuf buffer) (*SelectResult, error) { fmt.Println("调用 parseSelectResult") data := &SelectResult{} char := readBuf.peekChar() fmt.Println("--=char: ", string(char)) switch char { case 'A': readBuf.idx++ //Field_Num Field_Num := binary.LittleEndian.Uint32(readBuf.readNext(4, true)) data.Field_Num = Field_Num data.rowIdx = 0 fmt.Println("Field_Num: ", data.Field_Num) //获取字段信息 for i := 0; i < int(Field_Num); i++ { field := FieldDescri{} //Field_Name_Len field.FieldNameLen = int(binary.LittleEndian.Uint32(readBuf.readNext(4, true))) fmt.Println("field.FieldNameLen: ", field.FieldNameLen) //Field_Name: field.FieldName = string(readBuf.readNext(field.FieldNameLen, false)) fmt.Println("field.Field_Name: ", field.FieldName) //Field_DType: field.FieldType = fieldType(binary.LittleEndian.Uint32(readBuf.readNext(4, true))) fmt.Println("field.FieldType: ", field.FieldType) //Field_Preci_Scale: field.FieldPreciScale = int(binary.LittleEndian.Uint32(readBuf.readNext(4, true))) fmt.Println("field.FieldPreciScale: ", field.FieldPreciScale) //Field_Flag: field.FieldFlag = int(binary.LittleEndian.Uint32(readBuf.readNext(4, true))) fmt.Println("field.FieldFlag: ", field.FieldFlag) data.Fields = append(data.Fields, field) } data.Values = make([][]ValueData, data.Field_Num) //获取字段的行值,并判断类型 // 使用 Peek 方法检查下一个字节是否为'R'或'K' fmt.Println("\n\n=========开始获取行数据=================================") char := readBuf.peekChar() fmt.Println(" --char: ", string(char)) readBuf.idx++ if char == 'K' { break } else if char == 'R' { colIdx := 0 typeIdx := 0 fmt.Println("开始循环 ") for { col := ValueData{} //获取数据的大小 col.Col_len = binary.LittleEndian.Uint32(readBuf.readNext(4, true)) fmt.Println("数据大小为: ", col.Col_len) //获取数据 //判断类型 fmt.Println("查看类型", data.Fields[typeIdx].FieldType) switch data.Fields[typeIdx].FieldType { case fieldType_CHAR, fieldType_NCHAR: col.Col_Data = readBuf.readNext(int(col.Col_len), false) fmt.Println("fieldTypeVarChar data: ", col.Col_Data, string(col.Col_Data)) data.Values[colIdx] = append(data.Values[colIdx], col) colIdx++ fmt.Println("从查询返回 解析出的值 :", col.Col_Data, string(col.Col_Data)) char := readBuf.peekChar() if char == 'R' { readBuf.idx++ colIdx = 0 if typeIdx >= int(data.Field_Num)-1 { typeIdx = 0 } else { typeIdx++ } continue } else if char == 'K' { return data, nil //break } typeIdx++ //fieldTypeTinyint, case fieldType_I1, fieldType_I4, fieldType_I8: col.Col_Data = reverseBytes(readBuf.readNext(int(col.Col_len), false)) data.Values[colIdx] = append(data.Values[colIdx], col) colIdx++ char := readBuf.peekChar() fmt.Println("从查询返回 解析出的值 :", col.Col_Data, string(col.Col_Data)) if char == 'R' { readBuf.idx++ colIdx = 0 if typeIdx >= int(data.Field_Num)-1 { fmt.Println("typeIdx <= int(data.Field_Num)-1: ", typeIdx, int(data.Field_Num)-1) typeIdx = 0 } else { typeIdx++ } continue } else if char == 'K' { return data, nil //break } typeIdx++ } //swich end fmt.Println("循环结束") return data, nil } //for end } else { break } default: return nil, errors.New("parseQueryResult error") } //swich end return data, nil } func parseInsertResult(readBuf buffer) (*InsertResult, error) { //Rowid_Len Rowid_Len := binary.LittleEndian.Uint32(readBuf.readNext(4, true)) //Rowid_Data encoded := readBuf.readNext(int(Rowid_Len), false) //检测是否结束 char := readBuf.peekChar() if char == 'K' { return &InsertResult{ RowidLen: Rowid_Len, RowidData: encoded, }, nil } return nil, errors.New("parseInsertResult error") } func parseUpdateResult(readBuf buffer) (*UpdateResult, error) { updateNum := binary.LittleEndian.Uint32(readBuf.readNext(4, true)) return &UpdateResult{UpdateNum: updateNum}, nil } func parseDeleteResult(readBuf buffer) (*DeleteResult, error) { deleteNum := binary.LittleEndian.Uint32(readBuf.readNext(4, true)) return &DeleteResult{DeleteNum: deleteNum}, nil } func parseProcRet(readBuf buffer) (*ProcRet, error) { retDType := binary.LittleEndian.Uint32(readBuf.readNext(4, true)) retDataLen := binary.LittleEndian.Uint32(readBuf.readNext(4, true)) retData := readBuf.readNext(int(retDataLen), false) return &ProcRet{RetDType: retDType, RetDataLen: retDataLen, RetData: retData}, nil } func parseOutParamRet(readBuf buffer) (*OutParamRet, error) { outParamNo := binary.LittleEndian.Uint32(readBuf.readNext(4, true)) outParamDType := binary.LittleEndian.Uint32(readBuf.readNext(4, true)) outParamLen := binary.LittleEndian.Uint32(readBuf.readNext(4, true)) outParamData := readBuf.readNext(int(outParamLen), false) return &OutParamRet{ OutParamNo: outParamNo, OutParamDType: outParamDType, OutParamLen: outParamLen, OutParamData: outParamData, }, nil } func parseErrInfo(readBuf buffer) (*ErrInfo, error) { errStrLen := binary.LittleEndian.Uint32(readBuf.readNext(4, true)) errStr := readBuf.readNext(int(errStrLen), false) return &ErrInfo{ErrStrLen: errStrLen, ErrStr: errStr}, nil } func parseWarnInfo(readBuf buffer) (*WarnInfo, error) { warnStrLen := binary.LittleEndian.Uint32(readBuf.readNext(4, true)) warnStr := readBuf.readNext(int(warnStrLen), false) return &WarnInfo{WarnStrLen: warnStrLen, WarnStr: warnStr}, nil } func parseMessage(readBuf buffer) (*Message, error) { msgStrLen := binary.LittleEndian.Uint32(readBuf.readNext(4, true)) msgStr := readBuf.readNext(int(msgStrLen), false) return &Message{MsgStrLen: msgStrLen, MsgStr: msgStr}, nil } func parseFormArgDescri(reader *bufio.Reader) (*FormArgDescri, error) { argNum, err := readInt32(reader) if err != nil { return nil, err } formArgDescri := &FormArgDescri{ArgNum: argNum} for i := 0; i < argNum; i++ { argDescri := ArgDescri{} argDescri.ArgNameLen, err = readInt32(reader) if err != nil { return nil, err } argDescri.ArgName, err = readString(reader, argDescri.ArgNameLen) if err != nil { return nil, err } argDescri.ArgNo, err = readInt32(reader) if err != nil { return nil, err } argDescri.ArgDType, err = readInt32(reader) if err != nil { return nil, err } argDescri.ArgPreciScale, err = readInt32(reader) if err != nil { return nil, err } formArgDescri.Args = append(formArgDescri.Args, argDescri) } return formArgDescri, nil }