From 5a614c110f454de2d03ea364eec6806dead8939e Mon Sep 17 00:00:00 2001 From: t_max <1172915550@qq.com> Date: Fri, 25 Aug 2023 13:57:09 +0800 Subject: [PATCH 1/3] enh: support varbinary and fix pointer check --- common/column.go | 1 + common/const.go | 3 + common/param/column.go | 12 +++ common/param/param.go | 16 +++ common/parser/block.go | 187 +++++++++++++++--------------------- common/parser/block_test.go | 33 ++++--- common/pointer/unsafe.go | 7 ++ common/reqid.go | 8 +- common/serializer/block.go | 28 ++++++ common/stmt/field.go | 2 + taosSql/driver_test.go | 44 ++++----- taosSql/statement.go | 9 ++ taosWS/rows.go | 3 +- types/taostype.go | 2 + wrapper/row.go | 10 +- wrapper/stmt.go | 29 ++++++ wrapper/stmt_test.go | 16 +++ wrapper/taosc.go | 3 +- wrapper/tmq.go | 5 +- ws/tmq/consumer.go | 3 +- 20 files changed, 263 insertions(+), 158 deletions(-) create mode 100644 common/pointer/unsafe.go diff --git a/common/column.go b/common/column.go index de5b840..068cd50 100644 --- a/common/column.go +++ b/common/column.go @@ -40,4 +40,5 @@ var ColumnTypeMap = map[int]reflect.Type{ TSDB_DATA_TYPE_NCHAR: NullString, TSDB_DATA_TYPE_TIMESTAMP: NullTime, TSDB_DATA_TYPE_JSON: NullJson, + TSDB_DATA_TYPE_VARBINARY: NullString, } diff --git a/common/const.go b/common/const.go index 9fa6b05..67e9f4e 100644 --- a/common/const.go +++ b/common/const.go @@ -64,6 +64,7 @@ const ( TSDB_DATA_TYPE_UINT_Str = "INT UNSIGNED" TSDB_DATA_TYPE_UBIGINT_Str = "BIGINT UNSIGNED" TSDB_DATA_TYPE_JSON_Str = "JSON" + TSDB_DATA_TYPE_VARBINARY_Str = "VARBINARY" ) var TypeNameMap = map[int]string{ @@ -83,6 +84,7 @@ var TypeNameMap = map[int]string{ TSDB_DATA_TYPE_UINT: TSDB_DATA_TYPE_UINT_Str, TSDB_DATA_TYPE_UBIGINT: TSDB_DATA_TYPE_UBIGINT_Str, TSDB_DATA_TYPE_JSON: TSDB_DATA_TYPE_JSON_Str, + TSDB_DATA_TYPE_VARBINARY: TSDB_DATA_TYPE_VARBINARY_Str, } var NameTypeMap = map[string]int{ @@ -102,6 +104,7 @@ var NameTypeMap = map[string]int{ TSDB_DATA_TYPE_UINT_Str: TSDB_DATA_TYPE_UINT, TSDB_DATA_TYPE_UBIGINT_Str: TSDB_DATA_TYPE_UBIGINT, TSDB_DATA_TYPE_JSON_Str: TSDB_DATA_TYPE_JSON, + TSDB_DATA_TYPE_VARBINARY_Str: TSDB_DATA_TYPE_VARBINARY, } const ( diff --git a/common/param/column.go b/common/param/column.go index 8e5b68f..a11839c 100644 --- a/common/param/column.go +++ b/common/param/column.go @@ -149,6 +149,18 @@ func (c *ColumnType) AddBinary(strMaxLen int) *ColumnType { return c } +func (c *ColumnType) AddVarBinary(strMaxLen int) *ColumnType { + if c.column >= c.size { + return c + } + c.value[c.column] = &types.ColumnType{ + Type: types.TaosVarBinaryType, + MaxLen: strMaxLen, + } + c.column += 1 + return c +} + func (c *ColumnType) AddNchar(strMaxLen int) *ColumnType { if c.column >= c.size { return c diff --git a/common/param/param.go b/common/param/param.go index a9ec02d..680d5f1 100644 --- a/common/param/param.go +++ b/common/param/param.go @@ -111,6 +111,13 @@ func (p *Param) SetBinary(offset int, value []byte) { p.value[offset] = taosTypes.TaosBinary(value) } +func (p *Param) SetVarBinary(offset int, value []byte) { + if offset >= p.size { + return + } + p.value[offset] = taosTypes.TaosVarBinary(value) +} + func (p *Param) SetNchar(offset int, value string) { if offset >= p.size { return @@ -252,6 +259,15 @@ func (p *Param) AddBinary(value []byte) *Param { return p } +func (p *Param) AddVarBinary(value []byte) *Param { + if p.offset >= p.size { + return p + } + p.value[p.offset] = taosTypes.TaosVarBinary(value) + p.offset += 1 + return p +} + func (p *Param) AddNchar(value string) *Param { if p.offset >= p.size { return p diff --git a/common/parser/block.go b/common/parser/block.go index f573804..29522a1 100644 --- a/common/parser/block.go +++ b/common/parser/block.go @@ -6,6 +6,7 @@ import ( "unsafe" "github.com/taosdata/driver-go/v3/common" + "github.com/taosdata/driver-go/v3/common/pointer" ) const ( @@ -33,27 +34,27 @@ const ( ) func RawBlockGetVersion(rawBlock unsafe.Pointer) int32 { - return *((*int32)(unsafe.Pointer(uintptr(rawBlock) + RawBlockVersionOffset))) + return *((*int32)(pointer.AddUintptr(rawBlock, RawBlockVersionOffset))) } func RawBlockGetLength(rawBlock unsafe.Pointer) int32 { - return *((*int32)(unsafe.Pointer(uintptr(rawBlock) + RawBlockLengthOffset))) + return *((*int32)(pointer.AddUintptr(rawBlock, RawBlockLengthOffset))) } func RawBlockGetNumOfRows(rawBlock unsafe.Pointer) int32 { - return *((*int32)(unsafe.Pointer(uintptr(rawBlock) + NumOfRowsOffset))) + return *((*int32)(pointer.AddUintptr(rawBlock, NumOfRowsOffset))) } func RawBlockGetNumOfCols(rawBlock unsafe.Pointer) int32 { - return *((*int32)(unsafe.Pointer(uintptr(rawBlock) + NumOfColsOffset))) + return *((*int32)(pointer.AddUintptr(rawBlock, NumOfColsOffset))) } func RawBlockGetHasColumnSegment(rawBlock unsafe.Pointer) int32 { - return *((*int32)(unsafe.Pointer(uintptr(rawBlock) + HasColumnSegmentOffset))) + return *((*int32)(pointer.AddUintptr(rawBlock, HasColumnSegmentOffset))) } func RawBlockGetGroupID(rawBlock unsafe.Pointer) uint64 { - return *((*uint64)(unsafe.Pointer(uintptr(rawBlock) + GroupIDOffset))) + return *((*uint64)(pointer.AddUintptr(rawBlock, GroupIDOffset))) } type RawBlockColInfo struct { @@ -63,9 +64,9 @@ type RawBlockColInfo struct { func RawBlockGetColInfo(rawBlock unsafe.Pointer, infos []RawBlockColInfo) { for i := 0; i < len(infos); i++ { - offset := uintptr(rawBlock) + ColInfoOffset + ColInfoSize*uintptr(i) - infos[i].ColType = *((*int8)(unsafe.Pointer(offset))) - infos[i].Bytes = *((*int32)(unsafe.Pointer(offset + Int8Size))) + offset := ColInfoOffset + ColInfoSize*uintptr(i) + infos[i].ColType = *((*int8)(pointer.AddUintptr(rawBlock, offset))) + infos[i].Bytes = *((*int32)(pointer.AddUintptr(rawBlock, offset+Int8Size))) } } @@ -80,7 +81,7 @@ func RawBlockGetColDataOffset(colCount int) uintptr { type FormatTimeFunc func(ts int64, precision int) driver.Value func IsVarDataType(colType uint8) bool { - return colType == common.TSDB_DATA_TYPE_BINARY || colType == common.TSDB_DATA_TYPE_NCHAR || colType == common.TSDB_DATA_TYPE_JSON + return colType == common.TSDB_DATA_TYPE_BINARY || colType == common.TSDB_DATA_TYPE_NCHAR || colType == common.TSDB_DATA_TYPE_JSON || colType == common.TSDB_DATA_TYPE_VARBINARY } func BitmapLen(n int) int { @@ -99,9 +100,9 @@ func BMIsNull(c byte, n int) bool { return c&(1<<(7-BitPos(n))) == (1 << (7 - BitPos(n))) } -type rawConvertFunc func(pStart uintptr, row int, arg ...interface{}) driver.Value +type rawConvertFunc func(pStart unsafe.Pointer, row int, arg ...interface{}) driver.Value -type rawConvertVarDataFunc func(pHeader, pStart uintptr, row int) driver.Value +type rawConvertVarDataFunc func(pHeader, pStart unsafe.Pointer, row int) driver.Value var rawConvertFuncMap = map[uint8]rawConvertFunc{ uint8(common.TSDB_DATA_TYPE_BOOL): rawConvertBool, @@ -119,81 +120,86 @@ var rawConvertFuncMap = map[uint8]rawConvertFunc{ } var rawConvertVarDataMap = map[uint8]rawConvertVarDataFunc{ - uint8(common.TSDB_DATA_TYPE_BINARY): rawConvertBinary, - uint8(common.TSDB_DATA_TYPE_NCHAR): rawConvertNchar, - uint8(common.TSDB_DATA_TYPE_JSON): rawConvertJson, + uint8(common.TSDB_DATA_TYPE_BINARY): rawConvertBinary, + uint8(common.TSDB_DATA_TYPE_NCHAR): rawConvertNchar, + uint8(common.TSDB_DATA_TYPE_JSON): rawConvertJson, + uint8(common.TSDB_DATA_TYPE_VARBINARY): rawConvertVarBinary, } -func ItemIsNull(pHeader uintptr, row int) bool { +func ItemIsNull(pHeader unsafe.Pointer, row int) bool { offset := CharOffset(row) - c := *((*byte)(unsafe.Pointer(pHeader + uintptr(offset)))) + c := *((*byte)(pointer.AddUintptr(pHeader, uintptr(offset)))) return BMIsNull(c, row) } -func rawConvertBool(pStart uintptr, row int, _ ...interface{}) driver.Value { - if (*((*byte)(unsafe.Pointer(pStart + uintptr(row)*1)))) != 0 { +func rawConvertBool(pStart unsafe.Pointer, row int, _ ...interface{}) driver.Value { + if (*((*byte)(pointer.AddUintptr(pStart, uintptr(row)*1)))) != 0 { return true } else { return false } } -func rawConvertTinyint(pStart uintptr, row int, _ ...interface{}) driver.Value { - return *((*int8)(unsafe.Pointer(pStart + uintptr(row)*Int8Size))) +func rawConvertTinyint(pStart unsafe.Pointer, row int, _ ...interface{}) driver.Value { + return *((*int8)(pointer.AddUintptr(pStart, uintptr(row)*Int8Size))) } -func rawConvertSmallint(pStart uintptr, row int, _ ...interface{}) driver.Value { - return *((*int16)(unsafe.Pointer(pStart + uintptr(row)*Int16Size))) +func rawConvertSmallint(pStart unsafe.Pointer, row int, _ ...interface{}) driver.Value { + return *((*int16)(pointer.AddUintptr(pStart, uintptr(row)*Int16Size))) } -func rawConvertInt(pStart uintptr, row int, _ ...interface{}) driver.Value { - return *((*int32)(unsafe.Pointer(pStart + uintptr(row)*Int32Size))) +func rawConvertInt(pStart unsafe.Pointer, row int, _ ...interface{}) driver.Value { + return *((*int32)(pointer.AddUintptr(pStart, uintptr(row)*Int32Size))) } -func rawConvertBigint(pStart uintptr, row int, _ ...interface{}) driver.Value { - return *((*int64)(unsafe.Pointer(pStart + uintptr(row)*Int64Size))) +func rawConvertBigint(pStart unsafe.Pointer, row int, _ ...interface{}) driver.Value { + return *((*int64)(pointer.AddUintptr(pStart, uintptr(row)*Int64Size))) } -func rawConvertUTinyint(pStart uintptr, row int, _ ...interface{}) driver.Value { - return *((*uint8)(unsafe.Pointer(pStart + uintptr(row)*UInt8Size))) +func rawConvertUTinyint(pStart unsafe.Pointer, row int, _ ...interface{}) driver.Value { + return *((*uint8)(pointer.AddUintptr(pStart, uintptr(row)*UInt8Size))) } -func rawConvertUSmallint(pStart uintptr, row int, _ ...interface{}) driver.Value { - return *((*uint16)(unsafe.Pointer(pStart + uintptr(row)*UInt16Size))) +func rawConvertUSmallint(pStart unsafe.Pointer, row int, _ ...interface{}) driver.Value { + return *((*uint16)(pointer.AddUintptr(pStart, uintptr(row)*UInt16Size))) } -func rawConvertUInt(pStart uintptr, row int, _ ...interface{}) driver.Value { - return *((*uint32)(unsafe.Pointer(pStart + uintptr(row)*UInt32Size))) +func rawConvertUInt(pStart unsafe.Pointer, row int, _ ...interface{}) driver.Value { + return *((*uint32)(pointer.AddUintptr(pStart, uintptr(row)*UInt32Size))) } -func rawConvertUBigint(pStart uintptr, row int, _ ...interface{}) driver.Value { - return *((*uint64)(unsafe.Pointer(pStart + uintptr(row)*UInt64Size))) +func rawConvertUBigint(pStart unsafe.Pointer, row int, _ ...interface{}) driver.Value { + return *((*uint64)(pointer.AddUintptr(pStart, uintptr(row)*UInt64Size))) } -func rawConvertFloat(pStart uintptr, row int, _ ...interface{}) driver.Value { - return math.Float32frombits(*((*uint32)(unsafe.Pointer(pStart + uintptr(row)*Float32Size)))) +func rawConvertFloat(pStart unsafe.Pointer, row int, _ ...interface{}) driver.Value { + return math.Float32frombits(*((*uint32)(pointer.AddUintptr(pStart, uintptr(row)*Float32Size)))) } -func rawConvertDouble(pStart uintptr, row int, _ ...interface{}) driver.Value { - return math.Float64frombits(*((*uint64)(unsafe.Pointer(pStart + uintptr(row)*Float64Size)))) +func rawConvertDouble(pStart unsafe.Pointer, row int, _ ...interface{}) driver.Value { + return math.Float64frombits(*((*uint64)(pointer.AddUintptr(pStart, uintptr(row)*Float64Size)))) } -func rawConvertTime(pStart uintptr, row int, arg ...interface{}) driver.Value { +func rawConvertTime(pStart unsafe.Pointer, row int, arg ...interface{}) driver.Value { if len(arg) == 1 { - return common.TimestampConvertToTime(*((*int64)(unsafe.Pointer(pStart + uintptr(row)*Int64Size))), arg[0].(int)) + return common.TimestampConvertToTime(*((*int64)(pointer.AddUintptr(pStart, uintptr(row)*Int64Size))), arg[0].(int)) } else if len(arg) == 2 { - return arg[1].(FormatTimeFunc)(*((*int64)(unsafe.Pointer(pStart + uintptr(row)*Int64Size))), arg[0].(int)) + return arg[1].(FormatTimeFunc)(*((*int64)(pointer.AddUintptr(pStart, uintptr(row)*Int64Size))), arg[0].(int)) } else { panic("convertTime error") } } -func rawConvertBinary(pHeader, pStart uintptr, row int) driver.Value { - offset := *((*int32)(unsafe.Pointer(pHeader + uintptr(row*4)))) +func rawConvertVarBinary(pHeader, pStart unsafe.Pointer, row int) driver.Value { + return rawConvertBinary(pHeader, pStart, row) +} + +func rawConvertBinary(pHeader, pStart unsafe.Pointer, row int) driver.Value { + offset := *((*int32)(pointer.AddUintptr(pHeader, uintptr(row*4)))) if offset == -1 { return nil } - currentRow := unsafe.Pointer(pStart + uintptr(offset)) + currentRow := pointer.AddUintptr(pStart, uintptr(offset)) clen := *((*int16)(currentRow)) currentRow = unsafe.Pointer(uintptr(currentRow) + 2) @@ -205,12 +211,12 @@ func rawConvertBinary(pHeader, pStart uintptr, row int) driver.Value { return string(binaryVal[:]) } -func rawConvertNchar(pHeader, pStart uintptr, row int) driver.Value { - offset := *((*int32)(unsafe.Pointer(pHeader + uintptr(row*4)))) +func rawConvertNchar(pHeader, pStart unsafe.Pointer, row int) driver.Value { + offset := *((*int32)(pointer.AddUintptr(pHeader, uintptr(row*4)))) if offset == -1 { return nil } - currentRow := unsafe.Pointer(pStart + uintptr(offset)) + currentRow := pointer.AddUintptr(pStart, uintptr(offset)) clen := *((*int16)(currentRow)) / 4 currentRow = unsafe.Pointer(uintptr(currentRow) + 2) @@ -222,19 +228,19 @@ func rawConvertNchar(pHeader, pStart uintptr, row int) driver.Value { return string(binaryVal) } -func rawConvertJson(pHeader, pStart uintptr, row int) driver.Value { - offset := *((*int32)(unsafe.Pointer(pHeader + uintptr(row*4)))) +func rawConvertJson(pHeader, pStart unsafe.Pointer, row int) driver.Value { + offset := *((*int32)(pointer.AddUintptr(pHeader, uintptr(row*4)))) if offset == -1 { return nil } - currentRow := unsafe.Pointer(pStart + uintptr(offset)) + currentRow := pointer.AddUintptr(pStart, uintptr(offset)) clen := *((*int16)(currentRow)) - currentRow = unsafe.Pointer(uintptr(currentRow) + 2) + currentRow = pointer.AddUintptr(currentRow, 2) binaryVal := make([]byte, clen) for index := int16(0); index < clen; index++ { - binaryVal[index] = *((*byte)(unsafe.Pointer(uintptr(currentRow) + uintptr(index)))) + binaryVal[index] = *((*byte)(pointer.AddUintptr(currentRow, uintptr(index)))) } return binaryVal[:] } @@ -245,13 +251,13 @@ func ReadBlock(block unsafe.Pointer, blockSize int, colTypes []uint8, precision colCount := len(colTypes) nullBitMapOffset := uintptr(BitmapLen(blockSize)) lengthOffset := RawBlockGetColumnLengthOffset(colCount) - pHeader := uintptr(block) + RawBlockGetColDataOffset(colCount) - var pStart uintptr + pHeader := pointer.AddUintptr(block, RawBlockGetColDataOffset(colCount)) + var pStart unsafe.Pointer for column := 0; column < colCount; column++ { - colLength := *((*int32)(unsafe.Pointer(uintptr(block) + lengthOffset + uintptr(column)*Int32Size))) + colLength := *((*int32)(pointer.AddUintptr(block, lengthOffset+uintptr(column)*Int32Size))) if IsVarDataType(colTypes[column]) { convertF := rawConvertVarDataMap[colTypes[column]] - pStart = pHeader + Int32Size*uintptr(blockSize) + pStart = pointer.AddUintptr(pHeader, Int32Size*uintptr(blockSize)) for row := 0; row < blockSize; row++ { if column == 0 { r[row] = make([]driver.Value, colCount) @@ -260,7 +266,7 @@ func ReadBlock(block unsafe.Pointer, blockSize int, colTypes []uint8, precision } } else { convertF := rawConvertFuncMap[colTypes[column]] - pStart = pHeader + nullBitMapOffset + pStart = pointer.AddUintptr(pHeader, nullBitMapOffset) for row := 0; row < blockSize; row++ { if column == 0 { r[row] = make([]driver.Value, colCount) @@ -272,7 +278,7 @@ func ReadBlock(block unsafe.Pointer, blockSize int, colTypes []uint8, precision } } } - pHeader = pStart + uintptr(colLength) + pHeader = pointer.AddUintptr(pStart, uintptr(colLength)) } return r } @@ -281,24 +287,24 @@ func ReadRow(dest []driver.Value, block unsafe.Pointer, blockSize int, row int, colCount := len(colTypes) nullBitMapOffset := uintptr(BitmapLen(blockSize)) lengthOffset := RawBlockGetColumnLengthOffset(colCount) - pHeader := uintptr(block) + RawBlockGetColDataOffset(colCount) - var pStart uintptr + pHeader := pointer.AddUintptr(block, RawBlockGetColDataOffset(colCount)) + var pStart unsafe.Pointer for column := 0; column < colCount; column++ { - colLength := *((*int32)(unsafe.Pointer(uintptr(block) + lengthOffset + uintptr(column)*Int32Size))) + colLength := *((*int32)(pointer.AddUintptr(block, lengthOffset+uintptr(column)*Int32Size))) if IsVarDataType(colTypes[column]) { convertF := rawConvertVarDataMap[colTypes[column]] - pStart = pHeader + Int32Size*uintptr(blockSize) + pStart = pointer.AddUintptr(pHeader, Int32Size*uintptr(blockSize)) dest[column] = convertF(pHeader, pStart, row) } else { convertF := rawConvertFuncMap[colTypes[column]] - pStart = pHeader + nullBitMapOffset + pStart = pointer.AddUintptr(pHeader, nullBitMapOffset) if ItemIsNull(pHeader, row) { dest[column] = nil } else { dest[column] = convertF(pStart, row, precision) } } - pHeader = pStart + uintptr(colLength) + pHeader = pointer.AddUintptr(pStart, uintptr(colLength)) } } @@ -307,13 +313,13 @@ func ReadBlockWithTimeFormat(block unsafe.Pointer, blockSize int, colTypes []uin colCount := len(colTypes) nullBitMapOffset := uintptr(BitmapLen(blockSize)) lengthOffset := RawBlockGetColumnLengthOffset(colCount) - pHeader := uintptr(block) + RawBlockGetColDataOffset(colCount) - var pStart uintptr + pHeader := pointer.AddUintptr(block, RawBlockGetColDataOffset(colCount)) + var pStart unsafe.Pointer for column := 0; column < colCount; column++ { - colLength := *((*int32)(unsafe.Pointer(uintptr(block) + lengthOffset + uintptr(column)*Int32Size))) + colLength := *((*int32)(pointer.AddUintptr(block, lengthOffset+uintptr(column)*Int32Size))) if IsVarDataType(colTypes[column]) { convertF := rawConvertVarDataMap[colTypes[column]] - pStart = pHeader + uintptr(4*blockSize) + pStart = pointer.AddUintptr(pHeader, uintptr(4*blockSize)) for row := 0; row < blockSize; row++ { if column == 0 { r[row] = make([]driver.Value, colCount) @@ -322,7 +328,7 @@ func ReadBlockWithTimeFormat(block unsafe.Pointer, blockSize int, colTypes []uin } } else { convertF := rawConvertFuncMap[colTypes[column]] - pStart = pHeader + nullBitMapOffset + pStart = pointer.AddUintptr(pHeader, nullBitMapOffset) for row := 0; row < blockSize; row++ { if column == 0 { r[row] = make([]driver.Value, colCount) @@ -334,52 +340,19 @@ func ReadBlockWithTimeFormat(block unsafe.Pointer, blockSize int, colTypes []uin } } } - pHeader = pStart + uintptr(colLength) + pHeader = pointer.AddUintptr(pStart, uintptr(colLength)) } return r } -func ItemRawBlock(colType uint8, pHeader, pStart uintptr, row int, precision int, timeFormat FormatTimeFunc) driver.Value { +func ItemRawBlock(colType uint8, pHeader, pStart unsafe.Pointer, row int, precision int, timeFormat FormatTimeFunc) driver.Value { if IsVarDataType(colType) { - switch colType { - case uint8(common.TSDB_DATA_TYPE_BINARY): - return rawConvertBinary(pHeader, pStart, row) - case uint8(common.TSDB_DATA_TYPE_NCHAR): - return rawConvertNchar(pHeader, pStart, row) - case uint8(common.TSDB_DATA_TYPE_JSON): - return rawConvertJson(pHeader, pStart, row) - } + return rawConvertVarDataMap[colType](pHeader, pStart, row) } else { if ItemIsNull(pHeader, row) { return nil } else { - switch colType { - case uint8(common.TSDB_DATA_TYPE_BOOL): - return rawConvertBool(pStart, row) - case uint8(common.TSDB_DATA_TYPE_TINYINT): - return rawConvertTinyint(pStart, row) - case uint8(common.TSDB_DATA_TYPE_SMALLINT): - return rawConvertSmallint(pStart, row) - case uint8(common.TSDB_DATA_TYPE_INT): - return rawConvertInt(pStart, row) - case uint8(common.TSDB_DATA_TYPE_BIGINT): - return rawConvertBigint(pStart, row) - case uint8(common.TSDB_DATA_TYPE_UTINYINT): - return rawConvertUTinyint(pStart, row) - case uint8(common.TSDB_DATA_TYPE_USMALLINT): - return rawConvertUSmallint(pStart, row) - case uint8(common.TSDB_DATA_TYPE_UINT): - return rawConvertUInt(pStart, row) - case uint8(common.TSDB_DATA_TYPE_UBIGINT): - return rawConvertUBigint(pStart, row) - case uint8(common.TSDB_DATA_TYPE_FLOAT): - return rawConvertFloat(pStart, row) - case uint8(common.TSDB_DATA_TYPE_DOUBLE): - return rawConvertDouble(pStart, row) - case uint8(common.TSDB_DATA_TYPE_TIMESTAMP): - return rawConvertTime(pStart, row, precision, timeFormat) - } + return rawConvertFuncMap[colType](pStart, row, precision, timeFormat) } } - return nil } diff --git a/common/parser/block_test.go b/common/parser/block_test.go index bd327de..8dc3517 100644 --- a/common/parser/block_test.go +++ b/common/parser/block_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/taosdata/driver-go/v3/common" + "github.com/taosdata/driver-go/v3/common/pointer" "github.com/taosdata/driver-go/v3/errors" "github.com/taosdata/driver-go/v3/wrapper" ) @@ -102,8 +103,8 @@ func TestReadBlock(t *testing.T) { return } precision := wrapper.TaosResultPrecision(res) - pHeaderList := make([]uintptr, fileCount) - pStartList := make([]uintptr, fileCount) + pHeaderList := make([]unsafe.Pointer, fileCount) + pStartList := make([]unsafe.Pointer, fileCount) var data [][]driver.Value for { blockSize, errCode, block := wrapper.TaosFetchRawBlock(res) @@ -119,20 +120,20 @@ func TestReadBlock(t *testing.T) { } nullBitMapOffset := uintptr(BitmapLen(blockSize)) lengthOffset := RawBlockGetColumnLengthOffset(fileCount) - tmpPHeader := uintptr(block) + RawBlockGetColDataOffset(fileCount) - var tmpPStart uintptr + tmpPHeader := pointer.AddUintptr(block, RawBlockGetColDataOffset(fileCount)) + var tmpPStart unsafe.Pointer for column := 0; column < fileCount; column++ { - colLength := *((*int32)(unsafe.Pointer(uintptr(block) + lengthOffset + uintptr(column)*Int32Size))) + colLength := *((*int32)(pointer.AddUintptr(block, lengthOffset+uintptr(column)*Int32Size))) if IsVarDataType(rh.ColTypes[column]) { pHeaderList[column] = tmpPHeader - tmpPStart = tmpPHeader + Int32Size*uintptr(blockSize) + tmpPStart = pointer.AddUintptr(tmpPHeader, Int32Size*uintptr(blockSize)) pStartList[column] = tmpPStart } else { pHeaderList[column] = tmpPHeader - tmpPStart = tmpPHeader + nullBitMapOffset + tmpPStart = pointer.AddUintptr(tmpPHeader, nullBitMapOffset) pStartList[column] = tmpPStart } - tmpPHeader = tmpPStart + uintptr(colLength) + tmpPHeader = pointer.AddUintptr(tmpPStart, uintptr(colLength)) } for row := 0; row < blockSize; row++ { rowV := make([]driver.Value, fileCount) @@ -244,8 +245,8 @@ func TestBlockTag(t *testing.T) { return } precision := wrapper.TaosResultPrecision(res) - pHeaderList := make([]uintptr, fileCount) - pStartList := make([]uintptr, fileCount) + pHeaderList := make([]unsafe.Pointer, fileCount) + pStartList := make([]unsafe.Pointer, fileCount) var data [][]driver.Value for { blockSize, errCode, block := wrapper.TaosFetchRawBlock(res) @@ -261,20 +262,20 @@ func TestBlockTag(t *testing.T) { } nullBitMapOffset := uintptr(BitmapLen(blockSize)) lengthOffset := RawBlockGetColumnLengthOffset(fileCount) - tmpPHeader := uintptr(block) + RawBlockGetColDataOffset(fileCount) // length i32, group u64 - var tmpPStart uintptr + tmpPHeader := pointer.AddUintptr(block, RawBlockGetColDataOffset(fileCount)) // length i32, group u64 + var tmpPStart unsafe.Pointer for column := 0; column < fileCount; column++ { - colLength := *((*int32)(unsafe.Pointer(uintptr(block) + lengthOffset + uintptr(column)*Int32Size))) + colLength := *((*int32)(pointer.AddUintptr(block, lengthOffset+uintptr(column)*Int32Size))) if IsVarDataType(rh.ColTypes[column]) { pHeaderList[column] = tmpPHeader - tmpPStart = tmpPHeader + Int32Size*uintptr(blockSize) + tmpPStart = pointer.AddUintptr(tmpPHeader, Int32Size*uintptr(blockSize)) pStartList[column] = tmpPStart } else { pHeaderList[column] = tmpPHeader - tmpPStart = tmpPHeader + nullBitMapOffset + tmpPStart = pointer.AddUintptr(tmpPHeader, nullBitMapOffset) pStartList[column] = tmpPStart } - tmpPHeader = tmpPStart + uintptr(colLength) + tmpPHeader = pointer.AddUintptr(tmpPStart, uintptr(colLength)) } for row := 0; row < blockSize; row++ { rowV := make([]driver.Value, fileCount) diff --git a/common/pointer/unsafe.go b/common/pointer/unsafe.go new file mode 100644 index 0000000..7e5e36f --- /dev/null +++ b/common/pointer/unsafe.go @@ -0,0 +1,7 @@ +package pointer + +import "unsafe" + +func AddUintptr(ptr unsafe.Pointer, len uintptr) unsafe.Pointer { + return unsafe.Pointer(uintptr(ptr) + len) +} diff --git a/common/reqid.go b/common/reqid.go index f5d711f..02f1c72 100644 --- a/common/reqid.go +++ b/common/reqid.go @@ -8,6 +8,7 @@ import ( "unsafe" "github.com/google/uuid" + "github.com/taosdata/driver-go/v3/common/pointer" ) var tUUIDHashId int64 @@ -36,10 +37,9 @@ func murmurHash32(data []byte, seed uint32) uint32 { h1 := seed nBlocks := len(data) / 4 - p := uintptr(unsafe.Pointer(&data[0])) - p1 := p + uintptr(4*nBlocks) - for ; p < p1; p += 4 { - k1 := *(*uint32)(unsafe.Pointer(p)) + p := unsafe.Pointer(&data[0]) + for i := 0; i < nBlocks; i++ { + k1 := *(*uint32)(pointer.AddUintptr(p, uintptr(i*4))) k1 *= c1 k1 = bits.RotateLeft32(k1, 15) diff --git a/common/serializer/block.go b/common/serializer/block.go index 4a23b53..830708e 100644 --- a/common/serializer/block.go +++ b/common/serializer/block.go @@ -366,6 +366,34 @@ func SerializeRawBlock(params []*param.Param, colType *param.ColumnType) ([]byte } lengthData = appendUint32(lengthData, uint32(length)) data = append(data, dataTmp...) + case taosTypes.TaosVarBinaryType: + colInfoData = append(colInfoData, common.TSDB_DATA_TYPE_VARBINARY) + colInfoData = appendUint32(colInfoData, uint32(0)) + length := 0 + dataTmp := make([]byte, Int32Size*rows) + rowData := params[colIndex].GetValues() + for rowIndex := 0; rowIndex < rows; rowIndex++ { + offset := Int32Size * rowIndex + if rowData[rowIndex] == nil { + for i := 0; i < Int32Size; i++ { + // -1 + dataTmp[offset+i] = byte(255) + } + } else { + v, is := rowData[rowIndex].(taosTypes.TaosVarBinary) + if !is { + return nil, DataTypeWrong + } + for i := 0; i < Int32Size; i++ { + dataTmp[offset+i] = byte(length >> (8 * i)) + } + dataTmp = appendUint16(dataTmp, uint16(len(v))) + dataTmp = append(dataTmp, v...) + length += len(v) + Int16Size + } + } + lengthData = appendUint32(lengthData, uint32(length)) + data = append(data, dataTmp...) case taosTypes.TaosNcharType: colInfoData = append(colInfoData, common.TSDB_DATA_TYPE_NCHAR) colInfoData = appendUint32(colInfoData, uint32(0)) diff --git a/common/stmt/field.go b/common/stmt/field.go index ee7e441..c8a46d4 100644 --- a/common/stmt/field.go +++ b/common/stmt/field.go @@ -41,6 +41,8 @@ func (s *StmtField) GetType() (*types.ColumnType, error) { return &types.ColumnType{Type: types.TaosDoubleType}, nil case common.TSDB_DATA_TYPE_BINARY: return &types.ColumnType{Type: types.TaosBinaryType}, nil + case common.TSDB_DATA_TYPE_VARBINARY: + return &types.ColumnType{Type: types.TaosVarBinaryType}, nil case common.TSDB_DATA_TYPE_NCHAR: return &types.ColumnType{Type: types.TaosNcharType}, nil case common.TSDB_DATA_TYPE_TIMESTAMP: diff --git a/taosSql/driver_test.go b/taosSql/driver_test.go index d12cd18..51a76be 100644 --- a/taosSql/driver_test.go +++ b/taosSql/driver_test.go @@ -309,43 +309,43 @@ func TestJson(t *testing.T) { } defer db.Close() defer func() { - _, err = db.Exec("drop database if exists test_json") + _, err = db.Exec("drop database if exists test_json_native") if err != nil { t.Error(err) return } }() - _, err = db.Exec("create database if not exists test_json") + _, err = db.Exec("create database if not exists test_json_native") if err != nil { t.Error(err) return } - _, err = db.Exec("drop table if exists test_json.tjson") + _, err = db.Exec("drop table if exists test_json_native.tjson") if err != nil { t.Error(err) return } - _, err = db.Exec("create stable if not exists test_json.tjson(ts timestamp,v int )tags(t json)") + _, err = db.Exec("create stable if not exists test_json_native.tjson(ts timestamp,v int )tags(t json)") if err != nil { t.Error(err) return } - _, err = db.Exec(`insert into test_json.tj_1 using test_json.tjson tags('{"a":1,"b":"b"}')values (now,1)`) + _, err = db.Exec(`insert into test_json_native.tj_1 using test_json_native.tjson tags('{"a":1,"b":"b"}')values (now,1)`) if err != nil { t.Error(err) return } - _, err = db.Exec(`insert into test_json.tj_2 using test_json.tjson tags('{"a":1,"c":"c"}')values (now,1)`) + _, err = db.Exec(`insert into test_json_native.tj_2 using test_json_native.tjson tags('{"a":1,"c":"c"}')values (now,1)`) if err != nil { t.Error(err) return } - _, err = db.Exec(`insert into test_json.tj_3 using test_json.tjson tags('null')values (now,1)`) + _, err = db.Exec(`insert into test_json_native.tj_3 using test_json_native.tjson tags('null')values (now,1)`) if err != nil { t.Error(err) return } - rows, err := db.Query("select * from test_json.tjson") + rows, err := db.Query("select * from test_json_native.tjson") if err != nil { t.Error(err) return @@ -385,38 +385,38 @@ func TestJsonSearch(t *testing.T) { } defer db.Close() defer func() { - _, err = db.Exec("drop database if exists test_json") + _, err = db.Exec("drop database if exists test_json_native_search") if err != nil { t.Error(err) return } }() - _, err = db.Exec("create database if not exists test_json") + _, err = db.Exec("create database if not exists test_json_native_search") if err != nil { t.Error(err) return } - _, err = db.Exec("drop table if exists test_json.tjson_search") + _, err = db.Exec("drop table if exists test_json_native_search.tjson_search") if err != nil { t.Error(err) return } - _, err = db.Exec("create stable if not exists test_json.tjson_search(ts timestamp,v int )tags(t json)") + _, err = db.Exec("create stable if not exists test_json_native_search.tjson_search(ts timestamp,v int )tags(t json)") if err != nil { t.Error(err) return } - _, err = db.Exec(`insert into test_json.tjs_1 using test_json.tjson_search tags('{"a":1,"b":"b"}')values (now,1)`) + _, err = db.Exec(`insert into test_json_native_search.tjs_1 using test_json_native_search.tjson_search tags('{"a":1,"b":"b"}')values (now,1)`) if err != nil { t.Error(err) return } - _, err = db.Exec(`insert into test_json.tjs_2 using test_json.tjson_search tags('{"a":1,"c":"c"}')values (now,2)`) + _, err = db.Exec(`insert into test_json_native_search.tjs_2 using test_json_native_search.tjson_search tags('{"a":1,"c":"c"}')values (now,2)`) if err != nil { t.Error(err) return } - rows, err := db.Query("select * from test_json.tjson_search where t contains 'a' and t->'b'='b' and v = 1") + rows, err := db.Query("select * from test_json_native_search.tjson_search where t contains 'a' and t->'b'='b' and v = 1") if err != nil { t.Error(err) return @@ -451,38 +451,38 @@ func TestJsonMatch(t *testing.T) { } defer db.Close() defer func() { - _, err = db.Exec("drop database if exists test_json") + _, err = db.Exec("drop database if exists test_json_native_match") if err != nil { t.Error(err) return } }() - _, err = db.Exec("create database if not exists test_json") + _, err = db.Exec("create database if not exists test_json_native_match") if err != nil { t.Error(err) return } - _, err = db.Exec("drop table if exists test_json.tjson_match") + _, err = db.Exec("drop table if exists test_json_native_match.tjson_match") if err != nil { t.Error(err) return } - _, err = db.Exec("create stable if not exists test_json.tjson_match(ts timestamp,v int )tags(t json)") + _, err = db.Exec("create stable if not exists test_json_native_match.tjson_match(ts timestamp,v int )tags(t json)") if err != nil { t.Error(err) return } - _, err = db.Exec(`insert into test_json.tjm_1 using test_json.tjson_match tags('{"a":1,"b":"b"}')values (now,1)`) + _, err = db.Exec(`insert into test_json_native_match.tjm_1 using test_json_native_match.tjson_match tags('{"a":1,"b":"b"}')values (now,1)`) if err != nil { t.Error(err) return } - _, err = db.Exec(`insert into test_json.tjm_2 using test_json.tjson_match tags('{"a":1,"c":"c"}')values (now,2)`) + _, err = db.Exec(`insert into test_json_native_match.tjm_2 using test_json_native_match.tjson_match tags('{"a":1,"c":"c"}')values (now,2)`) if err != nil { t.Error(err) return } - rows, err := db.Query("select * from test_json.tjson_match where t contains 'a' and t->'b' match '.*b.*|.*e.*' and v = 1") + rows, err := db.Query("select * from test_json_native_match.tjson_match where t contains 'a' and t->'b' match '.*b.*|.*e.*' and v = 1") if err != nil { t.Error(err) return diff --git a/taosSql/statement.go b/taosSql/statement.go index 399c9a6..c2219ad 100644 --- a/taosSql/statement.go +++ b/taosSql/statement.go @@ -307,6 +307,15 @@ func (stmt *Stmt) CheckNamedValue(v *driver.NamedValue) error { default: return fmt.Errorf("CheckNamedValue:%v can not convert to binary", v) } + case common.TSDB_DATA_TYPE_VARBINARY: + switch v.Value.(type) { + case string: + v.Value = types.TaosVarBinary(v.Value.(string)) + case []byte: + v.Value = types.TaosVarBinary(v.Value.([]byte)) + default: + return fmt.Errorf("CheckNamedValue:%v can not convert to varbinary", v) + } case common.TSDB_DATA_TYPE_TIMESTAMP: t, is := v.Value.(time.Time) if is { diff --git a/taosWS/rows.go b/taosWS/rows.go index b75f4e2..b462f4e 100644 --- a/taosWS/rows.go +++ b/taosWS/rows.go @@ -10,6 +10,7 @@ import ( "github.com/taosdata/driver-go/v3/common" "github.com/taosdata/driver-go/v3/common/parser" + "github.com/taosdata/driver-go/v3/common/pointer" taosErrors "github.com/taosdata/driver-go/v3/errors" ) @@ -151,7 +152,7 @@ func (rs *rows) fetchBlock() error { return err } rs.block = respBytes - rs.blockPtr = unsafe.Pointer(*(*uintptr)(unsafe.Pointer(&rs.block)) + uintptr(16)) + rs.blockPtr = pointer.AddUintptr(unsafe.Pointer(&rs.block[0]), 16) rs.blockOffset = 0 return nil } diff --git a/types/taostype.go b/types/taostype.go index 50a5da8..e6c7947 100644 --- a/types/taostype.go +++ b/types/taostype.go @@ -18,6 +18,7 @@ type ( TaosFloat float32 TaosDouble float64 TaosBinary []byte + TaosVarBinary []byte TaosNchar string TaosTimestamp struct { T time.Time @@ -39,6 +40,7 @@ var ( TaosFloatType = reflect.TypeOf(TaosFloat(0)) TaosDoubleType = reflect.TypeOf(TaosDouble(0)) TaosBinaryType = reflect.TypeOf(TaosBinary(nil)) + TaosVarBinaryType = reflect.TypeOf(TaosVarBinary(nil)) TaosNcharType = reflect.TypeOf(TaosNchar("")) TaosTimestampType = reflect.TypeOf(TaosTimestamp{}) TaosJsonType = reflect.TypeOf(TaosJson("")) diff --git a/wrapper/row.go b/wrapper/row.go index 6ee6508..042d4b3 100644 --- a/wrapper/row.go +++ b/wrapper/row.go @@ -9,6 +9,7 @@ import ( "unsafe" "github.com/taosdata/driver-go/v3/common" + "github.com/taosdata/driver-go/v3/common/pointer" ) const ( @@ -18,7 +19,8 @@ const ( type FormatTimeFunc func(ts int64, precision int) driver.Value func FetchRow(row unsafe.Pointer, offset int, colType uint8, length int, arg ...interface{}) driver.Value { - p := unsafe.Pointer(*(*uintptr)(unsafe.Pointer(uintptr(row) + uintptr(offset)*PointerSize))) + base := *(**C.void)(pointer.AddUintptr(row, uintptr(offset)*PointerSize)) + p := unsafe.Pointer(base) if p == nil { return nil } @@ -49,10 +51,10 @@ func FetchRow(row unsafe.Pointer, offset int, colType uint8, length int, arg ... return *((*float32)(p)) case C.TSDB_DATA_TYPE_DOUBLE: return *((*float64)(p)) - case C.TSDB_DATA_TYPE_BINARY, C.TSDB_DATA_TYPE_NCHAR: + case C.TSDB_DATA_TYPE_BINARY, C.TSDB_DATA_TYPE_NCHAR, C.TSDB_DATA_TYPE_VARBINARY: data := make([]byte, length) for i := 0; i < length; i++ { - data[i] = *((*byte)(unsafe.Pointer(uintptr(p) + uintptr(i)))) + data[i] = *((*byte)(pointer.AddUintptr(p, uintptr(i)))) } return string(data) case C.TSDB_DATA_TYPE_TIMESTAMP: @@ -66,7 +68,7 @@ func FetchRow(row unsafe.Pointer, offset int, colType uint8, length int, arg ... case C.TSDB_DATA_TYPE_JSON: data := make([]byte, length) for i := 0; i < length; i++ { - data[i] = *((*byte)(unsafe.Pointer(uintptr(p) + uintptr(i)))) + data[i] = *((*byte)(pointer.AddUintptr(p, uintptr(i)))) } return data default: diff --git a/wrapper/stmt.go b/wrapper/stmt.go index fe3239b..416c073 100644 --- a/wrapper/stmt.go +++ b/wrapper/stmt.go @@ -234,6 +234,17 @@ func generateTaosBindList(params []driver.Value) ([]C.TAOS_MULTI_BIND, []unsafe. *(bind.length) = C.int32_t(clen) needFreePointer = append(needFreePointer, p) bind.buffer_length = C.uintptr_t(clen) + case taosTypes.TaosVarBinary: + bind.buffer_type = C.TSDB_DATA_TYPE_BINARY + cbuf := C.CString(string(value)) + needFreePointer = append(needFreePointer, unsafe.Pointer(cbuf)) + bind.buffer = unsafe.Pointer(cbuf) + clen := int32(len(value)) + p := C.malloc(C.size_t(unsafe.Sizeof(clen))) + bind.length = (*C.int32_t)(p) + *(bind.length) = C.int32_t(clen) + needFreePointer = append(needFreePointer, p) + bind.buffer_length = C.uintptr_t(clen) case taosTypes.TaosNchar: bind.buffer_type = C.TSDB_DATA_TYPE_NCHAR p := unsafe.Pointer(C.CString(string(value))) @@ -518,6 +529,24 @@ func TaosStmtBindParamBatch(stmt unsafe.Pointer, multiBind [][]driver.Value, bin *(*C.int32_t)(l) = C.int32_t(len(value)) } } + case taosTypes.TaosVarBinaryType: + p = unsafe.Pointer(C.malloc(C.size_t(C.uint(columnType.MaxLen * rowLen)))) + bind.buffer_type = C.TSDB_DATA_TYPE_VARBINARY + bind.buffer_length = C.uintptr_t(columnType.MaxLen) + for i, rowData := range columnData { + currentNull := unsafe.Pointer(uintptr(nullList) + uintptr(i)) + if rowData == nil { + *(*C.char)(currentNull) = C.char(1) + } else { + *(*C.char)(currentNull) = C.char(0) + value := rowData.(taosTypes.TaosVarBinary) + for j := 0; j < len(value); j++ { + *(*C.char)(unsafe.Pointer(uintptr(p) + uintptr(columnType.MaxLen*i+j))) = (C.char)(value[j]) + } + l := unsafe.Pointer(uintptr(lengthList) + uintptr(4*i)) + *(*C.int32_t)(l) = C.int32_t(len(value)) + } + } case taosTypes.TaosNcharType: p = unsafe.Pointer(C.malloc(C.size_t(C.uint(columnType.MaxLen * rowLen)))) bind.buffer_type = C.TSDB_DATA_TYPE_NCHAR diff --git a/wrapper/stmt_test.go b/wrapper/stmt_test.go index b82402c..4d120e6 100644 --- a/wrapper/stmt_test.go +++ b/wrapper/stmt_test.go @@ -138,6 +138,16 @@ func TestStmt(t *testing.T) { }}, expectValue: "yes", }, //3 + { + tbType: "ts timestamp, v varbinary(8)", + pos: "?, ?", + params: [][]driver.Value{{taosTypes.TaosTimestamp{T: now, Precision: common.PrecisionMilliSecond}}, {taosTypes.TaosVarBinary("yes")}}, + bindType: []*taosTypes.ColumnType{{Type: taosTypes.TaosTimestampType}, { + Type: taosTypes.TaosVarBinaryType, + MaxLen: 3, + }}, + expectValue: "yes", + }, //3 { tbType: "ts timestamp, v nchar(8)", pos: "?, ?", @@ -336,6 +346,12 @@ func TestStmtExec(t *testing.T) { params: []driver.Value{taosTypes.TaosTimestamp{T: now, Precision: common.PrecisionMilliSecond}, taosTypes.TaosBinary("yes")}, expectValue: "yes", }, //3 + { + tbType: "ts timestamp, v varbinary(8)", + pos: "?, ?", + params: []driver.Value{taosTypes.TaosTimestamp{T: now, Precision: common.PrecisionMilliSecond}, taosTypes.TaosVarBinary("yes")}, + expectValue: "yes", + }, //3 { tbType: "ts timestamp, v nchar(8)", pos: "?, ?", diff --git a/wrapper/taosc.go b/wrapper/taosc.go index 803ed16..6cd3405 100644 --- a/wrapper/taosc.go +++ b/wrapper/taosc.go @@ -33,6 +33,7 @@ import ( "strings" "unsafe" + "github.com/taosdata/driver-go/v3/common/pointer" "github.com/taosdata/driver-go/v3/errors" "github.com/taosdata/driver-go/v3/wrapper/cgo" ) @@ -251,7 +252,7 @@ func TaosGetTablesVgID(conn unsafe.Pointer, db string, tables []string) (vgIDs [ } vgIDs = make([]int, numTables) for i := 0; i < numTables; i++ { - vgIDs[i] = int(*(*C.int)(unsafe.Pointer(uintptr(p) + uintptr(C.sizeof_int*C.int(i))))) + vgIDs[i] = int(*(*C.int)(pointer.AddUintptr(p, uintptr(C.sizeof_int*C.int(i))))) } return } diff --git a/wrapper/tmq.go b/wrapper/tmq.go index 1b969ad..72522df 100644 --- a/wrapper/tmq.go +++ b/wrapper/tmq.go @@ -14,6 +14,7 @@ import ( "sync" "unsafe" + "github.com/taosdata/driver-go/v3/common/pointer" "github.com/taosdata/driver-go/v3/common/tmq" "github.com/taosdata/driver-go/v3/errors" "github.com/taosdata/driver-go/v3/wrapper/cgo" @@ -107,10 +108,10 @@ func TMQListGetSize(list unsafe.Pointer) int32 { // TMQListToCArray char **tmq_list_to_c_array(const tmq_list_t *); func TMQListToCArray(list unsafe.Pointer, size int) []string { - head := uintptr(unsafe.Pointer(C.tmq_list_to_c_array((*C.tmq_list_t)(list)))) + head := unsafe.Pointer(C.tmq_list_to_c_array((*C.tmq_list_t)(list))) result := make([]string, size) for i := 0; i < size; i++ { - result[i] = C.GoString(*(**C.char)(unsafe.Pointer(head + PointerSize*uintptr(i)))) + result[i] = C.GoString(*(**C.char)(pointer.AddUintptr(head, PointerSize*uintptr(i)))) } return result } diff --git a/ws/tmq/consumer.go b/ws/tmq/consumer.go index dac2fdf..df1889b 100644 --- a/ws/tmq/consumer.go +++ b/ws/tmq/consumer.go @@ -588,7 +588,8 @@ func (c *Consumer) fetch(messageID uint64) ([]*tmq.Data, error) { return nil, err } block := respBytes[24:] - data := parser.ReadBlock(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(&block))), resp.Rows, resp.FieldsTypes, resp.Precision) + p := unsafe.Pointer(&block[0]) + data := parser.ReadBlock(p, resp.Rows, resp.FieldsTypes, resp.Precision) tmqData = append(tmqData, &tmq.Data{ TableName: resp.TableName, Data: data, From b7a0ca6811fe77fd8cac154713fbdbba129418b0 Mon Sep 17 00:00:00 2001 From: t_max <1172915550@qq.com> Date: Tue, 19 Sep 2023 15:49:29 +0800 Subject: [PATCH 2/3] fix: stmt bind varbinary --- wrapper/stmt.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrapper/stmt.go b/wrapper/stmt.go index 416c073..c6c482f 100644 --- a/wrapper/stmt.go +++ b/wrapper/stmt.go @@ -235,7 +235,7 @@ func generateTaosBindList(params []driver.Value) ([]C.TAOS_MULTI_BIND, []unsafe. needFreePointer = append(needFreePointer, p) bind.buffer_length = C.uintptr_t(clen) case taosTypes.TaosVarBinary: - bind.buffer_type = C.TSDB_DATA_TYPE_BINARY + bind.buffer_type = C.TSDB_DATA_TYPE_VARBINARY cbuf := C.CString(string(value)) needFreePointer = append(needFreePointer, unsafe.Pointer(cbuf)) bind.buffer = unsafe.Pointer(cbuf) From a8fdd64dc42d63b0af78cf568947602d20acbedf Mon Sep 17 00:00:00 2001 From: t_max <1172915550@qq.com> Date: Tue, 19 Sep 2023 16:25:21 +0800 Subject: [PATCH 3/3] fix: varbinary column type default byte array --- common/column.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/column.go b/common/column.go index 068cd50..0408b77 100644 --- a/common/column.go +++ b/common/column.go @@ -20,6 +20,7 @@ var ( NullTime = reflect.TypeOf(types.NullTime{}) NullBool = reflect.TypeOf(types.NullBool{}) NullString = reflect.TypeOf(types.NullString{}) + Bytes = reflect.TypeOf([]byte{}) NullJson = reflect.TypeOf(types.NullJson{}) UnknownType = reflect.TypeOf(new(interface{})).Elem() ) @@ -40,5 +41,5 @@ var ColumnTypeMap = map[int]reflect.Type{ TSDB_DATA_TYPE_NCHAR: NullString, TSDB_DATA_TYPE_TIMESTAMP: NullTime, TSDB_DATA_TYPE_JSON: NullJson, - TSDB_DATA_TYPE_VARBINARY: NullString, + TSDB_DATA_TYPE_VARBINARY: Bytes, }