This is an automated email from the ASF dual-hosted git repository.
haonan pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iotdb-client-go.git
The following commit(s) were added to refs/heads/main by this push:
new 4341368 Support new data types (#107)
4341368 is described below
commit 4341368b001bf966cc00ab05672326c34e4cb346
Author: Haonan <[email protected]>
AuthorDate: Fri Sep 27 19:24:00 2024 +0800
Support new data types (#107)
---
client/field.go | 6 ++
client/field_test.go | 89 ++++++++++++++++++++++++++++
client/protocol.go | 54 ++++++++---------
client/rpcdataset.go | 83 ++++++++++++++++++++------
client/rpcdataset_test.go | 81 ++++++++++++++++++++------
client/session.go | 85 ++++++++-------------------
client/tablet.go | 66 ++++++++++++++-------
client/tablet_test.go | 142 +++++++++++++++++++++++++++++++++++++++++++--
client/utils.go | 66 +++++++++++++++++----
client/utils_test.go | 36 ++++++++++--
example/session_example.go | 4 +-
test/e2e/e2e_test.go | 11 ++--
12 files changed, 551 insertions(+), 172 deletions(-)
diff --git a/client/field.go b/client/field.go
index 3e79445..4643fe6 100644
--- a/client/field.go
+++ b/client/field.go
@@ -19,6 +19,8 @@
package client
+import "time"
+
type Field struct {
dataType TSDataType
name string
@@ -89,6 +91,10 @@ func (f *Field) GetText() string {
return float64ToString(f.value.(float64))
case string:
return f.value.(string)
+ case []byte:
+ return bytesToHexString(f.value.([]byte))
+ case time.Time:
+ return f.value.(time.Time).Format("2006-01-02")
}
return ""
}
diff --git a/client/field_test.go b/client/field_test.go
index 859d8d5..9f49ed6 100644
--- a/client/field_test.go
+++ b/client/field_test.go
@@ -22,6 +22,7 @@ package client
import (
"reflect"
"testing"
+ "time"
)
func TestField_IsNull(t *testing.T) {
@@ -126,6 +127,38 @@ func TestField_GetDataType(t *testing.T) {
value: nil,
},
want: TEXT,
+ }, {
+ name: "GetDataType-STRING",
+ fields: fields{
+ dataType: STRING,
+ name: "",
+ value: nil,
+ },
+ want: STRING,
+ }, {
+ name: "GetDataType-BLOB",
+ fields: fields{
+ dataType: BLOB,
+ name: "",
+ value: nil,
+ },
+ want: BLOB,
+ }, {
+ name: "GetDataType-TIMESTAMP",
+ fields: fields{
+ dataType: TIMESTAMP,
+ name: "",
+ value: nil,
+ },
+ want: TIMESTAMP,
+ }, {
+ name: "GetDataType-DATE",
+ fields: fields{
+ dataType: DATE,
+ name: "",
+ value: nil,
+ },
+ want: DATE,
},
}
for _, tt := range tests {
@@ -201,6 +234,38 @@ func TestField_GetValue(t *testing.T) {
value: "TEXT",
},
want: "TEXT",
+ }, {
+ name: "GetValue-STRING",
+ fields: fields{
+ dataType: STRING,
+ name: "",
+ value: "STRING",
+ },
+ want: "STRING",
+ }, {
+ name: "GetValue-BLOB",
+ fields: fields{
+ dataType: BLOB,
+ name: "",
+ value: []byte("BLOB"),
+ },
+ want: []byte("BLOB"),
+ }, {
+ name: "GetValue-TIMESTAMP",
+ fields: fields{
+ dataType: TIMESTAMP,
+ name: "",
+ value: int64(65535),
+ },
+ want: int64(65535),
+ }, {
+ name: "GetValue-DATE",
+ fields: fields{
+ dataType: DATE,
+ name: "",
+ value: time.Date(2024, time.Month(4), 1, 0,
0, 0, 0, time.UTC),
+ },
+ want: time.Date(2024, time.Month(4), 1, 0, 0, 0, 0,
time.UTC),
},
}
for _, tt := range tests {
@@ -408,6 +473,30 @@ func TestField_GetText(t *testing.T) {
value: int32(1),
},
want: "1",
+ }, {
+ name: "GetText-04",
+ fields: fields{
+ dataType: STRING,
+ name: "",
+ value: "STRING",
+ },
+ want: "STRING",
+ }, {
+ name: "GetText-05",
+ fields: fields{
+ dataType: BLOB,
+ name: "",
+ value: []byte("BLOB"),
+ },
+ want: "0x424c4f42",
+ }, {
+ name: "GetText-06",
+ fields: fields{
+ dataType: DATE,
+ name: "",
+ value: time.Date(2024, time.Month(4), 1, 0,
0, 0, 0, time.UTC),
+ },
+ want: "2024-04-01",
},
}
for _, tt := range tests {
diff --git a/client/protocol.go b/client/protocol.go
index 883f9ae..edc211e 100644
--- a/client/protocol.go
+++ b/client/protocol.go
@@ -26,42 +26,42 @@ type TSEncoding uint8
type TSCompressionType uint8
const (
- UNKNOWN TSDataType = -1
- BOOLEAN TSDataType = 0
- INT32 TSDataType = 1
- INT64 TSDataType = 2
- FLOAT TSDataType = 3
- DOUBLE TSDataType = 4
- TEXT TSDataType = 5
+ UNKNOWN TSDataType = -1
+ BOOLEAN TSDataType = 0
+ INT32 TSDataType = 1
+ INT64 TSDataType = 2
+ FLOAT TSDataType = 3
+ DOUBLE TSDataType = 4
+ TEXT TSDataType = 5
+ TIMESTAMP TSDataType = 8
+ DATE TSDataType = 9
+ BLOB TSDataType = 10
+ STRING TSDataType = 11
)
const (
- PLAIN TSEncoding = 0
- PLAIN_DICTIONARY TSEncoding = 1
- RLE TSEncoding = 2
- DIFF TSEncoding = 3
- TS_2DIFF TSEncoding = 4
- BITMAP TSEncoding = 5
- GORILLA_V1 TSEncoding = 6
- REGULAR TSEncoding = 7
- GORILLA TSEncoding = 8
- ZIGZAG TSEncoding = 9
- FREQ TSEncoding = 10
- CHIMP TSEncoding = 11
- SPRINTZ TSEncoding = 12
- RLBE TSEncoding = 13
+ PLAIN TSEncoding = 0
+ DICTIONARY TSEncoding = 1
+ RLE TSEncoding = 2
+ DIFF TSEncoding = 3
+ TS_2DIFF TSEncoding = 4
+ BITMAP TSEncoding = 5
+ GORILLA_V1 TSEncoding = 6
+ REGULAR TSEncoding = 7
+ GORILLA TSEncoding = 8
+ ZIGZAG TSEncoding = 9
+ FREQ TSEncoding = 10
+ CHIMP TSEncoding = 11
+ SPRINTZ TSEncoding = 12
+ RLBE TSEncoding = 13
)
const (
UNCOMPRESSED TSCompressionType = 0
SNAPPY TSCompressionType = 1
GZIP TSCompressionType = 2
- LZO TSCompressionType = 3
- SDT TSCompressionType = 4
- PAA TSCompressionType = 5
- PLA TSCompressionType = 6
LZ4 TSCompressionType = 7
- ZSTD TSCompressionType = 8
+ ZSTD TSCompressionType = 8
LZMA2 TSCompressionType = 9
)
@@ -201,4 +201,4 @@ const (
CqAlreadyActive int32 = 1401
CqAlreadyExist int32 = 1402
CqUpdateLastExecTimeError int32 = 1403
-)
\ No newline at end of file
+)
diff --git a/client/rpcdataset.go b/client/rpcdataset.go
index 0dd77cd..8477950 100644
--- a/client/rpcdataset.go
+++ b/client/rpcdataset.go
@@ -39,12 +39,16 @@ const (
var (
errClosed error = errors.New("DataSet is Closed")
tsTypeMap map[string]TSDataType = map[string]TSDataType{
- "BOOLEAN": BOOLEAN,
- "INT32": INT32,
- "INT64": INT64,
- "FLOAT": FLOAT,
- "DOUBLE": DOUBLE,
- "TEXT": TEXT,
+ "BOOLEAN": BOOLEAN,
+ "INT32": INT32,
+ "INT64": INT64,
+ "FLOAT": FLOAT,
+ "DOUBLE": DOUBLE,
+ "TEXT": TEXT,
+ "TIMESTAMP": TIMESTAMP,
+ "DATE": DATE,
+ "BLOB": BLOB,
+ "STRING": STRING,
}
)
@@ -116,10 +120,10 @@ func (s *IoTDBRpcDataSet) constructOneRow() error {
case BOOLEAN:
s.values[i] = valueBuffer[:1]
s.queryDataSet.ValueList[i] = valueBuffer[1:]
- case INT32:
+ case INT32, DATE:
s.values[i] = valueBuffer[:4]
s.queryDataSet.ValueList[i] = valueBuffer[4:]
- case INT64:
+ case INT64, TIMESTAMP:
s.values[i] = valueBuffer[:8]
s.queryDataSet.ValueList[i] = valueBuffer[8:]
case FLOAT:
@@ -128,7 +132,7 @@ func (s *IoTDBRpcDataSet) constructOneRow() error {
case DOUBLE:
s.values[i] = valueBuffer[:8]
s.queryDataSet.ValueList[i] = valueBuffer[8:]
- case TEXT:
+ case TEXT, BLOB, STRING:
length := bytesToInt32(valueBuffer[:4])
s.values[i] = valueBuffer[4 : 4+length]
s.queryDataSet.ValueList[i] =
valueBuffer[4+length:]
@@ -178,7 +182,7 @@ func (s *IoTDBRpcDataSet) getString(columnIndex int,
dataType TSDataType) string
return "false"
case INT32:
return int32ToString(bytesToInt32(valueBytes))
- case INT64:
+ case INT64, TIMESTAMP:
return int64ToString(bytesToInt64(valueBytes))
case FLOAT:
bits := binary.BigEndian.Uint32(valueBytes)
@@ -186,8 +190,16 @@ func (s *IoTDBRpcDataSet) getString(columnIndex int,
dataType TSDataType) string
case DOUBLE:
bits := binary.BigEndian.Uint64(valueBytes)
return float64ToString(math.Float64frombits(bits))
- case TEXT:
+ case TEXT, STRING:
return string(valueBytes)
+ case BLOB:
+ return bytesToHexString(valueBytes)
+ case DATE:
+ date, err := bytesToDate(valueBytes)
+ if err != nil {
+ return ""
+ }
+ return date.Format("2006-01-02")
default:
return ""
}
@@ -206,10 +218,10 @@ func (s *IoTDBRpcDataSet) getValue(columnName string)
interface{} {
valueBytes := s.values[columnIndex]
switch dataType {
case BOOLEAN:
- return bool(valueBytes[0] != 0)
+ return valueBytes[0] != 0
case INT32:
return bytesToInt32(valueBytes)
- case INT64:
+ case INT64, TIMESTAMP:
return bytesToInt64(valueBytes)
case FLOAT:
bits := binary.BigEndian.Uint32(valueBytes)
@@ -217,8 +229,16 @@ func (s *IoTDBRpcDataSet) getValue(columnName string)
interface{} {
case DOUBLE:
bits := binary.BigEndian.Uint64(valueBytes)
return math.Float64frombits(bits)
- case TEXT:
+ case TEXT, STRING:
return string(valueBytes)
+ case BLOB:
+ return valueBytes
+ case DATE:
+ date, err := bytesToDate(valueBytes)
+ if err != nil {
+ return nil
+ }
+ return date
default:
return nil
}
@@ -281,7 +301,7 @@ func (s *IoTDBRpcDataSet) scan(dest ...interface{}) error {
case BOOLEAN:
switch t := d.(type) {
case *bool:
- *t = bool(valueBytes[0] != 0)
+ *t = valueBytes[0] != 0
case *string:
if valueBytes[0] != 0 {
*t = "true"
@@ -301,7 +321,7 @@ func (s *IoTDBRpcDataSet) scan(dest ...interface{}) error {
default:
return fmt.Errorf("dest[%d] types must be
*int32 or *string", i)
}
- case INT64:
+ case INT64, TIMESTAMP:
switch t := d.(type) {
case *int64:
*t = bytesToInt64(valueBytes)
@@ -332,12 +352,37 @@ func (s *IoTDBRpcDataSet) scan(dest ...interface{}) error
{
default:
return fmt.Errorf("dest[%d] types must be
*float64 or *string", i)
}
- case TEXT:
+ case TEXT, STRING:
switch t := d.(type) {
+ case *[]byte:
+ *t = valueBytes
case *string:
*t = string(valueBytes)
default:
- return fmt.Errorf("dest[%d] types must be
*string", i)
+ return fmt.Errorf("dest[%d] types must be
*[]byte or *string", i)
+ }
+ case BLOB:
+ switch t := d.(type) {
+ case *[]byte:
+ *t = valueBytes
+ case *string:
+ *t = bytesToHexString(valueBytes)
+ default:
+ return fmt.Errorf("dest[%d] types must be
*[]byte or *string", i)
+ }
+ case DATE:
+ switch t := d.(type) {
+ case *time.Time:
+ *t, _ = bytesToDate(valueBytes)
+ case *string:
+ *t = int32ToString(bytesToInt32(valueBytes))
+ date, err := bytesToDate(valueBytes)
+ if err != nil {
+ *t = ""
+ }
+ *t = date.Format("2006-01-02")
+ default:
+ return fmt.Errorf("dest[%d] types must be
*time.Time or *string", i)
}
default:
return nil
@@ -412,7 +457,7 @@ func (s *IoTDBRpcDataSet) hasCachedResults() bool {
if s.closed {
return false
}
- return (s.queryDataSet != nil && len(s.queryDataSet.Time) > 0)
+ return s.queryDataSet != nil && len(s.queryDataSet.Time) > 0
}
func (s *IoTDBRpcDataSet) next() (bool, error) {
diff --git a/client/rpcdataset_test.go b/client/rpcdataset_test.go
index 4201401..82dd3b0 100644
--- a/client/rpcdataset_test.go
+++ b/client/rpcdataset_test.go
@@ -20,6 +20,7 @@
package client
import (
+ "bytes"
"reflect"
"testing"
"time"
@@ -28,23 +29,49 @@ import (
)
func createIoTDBRpcDataSet() *IoTDBRpcDataSet {
- columns := []string{"root.ln.device1.restart_count",
"root.ln.device1.price", "root.ln.device1.tick_count",
"root.ln.device1.temperature", "root.ln.device1.description",
"root.ln.device1.status"}
- dataTypes := []string{"INT32", "DOUBLE", "INT64", "FLOAT", "TEXT",
"BOOLEAN"}
+ columns := []string{
+ "root.ln.device1.restart_count",
+ "root.ln.device1.price",
+ "root.ln.device1.tick_count",
+ "root.ln.device1.temperature",
+ "root.ln.device1.description",
+ "root.ln.device1.status",
+ "root.ln.device1.description_string",
+ "root.ln.device1.description_blob",
+ "root.ln.device1.date",
+ "root.ln.device1.ts",
+ }
+ dataTypes := []string{"INT32", "DOUBLE", "INT64", "FLOAT", "TEXT",
"BOOLEAN", "STRING", "BLOB", "DATE", "TIMESTAMP"}
columnNameIndex := map[string]int32{
- "root.ln.device1.restart_count": 2,
- "root.ln.device1.price": 1,
- "root.ln.device1.tick_count": 5,
- "root.ln.device1.temperature": 4,
- "root.ln.device1.description": 0,
- "root.ln.device1.status": 3,
+ "root.ln.device1.restart_count": 2,
+ "root.ln.device1.price": 1,
+ "root.ln.device1.tick_count": 5,
+ "root.ln.device1.temperature": 4,
+ "root.ln.device1.description": 0,
+ "root.ln.device1.status": 3,
+ "root.ln.device1.description_string": 6,
+ "root.ln.device1.description_blob": 7,
+ "root.ln.device1.date": 8,
+ "root.ln.device1.ts": 9,
}
var queyrId int64 = 1
var sessionId int64 = 1
var client *rpc.IClientRPCServiceClient = nil
queryDataSet := rpc.TSQueryDataSet{
- Time: []byte{0, 0, 1, 118, 76, 52, 0, 236, 0, 0, 1, 118,
76, 52, 25, 228, 0, 0, 1, 118, 76, 52, 41, 42, 0, 0, 1, 118, 76, 52, 243, 148,
0, 0, 1, 118, 76, 95, 98, 255},
- ValueList: [][]byte{{0, 0, 0, 13, 84, 101, 115, 116, 32, 68,
101, 118, 105, 99, 101, 32, 49, 0, 0, 0, 13, 84, 101, 115, 116, 32, 68, 101,
118, 105, 99, 101, 32, 49, 0, 0, 0, 13, 84, 101, 115, 116, 32, 68, 101, 118,
105, 99, 101, 32, 49, 0, 0, 0, 13, 84, 101, 115, 116, 32, 68, 101, 118, 105,
99, 101, 32, 49, 0, 0, 0, 13, 84, 101, 115, 116, 32, 68, 101, 118, 105, 99,
101, 32, 49}, {64, 159, 16, 204, 204, 204, 204, 205, 64, 159, 16, 204, 204,
204, 204, 205, 64, 159, 16, 204, 204, 204, 20 [...]
- BitmapList: [][]byte{{248}, {248}, {248}, {248}, {248}, {248}},
+ Time: []byte{0, 0, 1, 118, 76, 52, 0, 236, 0, 0, 1, 118, 76,
52, 25, 228, 0, 0, 1, 118, 76, 52, 41, 42, 0, 0, 1, 118, 76, 52, 243, 148, 0,
0, 1, 118, 76, 95, 98, 255},
+ ValueList: [][]byte{
+ {0, 0, 0, 13, 84, 101, 115, 116, 32, 68, 101, 118, 105,
99, 101, 32, 49, 0, 0, 0, 13, 84, 101, 115, 116, 32, 68, 101, 118, 105, 99,
101, 32, 49, 0, 0, 0, 13, 84, 101, 115, 116, 32, 68, 101, 118, 105, 99, 101,
32, 49, 0, 0, 0, 13, 84, 101, 115, 116, 32, 68, 101, 118, 105, 99, 101, 32, 49,
0, 0, 0, 13, 84, 101, 115, 116, 32, 68, 101, 118, 105, 99, 101, 32, 49},
+ {64, 159, 16, 204, 204, 204, 204, 205, 64, 159, 16,
204, 204, 204, 204, 205, 64, 159, 16, 204, 204, 204, 204, 205, 64, 159, 16,
204, 204, 204, 204, 205, 64, 159, 16, 204, 204, 204, 204, 205},
+ {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0,
0, 1},
+ {1, 1, 1, 1, 1},
+ {65, 65, 153, 154, 65, 65, 153, 154, 65, 65, 153, 154,
65, 65, 153, 154, 65, 65, 153, 154},
+ {0, 0, 0, 0, 0, 50, 220, 213, 0, 0, 0, 0, 0, 50, 220,
213, 0, 0, 0, 0, 0, 50, 220, 213, 0, 0, 0, 0, 0, 50, 220, 213, 0, 0, 0, 0, 0,
50, 220, 213},
+ {0, 0, 0, 13, 84, 101, 115, 116, 32, 68, 101, 118, 105,
99, 101, 32, 49, 0, 0, 0, 13, 84, 101, 115, 116, 32, 68, 101, 118, 105, 99,
101, 32, 49, 0, 0, 0, 13, 84, 101, 115, 116, 32, 68, 101, 118, 105, 99, 101,
32, 49, 0, 0, 0, 13, 84, 101, 115, 116, 32, 68, 101, 118, 105, 99, 101, 32, 49,
0, 0, 0, 13, 84, 101, 115, 116, 32, 68, 101, 118, 105, 99, 101, 32, 49},
+ {0, 0, 0, 13, 84, 101, 115, 116, 32, 68, 101, 118, 105,
99, 101, 32, 49, 0, 0, 0, 13, 84, 101, 115, 116, 32, 68, 101, 118, 105, 99,
101, 32, 49, 0, 0, 0, 13, 84, 101, 115, 116, 32, 68, 101, 118, 105, 99, 101,
32, 49, 0, 0, 0, 13, 84, 101, 115, 116, 32, 68, 101, 118, 105, 99, 101, 32, 49,
0, 0, 0, 13, 84, 101, 115, 116, 32, 68, 101, 118, 105, 99, 101, 32, 49},
+ {1, 52, 216, 17, 1, 52, 216, 17, 1, 52, 216, 17, 1, 52,
216, 17, 1, 52, 216, 17},
+ {0, 0, 0, 0, 0, 50, 220, 213, 0, 0, 0, 0, 0, 50, 220,
213, 0, 0, 0, 0, 0, 50, 220, 213, 0, 0, 0, 0, 0, 50, 220, 213, 0, 0, 0, 0, 0,
50, 220, 213},
+ },
+ BitmapList: [][]byte{{248}, {248}, {248}, {248}, {248}, {248},
{248}, {248}, {248}, {248}},
}
return NewIoTDBRpcDataSet("select * from root.ln.device1", columns,
dataTypes, columnNameIndex, queyrId, client, sessionId, &queryDataSet, false,
DefaultFetchSize, nil)
}
@@ -558,11 +585,27 @@ func TestIoTDBRpcDataSet_getRowRecord(t *testing.T) {
}, {
name:
"root.ln.device1.description",
dataType: TEXT,
- value: string("Test Device
1"),
+ value: "Test Device 1",
}, {
name:
"root.ln.device1.status",
dataType: BOOLEAN,
- value: bool(true),
+ value: true,
+ }, {
+ name:
"root.ln.device1.description_string",
+ dataType: STRING,
+ value: "Test Device 1",
+ }, {
+ name:
"root.ln.device1.description_blob",
+ dataType: BLOB,
+ value: []byte("Test Device
1"),
+ }, {
+ name:
"root.ln.device1.date",
+ dataType: DATE,
+ value: time.Date(2024,
time.April, 1, 0, 0, 0, 0, time.UTC),
+ }, {
+ name: "root.ln.device1.ts",
+ dataType: TIMESTAMP,
+ value: int64(3333333),
},
},
},
@@ -583,10 +626,14 @@ func TestIoTDBRpcDataSet_getRowRecord(t *testing.T) {
for i := 0; i < len(got.fields); i++ {
gotField := got.fields[i]
wantField := tt.want.fields[i]
-
- if gotField.dataType != wantField.dataType ||
gotField.name != wantField.name || gotField.value != wantField.value {
- match = false
-
+ if gotField.dataType != BLOB {
+ if gotField.dataType !=
wantField.dataType || gotField.name != wantField.name || gotField.value !=
wantField.value {
+ match = false
+ }
+ } else {
+ if gotField.dataType !=
wantField.dataType || gotField.name != wantField.name ||
!bytes.Equal(gotField.value.([]byte), wantField.value.([]byte)) {
+ match = false
+ }
}
}
if !match {
diff --git a/client/session.go b/client/session.go
index 47985f8..288faf0 100644
--- a/client/session.go
+++ b/client/session.go
@@ -90,9 +90,6 @@ func (s *Session) Open(enableRPCCompression bool,
connectionTimeoutInMs int) err
s.trans = thrift.NewTSocketConf(net.JoinHostPort(s.config.Host,
s.config.Port), &thrift.TConfiguration{
ConnectTimeout: time.Duration(connectionTimeoutInMs) *
time.Millisecond, // Use 0 for no timeout
})
- if err != nil {
- return err
- }
// s.trans = thrift.NewTFramedTransport(s.trans) // deprecated
var tmp_conf = thrift.TConfiguration{MaxFrameSize:
thrift.DEFAULT_MAX_FRAME_SIZE}
s.trans = thrift.NewTFramedTransportConf(s.trans, &tmp_conf)
@@ -951,7 +948,7 @@ func valuesToBytes(dataTypes []TSDataType, values
[]interface{}) ([]byte, error)
default:
return nil, fmt.Errorf("values[%d] %v(%v) must
be int32", i, v, reflect.TypeOf(v))
}
- case INT64:
+ case INT64, TIMESTAMP:
switch v.(type) {
case int64:
binary.Write(buff, binary.BigEndian, v)
@@ -972,77 +969,41 @@ func valuesToBytes(dataTypes []TSDataType, values
[]interface{}) ([]byte, error)
default:
return nil, fmt.Errorf("values[%d] %v(%v) must
be float64", i, v, reflect.TypeOf(v))
}
- case TEXT:
+ case TEXT, STRING:
switch s := v.(type) {
case string:
size := len(s)
binary.Write(buff, binary.BigEndian,
int32(size))
binary.Write(buff, binary.BigEndian, []byte(s))
+ case []byte:
+ size := len(s)
+ binary.Write(buff, binary.BigEndian,
int32(size))
+ binary.Write(buff, binary.BigEndian, s)
default:
- return nil, fmt.Errorf("values[%d] %v(%v) must
be string", i, v, reflect.TypeOf(v))
- }
- default:
- return nil, fmt.Errorf("types[%d] is incorrect, it must
in (BOOLEAN, INT32, INT64, FLOAT, DOUBLE, TEXT)", i)
- }
- }
- return buff.Bytes(), nil
-}
-
-func valuesToBytesForFast(dataTypes []TSDataType, values []interface{})
([]byte, error) {
- buff := &bytes.Buffer{}
- for i, t := range dataTypes {
- v := values[i]
- if v == nil {
- return nil, fmt.Errorf("values[%d] can't be nil", i)
- }
-
- switch t {
- case BOOLEAN:
- switch v.(type) {
- case bool:
- binary.Write(buff, binary.BigEndian, v)
- default:
- return nil, fmt.Errorf("values[%d] %v(%v) must
be bool", i, v, reflect.TypeOf(v))
- }
- case INT32:
- switch v.(type) {
- case int32:
- binary.Write(buff, binary.BigEndian, v)
- default:
- return nil, fmt.Errorf("values[%d] %v(%v) must
be int32", i, v, reflect.TypeOf(v))
- }
- case INT64:
- switch v.(type) {
- case int64:
- binary.Write(buff, binary.BigEndian, v)
- default:
- return nil, fmt.Errorf("values[%d] %v(%v) must
be int64", i, v, reflect.TypeOf(v))
- }
- case FLOAT:
- switch v.(type) {
- case float32:
- binary.Write(buff, binary.BigEndian, v)
- default:
- return nil, fmt.Errorf("values[%d] %v(%v) must
be float32", i, v, reflect.TypeOf(v))
- }
- case DOUBLE:
- switch v.(type) {
- case float64:
- binary.Write(buff, binary.BigEndian, v)
- default:
- return nil, fmt.Errorf("values[%d] %v(%v) must
be float64", i, v, reflect.TypeOf(v))
+ return nil, fmt.Errorf("values[%d] %v(%v) must
be string or []byte", i, v, reflect.TypeOf(v))
}
- case TEXT:
+ case BLOB:
switch s := v.(type) {
- case string:
+ case []byte:
size := len(s)
binary.Write(buff, binary.BigEndian,
int32(size))
- binary.Write(buff, binary.BigEndian, []byte(s))
+ binary.Write(buff, binary.BigEndian, s)
+ default:
+ return nil, fmt.Errorf("values[%d] %v(%v) must
be []byte", i, v, reflect.TypeOf(v))
+ }
+ case DATE:
+ switch s := v.(type) {
+ case time.Time:
+ date, err := dateToInt32(s)
+ if err != nil {
+ return nil, err
+ }
+ binary.Write(buff, binary.BigEndian, date)
default:
- return nil, fmt.Errorf("values[%d] %v(%v) must
be string", i, v, reflect.TypeOf(v))
+ return nil, fmt.Errorf("values[%d] %v(%v) must
be time.Time", i, v, reflect.TypeOf(v))
}
default:
- return nil, fmt.Errorf("types[%d] is incorrect, it must
in (BOOLEAN, INT32, INT64, FLOAT, DOUBLE, TEXT)", i)
+ return nil, fmt.Errorf("types[%d] is incorrect, it must
in (BOOLEAN, INT32, INT64, FLOAT, DOUBLE, TEXT, TIMESTAMP, BLOB, DATE,
STRING)", i)
}
}
return buff.Bytes(), nil
diff --git a/client/tablet.go b/client/tablet.go
index ff4ef57..e5d7daa 100644
--- a/client/tablet.go
+++ b/client/tablet.go
@@ -25,6 +25,7 @@ import (
"fmt"
"reflect"
"sort"
+ "time"
)
type MeasurementSchema struct {
@@ -52,10 +53,10 @@ func (t *Tablet) Swap(i, j int) {
case BOOLEAN:
sortedSlice := t.values[index].([]bool)
sortedSlice[i], sortedSlice[j] = sortedSlice[j],
sortedSlice[i]
- case INT32:
+ case INT32, DATE:
sortedSlice := t.values[index].([]int32)
sortedSlice[i], sortedSlice[j] = sortedSlice[j],
sortedSlice[i]
- case INT64:
+ case INT64, TIMESTAMP:
sortedSlice := t.values[index].([]int64)
sortedSlice[i], sortedSlice[j] = sortedSlice[j],
sortedSlice[i]
case FLOAT:
@@ -64,8 +65,8 @@ func (t *Tablet) Swap(i, j int) {
case DOUBLE:
sortedSlice := t.values[index].([]float64)
sortedSlice[i], sortedSlice[j] = sortedSlice[j],
sortedSlice[i]
- case TEXT:
- sortedSlice := t.values[index].([]string)
+ case TEXT, BLOB, STRING:
+ sortedSlice := t.values[index].([][]byte)
sortedSlice[i], sortedSlice[j] = sortedSlice[j],
sortedSlice[i]
}
}
@@ -141,7 +142,7 @@ func (t *Tablet) SetValueAt(value interface{}, columnIndex,
rowIndex int) error
default:
return fmt.Errorf("illegal argument value %v %v",
value, reflect.TypeOf(value))
}
- case INT64:
+ case INT64, TIMESTAMP:
values := t.values[columnIndex].([]int64)
switch v := value.(type) {
case int64:
@@ -171,13 +172,33 @@ func (t *Tablet) SetValueAt(value interface{},
columnIndex, rowIndex int) error
default:
return fmt.Errorf("illegal argument value %v %v",
value, reflect.TypeOf(value))
}
- case TEXT:
- values := t.values[columnIndex].([]string)
+ case TEXT, STRING:
+ values := t.values[columnIndex].([][]byte)
switch v := value.(type) {
case string:
+ values[rowIndex] = []byte(v)
+ case []byte:
values[rowIndex] = v
+ default:
+ return fmt.Errorf("illegal argument value %v %v",
value, reflect.TypeOf(value))
+ }
+ case BLOB:
+ values := t.values[columnIndex].([][]byte)
+ switch v := value.(type) {
case []byte:
- values[rowIndex] = string(v)
+ values[rowIndex] = v
+ default:
+ return fmt.Errorf("illegal argument value %v %v",
value, reflect.TypeOf(value))
+ }
+ case DATE:
+ values := t.values[columnIndex].([]int32)
+ switch v := value.(type) {
+ case time.Time:
+ val, err := dateToInt32(v)
+ if err != nil {
+ return err
+ }
+ values[rowIndex] = val
default:
return fmt.Errorf("illegal argument value %v %v",
value, reflect.TypeOf(value))
}
@@ -194,7 +215,6 @@ func (t *Tablet) GetValueAt(columnIndex, rowIndex int)
(interface{}, error) {
return nil, fmt.Errorf("illegal argument columnIndex %d",
columnIndex)
}
-
if rowIndex < 0 || rowIndex > t.maxRowNumber {
return nil, fmt.Errorf("illegal argument rowIndex %d", rowIndex)
}
@@ -209,14 +229,18 @@ func (t *Tablet) GetValueAt(columnIndex, rowIndex int)
(interface{}, error) {
return t.values[columnIndex].([]bool)[rowIndex], nil
case INT32:
return t.values[columnIndex].([]int32)[rowIndex], nil
- case INT64:
+ case INT64, TIMESTAMP:
return t.values[columnIndex].([]int64)[rowIndex], nil
case FLOAT:
return t.values[columnIndex].([]float32)[rowIndex], nil
case DOUBLE:
return t.values[columnIndex].([]float64)[rowIndex], nil
- case TEXT:
- return t.values[columnIndex].([]string)[rowIndex], nil
+ case TEXT, STRING:
+ return string(t.values[columnIndex].([][]byte)[rowIndex]), nil
+ case BLOB:
+ return t.values[columnIndex].([][]byte)[rowIndex], nil
+ case DATE:
+ return int32ToDate(t.values[columnIndex].([]int32)[rowIndex])
default:
return nil, fmt.Errorf("illegal datatype %v", schema.DataType)
}
@@ -250,18 +274,18 @@ func (t *Tablet) getValuesBytes() ([]byte, error) {
switch schema.DataType {
case BOOLEAN:
binary.Write(buff, binary.BigEndian,
t.values[i].([]bool)[0:t.RowSize])
- case INT32:
+ case INT32, DATE:
binary.Write(buff, binary.BigEndian,
t.values[i].([]int32)[0:t.RowSize])
- case INT64:
+ case INT64, TIMESTAMP:
binary.Write(buff, binary.BigEndian,
t.values[i].([]int64)[0:t.RowSize])
case FLOAT:
binary.Write(buff, binary.BigEndian,
t.values[i].([]float32)[0:t.RowSize])
case DOUBLE:
binary.Write(buff, binary.BigEndian,
t.values[i].([]float64)[0:t.RowSize])
- case TEXT:
- for _, s := range t.values[i].([]string)[0:t.RowSize] {
+ case TEXT, STRING, BLOB:
+ for _, s := range t.values[i].([][]byte)[0:t.RowSize] {
binary.Write(buff, binary.BigEndian,
int32(len(s)))
- binary.Write(buff, binary.BigEndian, []byte(s))
+ binary.Write(buff, binary.BigEndian, s)
}
default:
return nil, fmt.Errorf("illegal datatype %v",
schema.DataType)
@@ -301,16 +325,16 @@ func NewTablet(deviceId string, measurementSchemas
[]*MeasurementSchema, maxRowN
switch schema.DataType {
case BOOLEAN:
tablet.values[i] = make([]bool, maxRowNumber)
- case INT32:
+ case INT32, DATE:
tablet.values[i] = make([]int32, maxRowNumber)
- case INT64:
+ case INT64, TIMESTAMP:
tablet.values[i] = make([]int64, maxRowNumber)
case FLOAT:
tablet.values[i] = make([]float32, maxRowNumber)
case DOUBLE:
tablet.values[i] = make([]float64, maxRowNumber)
- case TEXT:
- tablet.values[i] = make([]string, maxRowNumber)
+ case TEXT, STRING, BLOB:
+ tablet.values[i] = make([][]byte, maxRowNumber)
default:
return nil, fmt.Errorf("illegal datatype %v",
schema.DataType)
}
diff --git a/client/tablet_test.go b/client/tablet_test.go
index 1b7579b..e4ecb73 100644
--- a/client/tablet_test.go
+++ b/client/tablet_test.go
@@ -22,6 +22,7 @@ package client
import (
"reflect"
"testing"
+ "time"
)
func createTablet(size int) (*Tablet, error) {
@@ -46,6 +47,22 @@ func createTablet(size int) (*Tablet, error) {
Measurement: "status",
DataType: BOOLEAN,
},
+ {
+ Measurement: "description_string",
+ DataType: STRING,
+ },
+ {
+ Measurement: "description_blob",
+ DataType: BLOB,
+ },
+ {
+ Measurement: "date",
+ DataType: DATE,
+ },
+ {
+ Measurement: "ts",
+ DataType: TIMESTAMP,
+ },
}, size)
return tablet, err
}
@@ -83,17 +100,28 @@ func TestTablet_getDataTypes(t *testing.T) {
}, {
Measurement: "description",
DataType: TEXT,
- },
- {
+ }, {
Measurement: "status",
DataType: BOOLEAN,
+ }, {
+ Measurement:
"description_string",
+ DataType: STRING,
+ }, {
+ Measurement: "description_blob",
+ DataType: BLOB,
+ }, {
+ Measurement: "date",
+ DataType: DATE,
+ }, {
+ Measurement: "ts",
+ DataType: TIMESTAMP,
},
},
timestamps: []int64{},
values: []interface{}{},
rowCount: 0,
},
- want: []int32{int32(INT32), int32(DOUBLE),
int32(INT64), int32(FLOAT), int32(TEXT), int32(BOOLEAN)},
+ want: []int32{int32(INT32), int32(DOUBLE),
int32(INT64), int32(FLOAT), int32(TEXT), int32(BOOLEAN), int32(STRING),
int32(BLOB), int32(DATE), int32(TIMESTAMP)},
},
}
for _, tt := range tests {
@@ -244,6 +272,38 @@ func TestTablet_SetValueAt(t *testing.T) {
rowIndex: 0,
},
wantErr: false,
+ }, {
+ name: "description_string",
+ args: args{
+ value: "Hello world!",
+ columnIndex: 6,
+ rowIndex: 0,
+ },
+ wantErr: false,
+ }, {
+ name: "description_blob",
+ args: args{
+ value: []byte("Hello world!"),
+ columnIndex: 7,
+ rowIndex: 0,
+ },
+ wantErr: false,
+ }, {
+ name: "date",
+ args: args{
+ value: time.Date(2024, time.April, 1, 0,
0, 0, 0, time.UTC),
+ columnIndex: 8,
+ rowIndex: 0,
+ },
+ wantErr: false,
+ }, {
+ name: "ts",
+ args: args{
+ value: int64(1608268702780),
+ columnIndex: 9,
+ rowIndex: 0,
+ },
+ wantErr: false,
},
}
for _, tt := range tests {
@@ -303,7 +363,7 @@ func TestTablet_GetValueAt(t *testing.T) {
want: float32(36.5),
wantErr: false,
}, {
- name: "STRING",
+ name: "TEXT",
args: args{
columnIndex: 4,
rowIndex: 0,
@@ -318,15 +378,51 @@ func TestTablet_GetValueAt(t *testing.T) {
},
want: true,
wantErr: false,
+ }, {
+ name: "TEXT",
+ args: args{
+ columnIndex: 6,
+ rowIndex: 0,
+ },
+ want: "Hello World!",
+ wantErr: false,
+ }, {
+ name: "BLOB",
+ args: args{
+ columnIndex: 7,
+ rowIndex: 0,
+ },
+ want: []byte("Hello World!"),
+ wantErr: false,
+ }, {
+ name: "DATE",
+ args: args{
+ columnIndex: 8,
+ rowIndex: 0,
+ },
+ want: time.Date(2024, time.April, 1, 0, 0, 0, 0,
time.UTC),
+ wantErr: false,
+ }, {
+ name: "TIMESTAMP",
+ args: args{
+ columnIndex: 9,
+ rowIndex: 0,
+ },
+ want: int64(1608268702780),
+ wantErr: false,
},
}
if tablet, err := createTablet(1); err == nil {
tablet.SetValueAt(int32(256), 0, 0)
- tablet.SetValueAt(float64(32.768), 1, 0)
+ tablet.SetValueAt(32.768, 1, 0)
tablet.SetValueAt(int64(65535), 2, 0)
tablet.SetValueAt(float32(36.5), 3, 0)
tablet.SetValueAt("Hello World!", 4, 0)
tablet.SetValueAt(true, 5, 0)
+ tablet.SetValueAt("Hello World!", 6, 0)
+ tablet.SetValueAt([]byte("Hello World!"), 7, 0)
+ tablet.SetValueAt(time.Date(2024, time.April, 1, 0, 0, 0, 0,
time.UTC), 8, 0)
+ tablet.SetValueAt(int64(1608268702780), 9, 0)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err :=
tablet.GetValueAt(tt.args.columnIndex, tt.args.rowIndex)
@@ -401,6 +497,38 @@ func TestTablet_GetNilValueAt(t *testing.T) {
},
want: true,
wantErr: false,
+ }, {
+ name: "STRING",
+ args: args{
+ columnIndex: 6,
+ rowIndex: 0,
+ },
+ want: nil,
+ wantErr: false,
+ }, {
+ name: "BLOB",
+ args: args{
+ columnIndex: 7,
+ rowIndex: 0,
+ },
+ want: nil,
+ wantErr: false,
+ }, {
+ name: "DATE",
+ args: args{
+ columnIndex: 8,
+ rowIndex: 0,
+ },
+ want: nil,
+ wantErr: false,
+ }, {
+ name: "TIMESTAMP",
+ args: args{
+ columnIndex: 9,
+ rowIndex: 0,
+ },
+ want: nil,
+ wantErr: false,
},
}
if tablet, err := createTablet(1); err == nil {
@@ -410,6 +538,10 @@ func TestTablet_GetNilValueAt(t *testing.T) {
tablet.SetValueAt(float32(36.5), 3, 0)
tablet.SetValueAt("Hello World!", 4, 0)
tablet.SetValueAt(true, 5, 0)
+ tablet.SetValueAt(nil, 6, 0)
+ tablet.SetValueAt(nil, 7, 0)
+ tablet.SetValueAt(nil, 8, 0)
+ tablet.SetValueAt(nil, 9, 0)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err :=
tablet.GetValueAt(tt.args.columnIndex, tt.args.rowIndex)
diff --git a/client/utils.go b/client/utils.go
index f3c465b..692e9a5 100644
--- a/client/utils.go
+++ b/client/utils.go
@@ -22,9 +22,11 @@ package client
import (
"bytes"
"encoding/binary"
+ "errors"
"fmt"
"github.com/apache/iotdb-client-go/common"
"strconv"
+ "time"
)
func int32ToString(n int32) string {
@@ -56,17 +58,61 @@ func int64ToBytes(n int64) []byte {
}
func bytesToInt32(bys []byte) int32 {
- bytebuff := bytes.NewBuffer(bys)
+ bytesBuffer := bytes.NewBuffer(bys)
var data int32
- binary.Read(bytebuff, binary.BigEndian, &data)
- return int32(data)
+ binary.Read(bytesBuffer, binary.BigEndian, &data)
+ return data
}
func bytesToInt64(bys []byte) int64 {
- bytebuff := bytes.NewBuffer(bys)
+ bytesBuffer := bytes.NewBuffer(bys)
var data int64
- binary.Read(bytebuff, binary.BigEndian, &data)
- return int64(data)
+ binary.Read(bytesBuffer, binary.BigEndian, &data)
+ return data
+}
+
+func bytesToHexString(input []byte) string {
+ hexString := "0x"
+ if input != nil {
+ for _, b := range input {
+ hexString += fmt.Sprintf("%02x", b)
+ }
+ }
+ return hexString
+}
+
+func dateToInt32(localDate time.Time) (int32, error) {
+ if localDate.IsZero() {
+ return 0, errors.New("date expression is null or empty")
+ }
+
+ year := localDate.Year()
+ if year < 1000 || year > 9999 {
+ return 0, errors.New("year must be between 1000 and 9999")
+ }
+
+ // Convert to YYYY/MM/DD format
+ result := year*10000 + int(localDate.Month())*100 + localDate.Day()
+ return int32(result), nil
+}
+
+func int32ToDate(val int32) (time.Time, error) {
+ date := int(val)
+ year := date / 10000
+ month := (date / 100) % 100
+ day := date % 100
+
+ localDate := time.Date(year, time.Month(month), day, 0, 0, 0, 0,
time.UTC)
+
+ if localDate.Year() != year || int(localDate.Month()) != month ||
localDate.Day() != day {
+ return time.Time{}, errors.New("invalid date format")
+ }
+
+ return localDate, nil
+}
+
+func bytesToDate(bys []byte) (time.Time, error) {
+ return int32ToDate(bytesToInt32(bys))
}
func verifySuccesses(statuses []*common.TSStatus) error {
@@ -76,8 +122,8 @@ func verifySuccesses(statuses []*common.TSStatus) error {
buff.WriteString(*status.Message + ";")
}
}
- errMsgs := buff.String()
- if len(errMsgs) > 0 {
+ errMsg := buff.String()
+ if len(errMsg) > 0 {
return NewBatchError(statuses)
}
return nil
@@ -96,9 +142,9 @@ func VerifySuccess(status *common.TSStatus) error {
}
if status.Code != SuccessStatus {
if status.Message != nil {
- return fmt.Errorf("Error Code: %d, Message: %v",
status.Code, *status.Message)
+ return fmt.Errorf("error code: %d, message: %v",
status.Code, *status.Message)
} else {
- return fmt.Errorf("Error Code: %d", status.Code)
+ return fmt.Errorf("error code: %d", status.Code)
}
}
return nil
diff --git a/client/utils_test.go b/client/utils_test.go
index f59a34b..00a8915 100644
--- a/client/utils_test.go
+++ b/client/utils_test.go
@@ -164,7 +164,7 @@ func Test_float64ToString(t *testing.T) {
want string
}{
{
- name: "Test Flota64",
+ name: "Test Float64",
args: args{
val: 0.39751212862981283,
},
@@ -180,11 +180,37 @@ func Test_float64ToString(t *testing.T) {
}
}
+func Test_bytesToHexString(t *testing.T) {
+ type args struct {
+ val []byte
+ }
+ tests := []struct {
+ name string
+ args args
+ want string
+ }{
+ {
+ name: "Test bytes",
+ args: args{
+ val: []byte("bytes"),
+ },
+ want: "0x6279746573",
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if got := bytesToHexString(tt.args.val); got != tt.want
{
+ t.Errorf("bytesToHexString() = %v, want %v",
got, tt.want)
+ }
+ })
+ }
+}
+
func Test_verifySuccess(t *testing.T) {
type args struct {
status *common.TSStatus
}
- var errMsg string = "error occurred"
+ var errMsg = "error occurred"
tests := []struct {
name string
args args
@@ -250,9 +276,9 @@ func Test_verifySuccesses(t *testing.T) {
type args struct {
statuses []*common.TSStatus
}
- var internalServerError string = "InternalServerError"
- var success string = "Success"
- var redirectionRecommend string = "RedirectionRecommend"
+ var internalServerError = "InternalServerError"
+ var success = "Success"
+ var redirectionRecommend = "RedirectionRecommend"
tests := []struct {
name string
args args
diff --git a/example/session_example.go b/example/session_example.go
index fbfba4f..4777486 100644
--- a/example/session_example.go
+++ b/example/session_example.go
@@ -227,13 +227,13 @@ func printDataSet0(sessionDataSet *client.SessionDataSet)
{
fmt.Print(sessionDataSet.GetBool(columnName))
case client.INT32:
fmt.Print(sessionDataSet.GetInt32(columnName))
- case client.INT64:
+ case client.INT64, client.TIMESTAMP:
fmt.Print(sessionDataSet.GetInt64(columnName))
case client.FLOAT:
fmt.Print(sessionDataSet.GetFloat(columnName))
case client.DOUBLE:
fmt.Print(sessionDataSet.GetDouble(columnName))
- case client.TEXT:
+ case client.TEXT, client.STRING, client.BLOB,
client.DATE:
fmt.Print(sessionDataSet.GetText(columnName))
default:
}
diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go
index c7a971e..fd50245 100644
--- a/test/e2e/e2e_test.go
+++ b/test/e2e/e2e_test.go
@@ -171,7 +171,7 @@ func (s *e2eTestSuite) Test_InsertAlignedRecords() {
var (
deviceIds = []string{"root.al1.dev2", "root.al1.dev3"}
measurements = [][]string{{"status"}, {"temperature"}}
- dataTypes = [][]client.TSDataType{{client.TEXT},
{client.TEXT}}
+ dataTypes = [][]client.TSDataType{{client.TEXT},
{client.STRING}}
values = [][]interface{}{{"33"}, {"44"}}
timestamps = []int64{12, 13}
)
@@ -193,26 +193,29 @@ func (s *e2eTestSuite)
Test_InsertAlignedRecordsOfOneDevice() {
measurementsSlice = [][]string{
{"restart_count", "tick_count", "price"},
{"temperature", "description", "status"},
+ {"description_blob", "date", "ts"},
}
dataTypes = [][]client.TSDataType{
{client.INT32, client.INT64, client.DOUBLE},
{client.FLOAT, client.TEXT, client.BOOLEAN},
+ {client.BLOB, client.DATE, client.TIMESTAMP},
}
values = [][]interface{}{
{int32(1), int64(2018), float64(1988.1)},
{float32(12.1), "Test Device 1", false},
+ {[]byte("Test Device 1"), time.Date(2024,
time.Month(4), 1, 0, 0, 0, 0, time.UTC), ts},
}
- timestamps = []int64{ts, ts - 1}
+ timestamps = []int64{ts, ts - 1, ts - 2}
)
s.checkError(s.session.InsertAlignedRecordsOfOneDevice(deviceId,
timestamps, measurementsSlice, dataTypes, values, false))
- ds, err := s.session.ExecuteStatement("select temperature from
root.al1.dev4")
+ ds, err := s.session.ExecuteStatement("select * from root.al1.dev4")
assert := s.Require()
assert.NoError(err)
defer ds.Close()
assert.True(ds.Next())
var status string
assert.NoError(ds.Scan(&status))
- assert.Equal(status, "12.1")
+ assert.Equal(status, "2024-04-01")
}
func (s *e2eTestSuite) Test_InsertAlignedTablet() {
var timeseries = []string{"root.ln.device1.**"}