From 055bb7c903b63714af3146503f22a3fcf1f51302 Mon Sep 17 00:00:00 2001 From: t_max <1172915550@qq.com> Date: Tue, 17 Dec 2024 18:18:46 +0800 Subject: [PATCH 1/4] feat: rename taos_stmt2_get_fields --- .github/workflows/go.yml | 76 ++- af/stmt2.go | 30 +- common/stmt/stmt2.go | 26 +- common/stmt/stmt2_test.go | 291 ++++++---- wrapper/notify_test.go | 20 +- wrapper/stmt2.go | 303 +++------- wrapper/stmt2_test.go | 1079 ++++++++++++++++++++++++++++++----- wrapper/stmt2binary.go | 272 +++++++++ wrapper/stmt_test.go | 2 +- wrapper/whitelistcb_test.go | 1 + 10 files changed, 1606 insertions(+), 494 deletions(-) create mode 100644 wrapper/stmt2binary.go diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 3009faf..70674ff 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -204,4 +204,78 @@ jobs: with: files: ./coverage.txt env: - CODECOV_TOKEN: ${{ secrets.CODECOV_ORG_TOKEN }} \ No newline at end of file + CODECOV_TOKEN: ${{ secrets.CODECOV_ORG_TOKEN }} + + test_asan: + runs-on: ubuntu-latest + needs: build + strategy: + matrix: + go: [ 'stable' ] + name: Go-ASAN-${{ matrix.go }} + steps: + - name: get cache server by pr + if: github.event_name == 'pull_request' + id: get-cache-server-pr + uses: actions/cache@v4 + with: + path: server.tar.gz + key: ${{ runner.os }}-build-${{ github.base_ref }}-${{ needs.build.outputs.commit_id }} + restore-keys: | + ${{ runner.os }}-build-${{ github.base_ref }}- + + - name: get cache server by push + if: github.event_name == 'push' + id: get-cache-server-push + uses: actions/cache@v4 + with: + path: server.tar.gz + key: ${{ runner.os }}-build-${{ github.ref_name }}-${{ needs.build.outputs.commit_id }} + restore-keys: | + ${{ runner.os }}-build-${{ github.ref_name }}- + + - name: cache server manually + if: github.event_name == 'workflow_dispatch' + id: get-cache-server-manually + uses: actions/cache@v4 + with: + path: server.tar.gz + key: ${{ runner.os }}-build-${{ inputs.tbBranch }}-${{ needs.build.outputs.commit_id }} + restore-keys: | + ${{ runner.os }}-build-${{ inputs.tbBranch }}- + + + - name: install + run: | + tar -zxvf server.tar.gz + cd release && sudo sh install.sh + + - name: checkout + uses: actions/checkout@v4 + + - name: copy taos cfg + run: | + sudo mkdir -p /etc/taos + sudo cp ./.github/workflows/taos.cfg /etc/taos/taos.cfg + sudo cp ./.github/workflows/taosadapter.toml /etc/taos/taosadapter.toml + + - name: shell + run: | + cat >start.sh<= 0; i-- { - if freePointer[i] != nil { - C.free(freePointer[i]) - } - } - }() - dataP := unsafe.Pointer(C.CBytes(data)) - freePointer = append(freePointer, dataP) - count := binary.LittleEndian.Uint32(data[stmt.CountPosition:]) - tagCount := binary.LittleEndian.Uint32(data[stmt.TagCountPosition:]) - colCount := binary.LittleEndian.Uint32(data[stmt.ColCountPosition:]) - tableNamesOffset := binary.LittleEndian.Uint32(data[stmt.TableNamesOffsetPosition:]) - tagsOffset := binary.LittleEndian.Uint32(data[stmt.TagsOffsetPosition:]) - colsOffset := binary.LittleEndian.Uint32(data[stmt.ColsOffsetPosition:]) - // check table names - if tableNamesOffset > 0 { - tableNameEnd := tableNamesOffset + count*2 - // table name lengths out of range - if tableNameEnd > totalLength { - return fmt.Errorf("table name lengths out of range, total length: %d, tableNamesLengthEnd: %d", totalLength, tableNameEnd) - } - for i := uint32(0); i < count; i++ { - tableNameLength := binary.LittleEndian.Uint16(data[tableNamesOffset+i*2:]) - tableNameEnd += uint32(tableNameLength) - } - if tableNameEnd > totalLength { - return fmt.Errorf("table names out of range, total length: %d, tableNameTotalLength: %d", totalLength, tableNameEnd) - } - } - // check tags - if tagsOffset > 0 { - if tagCount == 0 { - return fmt.Errorf("tag count is zero, but tags offset is not zero") - } - tagsEnd := tagsOffset + count*4 - if tagsEnd > totalLength { - return fmt.Errorf("tags lengths out of range, total length: %d, tagsLengthEnd: %d", totalLength, tagsEnd) - } - for i := uint32(0); i < count; i++ { - tagLength := binary.LittleEndian.Uint32(data[tagsOffset+i*4:]) - if tagLength == 0 { - return fmt.Errorf("tag length is zero, data index: %d", i) - } - tagsEnd += tagLength - } - if tagsEnd > totalLength { - return fmt.Errorf("tags out of range, total length: %d, tagsTotalLength: %d", totalLength, tagsEnd) - } +// TaosStmt2GetFields int taos_stmt2_get_fields(TAOS_STMT2 *stmt, int *count, TAOS_FIELD_ALL **fields); +func TaosStmt2GetFields(stmt2 unsafe.Pointer) (code, count int, fields unsafe.Pointer) { + code = int(C.taos_stmt2_get_fields(stmt2, (*C.int)(unsafe.Pointer(&count)), (**C.TAOS_FIELD_ALL)(unsafe.Pointer(&fields)))) + return +} + +//typedef struct TAOS_FIELD_ALL { +//char name[65]; +//int8_t type; +//uint8_t precision; +//uint8_t scale; +//int32_t bytes; +//TAOS_FIELD_T field_type; +//} TAOS_FIELD_ALL; + +func Stmt2ParseAllFields(num int, fields unsafe.Pointer) []*stmt.Stmt2AllField { + if num <= 0 { + return nil } - // check cols - if colsOffset > 0 { - if colCount == 0 { - return fmt.Errorf("col count is zero, but cols offset is not zero") - } - colsEnd := colsOffset + count*4 - if colsEnd > totalLength { - return fmt.Errorf("cols lengths out of range, total length: %d, colsLengthEnd: %d", totalLength, colsEnd) - } - for i := uint32(0); i < count; i++ { - colLength := binary.LittleEndian.Uint32(data[colsOffset+i*4:]) - if colLength == 0 { - return fmt.Errorf("col length is zero, data: %d", i) - } - colsEnd += colLength - } - if colsEnd > totalLength { - return fmt.Errorf("cols out of range, total length: %d, colsTotalLength: %d", totalLength, colsEnd) - } + if fields == nil { + return nil } - cBindv := C.TAOS_STMT2_BINDV{} - cBindv.count = C.int(count) - if tableNamesOffset > 0 { - tableNameLengthP := pointer.AddUintptr(dataP, uintptr(tableNamesOffset)) - cTableNames := C.malloc(C.size_t(uintptr(count) * PointerSize)) - freePointer = append(freePointer, cTableNames) - tableDataP := pointer.AddUintptr(tableNameLengthP, uintptr(count)*2) - var tableNamesArrayP unsafe.Pointer - for i := uint32(0); i < count; i++ { - tableNamesArrayP = pointer.AddUintptr(cTableNames, uintptr(i)*PointerSize) - *(**C.char)(tableNamesArrayP) = (*C.char)(tableDataP) - tableNameLength := *(*uint16)(pointer.AddUintptr(tableNameLengthP, uintptr(i*2))) - if tableNameLength == 0 { - return fmt.Errorf("table name length is zero, data index: %d", i) + result := make([]*stmt.Stmt2AllField, num) + buf := bytes.NewBufferString("") + for i := 0; i < num; i++ { + r := &stmt.Stmt2AllField{} + field := *(*C.TAOS_FIELD_ALL)(unsafe.Pointer(uintptr(fields) + uintptr(C.sizeof_struct_TAOS_FIELD_ALL*C.int(i)))) + for _, c := range field.name { + if c == 0 { + break } - tableDataP = pointer.AddUintptr(tableDataP, uintptr(tableNameLength)) + buf.WriteByte(byte(c)) } - cBindv.tbnames = (**C.char)(cTableNames) - } else { - cBindv.tbnames = nil - } - if tagsOffset > 0 { - tags, needFreePointer, err := generateStmt2Binds(count, tagCount, dataP, tagsOffset) - freePointer = append(freePointer, needFreePointer...) - if err != nil { - return fmt.Errorf("generate tags error: %s", err.Error()) - } - cBindv.tags = (**C.TAOS_STMT2_BIND)(tags) - } else { - cBindv.tags = nil - } - if colsOffset > 0 { - cols, needFreePointer, err := generateStmt2Binds(count, colCount, dataP, colsOffset) - freePointer = append(freePointer, needFreePointer...) - if err != nil { - return fmt.Errorf("generate cols error: %s", err.Error()) - } - cBindv.bind_cols = (**C.TAOS_STMT2_BIND)(cols) - } else { - cBindv.bind_cols = nil - } - code := int(C.taos_stmt2_bind_param(stmt2, &cBindv, C.int32_t(colIdx))) - if code != 0 { - errStr := TaosStmt2Error(stmt2) - return taosError.NewError(code, errStr) + r.Name = buf.String() + buf.Reset() + r.FieldType = int8(field._type) + r.Precision = uint8(field.precision) + r.Scale = uint8(field.scale) + r.Bytes = int32(field.bytes) + r.BindType = int8(field.field_type) + result[i] = r } - return nil + return result } -func generateStmt2Binds(count uint32, fieldCount uint32, dataP unsafe.Pointer, fieldsOffset uint32) (unsafe.Pointer, []unsafe.Pointer, error) { - var freePointer []unsafe.Pointer - bindsCList := unsafe.Pointer(C.malloc(C.size_t(uintptr(count) * PointerSize))) - freePointer = append(freePointer, bindsCList) - // dataLength [count]uint32 - // length have checked in TaosStmt2BindBinary - baseLengthPointer := pointer.AddUintptr(dataP, uintptr(fieldsOffset)) - // dataBuffer - dataPointer := pointer.AddUintptr(baseLengthPointer, uintptr(count)*4) - var bindsPointer unsafe.Pointer - for tableIndex := uint32(0); tableIndex < count; tableIndex++ { - bindsPointer = pointer.AddUintptr(bindsCList, uintptr(tableIndex)*PointerSize) - binds := unsafe.Pointer(C.malloc(C.size_t(C.size_t(fieldCount) * C.size_t(unsafe.Sizeof(C.TAOS_STMT2_BIND{}))))) - freePointer = append(freePointer, binds) - var bindDataP unsafe.Pointer - var bindDataTotalLength uint32 - var num int32 - var haveLength byte - var bufferLength uint32 - for fieldIndex := uint32(0); fieldIndex < fieldCount; fieldIndex++ { - // field data - bindDataP = dataPointer - // totalLength - bindDataTotalLength = *(*uint32)(bindDataP) - bindDataP = pointer.AddUintptr(bindDataP, common.UInt32Size) - bind := (*C.TAOS_STMT2_BIND)(unsafe.Pointer(uintptr(binds) + uintptr(fieldIndex)*unsafe.Sizeof(C.TAOS_STMT2_BIND{}))) - // buffer_type - bind.buffer_type = *(*C.int)(bindDataP) - bindDataP = pointer.AddUintptr(bindDataP, common.Int32Size) - // num - num = *(*int32)(bindDataP) - bind.num = C.int(num) - bindDataP = pointer.AddUintptr(bindDataP, common.Int32Size) - // is_null - bind.is_null = (*C.char)(bindDataP) - bindDataP = pointer.AddUintptr(bindDataP, uintptr(num)) - // haveLength - haveLength = *(*byte)(bindDataP) - bindDataP = pointer.AddUintptr(bindDataP, common.Int8Size) - if haveLength == 0 { - bind.length = nil - } else { - // length [num]int32 - bind.length = (*C.int32_t)(bindDataP) - bindDataP = pointer.AddUintptr(bindDataP, common.Int32Size*uintptr(num)) - } - // bufferLength - bufferLength = *(*uint32)(bindDataP) - bindDataP = pointer.AddUintptr(bindDataP, common.UInt32Size) - // buffer - if bufferLength == 0 { - bind.buffer = nil - } else { - bind.buffer = bindDataP - } - bindDataP = pointer.AddUintptr(bindDataP, uintptr(bufferLength)) - // check bind data length - bindDataLen := uintptr(bindDataP) - uintptr(dataPointer) - if bindDataLen != uintptr(bindDataTotalLength) { - return nil, freePointer, fmt.Errorf("bind data length not match, expect %d, but get %d, tableIndex:%d", bindDataTotalLength, bindDataLen, tableIndex) - } - dataPointer = bindDataP - } - *(**C.TAOS_STMT2_BIND)(bindsPointer) = (*C.TAOS_STMT2_BIND)(binds) +// stringHeader instead of reflect.StringHeader +type stringHeader struct { + data unsafe.Pointer + len int +} + +// sliceHeader instead of reflect.SliceHeader +type sliceHeader struct { + data unsafe.Pointer + len int + cap int +} + +// ToUnsafeBytes converts s to a byte slice without memory allocations. +// +// The returned byte slice is valid only until s is reachable and unmodified. +func ToUnsafeBytes(s string) (b []byte) { + if len(s) == 0 { + return []byte{} } - return bindsCList, freePointer, nil + hdr := (*sliceHeader)(unsafe.Pointer(&b)) + hdr.data = (*stringHeader)(unsafe.Pointer(&s)).data + hdr.cap = len(s) + hdr.len = len(s) + return b } diff --git a/wrapper/stmt2_test.go b/wrapper/stmt2_test.go index 1500977..bf47c2b 100644 --- a/wrapper/stmt2_test.go +++ b/wrapper/stmt2_test.go @@ -1193,17 +1193,18 @@ func TestStmt2BindData(t *testing.T) { return } assert.True(t, isInsert) - code, count, cfields := TaosStmt2GetFields(insertStmt, stmt.TAOS_FIELD_COL) + code, count, cfields := TaosStmt2GetFields(insertStmt) if code != 0 { errStr := TaosStmt2Error(insertStmt) err = taosError.NewError(code, errStr) t.Error(err) return } + defer TaosStmt2FreeFields(insertStmt, cfields) assert.Equal(t, 2, count) - fields := StmtParseFields(count, cfields) - err = TaosStmt2BindParam(insertStmt, true, tc.params, fields, nil, -1) + fields := Stmt2ParseAllFields(count, cfields) + err = TaosStmt2BindParam(insertStmt, true, tc.params, fields, -1) if err != nil { t.Error(err) return @@ -2367,7 +2368,7 @@ func TestStmt2BindBinary(t *testing.T) { return } assert.True(t, isInsert) - code, count, cfields := TaosStmt2GetFields(insertStmt, stmt.TAOS_FIELD_COL) + code, count, cfields := TaosStmt2GetFields(insertStmt) if code != 0 { errStr := TaosStmt2Error(insertStmt) err = taosError.NewError(code, errStr) @@ -2376,8 +2377,8 @@ func TestStmt2BindBinary(t *testing.T) { } defer TaosStmt2FreeFields(insertStmt, cfields) assert.Equal(t, 2, count) - fields := StmtParseFields(count, cfields) - bs, err := stmt.MarshalStmt2Binary(tc.params, true, fields, nil) + fields := Stmt2ParseAllFields(count, cfields) + bs, err := stmt.MarshalStmt2Binary(tc.params, true, fields) if err != nil { t.Error("marshal binary error:", err) return @@ -2496,22 +2497,12 @@ func TestStmt2AllType(t *testing.T) { params := []*stmt.TaosStmt2BindData{{ TableName: "ctb1", }} - err = TaosStmt2BindParam(insertStmt, true, params, nil, nil, -1) + err = TaosStmt2BindParam(insertStmt, true, params, nil, -1) if err != nil { t.Error(err) return } - code, count, cTablefields := TaosStmt2GetFields(insertStmt, stmt.TAOS_FIELD_TBNAME) - if code != 0 { - errStr := TaosStmt2Error(insertStmt) - err = taosError.NewError(code, errStr) - t.Error(err) - return - } - assert.Equal(t, 1, count) - assert.Equal(t, unsafe.Pointer(nil), cTablefields) - isInsert, code := TaosStmt2IsInsert(insertStmt) if code != 0 { errStr := TaosStmt2Error(insertStmt) @@ -2520,28 +2511,17 @@ func TestStmt2AllType(t *testing.T) { return } assert.True(t, isInsert) - code, count, cColFields := TaosStmt2GetFields(insertStmt, stmt.TAOS_FIELD_COL) + code, count, cFields := TaosStmt2GetFields(insertStmt) if code != 0 { errStr := TaosStmt2Error(insertStmt) err = taosError.NewError(code, errStr) t.Error(err) return } - defer TaosStmt2FreeFields(insertStmt, cColFields) - assert.Equal(t, 16, count) - colFields := StmtParseFields(count, cColFields) - t.Log(colFields) - code, count, cTagfields := TaosStmt2GetFields(insertStmt, stmt.TAOS_FIELD_TAG) - if code != 0 { - errStr := TaosStmt2Error(insertStmt) - err = taosError.NewError(code, errStr) - t.Error(err) - return - } - defer TaosStmt2FreeFields(insertStmt, cTagfields) - assert.Equal(t, 16, count) - tagFields := StmtParseFields(count, cTagfields) - t.Log(tagFields) + defer TaosStmt2FreeFields(insertStmt, cFields) + assert.Equal(t, 32, count) + fields := Stmt2ParseAllFields(count, cFields) + t.Log(fields) now := time.Now() //colTypes := []int8{ // common.TSDB_DATA_TYPE_TIMESTAMP, @@ -2681,7 +2661,7 @@ func TestStmt2AllType(t *testing.T) { }, }} - err = TaosStmt2BindParam(insertStmt, true, params2, colFields, tagFields, -1) + err = TaosStmt2BindParam(insertStmt, true, params2, fields, -1) if err != nil { t.Error(err) return @@ -2787,7 +2767,7 @@ func TestStmt2AllTypeBytes(t *testing.T) { params := []*stmt.TaosStmt2BindData{{ TableName: "ctb1", }} - bs, err := stmt.MarshalStmt2Binary(params, true, nil, nil) + bs, err := stmt.MarshalStmt2Binary(params, true, nil) if err != nil { t.Error(err) return @@ -2798,16 +2778,6 @@ func TestStmt2AllTypeBytes(t *testing.T) { return } - code, count, cTablefields := TaosStmt2GetFields(insertStmt, stmt.TAOS_FIELD_TBNAME) - if code != 0 { - errStr := TaosStmt2Error(insertStmt) - err = taosError.NewError(code, errStr) - t.Error(err) - return - } - assert.Equal(t, 1, count) - assert.Equal(t, unsafe.Pointer(nil), cTablefields) - isInsert, code := TaosStmt2IsInsert(insertStmt) if code != 0 { errStr := TaosStmt2Error(insertStmt) @@ -2816,28 +2786,18 @@ func TestStmt2AllTypeBytes(t *testing.T) { return } assert.True(t, isInsert) - code, count, cColFields := TaosStmt2GetFields(insertStmt, stmt.TAOS_FIELD_COL) - if code != 0 { - errStr := TaosStmt2Error(insertStmt) - err = taosError.NewError(code, errStr) - t.Error(err) - return - } - defer TaosStmt2FreeFields(insertStmt, cColFields) - assert.Equal(t, 16, count) - colFields := StmtParseFields(count, cColFields) - t.Log(colFields) - code, count, cTagfields := TaosStmt2GetFields(insertStmt, stmt.TAOS_FIELD_TAG) + + code, count, cFields := TaosStmt2GetFields(insertStmt) if code != 0 { errStr := TaosStmt2Error(insertStmt) err = taosError.NewError(code, errStr) t.Error(err) return } - defer TaosStmt2FreeFields(insertStmt, cTagfields) - assert.Equal(t, 16, count) - tagFields := StmtParseFields(count, cTagfields) - t.Log(tagFields) + defer TaosStmt2FreeFields(insertStmt, cFields) + assert.Equal(t, 32, count) + fields := Stmt2ParseAllFields(count, cFields) + t.Log(fields) now := time.Now() //colTypes := []int8{ // common.TSDB_DATA_TYPE_TIMESTAMP, @@ -2976,7 +2936,7 @@ func TestStmt2AllTypeBytes(t *testing.T) { }, }, }} - bs, err = stmt.MarshalStmt2Binary(params2, true, colFields, tagFields) + bs, err = stmt.MarshalStmt2Binary(params2, true, fields) if err != nil { t.Error(err) return @@ -3060,13 +3020,15 @@ func TestStmt2Query(t *testing.T) { } assert.True(t, isInsert) now := time.Now().Round(time.Millisecond) - colTypes := []*stmt.StmtField{ + colTypes := []*stmt.Stmt2AllField{ { FieldType: common.TSDB_DATA_TYPE_TIMESTAMP, Precision: common.PrecisionMilliSecond, + BindType: stmt.TAOS_FIELD_COL, }, { FieldType: common.TSDB_DATA_TYPE_INT, + BindType: stmt.TAOS_FIELD_COL, }, } params := []*stmt.TaosStmt2BindData{ @@ -3097,7 +3059,7 @@ func TestStmt2Query(t *testing.T) { }, }, } - err = TaosStmt2BindParam(stmt2, true, params, colTypes, nil, -1) + err = TaosStmt2BindParam(stmt2, true, params, colTypes, -1) if err != nil { t.Error(err) return @@ -3145,7 +3107,7 @@ func TestStmt2Query(t *testing.T) { }, } - err = TaosStmt2BindParam(stmt2, false, params, nil, nil, -1) + err = TaosStmt2BindParam(stmt2, false, params, nil, -1) if err != nil { t.Error(err) return @@ -3254,13 +3216,15 @@ func TestStmt2QueryBytes(t *testing.T) { } assert.True(t, isInsert) now := time.Now().Round(time.Millisecond) - colTypes := []*stmt.StmtField{ + colTypes := []*stmt.Stmt2AllField{ { FieldType: common.TSDB_DATA_TYPE_TIMESTAMP, Precision: common.PrecisionMilliSecond, + BindType: stmt.TAOS_FIELD_COL, }, { FieldType: common.TSDB_DATA_TYPE_INT, + BindType: stmt.TAOS_FIELD_COL, }, } params := []*stmt.TaosStmt2BindData{ @@ -3291,7 +3255,7 @@ func TestStmt2QueryBytes(t *testing.T) { }, }, } - bs, err := stmt.MarshalStmt2Binary(params, true, colTypes, nil) + bs, err := stmt.MarshalStmt2Binary(params, true, colTypes) if err != nil { t.Error(err) return @@ -3343,7 +3307,7 @@ func TestStmt2QueryBytes(t *testing.T) { }, }, } - bs, err = stmt.MarshalStmt2Binary(params, false, nil, nil) + bs, err = stmt.MarshalStmt2Binary(params, false, nil) if err != nil { t.Error(err) return @@ -3458,23 +3422,23 @@ func TestStmt2QueryAllType(t *testing.T) { handler := cgo.NewHandle(caller) stmt2 := TaosStmt2Init(conn, 0xcc123, false, false, handler) prepareInsertSql := "insert into t values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)" - colTypes := []*stmt.StmtField{ - {FieldType: common.TSDB_DATA_TYPE_TIMESTAMP, Precision: common.PrecisionMilliSecond}, - {FieldType: common.TSDB_DATA_TYPE_BOOL}, - {FieldType: common.TSDB_DATA_TYPE_TINYINT}, - {FieldType: common.TSDB_DATA_TYPE_SMALLINT}, - {FieldType: common.TSDB_DATA_TYPE_INT}, - {FieldType: common.TSDB_DATA_TYPE_BIGINT}, - {FieldType: common.TSDB_DATA_TYPE_UTINYINT}, - {FieldType: common.TSDB_DATA_TYPE_USMALLINT}, - {FieldType: common.TSDB_DATA_TYPE_UINT}, - {FieldType: common.TSDB_DATA_TYPE_UBIGINT}, - {FieldType: common.TSDB_DATA_TYPE_FLOAT}, - {FieldType: common.TSDB_DATA_TYPE_DOUBLE}, - {FieldType: common.TSDB_DATA_TYPE_BINARY}, - {FieldType: common.TSDB_DATA_TYPE_VARBINARY}, - {FieldType: common.TSDB_DATA_TYPE_GEOMETRY}, - {FieldType: common.TSDB_DATA_TYPE_NCHAR}, + colTypes := []*stmt.Stmt2AllField{ + {FieldType: common.TSDB_DATA_TYPE_TIMESTAMP, Precision: common.PrecisionMilliSecond, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_BOOL, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_TINYINT, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_SMALLINT, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_INT, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_BIGINT, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_UTINYINT, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_USMALLINT, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_UINT, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_UBIGINT, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_FLOAT, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_DOUBLE, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_BINARY, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_VARBINARY, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_GEOMETRY, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_NCHAR, BindType: stmt.TAOS_FIELD_COL}, } now := time.Now() @@ -3578,7 +3542,7 @@ func TestStmt2QueryAllType(t *testing.T) { return } assert.True(t, isInsert) - err = TaosStmt2BindParam(stmt2, true, params2, colTypes, nil, -1) + err = TaosStmt2BindParam(stmt2, true, params2, colTypes, -1) if err != nil { t.Error(err) return @@ -3636,7 +3600,7 @@ func TestStmt2QueryAllType(t *testing.T) { }, }, } - err = TaosStmt2BindParam(stmt2, false, params, nil, nil, -1) + err = TaosStmt2BindParam(stmt2, false, params, nil, -1) if err != nil { t.Error(err) return @@ -3732,23 +3696,23 @@ func TestStmt2QueryAllTypeBytes(t *testing.T) { handler := cgo.NewHandle(caller) stmt2 := TaosStmt2Init(conn, 0xcc123, false, false, handler) prepareInsertSql := "insert into t values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)" - colTypes := []*stmt.StmtField{ - {FieldType: common.TSDB_DATA_TYPE_TIMESTAMP, Precision: common.PrecisionMilliSecond}, - {FieldType: common.TSDB_DATA_TYPE_BOOL}, - {FieldType: common.TSDB_DATA_TYPE_TINYINT}, - {FieldType: common.TSDB_DATA_TYPE_SMALLINT}, - {FieldType: common.TSDB_DATA_TYPE_INT}, - {FieldType: common.TSDB_DATA_TYPE_BIGINT}, - {FieldType: common.TSDB_DATA_TYPE_UTINYINT}, - {FieldType: common.TSDB_DATA_TYPE_USMALLINT}, - {FieldType: common.TSDB_DATA_TYPE_UINT}, - {FieldType: common.TSDB_DATA_TYPE_UBIGINT}, - {FieldType: common.TSDB_DATA_TYPE_FLOAT}, - {FieldType: common.TSDB_DATA_TYPE_DOUBLE}, - {FieldType: common.TSDB_DATA_TYPE_BINARY}, - {FieldType: common.TSDB_DATA_TYPE_VARBINARY}, - {FieldType: common.TSDB_DATA_TYPE_GEOMETRY}, - {FieldType: common.TSDB_DATA_TYPE_NCHAR}, + colTypes := []*stmt.Stmt2AllField{ + {FieldType: common.TSDB_DATA_TYPE_TIMESTAMP, Precision: common.PrecisionMilliSecond, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_BOOL, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_TINYINT, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_SMALLINT, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_INT, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_BIGINT, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_UTINYINT, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_USMALLINT, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_UINT, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_UBIGINT, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_FLOAT, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_DOUBLE, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_BINARY, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_VARBINARY, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_GEOMETRY, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_NCHAR, BindType: stmt.TAOS_FIELD_COL}, } now := time.Now() @@ -3852,7 +3816,7 @@ func TestStmt2QueryAllTypeBytes(t *testing.T) { return } assert.True(t, isInsert) - bs, err := stmt.MarshalStmt2Binary(params2, true, colTypes, nil) + bs, err := stmt.MarshalStmt2Binary(params2, true, colTypes) if err != nil { t.Error(err) return @@ -3915,7 +3879,7 @@ func TestStmt2QueryAllTypeBytes(t *testing.T) { }, }, } - bs, err = stmt.MarshalStmt2Binary(params, false, nil, nil) + bs, err = stmt.MarshalStmt2Binary(params, false, nil) if err != nil { t.Error(err) return @@ -4024,14 +3988,12 @@ func TestStmt2Json(t *testing.T) { {int32(1)}, }, }} - colTypes := []*stmt.StmtField{ - {FieldType: common.TSDB_DATA_TYPE_TIMESTAMP, Precision: common.PrecisionMilliSecond}, - {FieldType: common.TSDB_DATA_TYPE_INT}, - } - tagTypes := []*stmt.StmtField{ - {FieldType: common.TSDB_DATA_TYPE_JSON}, + types := []*stmt.Stmt2AllField{ + {FieldType: common.TSDB_DATA_TYPE_TIMESTAMP, Precision: common.PrecisionMilliSecond, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_INT, BindType: stmt.TAOS_FIELD_COL}, + {FieldType: common.TSDB_DATA_TYPE_JSON, BindType: stmt.TAOS_FIELD_TAG}, } - err = TaosStmt2BindParam(stmt2, true, params, colTypes, tagTypes, -1) + err = TaosStmt2BindParam(stmt2, true, params, types, -1) if err != nil { t.Error(err) return @@ -4058,7 +4020,7 @@ func TestStmt2Json(t *testing.T) { {int32(1)}, }, }} - err = TaosStmt2BindParam(stmt2, false, params, nil, nil, -1) + err = TaosStmt2BindParam(stmt2, false, params, nil, -1) if err != nil { t.Error(err) return @@ -4185,21 +4147,21 @@ func TestStmt2BindMultiTables(t *testing.T) { Tags: []driver.Value{int32(3)}, }, } - colType := []*stmt.StmtField{ + fields := []*stmt.Stmt2AllField{ { FieldType: common.TSDB_DATA_TYPE_TIMESTAMP, Precision: common.PrecisionMilliSecond, + BindType: stmt.TAOS_FIELD_COL, }, { FieldType: common.TSDB_DATA_TYPE_BIGINT, + BindType: stmt.TAOS_FIELD_COL, }, - } - tagType := []*stmt.StmtField{ { FieldType: common.TSDB_DATA_TYPE_INT, + BindType: stmt.TAOS_FIELD_TAG, }, } - isInsert, code := TaosStmt2IsInsert(insertStmt) if code != 0 { errStr := TaosStmt2Error(insertStmt) @@ -4209,7 +4171,7 @@ func TestStmt2BindMultiTables(t *testing.T) { } assert.True(t, isInsert) - err = TaosStmt2BindParam(insertStmt, true, binds, colType, tagType, -1) + err = TaosStmt2BindParam(insertStmt, true, binds, fields, -1) if err != nil { t.Error(err) return @@ -4288,6 +4250,18 @@ func TestTaosStmt2BindBinaryParse(t *testing.T) { args args wantErr assert.ErrorAssertionFunc }{ + { + name: "wrong data length", + args: args{ + sql: "insert into ? values (?,?)", + data: []byte{ + // total Length + 0x00, 0x00, 0x00, 0x00, + }, + colIdx: -1, + }, + wantErr: assert.Error, + }, { name: "normal table name", args: args{ @@ -4901,40 +4875,6 @@ func TestTaosStmt2BindBinaryParse(t *testing.T) { }, wantErr: assert.Error, }, - { - name: "wrong param count", - args: args{ - sql: "insert into test1 values (?,?)", - data: []byte{ - // total Length - 0x3A, 0x00, 0x00, 0x00, - // tableCount - 0x01, 0x00, 0x00, 0x00, - // TagCount - 0x00, 0x00, 0x00, 0x00, - // ColCount - 0x01, 0x00, 0x00, 0x00, - // TableNamesOffset - 0x00, 0x00, 0x00, 0x00, - // TagsOffset - 0x00, 0x00, 0x00, 0x00, - // ColOffset - 0x1c, 0x00, 0x00, 0x00, - // cols - 0x1a, 0x00, 0x00, 0x00, - - 0x1a, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, - 0x00, - 0x00, - 0x08, 0x00, 0x00, 0x00, - 0xba, 0x08, 0x32, 0x27, 0x92, 0x01, 0x00, 0x00, - }, - colIdx: -1, - }, - wantErr: assert.Error, - }, { name: "bind binary", args: args{ @@ -5074,3 +5014,836 @@ func TestTaosStmt2BindBinaryParse(t *testing.T) { }) } } + +func TestTaosStmt2GetStbFields(t *testing.T) { + conn, err := TaosConnect("", "root", "taosdata", "", 0) + if err != nil { + t.Error(err) + return + } + defer TaosClose(conn) + defer func() { + err = exec(conn, "drop database if exists test_stmt2_stb_fields") + if err != nil { + t.Error(err) + return + } + }() + err = exec(conn, "create database test_stmt2_stb_fields precision 'ns'") + if err != nil { + t.Error(err) + return + } + err = exec(conn, "use test_stmt2_stb_fields") + if err != nil { + t.Error(err) + return + } + err = exec(conn, "create table if not exists all_stb("+ + "ts timestamp, "+ + "v1 bool, "+ + "v2 tinyint, "+ + "v3 smallint, "+ + "v4 int, "+ + "v5 bigint, "+ + "v6 tinyint unsigned, "+ + "v7 smallint unsigned, "+ + "v8 int unsigned, "+ + "v9 bigint unsigned, "+ + "v10 float, "+ + "v11 double, "+ + "v12 binary(20), "+ + "v13 varbinary(20), "+ + "v14 geometry(100), "+ + "v15 nchar(20))"+ + "tags("+ + "tts timestamp, "+ + "tv1 bool, "+ + "tv2 tinyint, "+ + "tv3 smallint, "+ + "tv4 int, "+ + "tv5 bigint, "+ + "tv6 tinyint unsigned, "+ + "tv7 smallint unsigned, "+ + "tv8 int unsigned, "+ + "tv9 bigint unsigned, "+ + "tv10 float, "+ + "tv11 double, "+ + "tv12 binary(20), "+ + "tv13 varbinary(20), "+ + "tv14 geometry(100), "+ + "tv15 nchar(20))") + if err != nil { + t.Error(err) + return + } + err = exec(conn, "create table if not exists commontb("+ + "ts timestamp, "+ + "v1 bool, "+ + "v2 tinyint, "+ + "v3 smallint, "+ + "v4 int, "+ + "v5 bigint, "+ + "v6 tinyint unsigned, "+ + "v7 smallint unsigned, "+ + "v8 int unsigned, "+ + "v9 bigint unsigned, "+ + "v10 float, "+ + "v11 double, "+ + "v12 binary(20), "+ + "v13 varbinary(20), "+ + "v14 geometry(100), "+ + "v15 nchar(20))") + if err != nil { + t.Error(err) + return + } + expectMap := map[string]*stmt.Stmt2AllField{ + "tts": { + Name: "tts", + FieldType: common.TSDB_DATA_TYPE_TIMESTAMP, + Precision: common.PrecisionNanoSecond, + Bytes: 8, + BindType: stmt.TAOS_FIELD_TAG, + }, + "tv1": { + Name: "tv1", + FieldType: common.TSDB_DATA_TYPE_BOOL, + Bytes: 1, + BindType: stmt.TAOS_FIELD_TAG, + }, + "tv2": { + Name: "tv2", + FieldType: common.TSDB_DATA_TYPE_TINYINT, + Bytes: 1, + BindType: stmt.TAOS_FIELD_TAG, + }, + "tv3": { + Name: "tv3", + FieldType: common.TSDB_DATA_TYPE_SMALLINT, + Bytes: 2, + BindType: stmt.TAOS_FIELD_TAG, + }, + "tv4": { + Name: "tv4", + FieldType: common.TSDB_DATA_TYPE_INT, + Bytes: 4, + BindType: stmt.TAOS_FIELD_TAG, + }, + "tv5": { + Name: "tv5", + FieldType: common.TSDB_DATA_TYPE_BIGINT, + Bytes: 8, + BindType: stmt.TAOS_FIELD_TAG, + }, + "tv6": { + Name: "tv6", + FieldType: common.TSDB_DATA_TYPE_UTINYINT, + Bytes: 1, + BindType: stmt.TAOS_FIELD_TAG, + }, + "tv7": { + Name: "tv7", + FieldType: common.TSDB_DATA_TYPE_USMALLINT, + Bytes: 2, + BindType: stmt.TAOS_FIELD_TAG, + }, + "tv8": { + Name: "tv8", + FieldType: common.TSDB_DATA_TYPE_UINT, + Bytes: 4, + BindType: stmt.TAOS_FIELD_TAG, + }, + "tv9": { + Name: "tv9", + FieldType: common.TSDB_DATA_TYPE_UBIGINT, + Bytes: 8, + BindType: stmt.TAOS_FIELD_TAG, + }, + "tv10": { + Name: "tv10", + FieldType: common.TSDB_DATA_TYPE_FLOAT, + Bytes: 4, + BindType: stmt.TAOS_FIELD_TAG, + }, + "tv11": { + Name: "tv11", + FieldType: common.TSDB_DATA_TYPE_DOUBLE, + Bytes: 8, + BindType: stmt.TAOS_FIELD_TAG, + }, + "tv12": { + Name: "tv12", + FieldType: common.TSDB_DATA_TYPE_BINARY, + Bytes: 22, + BindType: stmt.TAOS_FIELD_TAG, + }, + "tv13": { + Name: "tv13", + FieldType: common.TSDB_DATA_TYPE_VARBINARY, + Bytes: 22, + BindType: stmt.TAOS_FIELD_TAG, + }, + "tv14": { + Name: "tv14", + FieldType: common.TSDB_DATA_TYPE_GEOMETRY, + Bytes: 102, + BindType: stmt.TAOS_FIELD_TAG, + }, + "tv15": { + Name: "tv15", + FieldType: common.TSDB_DATA_TYPE_NCHAR, + Bytes: 82, + BindType: stmt.TAOS_FIELD_TAG, + }, + "ts": { + Name: "ts", + FieldType: common.TSDB_DATA_TYPE_TIMESTAMP, + Precision: common.PrecisionNanoSecond, + Bytes: 8, + BindType: stmt.TAOS_FIELD_COL, + }, + "v1": { + Name: "v1", + FieldType: common.TSDB_DATA_TYPE_BOOL, + Bytes: 1, + BindType: stmt.TAOS_FIELD_COL, + }, + "v2": { + Name: "v2", + FieldType: common.TSDB_DATA_TYPE_TINYINT, + Bytes: 1, + BindType: stmt.TAOS_FIELD_COL, + }, + "v3": { + Name: "v3", + FieldType: common.TSDB_DATA_TYPE_SMALLINT, + Bytes: 2, + BindType: stmt.TAOS_FIELD_COL, + }, + "v4": { + Name: "v4", + FieldType: common.TSDB_DATA_TYPE_INT, + Bytes: 4, + BindType: stmt.TAOS_FIELD_COL, + }, + "v5": { + Name: "v5", + FieldType: common.TSDB_DATA_TYPE_BIGINT, + Bytes: 8, + BindType: stmt.TAOS_FIELD_COL, + }, + "v6": { + Name: "v6", + FieldType: common.TSDB_DATA_TYPE_UTINYINT, + Bytes: 1, + BindType: stmt.TAOS_FIELD_COL, + }, + "v7": { + Name: "v7", + FieldType: common.TSDB_DATA_TYPE_USMALLINT, + Bytes: 2, + BindType: stmt.TAOS_FIELD_COL, + }, + "v8": { + Name: "v8", + FieldType: common.TSDB_DATA_TYPE_UINT, + Bytes: 4, + BindType: stmt.TAOS_FIELD_COL, + }, + "v9": { + Name: "v9", + FieldType: common.TSDB_DATA_TYPE_UBIGINT, + Bytes: 8, + BindType: stmt.TAOS_FIELD_COL, + }, + "v10": { + Name: "v10", + FieldType: common.TSDB_DATA_TYPE_FLOAT, + Bytes: 4, + BindType: stmt.TAOS_FIELD_COL, + }, + "v11": { + Name: "v11", + FieldType: common.TSDB_DATA_TYPE_DOUBLE, + Bytes: 8, + BindType: stmt.TAOS_FIELD_COL, + }, + "v12": { + Name: "v12", + FieldType: common.TSDB_DATA_TYPE_BINARY, + Bytes: 22, + BindType: stmt.TAOS_FIELD_COL, + }, + "v13": { + Name: "v13", + FieldType: common.TSDB_DATA_TYPE_VARBINARY, + Bytes: 22, + BindType: stmt.TAOS_FIELD_COL, + }, + "v14": { + Name: "v14", + FieldType: common.TSDB_DATA_TYPE_GEOMETRY, + Bytes: 102, + BindType: stmt.TAOS_FIELD_COL, + }, + "v15": { + Name: "v15", + FieldType: common.TSDB_DATA_TYPE_NCHAR, + Bytes: 82, + BindType: stmt.TAOS_FIELD_COL, + }, + "tbname": { + Name: "tbname", + FieldType: common.TSDB_DATA_TYPE_BINARY, + Bytes: 271, + BindType: stmt.TAOS_FIELD_TBNAME, + }, + } + tests := []struct { + name string + sql string + expect []string + }{ + { + name: "with subTableName", + sql: "insert into tb1 using all_stb tags(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", + expect: []string{"tts", "tv1", "tv2", "tv3", "tv4", "tv5", "tv6", "tv7", "tv8", "tv9", "tv10", "tv11", "tv12", "tv13", "tv14", "tv15", "ts", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15"}, + }, + { + name: "using stb", + sql: "insert into ? using all_stb tags(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", + expect: []string{"tbname", "tts", "tv1", "tv2", "tv3", "tv4", "tv5", "tv6", "tv7", "tv8", "tv9", "tv10", "tv11", "tv12", "tv13", "tv14", "tv15", "ts", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15"}, + }, + { + name: "tbname as value", + sql: "insert into all_stb (tbname,tts,tv1,tv2,tv3,tv4,tv5,tv6,tv7,tv8,tv9,tv10,tv11,tv12,tv13,tv14,tv15,ts,v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15) values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", + expect: []string{"tbname", "tts", "tv1", "tv2", "tv3", "tv4", "tv5", "tv6", "tv7", "tv8", "tv9", "tv10", "tv11", "tv12", "tv13", "tv14", "tv15", "ts", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15"}, + }, + { + name: "tbname as value random", + sql: "insert into all_stb (ts,v1,v2,v3,v4,v5,v6,tts,tv1,tv2,tv3,tv4,tv5,tv6,tv7,tv8,tv9,tv10,tv11,tv12,tv13,tv14,tbname,tv15,v7,v8,v9,v10,v11,v12,v13,v14,v15) values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", + expect: []string{"ts", "v1", "v2", "v3", "v4", "v5", "v6", "tts", "tv1", "tv2", "tv3", "tv4", "tv5", "tv6", "tv7", "tv8", "tv9", "tv10", "tv11", "tv12", "tv13", "tv14", "tbname", "tv15", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15"}, + }, + { + name: "common table", + sql: "insert into commontb values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", + expect: []string{"ts", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15"}, + }, + } + for _, tt := range tests { + caller := NewStmtCallBackTest() + handler := cgo.NewHandle(caller) + stmt2 := TaosStmt2Init(conn, 0xed123, false, false, handler) + defer TaosStmt2Close(stmt2) + code := TaosStmt2Prepare(stmt2, tt.sql) + if code != 0 { + errStr := TaosStmt2Error(stmt2) + err := taosError.NewError(code, errStr) + t.Error(err) + return + } + code, count, fields := TaosStmt2GetFields(stmt2) + if code != 0 { + errStr := TaosStmt2Error(stmt2) + err := taosError.NewError(code, errStr) + t.Error(err) + return + } + fs := Stmt2ParseAllFields(count, fields) + TaosStmt2FreeFields(stmt2, fields) + expect := make([]*stmt.Stmt2AllField, len(tt.expect)) + for i := 0; i < len(tt.expect); i++ { + assert.Equal(t, expectMap[tt.expect[i]].Name, fs[i].Name) + assert.Equal(t, expectMap[tt.expect[i]].FieldType, fs[i].FieldType) + assert.Equal(t, expectMap[tt.expect[i]].Bytes, fs[i].Bytes) + assert.Equal(t, expectMap[tt.expect[i]].BindType, fs[i].BindType) + if expectMap[tt.expect[i]].FieldType == common.TSDB_DATA_TYPE_TIMESTAMP { + assert.Equal(t, expectMap[tt.expect[i]].Precision, fs[i].Precision) + } + expect[i] = expectMap[tt.expect[i]] + } + } + + caller := NewStmtCallBackTest() + handler := cgo.NewHandle(caller) + stmt2 := TaosStmt2Init(conn, 0xfd123, false, false, handler) + defer TaosStmt2Close(stmt2) + code := TaosStmt2Prepare(stmt2, "select * from commontb where ts = ? and v1 = ?") + if code != 0 { + errStr := TaosStmt2Error(stmt2) + err := taosError.NewError(code, errStr) + t.Error(err) + return + } + code, count, fields := TaosStmt2GetFields(stmt2) + if code != 0 { + errStr := TaosStmt2Error(stmt2) + err := taosError.NewError(code, errStr) + t.Error(err) + return + } + TaosStmt2FreeFields(stmt2, fields) + assert.Equal(t, 2, count) +} + +func TestWrongParseStmt2StbFields(t *testing.T) { + fs := Stmt2ParseAllFields(0, nil) + assert.Nil(t, fs) + fs = Stmt2ParseAllFields(2, nil) + assert.Nil(t, fs) +} + +func TestStmt2BindTbnameAsValue(t *testing.T) { + conn, err := TaosConnect("", "root", "taosdata", "", 0) + if err != nil { + t.Error(err) + return + } + defer TaosClose(conn) + defer func() { + err = exec(conn, "drop database if exists test_stmt2_bind_tbname_as_value") + if err != nil { + t.Error(err) + return + } + }() + err = exec(conn, "create database if not exists test_stmt2_bind_tbname_as_value precision 'ns' keep 36500") + if err != nil { + t.Error(err) + return + } + err = exec(conn, "use test_stmt2_bind_tbname_as_value") + if err != nil { + t.Error(err) + return + } + err = exec(conn, "create table if not exists all_stb("+ + "ts timestamp, "+ + "v1 bool, "+ + "v2 tinyint, "+ + "v3 smallint, "+ + "v4 int, "+ + "v5 bigint, "+ + "v6 tinyint unsigned, "+ + "v7 smallint unsigned, "+ + "v8 int unsigned, "+ + "v9 bigint unsigned, "+ + "v10 float, "+ + "v11 double, "+ + "v12 binary(20), "+ + "v13 varbinary(20), "+ + "v14 geometry(100), "+ + "v15 nchar(20))"+ + "tags("+ + "tts timestamp, "+ + "tv1 bool, "+ + "tv2 tinyint, "+ + "tv3 smallint, "+ + "tv4 int, "+ + "tv5 bigint, "+ + "tv6 tinyint unsigned, "+ + "tv7 smallint unsigned, "+ + "tv8 int unsigned, "+ + "tv9 bigint unsigned, "+ + "tv10 float, "+ + "tv11 double, "+ + "tv12 binary(20), "+ + "tv13 varbinary(20), "+ + "tv14 geometry(100), "+ + "tv15 nchar(20))") + if err != nil { + t.Error(err) + return + } + caller := NewStmtCallBackTest() + handler := cgo.NewHandle(caller) + insertStmt := TaosStmt2Init(conn, 0xff1234, false, false, handler) + prepareInsertSql := "insert into all_stb (ts ,v1 ,v2 ,v3 ,v4 ,v5 ,v6 ,v7 ,v8 ,v9 ,v10,v11,v12,v13,v14,v15,tbname,tts,tv1 ,tv2 ,tv3 ,tv4 ,tv5 ,tv6 ,tv7 ,tv8 ,tv9 ,tv10,tv11,tv12,tv13,tv14,tv15) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)" + code := TaosStmt2Prepare(insertStmt, prepareInsertSql) + if code != 0 { + errStr := TaosStmt2Error(insertStmt) + err = taosError.NewError(code, errStr) + t.Error(err) + return + } + + isInsert, code := TaosStmt2IsInsert(insertStmt) + if code != 0 { + errStr := TaosStmt2Error(insertStmt) + err = taosError.NewError(code, errStr) + t.Error(err) + return + } + assert.True(t, isInsert) + + code, count, cFields := TaosStmt2GetFields(insertStmt) + if code != 0 { + errStr := TaosStmt2Error(insertStmt) + err = taosError.NewError(code, errStr) + t.Error(err) + return + } + defer TaosStmt2FreeFields(insertStmt, cFields) + assert.Equal(t, 33, count) + fields := Stmt2ParseAllFields(count, cFields) + assert.Equal(t, 33, len(fields)) + expectMap := map[string]*stmt.Stmt2AllField{ + "tts": { + Name: "tts", + FieldType: common.TSDB_DATA_TYPE_TIMESTAMP, + Precision: common.PrecisionNanoSecond, + Bytes: 8, + BindType: stmt.TAOS_FIELD_TAG, + }, + "tv1": { + Name: "tv1", + FieldType: common.TSDB_DATA_TYPE_BOOL, + Bytes: 1, + BindType: stmt.TAOS_FIELD_TAG, + }, + "tv2": { + Name: "tv2", + FieldType: common.TSDB_DATA_TYPE_TINYINT, + Bytes: 1, + BindType: stmt.TAOS_FIELD_TAG, + }, + "tv3": { + Name: "tv3", + FieldType: common.TSDB_DATA_TYPE_SMALLINT, + Bytes: 2, + BindType: stmt.TAOS_FIELD_TAG, + }, + "tv4": { + Name: "tv4", + FieldType: common.TSDB_DATA_TYPE_INT, + Bytes: 4, + BindType: stmt.TAOS_FIELD_TAG, + }, + "tv5": { + Name: "tv5", + FieldType: common.TSDB_DATA_TYPE_BIGINT, + Bytes: 8, + BindType: stmt.TAOS_FIELD_TAG, + }, + "tv6": { + Name: "tv6", + FieldType: common.TSDB_DATA_TYPE_UTINYINT, + Bytes: 1, + BindType: stmt.TAOS_FIELD_TAG, + }, + "tv7": { + Name: "tv7", + FieldType: common.TSDB_DATA_TYPE_USMALLINT, + Bytes: 2, + BindType: stmt.TAOS_FIELD_TAG, + }, + "tv8": { + Name: "tv8", + FieldType: common.TSDB_DATA_TYPE_UINT, + Bytes: 4, + BindType: stmt.TAOS_FIELD_TAG, + }, + "tv9": { + Name: "tv9", + FieldType: common.TSDB_DATA_TYPE_UBIGINT, + Bytes: 8, + BindType: stmt.TAOS_FIELD_TAG, + }, + "tv10": { + Name: "tv10", + FieldType: common.TSDB_DATA_TYPE_FLOAT, + Bytes: 4, + BindType: stmt.TAOS_FIELD_TAG, + }, + "tv11": { + Name: "tv11", + FieldType: common.TSDB_DATA_TYPE_DOUBLE, + Bytes: 8, + BindType: stmt.TAOS_FIELD_TAG, + }, + "tv12": { + Name: "tv12", + FieldType: common.TSDB_DATA_TYPE_BINARY, + Bytes: 22, + BindType: stmt.TAOS_FIELD_TAG, + }, + "tv13": { + Name: "tv13", + FieldType: common.TSDB_DATA_TYPE_VARBINARY, + Bytes: 22, + BindType: stmt.TAOS_FIELD_TAG, + }, + "tv14": { + Name: "tv14", + FieldType: common.TSDB_DATA_TYPE_GEOMETRY, + Bytes: 102, + BindType: stmt.TAOS_FIELD_TAG, + }, + "tv15": { + Name: "tv15", + FieldType: common.TSDB_DATA_TYPE_NCHAR, + Bytes: 82, + BindType: stmt.TAOS_FIELD_TAG, + }, + "ts": { + Name: "ts", + FieldType: common.TSDB_DATA_TYPE_TIMESTAMP, + Precision: common.PrecisionNanoSecond, + Bytes: 8, + BindType: stmt.TAOS_FIELD_COL, + }, + "v1": { + Name: "v1", + FieldType: common.TSDB_DATA_TYPE_BOOL, + Bytes: 1, + BindType: stmt.TAOS_FIELD_COL, + }, + "v2": { + Name: "v2", + FieldType: common.TSDB_DATA_TYPE_TINYINT, + Bytes: 1, + BindType: stmt.TAOS_FIELD_COL, + }, + "v3": { + Name: "v3", + FieldType: common.TSDB_DATA_TYPE_SMALLINT, + Bytes: 2, + BindType: stmt.TAOS_FIELD_COL, + }, + "v4": { + Name: "v4", + FieldType: common.TSDB_DATA_TYPE_INT, + Bytes: 4, + BindType: stmt.TAOS_FIELD_COL, + }, + "v5": { + Name: "v5", + FieldType: common.TSDB_DATA_TYPE_BIGINT, + Bytes: 8, + BindType: stmt.TAOS_FIELD_COL, + }, + "v6": { + Name: "v6", + FieldType: common.TSDB_DATA_TYPE_UTINYINT, + Bytes: 1, + BindType: stmt.TAOS_FIELD_COL, + }, + "v7": { + Name: "v7", + FieldType: common.TSDB_DATA_TYPE_USMALLINT, + Bytes: 2, + BindType: stmt.TAOS_FIELD_COL, + }, + "v8": { + Name: "v8", + FieldType: common.TSDB_DATA_TYPE_UINT, + Bytes: 4, + BindType: stmt.TAOS_FIELD_COL, + }, + "v9": { + Name: "v9", + FieldType: common.TSDB_DATA_TYPE_UBIGINT, + Bytes: 8, + BindType: stmt.TAOS_FIELD_COL, + }, + "v10": { + Name: "v10", + FieldType: common.TSDB_DATA_TYPE_FLOAT, + Bytes: 4, + BindType: stmt.TAOS_FIELD_COL, + }, + "v11": { + Name: "v11", + FieldType: common.TSDB_DATA_TYPE_DOUBLE, + Bytes: 8, + BindType: stmt.TAOS_FIELD_COL, + }, + "v12": { + Name: "v12", + FieldType: common.TSDB_DATA_TYPE_BINARY, + Bytes: 22, + BindType: stmt.TAOS_FIELD_COL, + }, + "v13": { + Name: "v13", + FieldType: common.TSDB_DATA_TYPE_VARBINARY, + Bytes: 22, + BindType: stmt.TAOS_FIELD_COL, + }, + "v14": { + Name: "v14", + FieldType: common.TSDB_DATA_TYPE_GEOMETRY, + Bytes: 102, + BindType: stmt.TAOS_FIELD_COL, + }, + "v15": { + Name: "v15", + FieldType: common.TSDB_DATA_TYPE_NCHAR, + Bytes: 82, + BindType: stmt.TAOS_FIELD_COL, + }, + "tbname": { + Name: "tbname", + FieldType: common.TSDB_DATA_TYPE_BINARY, + Bytes: 271, + BindType: stmt.TAOS_FIELD_TBNAME, + }, + } + + for i := 0; i < 33; i++ { + expect := expectMap[fields[i].Name] + assert.Equal(t, expect, fields[i]) + } + + now := time.Now() + params2 := []*stmt.TaosStmt2BindData{{ + TableName: "ctb1", + Tags: []driver.Value{ + // TIMESTAMP + now, + // BOOL + true, + // TINYINT + int8(1), + // SMALLINT + int16(1), + // INT + int32(1), + // BIGINT + int64(1), + // UTINYINT + uint8(1), + // USMALLINT + uint16(1), + // UINT + uint32(1), + // UBIGINT + uint64(1), + // FLOAT + float32(1.2), + // DOUBLE + float64(1.2), + // BINARY + []byte("binary"), + // VARBINARY + []byte("varbinary"), + // GEOMETRY + []byte{0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x40}, + // NCHAR + "nchar", + }, + Cols: [][]driver.Value{ + { + now, + now.Add(time.Second), + now.Add(time.Second * 2), + }, + { + true, + nil, + false, + }, + { + int8(11), + nil, + int8(12), + }, + { + int16(11), + nil, + int16(12), + }, + { + int32(11), + nil, + int32(12), + }, + { + int64(11), + nil, + int64(12), + }, + { + uint8(11), + nil, + uint8(12), + }, + { + uint16(11), + nil, + uint16(12), + }, + { + uint32(11), + nil, + uint32(12), + }, + { + uint64(11), + nil, + uint64(12), + }, + { + float32(11.2), + nil, + float32(12.2), + }, + { + float64(11.2), + nil, + float64(12.2), + }, + { + []byte("binary1"), + nil, + []byte("binary2"), + }, + { + []byte("varbinary1"), + nil, + []byte("varbinary2"), + }, + { + []byte{0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x40}, + nil, + []byte{0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x40}, + }, + { + "nchar1", + nil, + "nchar2", + }, + }, + }} + bs, err := stmt.MarshalStmt2Binary(params2, true, fields) + assert.NoError(t, err) + err = TaosStmt2BindBinary(insertStmt, bs, -1) + if err != nil { + t.Error(err) + return + } + code = TaosStmt2Exec(insertStmt) + if code != 0 { + errStr := TaosStmt2Error(insertStmt) + err = taosError.NewError(code, errStr) + t.Error(err) + return + } + r := <-caller.ExecResult + if r.n != 0 { + errStr := TaosStmt2Error(insertStmt) + err = taosError.NewError(r.n, errStr) + t.Error(err) + return + } + assert.Equal(t, 3, r.affected) + + code = TaosStmt2Close(insertStmt) + if code != 0 { + errStr := TaosStmt2Error(insertStmt) + err = taosError.NewError(code, errStr) + t.Error(err) + return + } +} diff --git a/wrapper/stmt2binary.go b/wrapper/stmt2binary.go new file mode 100644 index 0000000..8e7115f --- /dev/null +++ b/wrapper/stmt2binary.go @@ -0,0 +1,272 @@ +package wrapper + +/* +#include +#include +#include +#include + +int +go_generate_stmt2_binds(char *data, uint32_t count, uint32_t field_count, uint32_t field_offset, + TAOS_STMT2_BIND *bind_struct, + TAOS_STMT2_BIND **bind_ptr, char *err_msg) { + uint32_t *base_length = (uint32_t *) (data + field_offset); + char *data_ptr = (char *) (base_length + count); + for (int table_index = 0; table_index < count; table_index++) { + bind_ptr[table_index] = bind_struct + table_index * field_count; + char *bind_data_ptr; + for (uint32_t field_index = 0; field_index < field_count; field_index++) { + bind_data_ptr = data_ptr; + TAOS_STMT2_BIND *bind = bind_ptr[table_index] + field_index; + // total length + uint32_t bind_data_totalLength = *(uint32_t *) bind_data_ptr; + bind_data_ptr += 4; + // buffer_type + bind->buffer_type = *(int *) bind_data_ptr; + bind_data_ptr += 4; + // num + bind->num = *(int *) bind_data_ptr; + bind_data_ptr += 4; + // is_null + bind->is_null = (char *) bind_data_ptr; + bind_data_ptr += bind->num; + // have_length + char have_length = *(char *) bind_data_ptr; + bind_data_ptr += 1; + if (have_length == 0) { + bind->length = NULL; + } else { + bind->length = (int32_t *) bind_data_ptr; + bind_data_ptr += bind->num * 4; + } + // buffer_length + int32_t buffer_length = *(int32_t *) bind_data_ptr; + bind_data_ptr += 4; + // buffer + if (buffer_length > 0) { + bind->buffer = (void *) bind_data_ptr; + bind_data_ptr += buffer_length; + } else { + bind->buffer = NULL; + } + // check bind data length + if (bind_data_ptr - data_ptr != bind_data_totalLength) { + snprintf(err_msg, 128, "bind data length error, tableIndex: %d, fieldIndex: %d", table_index, field_index); + return -1; + } + data_ptr = bind_data_ptr; + } + } + return 0; +} + + +int go_stmt2_bind_binary(TAOS_STMT2 *stmt, char *data, int32_t col_idx, char *err_msg) { + uint32_t *header = (uint32_t *) data; + uint32_t total_length = header[0]; + uint32_t count = header[1]; + uint32_t tag_count = header[2]; + uint32_t col_count = header[3]; + uint32_t table_names_offset = header[4]; + uint32_t tags_offset = header[5]; + uint32_t cols_offset = header[6]; + // check table names + if (table_names_offset > 0) { + uint32_t table_name_end = table_names_offset + count * 2; + if (table_name_end > total_length) { + snprintf(err_msg, 128, "table name lengths out of range, total length: %d, tableNamesLengthEnd: %d", total_length, + table_name_end); + return -1; + } + uint16_t *table_name_length_ptr = (uint16_t *) (data + table_names_offset); + for (int32_t i = 0; i < count; ++i) { + if (table_name_length_ptr[i] == 0) { + snprintf(err_msg, 128, "table name length is 0, tableIndex: %d", i); + return -1; + } + table_name_end += (uint32_t) table_name_length_ptr[i]; + } + if (table_name_end > total_length) { + snprintf(err_msg, 128, "table names out of range, total length: %d, tableNameTotalLength: %d", total_length, + table_name_end); + return -1; + } + } + // check tags + if (tags_offset > 0) { + if (tag_count == 0) { + snprintf(err_msg, 128, "tag count is 0, but tags offset is not 0"); + return -1; + } + uint32_t tag_end = tags_offset + count * 4; + if (tag_end > total_length) { + snprintf(err_msg, 128, "tags out of range, total length: %d, tagEnd: %d", total_length, tag_end); + return -1; + } + uint32_t *tab_length_ptr = (uint32_t *) (data + tags_offset); + for (int32_t i = 0; i < count; ++i) { + if (tab_length_ptr[i] == 0) { + snprintf(err_msg, 128, "tag length is 0, tableIndex: %d", i); + return -1; + } + tag_end += tab_length_ptr[i]; + } + if (tag_end > total_length) { + snprintf(err_msg, 128, "tags out of range, total length: %d, tagsTotalLength: %d", total_length, tag_end); + return -1; + } + } + // check cols + if (cols_offset > 0) { + if (col_count == 0) { + snprintf(err_msg, 128, "col count is 0, but cols offset is not 0"); + return -1; + } + uint32_t colEnd = cols_offset + count * 4; + if (colEnd > total_length) { + snprintf(err_msg, 128, "cols out of range, total length: %d, colEnd: %d", total_length, colEnd); + return -1; + } + uint32_t *col_length_ptr = (uint32_t *) (data + cols_offset); + for (int32_t i = 0; i < count; ++i) { + if (col_length_ptr[i] == 0) { + snprintf(err_msg, 128, "col length is 0, tableIndex: %d", i); + return -1; + } + colEnd += col_length_ptr[i]; + } + if (colEnd > total_length) { + snprintf(err_msg, 128, "cols out of range, total length: %d, colsTotalLength: %d", total_length, colEnd); + return -1; + } + } + // generate bindv struct + TAOS_STMT2_BINDV bind_v; + bind_v.count = (int) count; + if (table_names_offset > 0) { + uint16_t *table_name_length_ptr = (uint16_t *) (data + table_names_offset); + char *table_name_data_ptr = (char *) (table_name_length_ptr) + 2 * count; + char **table_name = (char **) malloc(sizeof(char *) * count); + if (table_name == NULL) { + snprintf(err_msg, 128, "malloc tableName error"); + return -1; + } + for (int i = 0; i < count; i++) { + table_name[i] = table_name_data_ptr; + table_name_data_ptr += table_name_length_ptr[i]; + } + bind_v.tbnames = table_name; + } else { + bind_v.tbnames = NULL; + } + uint32_t bind_struct_count = 0; + uint32_t bind_ptr_count = 0; + if (tags_offset == 0) { + bind_v.tags = NULL; + } else { + bind_struct_count += count * tag_count; + bind_ptr_count += count; + } + if (cols_offset == 0) { + bind_v.bind_cols = NULL; + } else { + bind_struct_count += count * col_count; + bind_ptr_count += count; + } + TAOS_STMT2_BIND *bind_struct = NULL; + TAOS_STMT2_BIND **bind_ptr = NULL; + if (bind_struct_count == 0) { + bind_v.tags = NULL; + bind_v.bind_cols = NULL; + } else { + // []TAOS_STMT2_BIND bindStruct + bind_struct = (TAOS_STMT2_BIND *) malloc(sizeof(TAOS_STMT2_BIND) * bind_struct_count); + if (bind_struct == NULL) { + snprintf(err_msg, 128, "malloc bind struct error"); + free(bind_v.tbnames); + return -1; + } + // []TAOS_STMT2_BIND *bindPtr + bind_ptr = (TAOS_STMT2_BIND **) malloc(sizeof(TAOS_STMT2_BIND *) * bind_ptr_count); + if (bind_ptr == NULL) { + snprintf(err_msg, 128, "malloc bind pointer error"); + free(bind_struct); + free(bind_v.tbnames); + return -1; + } + uint32_t struct_index = 0; + uint32_t ptr_index = 0; + if (tags_offset > 0) { + int code = go_generate_stmt2_binds(data, count, tag_count, tags_offset, bind_struct, bind_ptr, err_msg); + if (code != 0) { + free(bind_struct); + free(bind_ptr); + free(bind_v.tbnames); + return code; + } + bind_v.tags = bind_ptr; + struct_index += count * tag_count; + ptr_index += count; + } + if (cols_offset > 0) { + TAOS_STMT2_BIND *col_bind_struct = bind_struct + struct_index; + TAOS_STMT2_BIND **col_bind_ptr = bind_ptr + ptr_index; + int code = go_generate_stmt2_binds(data, count, col_count, cols_offset, col_bind_struct, col_bind_ptr, + err_msg); + if (code != 0) { + free(bind_struct); + free(bind_ptr); + free(bind_v.tbnames); + return code; + } + bind_v.bind_cols = col_bind_ptr; + } + } + int code = taos_stmt2_bind_param(stmt, &bind_v, col_idx); + if (code != 0) { + char *msg = taos_stmt2_error(stmt); + snprintf(err_msg, 128, "%s", msg); + } + if (bind_v.tbnames != NULL) { + free(bind_v.tbnames); + } + if (bind_struct != NULL) { + free(bind_struct); + } + if (bind_ptr != NULL) { + free(bind_ptr); + } + return code; +} +*/ +import "C" +import ( + "encoding/binary" + "fmt" + "unsafe" + + "github.com/taosdata/driver-go/v3/common/stmt" + taosError "github.com/taosdata/driver-go/v3/errors" +) + +// TaosStmt2BindBinary bind binary data to stmt2 +func TaosStmt2BindBinary(stmt2 unsafe.Pointer, data []byte, colIdx int32) error { + if len(data) < stmt.DataPosition { + return fmt.Errorf("data length is less than 28") + } + totalLength := binary.LittleEndian.Uint32(data[stmt.TotalLengthPosition:]) + if totalLength != uint32(len(data)) { + return fmt.Errorf("total length not match, expect %d, but get %d", len(data), totalLength) + } + dataP := C.CBytes(data) + defer C.free(dataP) + errMsg := (*C.char)(C.malloc(128)) + defer C.free(unsafe.Pointer(errMsg)) + + code := C.go_stmt2_bind_binary(stmt2, (*C.char)(dataP), C.int32_t(colIdx), errMsg) + if code != 0 { + msg := C.GoString(errMsg) + return taosError.NewError(int(code), msg) + } + return nil +} diff --git a/wrapper/stmt_test.go b/wrapper/stmt_test.go index 557b10d..8ce160a 100644 --- a/wrapper/stmt_test.go +++ b/wrapper/stmt_test.go @@ -898,7 +898,7 @@ func TestGetFieldsCommonTable(t *testing.T) { return } code, num, _ := TaosStmtGetTagFields(stmt) - assert.Equal(t, 0, code) + assert.NotEqual(t, 0, code) assert.Equal(t, 0, num) code, columnCount, columnsP := TaosStmtGetColFields(stmt) if code != 0 { diff --git a/wrapper/whitelistcb_test.go b/wrapper/whitelistcb_test.go index 86d01cd..9afdb0b 100644 --- a/wrapper/whitelistcb_test.go +++ b/wrapper/whitelistcb_test.go @@ -28,6 +28,7 @@ func TestWhitelistCallback_Success(t *testing.T) { 192, 168, 1, 1, 24, // 192.168.1.1/24 0, 0, 0, 10, 0, 0, 1, 16, // 10.0.0.1/16 + 0, 0, 0, } // Create a channel to receive the result From ab39d6aef8aefdc71fbe625cd117f23b7a2809f2 Mon Sep 17 00:00:00 2001 From: t_max <1172915550@qq.com> Date: Tue, 17 Dec 2024 19:01:29 +0800 Subject: [PATCH 2/4] fix: stmt bind test error --- af/conn_test.go | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/af/conn_test.go b/af/conn_test.go index e3a9ccf..c8202f9 100644 --- a/af/conn_test.go +++ b/af/conn_test.go @@ -581,8 +581,22 @@ func TestFastInsertWithSetSubTableName(t *testing.T) { params []*param2.Param bindType *param2.ColumnType }{ - {"set_table_name_sub_int", "1,'int'", "ts timestamp, `value` int", "?, ?", []*param2.Param{param2.NewParam(1).AddTimestamp(now, common.PrecisionMicroSecond), param2.NewParam(1).AddInt(1)}, param2.NewColumnType(2).AddTimestamp().AddInt()}, - {"set_table_name_sub_nchar", "2,'nchar'", "ts timestamp, `value` nchar(8)", "?, ?", []*param2.Param{param2.NewParam(1).AddTimestamp(time.Now(), common.PrecisionMicroSecond), param2.NewParam(1).AddNchar("ttt")}, param2.NewColumnType(2).AddTimestamp().AddNchar(1)}, + { + sTableName: "set_table_name_sub_int", + tags: "1,'int'", + tbType: "ts timestamp, `value` int", + pos: "?, ?", + params: []*param2.Param{param2.NewParam(1).AddTimestamp(now, common.PrecisionMicroSecond), param2.NewParam(1).AddInt(1)}, + bindType: param2.NewColumnType(2).AddTimestamp().AddInt(), + }, + { + sTableName: "set_table_name_sub_nchar", + tags: "2,'nchar'", + tbType: "ts timestamp, `value` nchar(8)", + pos: "?, ?", + params: []*param2.Param{param2.NewParam(1).AddTimestamp(time.Now(), common.PrecisionMicroSecond), param2.NewParam(1).AddNchar("ttt")}, + bindType: param2.NewColumnType(2).AddTimestamp().AddNchar(5), + }, } { tbName := fmt.Sprintf("test_fast_insert_with_sub_table_name_%02d", i) tbType := tc.tbType From 87b58ebe3fc36ec89d81cec16d63d3fb242969b7 Mon Sep 17 00:00:00 2001 From: t_max <1172915550@qq.com> Date: Tue, 17 Dec 2024 19:47:27 +0800 Subject: [PATCH 3/4] test: add unit test for stmt2 --- af/stmt2_test.go | 46 +++++++++++++++++++++++++++++++++++++++++++ wrapper/stmt2_test.go | 12 +++++++++++ 2 files changed, 58 insertions(+) diff --git a/af/stmt2_test.go b/af/stmt2_test.go index f5d6ad8..1c327a4 100644 --- a/af/stmt2_test.go +++ b/af/stmt2_test.go @@ -283,3 +283,49 @@ func TestStmt2(t *testing.T) { assert.ErrorIs(t, err, io.EOF) } + +func TestStmt2_Prepare(t *testing.T) { + conn, err := Open("", "root", "taosdata", "", 0) + if !assert.NoError(t, err) { + return + } + stmt2 := conn.Stmt2(0x123456789, false) + if stmt2 == nil { + t.Errorf("Expected stmt to be not nil") + return + } + defer func() { + err = stmt2.Close() + assert.NoError(t, err) + }() + _, err = conn.Exec("create database if not exists stmt2_prepare_wrong_test") + if !assert.NoError(t, err) { + return + } + defer func() { + _, err = conn.Exec("drop database if exists stmt2_prepare_wrong_test") + assert.NoError(t, err) + }() + _, err = conn.Exec("use stmt2_prepare_wrong_test") + if !assert.NoError(t, err) { + return + } + err = stmt2.Prepare("insert into not_exist_table values(?,?,?)") + assert.Error(t, err) + _, err = conn.Exec("create table t (ts timestamp, b int, c int)") + assert.NoError(t, err) + err = stmt2.Prepare("") + assert.NoError(t, err) + err = stmt2.Bind([]*stmt.TaosStmt2BindData{ + { + Cols: [][]driver.Value{ + {time.Now()}, + {int32(1)}, + {int32(2)}, + }, + }, + }) + assert.Error(t, err) + err = stmt2.Prepare("insert into t values(?,?,?)") + assert.Error(t, err) +} diff --git a/wrapper/stmt2_test.go b/wrapper/stmt2_test.go index bf47c2b..6e8b774 100644 --- a/wrapper/stmt2_test.go +++ b/wrapper/stmt2_test.go @@ -1,6 +1,7 @@ package wrapper import ( + "bytes" "database/sql/driver" "fmt" "testing" @@ -5847,3 +5848,14 @@ func TestStmt2BindTbnameAsValue(t *testing.T) { return } } + +func TestToUnsafeBytes(t *testing.T) { + s := "str" + if !bytes.Equal([]byte("str"), ToUnsafeBytes(s)) { + t.Fatalf(`[]bytes(%s) doesnt equal to %s `, s, s) + } + s = "" + if !bytes.Equal([]byte(""), ToUnsafeBytes(s)) { + t.Fatalf(`[]bytes(%s) doesnt equal to %s `, s, s) + } +} From 2cd6f2c4a9376dfb365f07446b4d7e7a0afc8549 Mon Sep 17 00:00:00 2001 From: t_max <1172915550@qq.com> Date: Wed, 18 Dec 2024 10:15:48 +0800 Subject: [PATCH 4/4] test: add unit test for stmt2 --- wrapper/stmt2_test.go | 60 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/wrapper/stmt2_test.go b/wrapper/stmt2_test.go index 6e8b774..fefb69f 100644 --- a/wrapper/stmt2_test.go +++ b/wrapper/stmt2_test.go @@ -5849,6 +5849,66 @@ func TestStmt2BindTbnameAsValue(t *testing.T) { } } +func TestStmt2BindError(t *testing.T) { + conn, err := TaosConnect("", "root", "taosdata", "", 0) + if err != nil { + t.Error(err) + return + } + defer TaosClose(conn) + defer func() { + err = exec(conn, "drop database if exists test_stmt2_bind_error") + if err != nil { + t.Error(err) + return + } + }() + err = exec(conn, "create database if not exists test_stmt2_bind_error precision 'ns' keep 36500") + if err != nil { + t.Error(err) + return + } + err = exec(conn, "use test_stmt2_bind_error") + if err != nil { + t.Error(err) + return + } + caller := NewStmtCallBackTest() + handler := cgo.NewHandle(caller) + stmt2 := TaosStmt2Init(conn, 0xff1234, false, false, handler) + defer func() { + code := TaosStmt2Close(stmt2) + if code != 0 { + errStr := TaosStmt2Error(stmt2) + err = taosError.NewError(code, errStr) + t.Error(err) + return + } + }() + fields := []*stmt.Stmt2AllField{ + { + FieldType: common.TSDB_DATA_TYPE_TIMESTAMP, + BindType: stmt.TAOS_FIELD_COL, + Precision: TSDB_SML_TIMESTAMP_NANO_SECONDS, + }, + { + FieldType: common.TSDB_DATA_TYPE_INT, + BindType: stmt.TAOS_FIELD_COL, + }, + } + params := []*stmt.TaosStmt2BindData{ + { + Cols: [][]driver.Value{ + {time.Now()}, + {int32(1)}, + }, + }, + } + // without prepare + err = TaosStmt2BindParam(stmt2, false, params, fields, -1) + assert.Error(t, err) +} + func TestToUnsafeBytes(t *testing.T) { s := "str" if !bytes.Equal([]byte("str"), ToUnsafeBytes(s)) {