From fc147a98588180ea98970bcf5d129a7f6aa47d36 Mon Sep 17 00:00:00 2001 From: shuwenwei Date: Mon, 24 Mar 2025 15:44:57 +0800 Subject: [PATCH 01/16] add tsblock --- client/column.go | 821 +++++++++++++++++++++++++++++++++ client/column_encoder.go | 298 ++++++++++++ client/protocol.go | 48 ++ client/rpcdataset.go | 924 +++++++++++++++++--------------------- client/rpcdataset_test.go | 666 --------------------------- client/session.go | 22 +- client/sessiondataset.go | 128 +++--- client/tsblock.go | 162 +++++++ client/utils.go | 12 + test/e2e/e2e_test.go | 2 +- 10 files changed, 1825 insertions(+), 1258 deletions(-) create mode 100644 client/column.go create mode 100644 client/column_encoder.go delete mode 100644 client/rpcdataset_test.go create mode 100644 client/tsblock.go diff --git a/client/column.go b/client/column.go new file mode 100644 index 0000000..962714f --- /dev/null +++ b/client/column.go @@ -0,0 +1,821 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package client + +import "fmt" + +type ColumnEncoding uint8 + +const ( + BYTE_ARRAY_COLUMN_ENCODING = ColumnEncoding(iota) + INT32_ARRAY_COLUMN_ENCODING + INT64_ARRAY_COLUMN_ENCODING + BINARY_ARRAY_COLUMN_ENCODING + RLE_COLUMN_ENCODING +) + +var encodingToDecoder = map[ColumnEncoding]ColumnDecoder{ + INT32_ARRAY_COLUMN_ENCODING: new(Int32ArrayColumnDecoder), + INT64_ARRAY_COLUMN_ENCODING: new(Int64ArrayColumnDecoder), + BYTE_ARRAY_COLUMN_ENCODING: new(ByteArrayColumnDecoder), + BINARY_ARRAY_COLUMN_ENCODING: new(BinaryArrayColumnDecoder), + RLE_COLUMN_ENCODING: new(RunLengthColumnDecoder), +} + +var byteToEncoding = map[byte]ColumnEncoding{ + 0: INT32_ARRAY_COLUMN_ENCODING, + 1: INT32_ARRAY_COLUMN_ENCODING, + 2: INT64_ARRAY_COLUMN_ENCODING, + 3: BINARY_ARRAY_COLUMN_ENCODING, + 4: RLE_COLUMN_ENCODING, +} + +func getColumnDecoder(encoding ColumnEncoding) (ColumnDecoder, error) { + decoder, exists := encodingToDecoder[encoding] + if !exists { + return nil, fmt.Errorf("unsupported column encoding: %v", encoding) + } + return decoder, nil +} + +func getColumnEncodingByByte(b byte) (ColumnEncoding, error) { + encoding, exists := byteToEncoding[b] + if !exists { + return INT32_ARRAY_COLUMN_ENCODING, fmt.Errorf("invalid value: %v", b) + } + return encoding, nil +} + +type Column interface { + GetDataType() TSDataType + GetEncoding() ColumnEncoding + GetBoolean(position int32) (bool, error) + GetInt(position int32) (int32, error) + GetLong(position int32) (int64, error) + GetFloat(position int32) (float32, error) + GetDouble(position int32) (float64, error) + GetBinary(position int32) (*Binary, error) + GetObject(position int32) (interface{}, error) + + GetBooleans() ([]bool, error) + GetInts() ([]int32, error) + GetLongs() ([]int64, error) + GetFloats() ([]float32, error) + GetDoubles() ([]float64, error) + GetBinaries() ([]*Binary, error) + GetObjects() ([]interface{}, error) + + MayHaveNull() bool + IsNull(position int32) bool + IsNulls() []bool + + GetPositionCount() int32 +} + +type baseColumn struct { +} + +func (c *baseColumn) GetBoolean(position int32) (bool, error) { + return false, fmt.Errorf("unsupported operation: GetBoolean") +} + +func (c *baseColumn) GetInt(position int32) (int32, error) { + return 0, fmt.Errorf("unsupported operation: GetInt") +} + +func (c *baseColumn) GetLong(position int32) (int64, error) { + return 0, fmt.Errorf("unsupported operation: GetLong") +} + +func (c *baseColumn) GetFloat(position int32) (float32, error) { + return 0, fmt.Errorf("unsupported operation: GetFloat") +} + +func (c *baseColumn) GetDouble(position int32) (float64, error) { + return 0, fmt.Errorf("unsupported operation: GetDouble") +} + +func (c *baseColumn) GetBinary(position int32) (*Binary, error) { + return nil, fmt.Errorf("unsupported operation: GetBinary") +} + +func (c *baseColumn) GetObject(position int32) (interface{}, error) { + return nil, fmt.Errorf("unsupported operation: GetObject") +} + +func (c *baseColumn) GetBooleans() ([]bool, error) { + return nil, fmt.Errorf("unsupported operation: GetBooleans") +} + +func (c *baseColumn) GetInts() ([]int32, error) { + return nil, fmt.Errorf("unsupported operation: GetInts") +} + +func (c *baseColumn) GetLongs() ([]int64, error) { + return nil, fmt.Errorf("unsupported operation: GetLongs") +} + +func (c *baseColumn) GetFloats() ([]float32, error) { + return nil, fmt.Errorf("unsupported operation: GetFloats") +} + +func (c *baseColumn) GetDoubles() ([]float64, error) { + return nil, fmt.Errorf("unsupported operation: GetDoubles") +} + +func (c *baseColumn) GetBinaries() ([]*Binary, error) { + return nil, fmt.Errorf("unsupported operation: GetBinaries") +} + +func (c *baseColumn) GetObjects() ([]interface{}, error) { + return nil, fmt.Errorf("unsupported operation: GetObjects") +} + +type TimeColumn struct { + baseColumn + arrayOffset int32 + positionCount int32 + values []int64 +} + +func NewTimeColumn(arrayOffset int32, positionCount int32, values []int64) (*TimeColumn, error) { + if arrayOffset < 0 { + return nil, fmt.Errorf("arrayOffset is negative") + } + if positionCount < 0 { + return nil, fmt.Errorf("arrayOffset is negative") + } + if int32(len(values))-arrayOffset < positionCount { + return nil, fmt.Errorf("values length is less than positionCount") + } + return &TimeColumn{ + arrayOffset: arrayOffset, + positionCount: positionCount, + values: values, + }, nil +} + +func (tc *TimeColumn) GetDataType() TSDataType { + return INT64 +} + +func (tc *TimeColumn) GetEncoding() ColumnEncoding { + return INT64_ARRAY_COLUMN_ENCODING +} + +func (tc *TimeColumn) GetLong(position int32) (int64, error) { + return tc.values[position+tc.arrayOffset], nil +} + +func (tc *TimeColumn) MayHaveNull() bool { + return false +} + +func (tc *TimeColumn) IsNull(position int32) bool { + return false +} + +func (tc *TimeColumn) IsNulls() []bool { + return nil +} + +func (tc *TimeColumn) GetPositionCount() int32 { + return tc.positionCount +} + +func (tc *TimeColumn) GetStartTime() int64 { + return tc.values[tc.arrayOffset] +} + +func (tc *TimeColumn) GetEndTime() int64 { + return tc.values[tc.positionCount+tc.arrayOffset-1] +} + +func (tc *TimeColumn) GetTimes() []int64 { + return tc.values +} + +func (tc *TimeColumn) GetLongs() ([]int64, error) { + return tc.GetTimes(), nil +} + +type BinaryColumn struct { + baseColumn + arrayOffset int32 + positionCount int32 + valueIsNull []bool + values []*Binary +} + +func NewBinaryColumn(arrayOffset int32, positionCount int32, valueIsNull []bool, values []*Binary) (*BinaryColumn, error) { + if arrayOffset < 0 { + return nil, fmt.Errorf("arrayOffset is negative") + } + if positionCount < 0 { + return nil, fmt.Errorf("positionCount is negative") + } + if int32(len(values))-arrayOffset < positionCount { + return nil, fmt.Errorf("values length is less than positionCount") + } + if valueIsNull != nil && int32(len(valueIsNull))-arrayOffset < positionCount { + return nil, fmt.Errorf("isNull length is less than positionCount") + } + return &BinaryColumn{ + arrayOffset: arrayOffset, + positionCount: positionCount, + valueIsNull: valueIsNull, + values: values, + }, nil +} + +func (c *BinaryColumn) GetDataType() TSDataType { + return TEXT +} + +func (c *BinaryColumn) GetEncoding() ColumnEncoding { + return BINARY_ARRAY_COLUMN_ENCODING +} + +func (c *BinaryColumn) GetBinary(position int32) (*Binary, error) { + return c.values[position+c.arrayOffset], nil +} + +func (c *BinaryColumn) GetBinaries() ([]*Binary, error) { + return c.values, nil +} + +func (c *BinaryColumn) GetObject(position int32) (interface{}, error) { + return c.GetBinary(position) +} + +func (c *BinaryColumn) MayHaveNull() bool { + return c.valueIsNull != nil +} + +func (c *BinaryColumn) IsNull(position int32) bool { + return c.valueIsNull != nil && c.valueIsNull[position+c.arrayOffset] +} + +func (c *BinaryColumn) IsNulls() []bool { + if c.valueIsNull != nil { + return c.valueIsNull + } + result := make([]bool, c.positionCount) + for i := int32(0); i < c.positionCount; i++ { + result[i] = false + } + return result +} + +func (c *BinaryColumn) GetPositionCount() int32 { + return c.positionCount +} + +type IntColumn struct { + baseColumn + arrayOffset int32 + positionCount int32 + valueIsNull []bool + values []int32 +} + +func NewIntColumn(arrayOffset int32, positionCount int32, valueIsNull []bool, values []int32) (*IntColumn, error) { + if arrayOffset < 0 { + return nil, fmt.Errorf("arrayOffset is negative") + } + if positionCount < 0 { + return nil, fmt.Errorf("positionCount is negative") + } + if int32(len(values))-arrayOffset < positionCount { + return nil, fmt.Errorf("values length is less than positionCount") + } + if valueIsNull != nil && int32(len(valueIsNull))-arrayOffset < positionCount { + return nil, fmt.Errorf("isNull length is less than positionCount") + } + return &IntColumn{ + arrayOffset: arrayOffset, + positionCount: positionCount, + valueIsNull: valueIsNull, + values: values, + }, nil +} + +func (c *IntColumn) GetDataType() TSDataType { + return INT32 +} + +func (c *IntColumn) GetEncoding() ColumnEncoding { + return INT32_ARRAY_COLUMN_ENCODING +} + +func (c *IntColumn) GetInt(position int32) (int32, error) { + return c.values[position+c.arrayOffset], nil +} + +func (c *IntColumn) GetInts() ([]int32, error) { + return c.values, nil +} + +func (c *IntColumn) GetObject(position int32) (interface{}, error) { + return c.GetInt(position) +} + +func (c *IntColumn) MayHaveNull() bool { + return c.valueIsNull != nil +} + +func (c *IntColumn) IsNull(position int32) bool { + return c.valueIsNull != nil && c.valueIsNull[position+c.arrayOffset] +} + +func (c *IntColumn) IsNulls() []bool { + if c.valueIsNull != nil { + return c.valueIsNull + } + result := make([]bool, c.positionCount) + for i := int32(0); i < c.positionCount; i++ { + result[i] = false + } + return result +} + +func (c *IntColumn) GetPositionCount() int32 { + return c.positionCount +} + +type FloatColumn struct { + baseColumn + arrayOffset int32 + positionCount int32 + valueIsNull []bool + values []float32 +} + +func NewFloatColumn(arrayOffset int32, positionCount int32, valueIsNull []bool, values []float32) (*FloatColumn, error) { + if arrayOffset < 0 { + return nil, fmt.Errorf("arrayOffset is negative") + } + if positionCount < 0 { + return nil, fmt.Errorf("positionCount is negative") + } + if int32(len(values))-arrayOffset < positionCount { + return nil, fmt.Errorf("values length is less than positionCount") + } + if valueIsNull != nil && int32(len(valueIsNull))-arrayOffset < positionCount { + return nil, fmt.Errorf("isNull length is less than positionCount") + } + return &FloatColumn{ + arrayOffset: arrayOffset, + positionCount: positionCount, + valueIsNull: valueIsNull, + values: values, + }, nil +} + +func (c *FloatColumn) GetDataType() TSDataType { + return FLOAT +} + +func (c *FloatColumn) GetEncoding() ColumnEncoding { + return INT32_ARRAY_COLUMN_ENCODING +} + +func (c *FloatColumn) GetFloat(position int32) (float32, error) { + return c.values[position+c.arrayOffset], nil +} + +func (c *FloatColumn) GetFloats() ([]float32, error) { + return c.values, nil +} + +func (c *FloatColumn) GetObject(position int32) (interface{}, error) { + return c.GetFloat(position) +} + +func (c *FloatColumn) MayHaveNull() bool { + return c.valueIsNull != nil +} + +func (c *FloatColumn) IsNull(position int32) bool { + return c.valueIsNull != nil && c.valueIsNull[position+c.arrayOffset] +} + +func (c *FloatColumn) IsNulls() []bool { + if c.valueIsNull != nil { + return c.valueIsNull + } + result := make([]bool, c.positionCount) + for i := int32(0); i < c.positionCount; i++ { + result[i] = false + } + return result +} + +func (c *FloatColumn) GetPositionCount() int32 { + return c.positionCount +} + +type LongColumn struct { + baseColumn + arrayOffset int32 + positionCount int32 + valueIsNull []bool + values []int64 +} + +func NewLongColumn(arrayOffset int32, positionCount int32, valueIsNull []bool, values []int64) (*LongColumn, error) { + if arrayOffset < 0 { + return nil, fmt.Errorf("arrayOffset is negative") + } + if positionCount < 0 { + return nil, fmt.Errorf("positionCount is negative") + } + if int32(len(values))-arrayOffset < positionCount { + return nil, fmt.Errorf("values length is less than positionCount") + } + if valueIsNull != nil && int32(len(valueIsNull))-arrayOffset < positionCount { + return nil, fmt.Errorf("isNull length is less than positionCount") + } + return &LongColumn{ + arrayOffset: arrayOffset, + positionCount: positionCount, + valueIsNull: valueIsNull, + values: values, + }, nil +} + +func (c *LongColumn) GetDataType() TSDataType { + return INT64 +} + +func (c *LongColumn) GetEncoding() ColumnEncoding { + return INT64_ARRAY_COLUMN_ENCODING +} + +func (c *LongColumn) GetLong(position int32) (int64, error) { + return c.values[position+c.arrayOffset], nil +} + +func (c *LongColumn) GetLongs() ([]int64, error) { + return c.values, nil +} + +func (c *LongColumn) GetObject(position int32) (interface{}, error) { + return c.GetLong(position) +} + +func (c *LongColumn) MayHaveNull() bool { + return c.valueIsNull != nil +} + +func (c *LongColumn) IsNull(position int32) bool { + return c.valueIsNull != nil && c.valueIsNull[position+c.arrayOffset] +} + +func (c *LongColumn) IsNulls() []bool { + if c.valueIsNull != nil { + return c.valueIsNull + } + result := make([]bool, c.positionCount) + for i := int32(0); i < c.positionCount; i++ { + result[i] = false + } + return result +} + +func (c *LongColumn) GetPositionCount() int32 { + return c.positionCount +} + +type DoubleColumn struct { + baseColumn + arrayOffset int32 + positionCount int32 + valueIsNull []bool + values []float64 +} + +func NewDoubleColumn(arrayOffset int32, positionCount int32, valueIsNull []bool, values []float64) (*DoubleColumn, error) { + if arrayOffset < 0 { + return nil, fmt.Errorf("arrayOffset is negative") + } + if positionCount < 0 { + return nil, fmt.Errorf("positionCount is negative") + } + if int32(len(values))-arrayOffset < positionCount { + return nil, fmt.Errorf("values length is less than positionCount") + } + if valueIsNull != nil && int32(len(valueIsNull))-arrayOffset < positionCount { + return nil, fmt.Errorf("isNull length is less than positionCount") + } + return &DoubleColumn{ + arrayOffset: arrayOffset, + positionCount: positionCount, + valueIsNull: valueIsNull, + values: values, + }, nil +} + +func (c *DoubleColumn) GetDataType() TSDataType { + return DOUBLE +} + +func (c *DoubleColumn) GetEncoding() ColumnEncoding { + return INT64_ARRAY_COLUMN_ENCODING +} + +func (c *DoubleColumn) GetDouble(position int32) (float64, error) { + return c.values[position+c.arrayOffset], nil +} + +func (c *DoubleColumn) GetDoubles() ([]float64, error) { + return c.values, nil +} + +func (c *DoubleColumn) GetObject(position int32) (interface{}, error) { + return c.GetDouble(position) +} + +func (c *DoubleColumn) MayHaveNull() bool { + return c.valueIsNull != nil +} + +func (c *DoubleColumn) IsNull(position int32) bool { + return c.valueIsNull != nil && c.valueIsNull[position+c.arrayOffset] +} + +func (c *DoubleColumn) IsNulls() []bool { + if c.valueIsNull != nil { + return c.valueIsNull + } + result := make([]bool, c.positionCount) + for i := int32(0); i < c.positionCount; i++ { + result[i] = false + } + return result +} + +func (c *DoubleColumn) GetPositionCount() int32 { + return c.positionCount +} + +type BooleanColumn struct { + baseColumn + arrayOffset int32 + positionCount int32 + valueIsNull []bool + values []bool +} + +func NewBooleanColumn(arrayOffset int32, positionCount int32, valueIsNull []bool, values []bool) (*BooleanColumn, error) { + if arrayOffset < 0 { + return nil, fmt.Errorf("arrayOffset is negative") + } + if positionCount < 0 { + return nil, fmt.Errorf("positionCount is negative") + } + if int32(len(values))-arrayOffset < positionCount { + return nil, fmt.Errorf("values length is less than positionCount") + } + if valueIsNull != nil && int32(len(valueIsNull))-arrayOffset < positionCount { + return nil, fmt.Errorf("isNull length is less than positionCount") + } + return &BooleanColumn{ + arrayOffset: arrayOffset, + positionCount: positionCount, + valueIsNull: valueIsNull, + values: values, + }, nil +} + +func (c *BooleanColumn) GetDataType() TSDataType { + return BOOLEAN +} + +func (c *BooleanColumn) GetEncoding() ColumnEncoding { + return BYTE_ARRAY_COLUMN_ENCODING +} + +func (c *BooleanColumn) GetBoolean(position int32) (bool, error) { + return c.values[position+c.arrayOffset], nil +} + +func (c *BooleanColumn) GetBooleans() ([]bool, error) { + return c.values, nil +} + +func (c *BooleanColumn) GetObject(position int32) (interface{}, error) { + return c.GetBoolean(position) +} + +func (c *BooleanColumn) MayHaveNull() bool { + return c.valueIsNull != nil +} + +func (c *BooleanColumn) IsNull(position int32) bool { + return c.valueIsNull != nil && c.valueIsNull[position+c.arrayOffset] +} + +func (c *BooleanColumn) IsNulls() []bool { + if c.valueIsNull != nil { + return c.valueIsNull + } + result := make([]bool, c.positionCount) + for i := int32(0); i < c.positionCount; i++ { + result[i] = false + } + return result +} + +func (c *BooleanColumn) GetPositionCount() int32 { + return c.positionCount +} + +type RunLengthEncodedColumn struct { + baseColumn + value Column + positionCount int32 +} + +func NewRunLengthEncodedColumn(value Column, positionCount int32) (*RunLengthEncodedColumn, error) { + if value == nil { + return nil, fmt.Errorf("value is null") + } + if value.GetPositionCount() != 1 { + return nil, fmt.Errorf("expected value to contain a single position but has %v positions", value.GetPositionCount()) + } + if positionCount < 0 { + return nil, fmt.Errorf("positionCount is negative") + } + column := new(RunLengthEncodedColumn) + switch (value).(type) { + case *RunLengthEncodedColumn: + column.value = (value.(*RunLengthEncodedColumn)).GetValue() + default: + column.value = value + } + column.positionCount = positionCount + return column, nil +} + +func (c *RunLengthEncodedColumn) GetValue() Column { + return c.value +} + +func (c *RunLengthEncodedColumn) GetDataType() TSDataType { + return c.value.GetDataType() +} + +func (c *RunLengthEncodedColumn) GetEncoding() ColumnEncoding { + return RLE_COLUMN_ENCODING +} + +func (c *RunLengthEncodedColumn) GetBoolean(position int32) (bool, error) { + return c.value.GetBoolean(0) +} + +func (c *RunLengthEncodedColumn) GetInt(position int32) (int32, error) { + return c.value.GetInt(0) +} + +func (c *RunLengthEncodedColumn) GetLong(position int32) (int64, error) { + return c.value.GetLong(0) +} + +func (c *RunLengthEncodedColumn) GetFloat(position int32) (float32, error) { + return c.value.GetFloat(0) +} + +func (c *RunLengthEncodedColumn) GetDouble(position int32) (float64, error) { + return c.value.GetDouble(0) +} + +func (c *RunLengthEncodedColumn) GetBinary(position int32) (*Binary, error) { + return c.value.GetBinary(0) +} + +func (c *RunLengthEncodedColumn) GetObject(position int32) (interface{}, error) { + return c.value.GetObject(position) +} + +func (c *RunLengthEncodedColumn) GetBooleans() ([]bool, error) { + v, err := c.value.GetBoolean(0) + if err != nil { + return nil, err + } + result := make([]bool, c.positionCount) + for i := int32(0); i < c.positionCount; i++ { + result[i] = v + } + return result, err +} + +func (c *RunLengthEncodedColumn) GetInts() ([]int32, error) { + v, err := c.value.GetInt(0) + if err != nil { + return nil, err + } + result := make([]int32, c.positionCount) + for i := int32(0); i < c.positionCount; i++ { + result[i] = v + } + return result, err +} + +func (c *RunLengthEncodedColumn) GetLongs() ([]int64, error) { + v, err := c.value.GetLong(0) + if err != nil { + return nil, err + } + result := make([]int64, c.positionCount) + for i := int32(0); i < c.positionCount; i++ { + result[i] = v + } + return result, err +} + +func (c *RunLengthEncodedColumn) GetFloats() ([]float32, error) { + v, err := c.value.GetFloat(0) + if err != nil { + return nil, err + } + result := make([]float32, c.positionCount) + for i := int32(0); i < c.positionCount; i++ { + result[i] = v + } + return result, err +} + +func (c *RunLengthEncodedColumn) GetDoubles() ([]float64, error) { + v, err := c.value.GetDouble(0) + if err != nil { + return nil, err + } + result := make([]float64, c.positionCount) + for i := int32(0); i < c.positionCount; i++ { + result[i] = v + } + return result, err +} + +func (c *RunLengthEncodedColumn) GetBinaries() ([]*Binary, error) { + v, err := c.value.GetBinary(0) + if err != nil { + return nil, err + } + result := make([]*Binary, c.positionCount) + for i := int32(0); i < c.positionCount; i++ { + result[i] = v + } + return result, err +} + +func (c *RunLengthEncodedColumn) GetObjects() ([]interface{}, error) { + v, err := c.value.GetObject(0) + if err != nil { + return nil, err + } + result := make([]interface{}, c.positionCount) + for i := int32(0); i < c.positionCount; i++ { + result[i] = v + } + return result, err +} + +func (c *RunLengthEncodedColumn) MayHaveNull() bool { + return c.value.MayHaveNull() +} + +func (c *RunLengthEncodedColumn) IsNull(position int32) bool { + return c.value.IsNull(0) +} + +func (c *RunLengthEncodedColumn) IsNulls() []bool { + result := make([]bool, c.positionCount) + v := c.value.IsNull(0) + for i := int32(0); i < c.positionCount; i++ { + result[i] = v + } + return result +} + +func (c *RunLengthEncodedColumn) GetPositionCount() int32 { + return c.positionCount +} diff --git a/client/column_encoder.go b/client/column_encoder.go new file mode 100644 index 0000000..07ba531 --- /dev/null +++ b/client/column_encoder.go @@ -0,0 +1,298 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package client + +import ( + "bytes" + "encoding/binary" + "fmt" +) + +type ColumnDecoder interface { + ReadTimeColumn(reader *bytes.Reader, positionCount int32) (*TimeColumn, error) + ReadColumn(reader *bytes.Reader, dataType TSDataType, positionCount int32) (Column, error) +} + +func deserializeNullIndicators(reader *bytes.Reader, positionCount int32) ([]bool, error) { + b, err := reader.ReadByte() + if err != nil { + return nil, err + } + mayHaveNull := b != 0 + if !mayHaveNull { + return nil, nil + } + return deserializeBooleanArray(reader, positionCount) +} + +func deserializeBooleanArray(reader *bytes.Reader, size int32) ([]bool, error) { + packedSize := (size + 7) / 8 + packedBytes := make([]byte, packedSize) + + _, err := reader.Read(packedBytes) + if err != nil { + return nil, err + } + + // read null bits 8 at a time + output := make([]bool, size) + currentByte := 0 + fullGroups := int(size) & ^0b111 + for pos := 0; pos < fullGroups; pos += 8 { + b := packedBytes[currentByte] + currentByte++ + + output[pos+0] = (b & 0b10000000) != 0 + output[pos+1] = (b & 0b01000000) != 0 + output[pos+2] = (b & 0b00100000) != 0 + output[pos+3] = (b & 0b00010000) != 0 + output[pos+4] = (b & 0b00001000) != 0 + output[pos+5] = (b & 0b00000100) != 0 + output[pos+6] = (b & 0b00000010) != 0 + output[pos+7] = (b & 0b00000001) != 0 + } + + // read last null bits + if remaining := int(size) % 8; remaining > 0 { + b := packedBytes[len(packedBytes)-1] + mask := uint8(0b10000000) + + for pos := fullGroups; pos < int(size); pos++ { + output[pos] = (b & mask) != 0 + mask >>= 1 + } + } + + return output, nil +} + +type baseColumnDecoder struct{} + +func (_ *baseColumnDecoder) ReadTimeColumn(_ *bytes.Reader, _ int32) (*TimeColumn, error) { + return nil, fmt.Errorf("unsupported operation: ReadTimeColumn") +} + +type Int32ArrayColumnDecoder struct { + baseColumnDecoder +} + +func (decoder *Int32ArrayColumnDecoder) ReadColumn(reader *bytes.Reader, dataType TSDataType, positionCount int32) (Column, error) { + // Serialized data layout: + // +---------------+-----------------+-------------+ + // | may have null | null indicators | values | + // +---------------+-----------------+-------------+ + // | byte | list[byte] | list[int32] | + // +---------------+-----------------+-------------+ + nullIndicators, err := deserializeNullIndicators(reader, positionCount) + if err != nil { + return nil, err + } + switch dataType { + case INT32: + case DATE: + intValues := make([]int32, positionCount) + for i := int32(0); i < positionCount; i++ { + if nullIndicators != nil && nullIndicators[i] { + continue + } + err := binary.Read(reader, binary.BigEndian, &intValues[i]) + if err != nil { + return nil, err + } + } + return NewIntColumn(0, positionCount, nullIndicators, intValues) + case FLOAT: + floatValues := make([]float32, positionCount) + for i := int32(0); i < positionCount; i++ { + if nullIndicators != nil && nullIndicators[i] { + continue + } + err := binary.Read(reader, binary.BigEndian, &floatValues[i]) + if err != nil { + return nil, err + } + } + return NewFloatColumn(0, positionCount, nullIndicators, floatValues) + } + return nil, fmt.Errorf("invalid data type: %v", dataType) +} + +type Int64ArrayColumnDecoder struct { + baseColumnDecoder +} + +func (decoder *Int64ArrayColumnDecoder) ReadTimeColumn(reader *bytes.Reader, positionCount int32) (*TimeColumn, error) { + // Serialized data layout: + // +---------------+-----------------+-------------+ + // | may have null | null indicators | values | + // +---------------+-----------------+-------------+ + // | byte | list[byte] | list[int64] | + // +---------------+-----------------+-------------+ + + nullIndicators, err := deserializeNullIndicators(reader, positionCount) + if err != nil { + return nil, err + } + if nullIndicators != nil { + return nil, fmt.Errorf("time column should not contain null values") + } + values := make([]int64, positionCount) + for i := int32(0); i < positionCount; i++ { + err = binary.Read(reader, binary.BigEndian, &values[i]) + } + return NewTimeColumn(0, positionCount, values) +} + +func (decoder *Int64ArrayColumnDecoder) ReadColumn(reader *bytes.Reader, dataType TSDataType, positionCount int32) (Column, error) { + // Serialized data layout: + // +---------------+-----------------+-------------+ + // | may have null | null indicators | values | + // +---------------+-----------------+-------------+ + // | byte | list[byte] | list[int64] | + // +---------------+-----------------+-------------+ + nullIndicators, err := deserializeNullIndicators(reader, positionCount) + if err != nil { + return nil, err + } + switch dataType { + case INT64: + case TIMESTAMP: + values := make([]int64, positionCount) + for i := int32(0); i < positionCount; i++ { + if nullIndicators != nil && nullIndicators[i] { + continue + } + if err = binary.Read(reader, binary.BigEndian, &values[i]); err != nil { + return nil, err + } + } + return NewLongColumn(0, positionCount, nullIndicators, values) + case DOUBLE: + values := make([]float64, positionCount) + for i := int32(0); i < positionCount; i++ { + if nullIndicators != nil && nullIndicators[i] { + continue + } + if err = binary.Read(reader, binary.BigEndian, &values[i]); err != nil { + return nil, err + } + } + return NewDoubleColumn(0, positionCount, nullIndicators, values) + } + return nil, fmt.Errorf("invalid data type: %v", dataType) +} + +type ByteArrayColumnDecoder struct { + baseColumnDecoder +} + +func (decoder *ByteArrayColumnDecoder) ReadColumn(reader *bytes.Reader, dataType TSDataType, positionCount int32) (Column, error) { + // Serialized data layout: + // +---------------+-----------------+-------------+ + // | may have null | null indicators | values | + // +---------------+-----------------+-------------+ + // | byte | list[byte] | list[byte] | + // +---------------+-----------------+-------------+ + + if dataType != BOOLEAN { + return nil, fmt.Errorf("invalid data type: %v", dataType) + } + nullIndicators, err := deserializeNullIndicators(reader, positionCount) + if err != nil { + return nil, err + } + values, err := deserializeBooleanArray(reader, positionCount) + if err != nil { + return nil, err + } + return NewBooleanColumn(0, positionCount, nullIndicators, values) +} + +type BinaryArrayColumnDecoder struct { + baseColumnDecoder +} + +func (decoder *BinaryArrayColumnDecoder) ReadColumn(reader *bytes.Reader, dataType TSDataType, positionCount int32) (Column, error) { + // Serialized data layout: + // +---------------+-----------------+-------------+ + // | may have null | null indicators | values | + // +---------------+-----------------+-------------+ + // | byte | list[byte] | list[entry] | + // +---------------+-----------------+-------------+ + // + // Each entry is represented as: + // +---------------+-------+ + // | value length | value | + // +---------------+-------+ + // | int32 | bytes | + // +---------------+-------+ + + if TEXT != dataType { + return nil, fmt.Errorf("invalid data type: %v", dataType) + } + nullIndicators, err := deserializeNullIndicators(reader, positionCount) + if err != nil { + return nil, err + } + values := make([]*Binary, positionCount) + for i := int32(0); i < positionCount; i++ { + if nullIndicators != nil && nullIndicators[i] { + continue + } + var length int32 + err := binary.Read(reader, binary.BigEndian, &length) + if err != nil { + return nil, err + } + value := make([]byte, length) + _, err = reader.Read(value) + if err != nil { + return nil, err + } + values[i] = NewBinary(value) + } + return NewBinaryColumn(0, positionCount, nullIndicators, values) +} + +type RunLengthColumnDecoder struct { + baseColumnDecoder +} + +func (decoder *RunLengthColumnDecoder) ReadColumn(reader *bytes.Reader, dataType TSDataType, positionCount int32) (Column, error) { + // Serialized data layout: + // +-----------+-------------------------+ + // | encoding | serialized inner column | + // +-----------+-------------------------+ + // | byte | list[byte] | + // +-----------+-------------------------+ + columnEncoding, err := deserializeColumnEncoding(reader) + if err != nil { + return nil, err + } + columnDecoder, err := getColumnDecoder(columnEncoding) + if err != nil { + return nil, err + } + column, err := columnDecoder.ReadColumn(reader, dataType, 1) + if err != nil { + return nil, err + } + return NewRunLengthEncodedColumn(column, positionCount) +} diff --git a/client/protocol.go b/client/protocol.go index edc211e..b1df25d 100644 --- a/client/protocol.go +++ b/client/protocol.go @@ -19,6 +19,8 @@ package client +import "fmt" + type TSDataType int8 type TSEncoding uint8 @@ -39,6 +41,48 @@ const ( STRING TSDataType = 11 ) +var tsTypeMap = map[string]TSDataType{ + "BOOLEAN": BOOLEAN, + "INT32": INT32, + "INT64": INT64, + "FLOAT": FLOAT, + "DOUBLE": DOUBLE, + "TEXT": TEXT, + "TIMESTAMP": TIMESTAMP, + "DATE": DATE, + "BLOB": BLOB, + "STRING": STRING, +} + +var byteToTsDataType = map[byte]TSDataType{ + 0: BOOLEAN, + 1: INT32, + 2: INT64, + 3: FLOAT, + 4: DOUBLE, + 5: TEXT, + 8: TIMESTAMP, + 9: DATE, + 10: BLOB, + 11: STRING, +} + +func getDataTypeByStr(name string) (TSDataType, error) { + dataType, exists := tsTypeMap[name] + if !exists { + return UNKNOWN, fmt.Errorf("invalid input: %v", name) + } + return dataType, nil +} + +func getDataTypeByByte(b byte) (TSDataType, error) { + dataType, exists := byteToTsDataType[b] + if !exists { + return UNKNOWN, fmt.Errorf("invalid input: %v", b) + } + return dataType, nil +} + const ( PLAIN TSEncoding = 0 DICTIONARY TSEncoding = 1 @@ -202,3 +246,7 @@ const ( CqAlreadyExist int32 = 1402 CqUpdateLastExecTimeError int32 = 1403 ) + +const ( + TimestampColumnName = "Time" +) diff --git a/client/rpcdataset.go b/client/rpcdataset.go index 11ec81a..3f2ced1 100644 --- a/client/rpcdataset.go +++ b/client/rpcdataset.go @@ -1,616 +1,534 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - package client import ( "context" - "encoding/binary" - "errors" "fmt" "github.com/apache/iotdb-client-go/common" - "math" - "time" - "github.com/apache/iotdb-client-go/rpc" + "strconv" + "time" ) -const ( - startIndex = 2 - flag = 0x80 -) - -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, - "TIMESTAMP": TIMESTAMP, - "DATE": DATE, - "BLOB": BLOB, - "STRING": STRING, - } -) +const startIndex = 2 type IoTDBRpcDataSet struct { - columnCount int - sessionId int64 - queryId int64 - lastReadWasNull bool - rowsIndex int - queryDataSet *rpc.TSQueryDataSet - sql string - fetchSize int32 - columnNameList []string - columnTypeList []TSDataType - columnOrdinalMap map[string]int32 - columnTypeDeduplicatedList []TSDataType - currentBitmap []byte - time []byte - values [][]byte - client *rpc.IClientRPCServiceClient - emptyResultSet bool - ignoreTimeStamp bool - closed bool - timeoutMs *int64 -} - -func (s *IoTDBRpcDataSet) getColumnIndex(columnName string) int32 { - if s.closed { - return -1 - } - return s.columnOrdinalMap[columnName] - startIndex + Sql string + IsClosed bool + Client *rpc.IClientRPCServiceClient + ColumnNameList []string + ColumnTypeList []string + ColumnOrdinalMap map[string]int32 + ColumnTypeDeduplicatedList []TSDataType + FetchSize int32 + Timeout int64 + HasCachedRecord bool + LastReadWasNull bool + + ColumnSize int32 + + SessionId int64 + QueryId int64 + StatementId int64 + Time int64 + IgnoreTimestamp bool + // indicates that there is still more data in server side and we can call fetchResult to get more + MoreData bool + + QueryResult [][]byte + CurTsBlock *TsBlock + QueryResultSize int32 // the length of queryResult + QueryResultIndex int32 // the index of bytebuffer in queryResult + TsBlockSize int32 // the size of current tsBlock + TsBlockIndex int32 // the row index in current tsBlock } -func (s *IoTDBRpcDataSet) getColumnType(columnName string) TSDataType { - if s.closed { - return UNKNOWN - } - return s.columnTypeDeduplicatedList[s.getColumnIndex(columnName)] -} - -func (s *IoTDBRpcDataSet) isNullWithColumnName(columnName string) bool { - return s.isNull(int(s.getColumnIndex(columnName)), s.rowsIndex-1) -} +func NewIoTDBRpcDataSet(sql string, columnNameList []string, columnTypeList []string, columnNameIndex map[string]int32, ignoreTimestamp bool, moreData bool, queryId int64, statementId int64, client *rpc.IClientRPCServiceClient, sessionId int64, queryResult [][]byte, fetchSize int32, timeout int64) (rpcDataSet *IoTDBRpcDataSet, err error) { + ds := &IoTDBRpcDataSet{ + SessionId: sessionId, + StatementId: statementId, + IgnoreTimestamp: ignoreTimestamp, + Sql: sql, + QueryId: queryId, + Client: client, + FetchSize: fetchSize, + Timeout: timeout, + MoreData: moreData, + ColumnSize: int32(len(columnNameList)), + ColumnNameList: columnNameList, + ColumnTypeList: columnTypeList, + ColumnOrdinalMap: make(map[string]int32), + } + if !ignoreTimestamp { + ds.ColumnNameList = append(ds.ColumnNameList, TimestampColumnName) + ds.ColumnTypeList = append(ds.ColumnTypeList, "INT64") + ds.ColumnOrdinalMap[TimestampColumnName] = 1 + } + ds.ColumnNameList = append(ds.ColumnNameList, columnNameList...) + ds.ColumnTypeList = append(ds.ColumnTypeList, columnTypeList...) -func (s *IoTDBRpcDataSet) isNull(columnIndex int, rowIndex int) bool { - if s.closed { - return true - } - bitmap := s.currentBitmap[columnIndex] - shift := rowIndex % 8 - return ((flag >> shift) & (bitmap & 0xff)) == 0 -} + if columnNameIndex != nil { + deduplicatedColumnSize := getDeduplicatedColumnSize(columnNameIndex) + ds.ColumnTypeDeduplicatedList = make([]TSDataType, deduplicatedColumnSize) + for i, name := range columnNameList { + if _, exists := ds.ColumnOrdinalMap[name]; exists { + continue + } -func (s *IoTDBRpcDataSet) constructOneRow() error { - if s.closed { - return errClosed - } + index := columnNameIndex[name] + targetIndex := index + startIndex - // simulating buffer, read 8 bytes from data set and discard first 8 bytes which have been read. - s.time = s.queryDataSet.Time[:8] - s.queryDataSet.Time = s.queryDataSet.Time[8:] + valueExists := false + for _, v := range ds.ColumnOrdinalMap { + if v == targetIndex { + valueExists = true + break + } + } - for i := 0; i < len(s.queryDataSet.BitmapList); i++ { - bitmapBuffer := s.queryDataSet.BitmapList[i] - if s.rowsIndex%8 == 0 { - s.currentBitmap[i] = bitmapBuffer[0] - s.queryDataSet.BitmapList[i] = bitmapBuffer[1:] + if !valueExists { + if int(index) < len(ds.ColumnTypeDeduplicatedList) { + if ds.ColumnTypeDeduplicatedList[index], err = getDataTypeByStr(columnTypeList[i]); err != nil { + return nil, err + } + } + } + ds.ColumnOrdinalMap[name] = targetIndex } - if !s.isNull(i, s.rowsIndex) { - valueBuffer := s.queryDataSet.ValueList[i] - dataType := s.columnTypeDeduplicatedList[i] - switch dataType { - case BOOLEAN: - s.values[i] = valueBuffer[:1] - s.queryDataSet.ValueList[i] = valueBuffer[1:] - case INT32, DATE: - s.values[i] = valueBuffer[:4] - s.queryDataSet.ValueList[i] = valueBuffer[4:] - case INT64, TIMESTAMP: - s.values[i] = valueBuffer[:8] - s.queryDataSet.ValueList[i] = valueBuffer[8:] - case FLOAT: - s.values[i] = valueBuffer[:4] - s.queryDataSet.ValueList[i] = valueBuffer[4:] - case DOUBLE: - s.values[i] = valueBuffer[:8] - s.queryDataSet.ValueList[i] = valueBuffer[8:] - case TEXT, BLOB, STRING: - length := bytesToInt32(valueBuffer[:4]) - s.values[i] = valueBuffer[4 : 4+length] - s.queryDataSet.ValueList[i] = valueBuffer[4+length:] - default: - return fmt.Errorf("unsupported data type %d", dataType) + } else { + ds.ColumnTypeDeduplicatedList = make([]TSDataType, 0) + index := startIndex + for i := 0; i < len(columnNameList); i++ { + name := columnNameList[i] + if _, exists := ds.ColumnOrdinalMap[name]; !exists { + dataType, err := getDataTypeByStr(columnTypeList[i]) + if err != nil { + return nil, err + } + ds.ColumnTypeDeduplicatedList = append(ds.ColumnTypeDeduplicatedList, dataType) + ds.ColumnOrdinalMap[name] = int32(index) + index++ } } } - s.rowsIndex++ - return nil + ds.QueryResult = queryResult + if queryResult != nil { + ds.QueryResultSize = int32(len(queryResult)) + } else { + ds.QueryResultSize = 0 + } + ds.QueryResultIndex = 0 + ds.TsBlockSize = 0 + ds.TsBlockIndex = -1 + return ds, nil } -func (s *IoTDBRpcDataSet) GetTimestamp() int64 { - if s.closed { - return -1 +func getDeduplicatedColumnSize(columnNameList map[string]int32) int { + uniqueIndexes := make(map[int32]struct{}) + for _, idx := range columnNameList { + uniqueIndexes[idx] = struct{}{} } - return bytesToInt64(s.time) + return len(uniqueIndexes) } -func (s *IoTDBRpcDataSet) getText(columnName string) string { - if s.closed { - return "" +func (s *IoTDBRpcDataSet) Close() (err error) { + if s.IsClosed { + return nil } - if columnName == TimestampColumnName { - return time.Unix(0, bytesToInt64(s.time)*1000000).Format(time.RFC3339) + closeRequest := &rpc.TSCloseOperationReq{ + SessionId: s.SessionId, + QueryId: &s.QueryId, } - columnIndex := s.getColumnIndex(columnName) - if columnIndex < 0 || int(columnIndex) >= len(s.values) || s.isNull(int(columnIndex), s.rowsIndex-1) { - s.lastReadWasNull = true - return "" + var status *common.TSStatus + status, err = s.Client.CloseOperation(context.Background(), closeRequest) + if err == nil { + err = VerifySuccess(status) } - s.lastReadWasNull = false - return s.getString(int(columnIndex), s.columnTypeDeduplicatedList[columnIndex]) + s.Client = nil + s.IsClosed = true + return err } -func (s *IoTDBRpcDataSet) getString(columnIndex int, dataType TSDataType) string { - if s.closed { - return "" +func (s *IoTDBRpcDataSet) Next() (result bool, err error) { + if s.hasCachedBlock() { + s.LastReadWasNull = false + err = s.constructOneRow() + return true, err } - valueBytes := s.values[columnIndex] - switch dataType { - case BOOLEAN: - if valueBytes[0] != 0 { - return "true" + if s.hasCachedByteBuffer() { + if err = s.constructOneTsBlock(); err != nil { + return false, err } - return "false" - case INT32: - return int32ToString(bytesToInt32(valueBytes)) - case INT64, TIMESTAMP: - return int64ToString(bytesToInt64(valueBytes)) - case FLOAT: - bits := binary.BigEndian.Uint32(valueBytes) - return float32ToString(math.Float32frombits(bits)) - case DOUBLE: - bits := binary.BigEndian.Uint64(valueBytes) - return float64ToString(math.Float64frombits(bits)) - case TEXT, STRING: - return string(valueBytes) - case BLOB: - return bytesToHexString(valueBytes) - case DATE: - date, err := bytesToDate(valueBytes) + err = s.constructOneRow() + return true, err + } + + if s.MoreData { + hasResultSet, err := s.fetchResults() if err != nil { - return "" + return false, err + } + if hasResultSet && s.hasCachedByteBuffer() { + if err = s.constructOneTsBlock(); err != nil { + return false, err + } + err = s.constructOneRow() + return true, err } - return date.Format("2006-01-02") - default: - return "" } + err = s.Close() + if err != nil { + return false, err + } + return false, nil } -func (s *IoTDBRpcDataSet) getValue(columnName string) interface{} { - if s.closed { - return nil +func (s *IoTDBRpcDataSet) fetchResults() (bool, error) { + if s.IsClosed { + return false, fmt.Errorf("this data set is already closed") } - columnIndex := int(s.getColumnIndex(columnName)) - if s.isNull(columnIndex, s.rowsIndex-1) { - return nil + req := rpc.TSFetchResultsReq{ + SessionId: s.SessionId, + Statement: s.Sql, + FetchSize: s.FetchSize, + QueryId: s.QueryId, + IsAlign: true, } + req.Timeout = &s.Timeout - dataType := s.getColumnType(columnName) - valueBytes := s.values[columnIndex] - switch dataType { - case BOOLEAN: - return valueBytes[0] != 0 - case INT32: - return bytesToInt32(valueBytes) - case INT64, TIMESTAMP: - return bytesToInt64(valueBytes) - case FLOAT: - bits := binary.BigEndian.Uint32(valueBytes) - return math.Float32frombits(bits) - case DOUBLE: - bits := binary.BigEndian.Uint64(valueBytes) - return math.Float64frombits(bits) - 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 + resp, err := s.Client.FetchResults(context.Background(), &req) + + if err != nil { + return false, err } -} -func (s *IoTDBRpcDataSet) getRowRecord() (*RowRecord, error) { - if s.closed { - return nil, errClosed + if err = VerifySuccess(resp.Status); err != nil { + return false, err } - fields := make([]*Field, s.columnCount) - for i := 0; i < s.columnCount; i++ { - columnName := s.columnNameList[i] - field := Field{ - name: columnName, - dataType: s.getColumnType(columnName), - value: s.getValue(columnName), + if !resp.HasResultSet { + err = s.Close() + } else { + s.QueryResult = resp.GetQueryResult_() + s.QueryResultIndex = 0 + if s.QueryResult != nil { + s.QueryResultSize = int32(len(s.QueryResult)) + } else { + s.QueryResultSize = 0 } - fields[i] = &field + s.TsBlockSize = 0 + s.TsBlockIndex = -1 } - return &RowRecord{ - timestamp: s.GetTimestamp(), - fields: fields, - }, nil + return resp.HasResultSet, err } -func (s *IoTDBRpcDataSet) getBool(columnName string) bool { - if s.closed { - return false - } - columnIndex := s.getColumnIndex(columnName) - if !s.isNull(int(columnIndex), s.rowsIndex-1) { - return s.values[columnIndex][0] != 0 - } - s.lastReadWasNull = true - return false +func (s *IoTDBRpcDataSet) hasCachedBlock() bool { + return s.CurTsBlock != nil && s.TsBlockIndex < s.TsBlockSize-1 } -func (s *IoTDBRpcDataSet) scan(dest ...interface{}) error { - if s.closed { - return errClosed - } - - count := s.columnCount - if count > len(dest) { - count = len(dest) - } +func (s *IoTDBRpcDataSet) hasCachedByteBuffer() bool { + return s.QueryResult != nil && s.QueryResultIndex < s.QueryResultSize +} - for i := 0; i < count; i++ { - columnName := s.columnNameList[i] - columnIndex := int(s.getColumnIndex(columnName)) - if s.isNull(columnIndex, s.rowsIndex-1) { - continue - } +func (s *IoTDBRpcDataSet) constructOneRow() (err error) { + s.TsBlockIndex++ + s.HasCachedRecord = true + s.Time, err = s.CurTsBlock.GetTimeColumn().GetLong(s.TsBlockIndex) + return err +} - dataType := s.getColumnType(columnName) - d := dest[i] - valueBytes := s.values[columnIndex] - switch dataType { - case BOOLEAN: - switch t := d.(type) { - case *bool: - *t = valueBytes[0] != 0 - case *string: - if valueBytes[0] != 0 { - *t = "true" - } else { - *t = "false" - } - default: - return fmt.Errorf("dest[%d] types must be *bool or *string", i) - } +func (s *IoTDBRpcDataSet) constructOneTsBlock() (err error) { + s.LastReadWasNull = false + curTsBlockBytes := s.QueryResult[s.QueryResultIndex] + s.QueryResultIndex = s.QueryResultIndex + 1 + s.CurTsBlock, err = DeserializeTsBlock(curTsBlockBytes) + s.TsBlockIndex = -1 + s.TsBlockSize = s.CurTsBlock.GetPositionCount() + return err +} - case INT32: - switch t := d.(type) { - case *int32: - *t = bytesToInt32(valueBytes) - case *string: - *t = int32ToString(bytesToInt32(valueBytes)) - default: - return fmt.Errorf("dest[%d] types must be *int32 or *string", i) - } - case INT64, TIMESTAMP: - switch t := d.(type) { - case *int64: - *t = bytesToInt64(valueBytes) - case *string: - *t = int64ToString(bytesToInt64(valueBytes)) - default: - return fmt.Errorf("dest[%d] types must be *int64 or *string", i) - } - case FLOAT: - switch t := d.(type) { - case *float32: - bits := binary.BigEndian.Uint32(valueBytes) - *t = math.Float32frombits(bits) - case *string: - bits := binary.BigEndian.Uint32(valueBytes) - *t = float32ToString(math.Float32frombits(bits)) - default: - return fmt.Errorf("dest[%d] types must be *float32 or *string", i) - } - case DOUBLE: - switch t := d.(type) { - case *float64: - bits := binary.BigEndian.Uint64(valueBytes) - *t = math.Float64frombits(bits) - case *string: - bits := binary.BigEndian.Uint64(valueBytes) - *t = float64ToString(math.Float64frombits(bits)) - default: - return fmt.Errorf("dest[%d] types must be *float64 or *string", i) - } - 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 *[]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 - } +func (s *IoTDBRpcDataSet) isNullByIndex(columnIndex int32) (bool, error) { + columnName, err := s.findColumnNameByIndex(columnIndex) + if err != nil { + return false, err + } + index := s.ColumnOrdinalMap[columnName] - startIndex + // time column will never be null + if index < 0 { + return true, nil } - return nil + return s.isNull(index, s.TsBlockIndex), nil } -func (s *IoTDBRpcDataSet) getFloat(columnName string) float32 { - if s.closed { - return 0 +func (s *IoTDBRpcDataSet) isNullByColumnName(columnName string) bool { + index := s.ColumnOrdinalMap[columnName] - startIndex + // time column will never be null + if index < 0 { + return true } - columnIndex := s.getColumnIndex(columnName) - if !s.isNull(int(columnIndex), s.rowsIndex-1) { - s.lastReadWasNull = false - bits := binary.BigEndian.Uint32(s.values[columnIndex]) - return math.Float32frombits(bits) + return s.isNull(index, s.TsBlockIndex) +} + +func (s *IoTDBRpcDataSet) isNull(index int32, rowNum int32) bool { + return s.CurTsBlock.GetColumn(index).IsNull(rowNum) +} + +func (s *IoTDBRpcDataSet) getBooleanByIndex(columnIndex int32) (bool, error) { + columnName, err := s.findColumnNameByIndex(columnIndex) + if err != nil { + return false, err } - s.lastReadWasNull = true - return 0 + return s.getBoolean(columnName) } -func (s *IoTDBRpcDataSet) getDouble(columnName string) float64 { - if s.closed { - return 0 +func (s *IoTDBRpcDataSet) getBoolean(columnName string) (bool, error) { + err := s.checkRecord() + if err != nil { + return false, err } - columnIndex := s.getColumnIndex(columnName) + index := s.ColumnOrdinalMap[columnName] - startIndex + if !s.isNull(index, s.TsBlockIndex) { + s.LastReadWasNull = false + return s.CurTsBlock.GetColumn(index).GetBoolean(s.TsBlockIndex) + } else { + s.LastReadWasNull = true + return false, nil + } +} - if !s.isNull(int(columnIndex), s.rowsIndex-1) { - s.lastReadWasNull = false - bits := binary.BigEndian.Uint64(s.values[columnIndex]) - return math.Float64frombits(bits) +func (s *IoTDBRpcDataSet) getDoubleByIndex(columnIndex int32) (float64, error) { + columnName, err := s.findColumnNameByIndex(columnIndex) + if err != nil { + return 0, err } - s.lastReadWasNull = true - return 0 + return s.getDouble(columnName) } -func (s *IoTDBRpcDataSet) getInt32(columnName string) int32 { - if s.closed { - return 0 +func (s *IoTDBRpcDataSet) getDouble(columnName string) (float64, error) { + err := s.checkRecord() + if err != nil { + return 0, err } - columnIndex := s.getColumnIndex(columnName) - if !s.isNull(int(columnIndex), s.rowsIndex-1) { - s.lastReadWasNull = false - return bytesToInt32(s.values[columnIndex]) + index := s.ColumnOrdinalMap[columnName] - startIndex + if !s.isNull(index, s.TsBlockIndex) { + s.LastReadWasNull = false + return s.CurTsBlock.GetColumn(index).GetDouble(s.TsBlockIndex) + } else { + s.LastReadWasNull = true + return 0, nil } +} - s.lastReadWasNull = true - return 0 +func (s *IoTDBRpcDataSet) getFloatByIndex(columnIndex int32) (float32, error) { + columnName, err := s.findColumnNameByIndex(columnIndex) + if err != nil { + return 0, err + } + return s.getFloat(columnName) } -func (s *IoTDBRpcDataSet) getInt64(columnName string) int64 { - if s.closed { - return 0 +func (s *IoTDBRpcDataSet) getFloat(columnName string) (float32, error) { + err := s.checkRecord() + if err != nil { + return 0, err } - if columnName == TimestampColumnName { - return bytesToInt64(s.time) + index := s.ColumnOrdinalMap[columnName] - startIndex + if !s.isNull(index, s.TsBlockIndex) { + s.LastReadWasNull = false + return s.CurTsBlock.GetColumn(index).GetFloat(s.TsBlockIndex) + } else { + s.LastReadWasNull = true + return 0, nil } +} - columnIndex := s.getColumnIndex(columnName) - bys := s.values[columnIndex] - - if !s.isNull(int(columnIndex), s.rowsIndex-1) { - s.lastReadWasNull = false - return bytesToInt64(bys) +func (s *IoTDBRpcDataSet) getIntByIndex(columnIndex int32) (int32, error) { + columnName, err := s.findColumnNameByIndex(columnIndex) + if err != nil { + return 0, err } - s.lastReadWasNull = true - return 0 + return s.getInt(columnName) } -func (s *IoTDBRpcDataSet) hasCachedResults() bool { - if s.closed { - return false +func (s *IoTDBRpcDataSet) getInt(columnName string) (int32, error) { + err := s.checkRecord() + if err != nil { + return 0, err + } + index := s.ColumnOrdinalMap[columnName] - startIndex + if !s.isNull(index, s.TsBlockIndex) { + s.LastReadWasNull = false + return s.CurTsBlock.GetColumn(index).GetInt(s.TsBlockIndex) + } else { + s.LastReadWasNull = true + return 0, nil } - return s.queryDataSet != nil && len(s.queryDataSet.Time) > 0 } -func (s *IoTDBRpcDataSet) next() (bool, error) { - if s.closed { - return false, errClosed +func (s *IoTDBRpcDataSet) getLongByIndex(columnIndex int32) (int64, error) { + columnName, err := s.findColumnNameByIndex(columnIndex) + if err != nil { + return 0, err } + return s.getLong(columnName) +} - if s.hasCachedResults() { - s.constructOneRow() - return true, nil +func (s *IoTDBRpcDataSet) getLong(columnName string) (int64, error) { + err := s.checkRecord() + if err != nil { + return 0, err } - if s.emptyResultSet { - return false, nil + index := s.ColumnOrdinalMap[columnName] - startIndex + if !s.isNull(index, s.TsBlockIndex) { + s.LastReadWasNull = false + return s.CurTsBlock.GetColumn(index).GetLong(s.TsBlockIndex) + } else { + s.LastReadWasNull = true + return 0, nil } +} - r, err := s.fetchResults() - if err == nil && r { - s.constructOneRow() - return true, nil +func (s *IoTDBRpcDataSet) getBinaryByIndex(columnIndex int32) (*Binary, error) { + columnName, err := s.findColumnNameByIndex(columnIndex) + if err != nil { + return nil, err } - return false, nil + return s.getBinary(columnName) } -func (s *IoTDBRpcDataSet) fetchResults() (bool, error) { - if s.closed { - return false, errClosed +func (s *IoTDBRpcDataSet) getBinary(columnName string) (*Binary, error) { + err := s.checkRecord() + if err != nil { + return nil, err } - s.rowsIndex = 0 - req := rpc.TSFetchResultsReq{ - SessionId: s.sessionId, - Statement: s.sql, - FetchSize: s.fetchSize, - QueryId: s.queryId, - IsAlign: true, - Timeout: s.timeoutMs, + index := s.ColumnOrdinalMap[columnName] - startIndex + if !s.isNull(index, s.TsBlockIndex) { + s.LastReadWasNull = false + return s.CurTsBlock.GetColumn(index).GetBinary(s.TsBlockIndex) + } else { + s.LastReadWasNull = true + return nil, nil } - resp, err := s.client.FetchResults(context.Background(), &req) +} +func (s *IoTDBRpcDataSet) getStringByIndex(columnIndex int32) (string, error) { + columnName, err := s.findColumnNameByIndex(columnIndex) if err != nil { - return false, err + return "", err } + return s.getValueByName(columnName) +} - if err = VerifySuccess(resp.Status); err != nil { - return false, err +func (s *IoTDBRpcDataSet) GetTimestampByIndex(columnIndex int32) (time.Time, error) { + longValue, err := s.getLongByIndex(columnIndex) + if err != nil { + return time.Time{}, err } + return time.UnixMilli(longValue), nil +} - if !resp.HasResultSet { - s.emptyResultSet = true - } else { - s.queryDataSet = resp.GetQueryDataSet() - } - return resp.HasResultSet, nil +func (s *IoTDBRpcDataSet) GetTimestamp(columnName string) (time.Time, error) { + return s.GetTimestampByIndex(s.findColumn(columnName)) } -func (s *IoTDBRpcDataSet) IsClosed() bool { - return s.closed +func (s *IoTDBRpcDataSet) findColumn(columnName string) int32 { + return s.ColumnOrdinalMap[columnName] } -func (s *IoTDBRpcDataSet) Close() (err error) { - if s.IsClosed() { - return nil +func (s *IoTDBRpcDataSet) getValueByName(columnName string) (string, error) { + err := s.checkRecord() + if err != nil { + return "", err } - if s.client != nil { - closeRequest := &rpc.TSCloseOperationReq{ - SessionId: s.sessionId, - QueryId: &s.queryId, + if columnName == TimestampColumnName { + if t, err := s.CurTsBlock.GetTimeByIndex(s.TsBlockIndex); err != nil { + return "", err + } else { + return int64ToString(t), nil } + } + index := s.ColumnOrdinalMap[columnName] - startIndex + if index < 0 || index >= int32(len(s.ColumnTypeDeduplicatedList)) || s.isNull(index, s.TsBlockIndex) { + s.LastReadWasNull = true + return "", err + } + s.LastReadWasNull = false + return s.getString(index, s.ColumnTypeDeduplicatedList[index]) +} - var status *common.TSStatus - status, err = s.client.CloseOperation(context.Background(), closeRequest) - if err == nil { - err = VerifySuccess(status) +func (s *IoTDBRpcDataSet) getString(index int32, tsDataType TSDataType) (string, error) { + switch tsDataType { + case BOOLEAN: + if v, err := s.CurTsBlock.GetColumn(index).GetBoolean(s.TsBlockIndex); err != nil { + return "", nil + } else { + return strconv.FormatBool(v), nil + } + case INT32: + if v, err := s.CurTsBlock.GetColumn(index).GetInt(s.TsBlockIndex); err != nil { + return "", err + } else { + return int32ToString(v), nil + } + case INT64: + case TIMESTAMP: + if v, err := s.CurTsBlock.GetColumn(index).GetLong(s.TsBlockIndex); err != nil { + return "", err + } else { + return int64ToString(v), nil + } + case FLOAT: + if v, err := s.CurTsBlock.GetColumn(index).GetFloat(s.TsBlockIndex); err != nil { + return "", err + } else { + return float32ToString(v), nil + } + case DOUBLE: + if v, err := s.CurTsBlock.GetColumn(index).GetDouble(s.TsBlockIndex); err != nil { + return "", err + } else { + return float64ToString(v), nil + } + case TEXT: + case STRING: + if v, err := s.CurTsBlock.GetColumn(index).GetBinary(s.TsBlockIndex); err != nil { + return "", err + } else { + return v.GetStringValue(), nil + } + case BLOB: + if v, err := s.CurTsBlock.GetColumn(index).GetBinary(s.TsBlockIndex); err != nil { + return "", err + } else { + return bytesToHexString(v.values), nil } + case DATE: + v, err := s.CurTsBlock.GetColumn(index).GetInt(s.TsBlockIndex) + if err != nil { + return "", err + } + t, err := int32ToDate(v) + if err != nil { + return "", err + } + return t.Format("2006-01-02"), nil } - - s.columnCount = 0 - s.sessionId = -1 - s.queryId = -1 - s.rowsIndex = -1 - s.queryDataSet = nil - s.sql = "" - s.fetchSize = 0 - s.columnNameList = nil - s.columnTypeList = nil - s.columnOrdinalMap = nil - s.columnTypeDeduplicatedList = nil - s.currentBitmap = nil - s.time = nil - s.values = nil - s.client = nil - s.emptyResultSet = true - s.closed = true - return err + return "", nil } -func NewIoTDBRpcDataSet(sql string, columnNameList []string, columnTypes []string, - columnNameIndex map[string]int32, - queryId int64, client *rpc.IClientRPCServiceClient, sessionId int64, queryDataSet *rpc.TSQueryDataSet, - ignoreTimeStamp bool, fetchSize int32, timeoutMs *int64) *IoTDBRpcDataSet { - - ds := &IoTDBRpcDataSet{ - sql: sql, - columnNameList: columnNameList, - ignoreTimeStamp: ignoreTimeStamp, - queryId: queryId, - client: client, - sessionId: sessionId, - queryDataSet: queryDataSet, - fetchSize: fetchSize, - currentBitmap: make([]byte, len(columnNameList)), - values: make([][]byte, len(columnTypes)), - columnCount: len(columnNameList), - closed: false, - timeoutMs: timeoutMs, +func (s *IoTDBRpcDataSet) findColumnNameByIndex(columnIndex int32) (string, error) { + if columnIndex <= 0 { + return "", fmt.Errorf("column index should start from 1") } - - ds.columnTypeList = make([]TSDataType, 0) - - // deduplicate and map - ds.columnOrdinalMap = make(map[string]int32) - if !ignoreTimeStamp { - ds.columnOrdinalMap[TimestampColumnName] = 1 + if columnIndex > int32(len(s.ColumnNameList)) { + return "", fmt.Errorf("column index %d out of range %d", columnIndex, len(s.ColumnNameList)) } + return s.ColumnNameList[columnIndex-1], nil +} - if columnNameIndex != nil { - ds.columnTypeDeduplicatedList = make([]TSDataType, len(columnNameIndex)) - for i, name := range columnNameList { - columnTypeString := columnTypes[i] - columnDataType := tsTypeMap[columnTypeString] - ds.columnTypeList = append(ds.columnTypeList, columnDataType) - if _, exists := ds.columnOrdinalMap[name]; !exists { - index := columnNameIndex[name] - ds.columnOrdinalMap[name] = index + startIndex - ds.columnTypeDeduplicatedList[index] = tsTypeMap[columnTypeString] - } - } - } else { - ds.columnTypeDeduplicatedList = make([]TSDataType, ds.columnCount) - index := startIndex - for i := 0; i < len(columnNameList); i++ { - name := columnNameList[i] - dataType := tsTypeMap[columnTypes[i]] - ds.columnTypeList = append(ds.columnTypeList, dataType) - ds.columnTypeDeduplicatedList[i] = dataType - if _, exists := ds.columnOrdinalMap[name]; !exists { - ds.columnOrdinalMap[name] = int32(index) - index++ - } - } +func (s *IoTDBRpcDataSet) checkRecord() (err error) { + if s.QueryResultIndex > s.QueryResultSize || s.TsBlockIndex >= s.TsBlockSize || s.QueryResult == nil || s.CurTsBlock == nil { + err = fmt.Errorf("no record remains") } - return ds + return err } diff --git a/client/rpcdataset_test.go b/client/rpcdataset_test.go deleted file mode 100644 index 82dd3b0..0000000 --- a/client/rpcdataset_test.go +++ /dev/null @@ -1,666 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package client - -import ( - "bytes" - "reflect" - "testing" - "time" - - "github.com/apache/iotdb-client-go/rpc" -) - -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", - "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.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, 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) -} - -func TestIoTDBRpcDataSet_getColumnType(t *testing.T) { - type args struct { - columnName string - } - - ds := createIoTDBRpcDataSet() - closedDataSet := createIoTDBRpcDataSet() - closedDataSet.Close() - tests := []struct { - name string - dataSet *IoTDBRpcDataSet - args args - want TSDataType - }{ - { - name: "Normal", - dataSet: ds, - args: args{ - columnName: "root.ln.device1.tick_count", - }, - want: INT64, - }, { - name: "Closed", - dataSet: closedDataSet, - args: args{ - columnName: "root.ln.device1.tick_count", - }, - want: UNKNOWN, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := tt.dataSet - if got := s.getColumnType(tt.args.columnName); got != tt.want { - t.Errorf("IoTDBRpcDataSet.getColumnType() = %v, want %v", got, tt.want) - } - s.Close() - }) - } -} - -func TestIoTDBRpcDataSet_getColumnIndex(t *testing.T) { - type args struct { - columnName string - } - closedDataSet := createIoTDBRpcDataSet() - closedDataSet.Close() - tests := []struct { - name string - dataset *IoTDBRpcDataSet - args args - want int32 - }{ - { - name: "Normal", - dataset: createIoTDBRpcDataSet(), - args: args{ - columnName: "root.ln.device1.tick_count", - }, - want: 5, - }, { - name: "Closed", - dataset: closedDataSet, - args: args{ - columnName: "root.ln.device1.tick_count", - }, - want: -1, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := tt.dataset - if got := s.getColumnIndex(tt.args.columnName); got != tt.want { - t.Errorf("IoTDBRpcDataSet.getColumnIndex() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIoTDBRpcDataSet_isNull(t *testing.T) { - type args struct { - columnIndex int - rowIndex int - } - ds := createIoTDBRpcDataSet() - ds.next() - - tests := []struct { - name string - args args - want bool - }{ - { - name: "Normal", - args: args{ - columnIndex: 0, - rowIndex: 0, - }, - want: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := createIoTDBRpcDataSet() - s.next() - if got := s.isNull(tt.args.columnIndex, tt.args.rowIndex); got != tt.want { - t.Errorf("IoTDBRpcDataSet.isNull() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIoTDBRpcDataSet_getValue(t *testing.T) { - - type args struct { - columnName string - } - tests := []struct { - name string - args args - want interface{} - }{ - { - name: "restart_count", - args: args{ - columnName: "root.ln.device1.restart_count", - }, - want: int32(1), - }, { - name: "tick_count", - args: args{ - columnName: "root.ln.device1.tick_count", - }, - want: int64(3333333), - }, { - name: "price", - args: args{ - columnName: "root.ln.device1.price", - }, - want: float64(1988.2), - }, { - name: "temperature", - args: args{ - columnName: "root.ln.device1.temperature", - }, - want: float32(12.1), - }, { - name: "description", - args: args{ - columnName: "root.ln.device1.description", - }, - want: "Test Device 1", - }, { - name: "status", - args: args{ - columnName: "root.ln.device1.status", - }, - want: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := createIoTDBRpcDataSet() - s.next() - if got := s.getValue(tt.args.columnName); !reflect.DeepEqual(got, tt.want) { - t.Errorf("IoTDBRpcDataSet.getValue() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIoTDBRpcDataSet_scan(t *testing.T) { - type args struct { - dest []interface{} - } - - type want struct { - err error - values []interface{} - } - - var restartCount int32 - var price float64 - var tickCount int64 - var temperature float32 - var description string - var status bool - - var restartCountStr string - var priceStr string - var tickCountStr string - var temperatureStr string - var descriptionStr string - var statusStr string - - var wantRestartCount int32 = 1 - var wantPrice float64 = 1988.2 - var wantTickCount int64 = 3333333 - var wantTemperature float32 = 12.1 - var wantDescription string = "Test Device 1" - var wantStatus bool = true - - var wantRestartCountStr string = "1" - var wantPriceStr string = "1988.2" - var wantTickCountStr string = "3333333" - var wantTemperatureStr string = "12.1" - var wantDescriptionStr string = "Test Device 1" - var wantStatusStr string = "true" - - tests := []struct { - name string - args args - want want - }{ - { - name: "Normal", - args: args{ - dest: []interface{}{&restartCount, &price, &tickCount, &temperature, &description, &status}, - }, - want: want{ - err: nil, - values: []interface{}{&wantRestartCount, &wantPrice, &wantTickCount, &wantTemperature, &wantDescription, &wantStatus}, - }, - }, { - name: "String", - args: args{ - dest: []interface{}{&restartCountStr, &priceStr, &tickCountStr, &temperatureStr, &descriptionStr, &statusStr}, - }, - want: want{ - err: nil, - values: []interface{}{&wantRestartCountStr, &wantPriceStr, &wantTickCountStr, &wantTemperatureStr, &wantDescriptionStr, &wantStatusStr}, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := createIoTDBRpcDataSet() - s.next() - if err := s.scan(tt.args.dest...); err != tt.want.err { - t.Errorf("IoTDBRpcDataSet.scan() error = %v, wantErr %v", err, tt.want.err) - } - if got := tt.args.dest; !reflect.DeepEqual(got, tt.want.values) { - t.Errorf("IoTDBRpcDataSet.scan(), dest = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIoTDBRpcDataSet_GetTimestamp(t *testing.T) { - tests := []struct { - name string - want int64 - }{ - { - name: "GetTimestamp", - want: 1607596245228, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := createIoTDBRpcDataSet() - s.next() - if got := s.GetTimestamp(); got != tt.want { - t.Errorf("IoTDBRpcDataSet.GetTimestamp() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIoTDBRpcDataSet_getText(t *testing.T) { - type args struct { - columnName string - } - tests := []struct { - name string - args args - want string - }{ - { - name: "restart_count", - args: args{ - columnName: "root.ln.device1.restart_count", - }, - want: "1", - }, { - name: "price", - args: args{ - columnName: "root.ln.device1.price", - }, - want: "1988.2", - }, { - name: "tick_count", - args: args{ - columnName: "root.ln.device1.tick_count", - }, - want: "3333333", - }, { - name: "temperature", - args: args{ - columnName: "root.ln.device1.temperature", - }, - want: "12.1", - }, { - name: "description", - args: args{ - columnName: "root.ln.device1.description", - }, - want: "Test Device 1", - }, { - name: "status", - args: args{ - columnName: "root.ln.device1.status", - }, - want: "true", - }, { - name: TimestampColumnName, - args: args{ - columnName: TimestampColumnName, - }, - want: time.Unix(0, 1607596245228000000).Format(time.RFC3339), - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := createIoTDBRpcDataSet() - s.next() - if got := s.getText(tt.args.columnName); got != tt.want { - t.Errorf("IoTDBRpcDataSet.getText() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIoTDBRpcDataSet_getBool(t *testing.T) { - type args struct { - columnName string - } - tests := []struct { - name string - args args - want bool - }{ - { - name: "status", - args: args{ - columnName: "root.ln.device1.status", - }, - want: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := createIoTDBRpcDataSet() - s.next() - if got := s.getBool(tt.args.columnName); got != tt.want { - t.Errorf("IoTDBRpcDataSet.getBool() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIoTDBRpcDataSet_getFloat(t *testing.T) { - type args struct { - columnName string - } - tests := []struct { - name string - args args - want float32 - }{ - { - name: "temperature", - args: args{ - columnName: "root.ln.device1.temperature", - }, - want: 12.1, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := createIoTDBRpcDataSet() - s.next() - if got := s.getFloat(tt.args.columnName); got != tt.want { - t.Errorf("IoTDBRpcDataSet.getFloat() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIoTDBRpcDataSet_getDouble(t *testing.T) { - type args struct { - columnName string - } - tests := []struct { - name string - args args - want float64 - }{ - { - name: "price", - args: args{ - columnName: "root.ln.device1.price", - }, - want: 1988.2, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := createIoTDBRpcDataSet() - s.next() - if got := s.getDouble(tt.args.columnName); got != tt.want { - t.Errorf("IoTDBRpcDataSet.getDouble() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIoTDBRpcDataSet_getInt32(t *testing.T) { - type args struct { - columnName string - } - tests := []struct { - name string - args args - want int32 - }{ - { - name: "restart_count", - args: args{ - columnName: "root.ln.device1.restart_count", - }, - want: 1, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := createIoTDBRpcDataSet() - s.next() - if got := s.getInt32(tt.args.columnName); got != tt.want { - t.Errorf("IoTDBRpcDataSet.getInt32() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIoTDBRpcDataSet_getInt64(t *testing.T) { - type args struct { - columnName string - } - tests := []struct { - name string - args args - want int64 - }{ - { - name: "tick_count", - args: args{ - columnName: "root.ln.device1.tick_count", - }, - want: 3333333, - }, { - name: TimestampColumnName, - args: args{ - columnName: TimestampColumnName, - }, - want: 1607596245228, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := createIoTDBRpcDataSet() - s.next() - if got := s.getInt64(tt.args.columnName); got != tt.want { - t.Errorf("IoTDBRpcDataSet.getInt64() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIoTDBRpcDataSet_getRowRecord(t *testing.T) { - tests := []struct { - name string - want *RowRecord - wantErr bool - }{ - { - name: "", - want: &RowRecord{ - timestamp: 0, - fields: []*Field{ - { - name: "root.ln.device1.restart_count", - dataType: INT32, - value: int32(1), - }, { - name: "root.ln.device1.price", - dataType: DOUBLE, - value: float64(1988.2), - }, { - name: "root.ln.device1.tick_count", - dataType: INT64, - value: int64(3333333), - }, { - name: "root.ln.device1.temperature", - dataType: FLOAT, - value: float32(12.1), - }, { - name: "root.ln.device1.description", - dataType: TEXT, - value: "Test Device 1", - }, { - name: "root.ln.device1.status", - dataType: BOOLEAN, - 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), - }, - }, - }, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := createIoTDBRpcDataSet() - s.next() - got, err := s.getRowRecord() - if (err != nil) != tt.wantErr { - t.Errorf("IoTDBRpcDataSet.getRowRecord() error = %v, wantErr %v", err, tt.wantErr) - return - } - - match := true - for i := 0; i < len(got.fields); i++ { - gotField := got.fields[i] - wantField := tt.want.fields[i] - 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 { - t.Errorf("IoTDBRpcDataSet.getRowRecord() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIoTDBRpcDataSet_Close(t *testing.T) { - - tests := []struct { - name string - wantErr bool - }{ - { - name: "", - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := createIoTDBRpcDataSet() - s.next() - if err := s.Close(); (err != nil) != tt.wantErr { - t.Errorf("IoTDBRpcDataSet.Close() error = %v, wantErr %v", err, tt.wantErr) - } - }) - } -} diff --git a/client/session.go b/client/session.go index e5f2184..e749820 100644 --- a/client/session.go +++ b/client/session.go @@ -434,7 +434,7 @@ func (s *Session) ExecuteStatement(sql string) (*SessionDataSet, error) { } } - return s.genDataSet(sql, resp), err + return s.genDataSet(sql, resp) } func (s *Session) ExecuteNonQueryStatement(sql string) (r *common.TSStatus, err error) { @@ -462,7 +462,7 @@ func (s *Session) ExecuteQueryStatement(sql string, timeoutMs *int64) (*SessionD FetchSize: &s.config.FetchSize, Timeout: timeoutMs} if resp, err := s.client.ExecuteQueryStatement(context.Background(), &request); err == nil { if statusErr := VerifySuccess(resp.Status); statusErr == nil { - return NewSessionDataSet(sql, resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.client, s.sessionId, resp.QueryDataSet, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, s.config.FetchSize, timeoutMs), err + return NewSessionDataSet(sql, resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, *timeoutMs, *resp.MoreData, s.config.FetchSize) } else { return nil, statusErr } @@ -472,7 +472,7 @@ func (s *Session) ExecuteQueryStatement(sql string, timeoutMs *int64) (*SessionD request.StatementId = s.requestStatementId resp, err = s.client.ExecuteQueryStatement(context.Background(), &request) if statusErr := VerifySuccess(resp.Status); statusErr == nil { - return NewSessionDataSet(sql, resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.client, s.sessionId, resp.QueryDataSet, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, s.config.FetchSize, timeoutMs), err + return NewSessionDataSet(sql, resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, *timeoutMs, *resp.MoreData, s.config.FetchSize) } else { return nil, statusErr } @@ -489,7 +489,7 @@ func (s *Session) ExecuteAggregationQuery(paths []string, aggregations []common. Aggregations: aggregations, StartTime: startTime, EndTime: endTime, Interval: interval, FetchSize: &s.config.FetchSize, Timeout: timeoutMs} if resp, err := s.client.ExecuteAggregationQuery(context.Background(), &request); err == nil { if statusErr := VerifySuccess(resp.Status); statusErr == nil { - return NewSessionDataSet("", resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.client, s.sessionId, resp.QueryDataSet, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, s.config.FetchSize, timeoutMs), err + return NewSessionDataSet("", resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, *timeoutMs, *resp.MoreData, s.config.FetchSize) } else { return nil, statusErr } @@ -498,7 +498,7 @@ func (s *Session) ExecuteAggregationQuery(paths []string, aggregations []common. request.SessionId = s.sessionId resp, err = s.client.ExecuteAggregationQuery(context.Background(), &request) if statusErr := VerifySuccess(resp.Status); statusErr == nil { - return NewSessionDataSet("", resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.client, s.sessionId, resp.QueryDataSet, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, s.config.FetchSize, timeoutMs), err + return NewSessionDataSet("", resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, *timeoutMs, *resp.MoreData, s.config.FetchSize) } else { return nil, statusErr } @@ -516,7 +516,7 @@ func (s *Session) ExecuteAggregationQueryWithLegalNodes(paths []string, aggregat Timeout: timeoutMs, LegalPathNodes: legalNodes} if resp, err := s.client.ExecuteAggregationQuery(context.Background(), &request); err == nil { if statusErr := VerifySuccess(resp.Status); statusErr == nil { - return NewSessionDataSet("", resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.client, s.sessionId, resp.QueryDataSet, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, s.config.FetchSize, timeoutMs), err + return NewSessionDataSet("", resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, *timeoutMs, *resp.MoreData, s.config.FetchSize) } else { return nil, statusErr } @@ -525,7 +525,7 @@ func (s *Session) ExecuteAggregationQueryWithLegalNodes(paths []string, aggregat request.SessionId = s.sessionId resp, err = s.client.ExecuteAggregationQuery(context.Background(), &request) if statusErr := VerifySuccess(resp.Status); statusErr == nil { - return NewSessionDataSet("", resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.client, s.sessionId, resp.QueryDataSet, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, s.config.FetchSize, timeoutMs), err + return NewSessionDataSet("", resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, *timeoutMs, *resp.MoreData, s.config.FetchSize) } else { return nil, statusErr } @@ -828,7 +828,7 @@ func (s *Session) ExecuteRawDataQuery(paths []string, startTime int64, endTime i } } - return s.genDataSet("", resp), err + return s.genDataSet("", resp) } func (s *Session) ExecuteUpdateStatement(sql string) (*SessionDataSet, error) { @@ -848,10 +848,10 @@ func (s *Session) ExecuteUpdateStatement(sql string) (*SessionDataSet, error) { } } - return s.genDataSet(sql, resp), err + return s.genDataSet(sql, resp) } -func (s *Session) genDataSet(sql string, resp *rpc.TSExecuteStatementResp) *SessionDataSet { +func (s *Session) genDataSet(sql string, resp *rpc.TSExecuteStatementResp) (*SessionDataSet, error) { var queryId int64 if resp.QueryId == nil { queryId = 0 @@ -859,7 +859,7 @@ func (s *Session) genDataSet(sql string, resp *rpc.TSExecuteStatementResp) *Sess queryId = *resp.QueryId } return NewSessionDataSet(sql, resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, - queryId, s.client, s.sessionId, resp.QueryDataSet, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, s.config.FetchSize, nil) + queryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, 60000, *resp.MoreData, s.config.FetchSize) } func (s *Session) genInsertTabletsReq(tablets []*Tablet, isAligned bool) (*rpc.TSInsertTabletsReq, error) { diff --git a/client/sessiondataset.go b/client/sessiondataset.go index b1fafd4..2f24308 100644 --- a/client/sessiondataset.go +++ b/client/sessiondataset.go @@ -1,128 +1,102 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - package client import ( "github.com/apache/iotdb-client-go/rpc" -) - -const ( - TimestampColumnName = "Time" + "time" ) type SessionDataSet struct { ioTDBRpcDataSet *IoTDBRpcDataSet } -// Next prepares the next result row for reading, -// returns true on success, or false if there is no next result row or an error -// appened while preparing it. -// consulted Err should be consulted to distinguish between the two cases. -// This is not goroutine safe +func NewSessionDataSet(sql string, columnNameList []string, columnTypeList []string, columnNameIndex map[string]int32, queryId int64, statementId int64, client *rpc.IClientRPCServiceClient, sessionId int64, queryResult [][]byte, ignoreTimestamp bool, timeout int64, moreData bool, fetchSize int32) (*SessionDataSet, error) { + rpcDataSet, err := NewIoTDBRpcDataSet(sql, columnNameList, columnTypeList, columnNameIndex, ignoreTimestamp, moreData, queryId, statementId, client, sessionId, queryResult, fetchSize, timeout) + if err != nil { + return nil, err + } + return &SessionDataSet{ioTDBRpcDataSet: rpcDataSet}, nil +} + func (s *SessionDataSet) Next() (bool, error) { - return s.ioTDBRpcDataSet.next() + return s.ioTDBRpcDataSet.Next() } -// GetText returns string value of column value on row. -// This is not goroutine safe -func (s *SessionDataSet) GetText(columnName string) string { - return s.ioTDBRpcDataSet.getText(columnName) +func (s *SessionDataSet) Close() error { + return s.ioTDBRpcDataSet.Close() } -func (s *SessionDataSet) IsNull(columnName string) bool { - return s.ioTDBRpcDataSet.isNullWithColumnName(columnName) +func (s *SessionDataSet) IsNull(columnName string) (bool, error) { + return s.ioTDBRpcDataSet.isNullByColumnName(columnName), nil } -func (s *SessionDataSet) GetBool(columnName string) bool { - return s.ioTDBRpcDataSet.getBool(columnName) +func (s *SessionDataSet) IsNullByIndex(columnIndex int32) (bool, error) { + return s.ioTDBRpcDataSet.isNullByIndex(columnIndex) } -func (s *SessionDataSet) Scan(dest ...interface{}) error { - return s.ioTDBRpcDataSet.scan(dest...) +func (s *SessionDataSet) GetBooleanByIndex(columnIndex int32) (bool, error) { + return s.ioTDBRpcDataSet.getBooleanByIndex(columnIndex) } -func (s *SessionDataSet) GetFloat(columnName string) float32 { - return s.ioTDBRpcDataSet.getFloat(columnName) +func (s *SessionDataSet) GetBoolean(columnName string) (bool, error) { + return s.ioTDBRpcDataSet.getBoolean(columnName) } -func (s *SessionDataSet) GetDouble(columnName string) float64 { - return s.ioTDBRpcDataSet.getDouble(columnName) +func (s *SessionDataSet) GetDoubleByIndex(columnIndex int32) (float64, error) { + return s.ioTDBRpcDataSet.getDoubleByIndex(columnIndex) } -func (s *SessionDataSet) GetInt32(columnName string) int32 { - return s.ioTDBRpcDataSet.getInt32(columnName) +func (s *SessionDataSet) GetDouble(columnName string) (float64, error) { + return s.ioTDBRpcDataSet.getDouble(columnName) } -func (s *SessionDataSet) GetInt64(columnName string) int64 { - return s.ioTDBRpcDataSet.getInt64(columnName) +func (s *SessionDataSet) GetFloatByIndex(columnIndex int32) (float32, error) { + return s.ioTDBRpcDataSet.getFloatByIndex(columnIndex) } -func (s *SessionDataSet) GetTimestamp() int64 { - return s.ioTDBRpcDataSet.GetTimestamp() +func (s *SessionDataSet) GetFloat(columnName string) (float32, error) { + return s.ioTDBRpcDataSet.getFloat(columnName) } -func (s *SessionDataSet) GetValue(columnName string) interface{} { - return s.ioTDBRpcDataSet.getValue(columnName) +func (s *SessionDataSet) GetIntByIndex(columnIndex int32) (int32, error) { + return s.ioTDBRpcDataSet.getIntByIndex(columnIndex) } -func (s *SessionDataSet) GetRowRecord() (*RowRecord, error) { - return s.ioTDBRpcDataSet.getRowRecord() +func (s *SessionDataSet) GetInt(columnName string) (int32, error) { + return s.ioTDBRpcDataSet.getInt(columnName) } -func (s *SessionDataSet) GetColumnCount() int { - return s.ioTDBRpcDataSet.columnCount +func (s *SessionDataSet) GetLongByIndex(columnIndex int32) (int64, error) { + return s.ioTDBRpcDataSet.getLongByIndex(columnIndex) } -func (s *SessionDataSet) GetColumnDataType(columnIndex int) TSDataType { - return s.ioTDBRpcDataSet.columnTypeList[columnIndex] +func (s *SessionDataSet) GetLong(columnName string) (int64, error) { + return s.ioTDBRpcDataSet.getLong(columnName) } -func (s *SessionDataSet) GetColumnName(columnIndex int) string { - return s.ioTDBRpcDataSet.columnNameList[columnIndex] +func (s *SessionDataSet) GetStringByIndex(columnIndex int32) (string, error) { + return s.ioTDBRpcDataSet.getStringByIndex(columnIndex) } -func (s *SessionDataSet) GetColumnNames() []string { - return s.ioTDBRpcDataSet.columnNameList +func (s *SessionDataSet) GetString(columnName string) (string, error) { + return s.ioTDBRpcDataSet.getValueByName(columnName) } -func (s *SessionDataSet) IsIgnoreTimeStamp() bool { - return s.ioTDBRpcDataSet.ignoreTimeStamp +func (s *SessionDataSet) GetTimestampByIndex(columnIndex int32) (time.Time, error) { + return s.ioTDBRpcDataSet.GetTimestampByIndex(columnIndex) } -func (s *SessionDataSet) IsClosed() bool { - return s.ioTDBRpcDataSet.IsClosed() +func (s *SessionDataSet) GetTimestamp(columnName string) (time.Time, error) { + return s.ioTDBRpcDataSet.GetTimestamp(columnName) } -func (s *SessionDataSet) Close() error { - return s.ioTDBRpcDataSet.Close() +func (s *SessionDataSet) FindColumn(columnName string) int32 { + return s.ioTDBRpcDataSet.findColumn(columnName) } -func NewSessionDataSet(sql string, columnNameList []string, columnTypeList []string, - columnNameIndex map[string]int32, - queryId int64, client *rpc.IClientRPCServiceClient, sessionId int64, queryDataSet *rpc.TSQueryDataSet, - ignoreTimeStamp bool, fetchSize int32, timeoutMs *int64) *SessionDataSet { +func (s *SessionDataSet) GetColumnNames() []string { + return s.ioTDBRpcDataSet.ColumnNameList +} - return &SessionDataSet{ - ioTDBRpcDataSet: NewIoTDBRpcDataSet(sql, columnNameList, columnTypeList, - columnNameIndex, - queryId, client, sessionId, queryDataSet, - ignoreTimeStamp, fetchSize, timeoutMs), - } +func (s *SessionDataSet) GetColumnTypes() []string { + return s.ioTDBRpcDataSet.ColumnTypeList } diff --git a/client/tsblock.go b/client/tsblock.go new file mode 100644 index 0000000..3ce9c32 --- /dev/null +++ b/client/tsblock.go @@ -0,0 +1,162 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package client + +import ( + "bytes" + "encoding/binary" + "fmt" +) + +type TsBlock struct { + timeColumn *TimeColumn + valueColumns []Column + positionCount int32 +} + +func NewTsBlock(positionCount int32, timeColumn *TimeColumn, valueColumns ...Column) (*TsBlock, error) { + if valueColumns == nil { + return nil, fmt.Errorf("blocks is null") + } + return &TsBlock{ + timeColumn: timeColumn, + valueColumns: valueColumns, + positionCount: positionCount, + }, nil +} + +func DeserializeTsBlock(data []byte) (*TsBlock, error) { + // Serialized tsblock: + // +-------------+---------------+---------+------------+-----------+----------+ + // | val col cnt | val col types | pos cnt | encodings | time col | val col | + // +-------------+---------------+---------+------------+-----------+----------+ + // | int32 | list[byte] | int32 | list[byte] | bytes | bytes | + // +-------------+---------------+---------+------------+-----------+----------+ + + reader := bytes.NewReader(data) + // value column count + var valueColumnCount int32 + if err := binary.Read(reader, binary.BigEndian, &valueColumnCount); err != nil { + return nil, err + } + + // value column data types + valueColumnDataTypes := make([]TSDataType, valueColumnCount) + for i := int32(0); i < valueColumnCount; i++ { + dataType, err := deserializeDataType(reader) + if err != nil { + return nil, err + } + valueColumnDataTypes[i] = dataType + } + + // position count + var positionCount int32 + if err := binary.Read(reader, binary.BigEndian, &positionCount); err != nil { + return nil, err + } + + // column encodings + columnEncodings := make([]ColumnEncoding, valueColumnCount+1) + for i := int32(0); i < valueColumnCount+1; i++ { + columnEncoding, err := deserializeColumnEncoding(reader) + if err != nil { + return nil, err + } + columnEncodings[i] = columnEncoding + } + + // time column + timeColumnDecoder, err := getColumnDecoder(columnEncodings[0]) + if err != nil { + return nil, err + } + timeColumn, err := timeColumnDecoder.ReadTimeColumn(reader, positionCount) + if err != nil { + return nil, err + } + + // value columns + valueColumns := make([]Column, valueColumnCount) + for i := int32(0); i < valueColumnCount; i++ { + valueColumnDecoder, err := getColumnDecoder(columnEncodings[i+1]) + if err != nil { + return nil, err + } + valueColumn, err := valueColumnDecoder.ReadColumn(reader, valueColumnDataTypes[i], positionCount) + if err != nil { + return nil, err + } + valueColumns[i] = valueColumn + } + return NewTsBlock(positionCount, timeColumn, valueColumns...) +} + +func deserializeDataType(reader *bytes.Reader) (TSDataType, error) { + b, err := reader.ReadByte() + if err != nil { + return UNKNOWN, err + } + return getDataTypeByByte(b) +} + +func deserializeColumnEncoding(reader *bytes.Reader) (ColumnEncoding, error) { + b, err := reader.ReadByte() + if err != nil { + return RLE_COLUMN_ENCODING, err + } + return getColumnEncodingByByte(b) +} + +func (t *TsBlock) GetPositionCount() int32 { + return t.positionCount +} + +func (t *TsBlock) GetStartTime() int64 { + return t.timeColumn.GetStartTime() +} + +func (t *TsBlock) GetEndTime() int64 { + return t.timeColumn.GetEndTime() +} + +func (t *TsBlock) IsEmpty() bool { + return t.positionCount == 0 +} + +func (t *TsBlock) GetTimeByIndex(index int32) (int64, error) { + return t.timeColumn.GetLong(index) +} + +func (t *TsBlock) GetValueColumnCount() int32 { + return int32(len(t.valueColumns)) +} + +func (t *TsBlock) GetTimeColumn() Column { + return t.GetTimeColumn() +} + +func (t *TsBlock) GetValueColumns() *[]Column { + return &t.valueColumns +} + +func (t *TsBlock) GetColumn(columnIndex int32) Column { + return t.valueColumns[columnIndex] +} diff --git a/client/utils.go b/client/utils.go index 692e9a5..19e9d17 100644 --- a/client/utils.go +++ b/client/utils.go @@ -149,3 +149,15 @@ func VerifySuccess(status *common.TSStatus) error { } return nil } + +type Binary struct { + values []byte +} + +func NewBinary(v []byte) *Binary { + return &Binary{v} +} + +func (b *Binary) GetStringValue() string { + return string(b.values) +} diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index e4b91ea..0311aa2 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -378,7 +378,7 @@ func (s *e2eTestSuite) Test_InsertAlignedTablets() { defer ds.Close() assert.True(ds.Next()) var status string - assert.NoError(ds.Scan(&status)) + assert.NoError(ds.Get(&status)) assert.Equal(status, "8") s.session.DeleteStorageGroup("root.ln.**") } From 050f033c6a050e7e6749edb058534a8f705e424e Mon Sep 17 00:00:00 2001 From: shuwenwei Date: Mon, 24 Mar 2025 16:48:30 +0800 Subject: [PATCH 02/16] fix bug --- client/rpcdataset.go | 8 ++++++-- client/session.go | 4 ++-- client/sessiondataset_test.go | 38 +++++++++++++++++++++++++++++++++++ client/tsblock.go | 2 +- 4 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 client/sessiondataset_test.go diff --git a/client/rpcdataset.go b/client/rpcdataset.go index 3f2ced1..dde027b 100644 --- a/client/rpcdataset.go +++ b/client/rpcdataset.go @@ -135,8 +135,9 @@ func (s *IoTDBRpcDataSet) Close() (err error) { return nil } closeRequest := &rpc.TSCloseOperationReq{ - SessionId: s.SessionId, - QueryId: &s.QueryId, + SessionId: s.SessionId, + StatementId: &s.StatementId, + QueryId: &s.QueryId, } var status *common.TSStatus @@ -378,6 +379,9 @@ func (s *IoTDBRpcDataSet) getLong(columnName string) (int64, error) { if err != nil { return 0, err } + if columnName == TimestampColumnName { + return s.CurTsBlock.GetTimeByIndex(s.TsBlockIndex) + } index := s.ColumnOrdinalMap[columnName] - startIndex if !s.isNull(index, s.TsBlockIndex) { s.LastReadWasNull = false diff --git a/client/session.go b/client/session.go index e749820..33800e6 100644 --- a/client/session.go +++ b/client/session.go @@ -460,7 +460,7 @@ func (s *Session) ExecuteNonQueryStatement(sql string) (r *common.TSStatus, err func (s *Session) ExecuteQueryStatement(sql string, timeoutMs *int64) (*SessionDataSet, error) { request := rpc.TSExecuteStatementReq{SessionId: s.sessionId, Statement: sql, StatementId: s.requestStatementId, FetchSize: &s.config.FetchSize, Timeout: timeoutMs} - if resp, err := s.client.ExecuteQueryStatement(context.Background(), &request); err == nil { + if resp, err := s.client.ExecuteQueryStatementV2(context.Background(), &request); err == nil { if statusErr := VerifySuccess(resp.Status); statusErr == nil { return NewSessionDataSet(sql, resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, *timeoutMs, *resp.MoreData, s.config.FetchSize) } else { @@ -470,7 +470,7 @@ func (s *Session) ExecuteQueryStatement(sql string, timeoutMs *int64) (*SessionD if s.reconnect() { request.SessionId = s.sessionId request.StatementId = s.requestStatementId - resp, err = s.client.ExecuteQueryStatement(context.Background(), &request) + resp, err = s.client.ExecuteQueryStatementV2(context.Background(), &request) if statusErr := VerifySuccess(resp.Status); statusErr == nil { return NewSessionDataSet(sql, resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, *timeoutMs, *resp.MoreData, s.config.FetchSize) } else { diff --git a/client/sessiondataset_test.go b/client/sessiondataset_test.go new file mode 100644 index 0000000..977099a --- /dev/null +++ b/client/sessiondataset_test.go @@ -0,0 +1,38 @@ +package client + +import ( + "log" + "testing" +) + +func TestSessionDataSet_Next(t *testing.T) { + session := NewSession(&Config{ + Host: "127.0.0.1", + Port: "6667", + UserName: "root", + Password: "root", + }) + err := session.Open(false, 40000) + if err != nil { + log.Fatalf("err is %v", err) + return + } + var timeout int64 = 10000 + sessionDataSet, err := session.ExecuteQueryStatement("select * from root.test.d1", &timeout) + if err != nil { + log.Fatalf("err is %v", err) + return + } + for { + hasNext, err := sessionDataSet.Next() + if err != nil { + log.Fatalf("err is %v", err) + } + if !hasNext { + break + } + t, _ := sessionDataSet.GetLong("Time") + log.Printf("time is %v", t) + } + session.Close() +} diff --git a/client/tsblock.go b/client/tsblock.go index 3ce9c32..b9365e7 100644 --- a/client/tsblock.go +++ b/client/tsblock.go @@ -150,7 +150,7 @@ func (t *TsBlock) GetValueColumnCount() int32 { } func (t *TsBlock) GetTimeColumn() Column { - return t.GetTimeColumn() + return t.timeColumn } func (t *TsBlock) GetValueColumns() *[]Column { From 85fe58b50a71dae5f6e15c0df10ce1d41073fadd Mon Sep 17 00:00:00 2001 From: shuwenwei Date: Tue, 25 Mar 2025 18:57:50 +0800 Subject: [PATCH 03/16] fix bug --- client/column.go | 36 +- .../{column_encoder.go => column_decoder.go} | 6 +- client/protocol.go | 2 +- client/rpcdataset.go | 321 +++++++++--------- client/session.go | 24 +- client/sessiondataset.go | 4 +- example/session_example.go | 128 +++---- example/session_pool/session_pool_example.go | 146 +++----- 8 files changed, 298 insertions(+), 369 deletions(-) rename client/{column_encoder.go => column_decoder.go} (99%) diff --git a/client/column.go b/client/column.go index 962714f..23cb274 100644 --- a/client/column.go +++ b/client/column.go @@ -40,7 +40,7 @@ var encodingToDecoder = map[ColumnEncoding]ColumnDecoder{ } var byteToEncoding = map[byte]ColumnEncoding{ - 0: INT32_ARRAY_COLUMN_ENCODING, + 0: BYTE_ARRAY_COLUMN_ENCODING, 1: INT32_ARRAY_COLUMN_ENCODING, 2: INT64_ARRAY_COLUMN_ENCODING, 3: BINARY_ARRAY_COLUMN_ENCODING, @@ -92,31 +92,31 @@ type Column interface { type baseColumn struct { } -func (c *baseColumn) GetBoolean(position int32) (bool, error) { +func (c *baseColumn) GetBoolean(_ int32) (bool, error) { return false, fmt.Errorf("unsupported operation: GetBoolean") } -func (c *baseColumn) GetInt(position int32) (int32, error) { +func (c *baseColumn) GetInt(_ int32) (int32, error) { return 0, fmt.Errorf("unsupported operation: GetInt") } -func (c *baseColumn) GetLong(position int32) (int64, error) { +func (c *baseColumn) GetLong(_ int32) (int64, error) { return 0, fmt.Errorf("unsupported operation: GetLong") } -func (c *baseColumn) GetFloat(position int32) (float32, error) { +func (c *baseColumn) GetFloat(_ int32) (float32, error) { return 0, fmt.Errorf("unsupported operation: GetFloat") } -func (c *baseColumn) GetDouble(position int32) (float64, error) { +func (c *baseColumn) GetDouble(_ int32) (float64, error) { return 0, fmt.Errorf("unsupported operation: GetDouble") } -func (c *baseColumn) GetBinary(position int32) (*Binary, error) { +func (c *baseColumn) GetBinary(_ int32) (*Binary, error) { return nil, fmt.Errorf("unsupported operation: GetBinary") } -func (c *baseColumn) GetObject(position int32) (interface{}, error) { +func (c *baseColumn) GetObject(_ int32) (interface{}, error) { return nil, fmt.Errorf("unsupported operation: GetObject") } @@ -188,7 +188,7 @@ func (tc *TimeColumn) MayHaveNull() bool { return false } -func (tc *TimeColumn) IsNull(position int32) bool { +func (tc *TimeColumn) IsNull(_ int32) bool { return false } @@ -687,32 +687,32 @@ func (c *RunLengthEncodedColumn) GetEncoding() ColumnEncoding { return RLE_COLUMN_ENCODING } -func (c *RunLengthEncodedColumn) GetBoolean(position int32) (bool, error) { +func (c *RunLengthEncodedColumn) GetBoolean(_ int32) (bool, error) { return c.value.GetBoolean(0) } -func (c *RunLengthEncodedColumn) GetInt(position int32) (int32, error) { +func (c *RunLengthEncodedColumn) GetInt(_ int32) (int32, error) { return c.value.GetInt(0) } -func (c *RunLengthEncodedColumn) GetLong(position int32) (int64, error) { +func (c *RunLengthEncodedColumn) GetLong(_ int32) (int64, error) { return c.value.GetLong(0) } -func (c *RunLengthEncodedColumn) GetFloat(position int32) (float32, error) { +func (c *RunLengthEncodedColumn) GetFloat(_ int32) (float32, error) { return c.value.GetFloat(0) } -func (c *RunLengthEncodedColumn) GetDouble(position int32) (float64, error) { +func (c *RunLengthEncodedColumn) GetDouble(_ int32) (float64, error) { return c.value.GetDouble(0) } -func (c *RunLengthEncodedColumn) GetBinary(position int32) (*Binary, error) { +func (c *RunLengthEncodedColumn) GetBinary(_ int32) (*Binary, error) { return c.value.GetBinary(0) } -func (c *RunLengthEncodedColumn) GetObject(position int32) (interface{}, error) { - return c.value.GetObject(position) +func (c *RunLengthEncodedColumn) GetObject(_ int32) (interface{}, error) { + return c.value.GetObject(0) } func (c *RunLengthEncodedColumn) GetBooleans() ([]bool, error) { @@ -803,7 +803,7 @@ func (c *RunLengthEncodedColumn) MayHaveNull() bool { return c.value.MayHaveNull() } -func (c *RunLengthEncodedColumn) IsNull(position int32) bool { +func (c *RunLengthEncodedColumn) IsNull(_ int32) bool { return c.value.IsNull(0) } diff --git a/client/column_encoder.go b/client/column_decoder.go similarity index 99% rename from client/column_encoder.go rename to client/column_decoder.go index 07ba531..3367911 100644 --- a/client/column_encoder.go +++ b/client/column_decoder.go @@ -105,8 +105,7 @@ func (decoder *Int32ArrayColumnDecoder) ReadColumn(reader *bytes.Reader, dataTyp return nil, err } switch dataType { - case INT32: - case DATE: + case INT32, DATE: intValues := make([]int32, positionCount) for i := int32(0); i < positionCount; i++ { if nullIndicators != nil && nullIndicators[i] { @@ -172,8 +171,7 @@ func (decoder *Int64ArrayColumnDecoder) ReadColumn(reader *bytes.Reader, dataTyp return nil, err } switch dataType { - case INT64: - case TIMESTAMP: + case INT64, TIMESTAMP: values := make([]int64, positionCount) for i := int32(0); i < positionCount; i++ { if nullIndicators != nil && nullIndicators[i] { diff --git a/client/protocol.go b/client/protocol.go index b1df25d..faedfad 100644 --- a/client/protocol.go +++ b/client/protocol.go @@ -67,7 +67,7 @@ var byteToTsDataType = map[byte]TSDataType{ 11: STRING, } -func getDataTypeByStr(name string) (TSDataType, error) { +func GetDataTypeByStr(name string) (TSDataType, error) { dataType, exists := tsTypeMap[name] if !exists { return UNKNOWN, fmt.Errorf("invalid input: %v", name) diff --git a/client/rpcdataset.go b/client/rpcdataset.go index dde027b..92f98b9 100644 --- a/client/rpcdataset.go +++ b/client/rpcdataset.go @@ -9,68 +9,68 @@ import ( "time" ) -const startIndex = 2 +const startIndex = int32(2) type IoTDBRpcDataSet struct { - Sql string - IsClosed bool - Client *rpc.IClientRPCServiceClient - ColumnNameList []string - ColumnTypeList []string - ColumnOrdinalMap map[string]int32 - ColumnTypeDeduplicatedList []TSDataType - FetchSize int32 - Timeout int64 - HasCachedRecord bool - LastReadWasNull bool - - ColumnSize int32 - - SessionId int64 - QueryId int64 - StatementId int64 - Time int64 - IgnoreTimestamp bool + sql string + isClosed bool + client *rpc.IClientRPCServiceClient + columnNameList []string + columnTypeList []string + columnOrdinalMap map[string]int32 + columnTypeDeduplicatedList []TSDataType + fetchSize int32 + timeout int64 + hasCachedRecord bool + lastReadWasNull bool + + columnSize int32 + + sessionId int64 + queryId int64 + statementId int64 + time int64 + ignoreTimestamp bool // indicates that there is still more data in server side and we can call fetchResult to get more - MoreData bool + moreData bool - QueryResult [][]byte - CurTsBlock *TsBlock - QueryResultSize int32 // the length of queryResult - QueryResultIndex int32 // the index of bytebuffer in queryResult - TsBlockSize int32 // the size of current tsBlock - TsBlockIndex int32 // the row index in current tsBlock + queryResult [][]byte + curTsBlock *TsBlock + queryResultSize int32 // the length of queryResult + queryResultIndex int32 // the index of bytebuffer in queryResult + tsBlockSize int32 // the size of current tsBlock + tsBlockIndex int32 // the row index in current tsBlock } func NewIoTDBRpcDataSet(sql string, columnNameList []string, columnTypeList []string, columnNameIndex map[string]int32, ignoreTimestamp bool, moreData bool, queryId int64, statementId int64, client *rpc.IClientRPCServiceClient, sessionId int64, queryResult [][]byte, fetchSize int32, timeout int64) (rpcDataSet *IoTDBRpcDataSet, err error) { ds := &IoTDBRpcDataSet{ - SessionId: sessionId, - StatementId: statementId, - IgnoreTimestamp: ignoreTimestamp, - Sql: sql, - QueryId: queryId, - Client: client, - FetchSize: fetchSize, - Timeout: timeout, - MoreData: moreData, - ColumnSize: int32(len(columnNameList)), - ColumnNameList: columnNameList, - ColumnTypeList: columnTypeList, - ColumnOrdinalMap: make(map[string]int32), + sessionId: sessionId, + statementId: statementId, + ignoreTimestamp: ignoreTimestamp, + sql: sql, + queryId: queryId, + client: client, + fetchSize: fetchSize, + timeout: timeout, + moreData: moreData, + columnSize: int32(len(columnNameList)), + columnNameList: make([]string, 0, len(columnNameList)+1), + columnTypeList: make([]string, 0, len(columnTypeList)+1), + columnOrdinalMap: make(map[string]int32), } if !ignoreTimestamp { - ds.ColumnNameList = append(ds.ColumnNameList, TimestampColumnName) - ds.ColumnTypeList = append(ds.ColumnTypeList, "INT64") - ds.ColumnOrdinalMap[TimestampColumnName] = 1 + ds.columnNameList = append(ds.columnNameList, TimestampColumnName) + ds.columnTypeList = append(ds.columnTypeList, "INT64") + ds.columnOrdinalMap[TimestampColumnName] = 1 } - ds.ColumnNameList = append(ds.ColumnNameList, columnNameList...) - ds.ColumnTypeList = append(ds.ColumnTypeList, columnTypeList...) + ds.columnNameList = append(ds.columnNameList, columnNameList...) + ds.columnTypeList = append(ds.columnTypeList, columnTypeList...) if columnNameIndex != nil { deduplicatedColumnSize := getDeduplicatedColumnSize(columnNameIndex) - ds.ColumnTypeDeduplicatedList = make([]TSDataType, deduplicatedColumnSize) + ds.columnTypeDeduplicatedList = make([]TSDataType, deduplicatedColumnSize) for i, name := range columnNameList { - if _, exists := ds.ColumnOrdinalMap[name]; exists { + if _, exists := ds.columnOrdinalMap[name]; exists { continue } @@ -78,7 +78,7 @@ func NewIoTDBRpcDataSet(sql string, columnNameList []string, columnTypeList []st targetIndex := index + startIndex valueExists := false - for _, v := range ds.ColumnOrdinalMap { + for _, v := range ds.columnOrdinalMap { if v == targetIndex { valueExists = true break @@ -86,39 +86,39 @@ func NewIoTDBRpcDataSet(sql string, columnNameList []string, columnTypeList []st } if !valueExists { - if int(index) < len(ds.ColumnTypeDeduplicatedList) { - if ds.ColumnTypeDeduplicatedList[index], err = getDataTypeByStr(columnTypeList[i]); err != nil { + if int(index) < len(ds.columnTypeDeduplicatedList) { + if ds.columnTypeDeduplicatedList[index], err = GetDataTypeByStr(columnTypeList[i]); err != nil { return nil, err } } } - ds.ColumnOrdinalMap[name] = targetIndex + ds.columnOrdinalMap[name] = targetIndex } } else { - ds.ColumnTypeDeduplicatedList = make([]TSDataType, 0) + ds.columnTypeDeduplicatedList = make([]TSDataType, 0) index := startIndex for i := 0; i < len(columnNameList); i++ { name := columnNameList[i] - if _, exists := ds.ColumnOrdinalMap[name]; !exists { - dataType, err := getDataTypeByStr(columnTypeList[i]) + if _, exists := ds.columnOrdinalMap[name]; !exists { + dataType, err := GetDataTypeByStr(columnTypeList[i]) if err != nil { return nil, err } - ds.ColumnTypeDeduplicatedList = append(ds.ColumnTypeDeduplicatedList, dataType) - ds.ColumnOrdinalMap[name] = int32(index) + ds.columnTypeDeduplicatedList = append(ds.columnTypeDeduplicatedList, dataType) + ds.columnOrdinalMap[name] = int32(index) index++ } } } - ds.QueryResult = queryResult + ds.queryResult = queryResult if queryResult != nil { - ds.QueryResultSize = int32(len(queryResult)) + ds.queryResultSize = int32(len(queryResult)) } else { - ds.QueryResultSize = 0 + ds.queryResultSize = 0 } - ds.QueryResultIndex = 0 - ds.TsBlockSize = 0 - ds.TsBlockIndex = -1 + ds.queryResultIndex = 0 + ds.tsBlockSize = 0 + ds.tsBlockIndex = -1 return ds, nil } @@ -131,28 +131,28 @@ func getDeduplicatedColumnSize(columnNameList map[string]int32) int { } func (s *IoTDBRpcDataSet) Close() (err error) { - if s.IsClosed { + if s.isClosed { return nil } closeRequest := &rpc.TSCloseOperationReq{ - SessionId: s.SessionId, - StatementId: &s.StatementId, - QueryId: &s.QueryId, + SessionId: s.sessionId, + StatementId: &s.statementId, + QueryId: &s.queryId, } var status *common.TSStatus - status, err = s.Client.CloseOperation(context.Background(), closeRequest) + status, err = s.client.CloseOperation(context.Background(), closeRequest) if err == nil { err = VerifySuccess(status) } - s.Client = nil - s.IsClosed = true + s.client = nil + s.isClosed = true return err } func (s *IoTDBRpcDataSet) Next() (result bool, err error) { if s.hasCachedBlock() { - s.LastReadWasNull = false + s.lastReadWasNull = false err = s.constructOneRow() return true, err } @@ -164,7 +164,7 @@ func (s *IoTDBRpcDataSet) Next() (result bool, err error) { return true, err } - if s.MoreData { + if s.moreData { hasResultSet, err := s.fetchResults() if err != nil { return false, err @@ -185,19 +185,19 @@ func (s *IoTDBRpcDataSet) Next() (result bool, err error) { } func (s *IoTDBRpcDataSet) fetchResults() (bool, error) { - if s.IsClosed { + if s.isClosed { return false, fmt.Errorf("this data set is already closed") } req := rpc.TSFetchResultsReq{ - SessionId: s.SessionId, - Statement: s.Sql, - FetchSize: s.FetchSize, - QueryId: s.QueryId, + SessionId: s.sessionId, + Statement: s.sql, + FetchSize: s.fetchSize, + QueryId: s.queryId, IsAlign: true, } - req.Timeout = &s.Timeout + req.Timeout = &s.timeout - resp, err := s.Client.FetchResults(context.Background(), &req) + resp, err := s.client.FetchResultsV2(context.Background(), &req) if err != nil { return false, err @@ -210,42 +210,45 @@ func (s *IoTDBRpcDataSet) fetchResults() (bool, error) { if !resp.HasResultSet { err = s.Close() } else { - s.QueryResult = resp.GetQueryResult_() - s.QueryResultIndex = 0 - if s.QueryResult != nil { - s.QueryResultSize = int32(len(s.QueryResult)) + s.queryResult = resp.GetQueryResult_() + s.queryResultIndex = 0 + if s.queryResult != nil { + s.queryResultSize = int32(len(s.queryResult)) } else { - s.QueryResultSize = 0 + s.queryResultSize = 0 } - s.TsBlockSize = 0 - s.TsBlockIndex = -1 + s.tsBlockSize = 0 + s.tsBlockIndex = -1 } return resp.HasResultSet, err } func (s *IoTDBRpcDataSet) hasCachedBlock() bool { - return s.CurTsBlock != nil && s.TsBlockIndex < s.TsBlockSize-1 + return s.curTsBlock != nil && s.tsBlockIndex < s.tsBlockSize-1 } func (s *IoTDBRpcDataSet) hasCachedByteBuffer() bool { - return s.QueryResult != nil && s.QueryResultIndex < s.QueryResultSize + return s.queryResult != nil && s.queryResultIndex < s.queryResultSize } func (s *IoTDBRpcDataSet) constructOneRow() (err error) { - s.TsBlockIndex++ - s.HasCachedRecord = true - s.Time, err = s.CurTsBlock.GetTimeColumn().GetLong(s.TsBlockIndex) + s.tsBlockIndex++ + s.hasCachedRecord = true + s.time, err = s.curTsBlock.GetTimeColumn().GetLong(s.tsBlockIndex) return err } func (s *IoTDBRpcDataSet) constructOneTsBlock() (err error) { - s.LastReadWasNull = false - curTsBlockBytes := s.QueryResult[s.QueryResultIndex] - s.QueryResultIndex = s.QueryResultIndex + 1 - s.CurTsBlock, err = DeserializeTsBlock(curTsBlockBytes) - s.TsBlockIndex = -1 - s.TsBlockSize = s.CurTsBlock.GetPositionCount() - return err + s.lastReadWasNull = false + curTsBlockBytes := s.queryResult[s.queryResultIndex] + s.queryResultIndex = s.queryResultIndex + 1 + s.curTsBlock, err = DeserializeTsBlock(curTsBlockBytes) + if err != nil { + return err + } + s.tsBlockIndex = -1 + s.tsBlockSize = s.curTsBlock.GetPositionCount() + return nil } func (s *IoTDBRpcDataSet) isNullByIndex(columnIndex int32) (bool, error) { @@ -253,25 +256,25 @@ func (s *IoTDBRpcDataSet) isNullByIndex(columnIndex int32) (bool, error) { if err != nil { return false, err } - index := s.ColumnOrdinalMap[columnName] - startIndex + index := s.columnOrdinalMap[columnName] - startIndex // time column will never be null if index < 0 { return true, nil } - return s.isNull(index, s.TsBlockIndex), nil + return s.isNull(index, s.tsBlockIndex), nil } func (s *IoTDBRpcDataSet) isNullByColumnName(columnName string) bool { - index := s.ColumnOrdinalMap[columnName] - startIndex + index := s.columnOrdinalMap[columnName] - startIndex // time column will never be null if index < 0 { return true } - return s.isNull(index, s.TsBlockIndex) + return s.isNull(index, s.tsBlockIndex) } func (s *IoTDBRpcDataSet) isNull(index int32, rowNum int32) bool { - return s.CurTsBlock.GetColumn(index).IsNull(rowNum) + return s.curTsBlock.GetColumn(index).IsNull(rowNum) } func (s *IoTDBRpcDataSet) getBooleanByIndex(columnIndex int32) (bool, error) { @@ -287,12 +290,12 @@ func (s *IoTDBRpcDataSet) getBoolean(columnName string) (bool, error) { if err != nil { return false, err } - index := s.ColumnOrdinalMap[columnName] - startIndex - if !s.isNull(index, s.TsBlockIndex) { - s.LastReadWasNull = false - return s.CurTsBlock.GetColumn(index).GetBoolean(s.TsBlockIndex) + index := s.columnOrdinalMap[columnName] - startIndex + if !s.isNull(index, s.tsBlockIndex) { + s.lastReadWasNull = false + return s.curTsBlock.GetColumn(index).GetBoolean(s.tsBlockIndex) } else { - s.LastReadWasNull = true + s.lastReadWasNull = true return false, nil } } @@ -310,12 +313,12 @@ func (s *IoTDBRpcDataSet) getDouble(columnName string) (float64, error) { if err != nil { return 0, err } - index := s.ColumnOrdinalMap[columnName] - startIndex - if !s.isNull(index, s.TsBlockIndex) { - s.LastReadWasNull = false - return s.CurTsBlock.GetColumn(index).GetDouble(s.TsBlockIndex) + index := s.columnOrdinalMap[columnName] - startIndex + if !s.isNull(index, s.tsBlockIndex) { + s.lastReadWasNull = false + return s.curTsBlock.GetColumn(index).GetDouble(s.tsBlockIndex) } else { - s.LastReadWasNull = true + s.lastReadWasNull = true return 0, nil } } @@ -333,12 +336,12 @@ func (s *IoTDBRpcDataSet) getFloat(columnName string) (float32, error) { if err != nil { return 0, err } - index := s.ColumnOrdinalMap[columnName] - startIndex - if !s.isNull(index, s.TsBlockIndex) { - s.LastReadWasNull = false - return s.CurTsBlock.GetColumn(index).GetFloat(s.TsBlockIndex) + index := s.columnOrdinalMap[columnName] - startIndex + if !s.isNull(index, s.tsBlockIndex) { + s.lastReadWasNull = false + return s.curTsBlock.GetColumn(index).GetFloat(s.tsBlockIndex) } else { - s.LastReadWasNull = true + s.lastReadWasNull = true return 0, nil } } @@ -356,12 +359,20 @@ func (s *IoTDBRpcDataSet) getInt(columnName string) (int32, error) { if err != nil { return 0, err } - index := s.ColumnOrdinalMap[columnName] - startIndex - if !s.isNull(index, s.TsBlockIndex) { - s.LastReadWasNull = false - return s.CurTsBlock.GetColumn(index).GetInt(s.TsBlockIndex) + index := s.columnOrdinalMap[columnName] - startIndex + if !s.isNull(index, s.tsBlockIndex) { + s.lastReadWasNull = false + dataType := s.curTsBlock.GetColumn(index).GetDataType() + if dataType == INT64 { + if v, err := s.curTsBlock.GetColumn(index).GetLong(s.tsBlockIndex); err != nil { + return 0, err + } else { + return int32(v), nil + } + } + return s.curTsBlock.GetColumn(index).GetInt(s.tsBlockIndex) } else { - s.LastReadWasNull = true + s.lastReadWasNull = true return 0, nil } } @@ -380,14 +391,14 @@ func (s *IoTDBRpcDataSet) getLong(columnName string) (int64, error) { return 0, err } if columnName == TimestampColumnName { - return s.CurTsBlock.GetTimeByIndex(s.TsBlockIndex) + return s.curTsBlock.GetTimeByIndex(s.tsBlockIndex) } - index := s.ColumnOrdinalMap[columnName] - startIndex - if !s.isNull(index, s.TsBlockIndex) { - s.LastReadWasNull = false - return s.CurTsBlock.GetColumn(index).GetLong(s.TsBlockIndex) + index := s.columnOrdinalMap[columnName] - startIndex + if !s.isNull(index, s.tsBlockIndex) { + s.lastReadWasNull = false + return s.curTsBlock.GetColumn(index).GetLong(s.tsBlockIndex) } else { - s.LastReadWasNull = true + s.lastReadWasNull = true return 0, nil } } @@ -405,12 +416,12 @@ func (s *IoTDBRpcDataSet) getBinary(columnName string) (*Binary, error) { if err != nil { return nil, err } - index := s.ColumnOrdinalMap[columnName] - startIndex - if !s.isNull(index, s.TsBlockIndex) { - s.LastReadWasNull = false - return s.CurTsBlock.GetColumn(index).GetBinary(s.TsBlockIndex) + index := s.columnOrdinalMap[columnName] - startIndex + if !s.isNull(index, s.tsBlockIndex) { + s.lastReadWasNull = false + return s.curTsBlock.GetColumn(index).GetBinary(s.tsBlockIndex) } else { - s.LastReadWasNull = true + s.lastReadWasNull = true return nil, nil } } @@ -436,7 +447,7 @@ func (s *IoTDBRpcDataSet) GetTimestamp(columnName string) (time.Time, error) { } func (s *IoTDBRpcDataSet) findColumn(columnName string) int32 { - return s.ColumnOrdinalMap[columnName] + return s.columnOrdinalMap[columnName] } func (s *IoTDBRpcDataSet) getValueByName(columnName string) (string, error) { @@ -445,69 +456,67 @@ func (s *IoTDBRpcDataSet) getValueByName(columnName string) (string, error) { return "", err } if columnName == TimestampColumnName { - if t, err := s.CurTsBlock.GetTimeByIndex(s.TsBlockIndex); err != nil { + if t, err := s.curTsBlock.GetTimeByIndex(s.tsBlockIndex); err != nil { return "", err } else { return int64ToString(t), nil } } - index := s.ColumnOrdinalMap[columnName] - startIndex - if index < 0 || index >= int32(len(s.ColumnTypeDeduplicatedList)) || s.isNull(index, s.TsBlockIndex) { - s.LastReadWasNull = true + index := s.columnOrdinalMap[columnName] - startIndex + if index < 0 || index >= int32(len(s.columnTypeDeduplicatedList)) || s.isNull(index, s.tsBlockIndex) { + s.lastReadWasNull = true return "", err } - s.LastReadWasNull = false - return s.getString(index, s.ColumnTypeDeduplicatedList[index]) + s.lastReadWasNull = false + return s.getString(index, s.columnTypeDeduplicatedList[index]) } func (s *IoTDBRpcDataSet) getString(index int32, tsDataType TSDataType) (string, error) { switch tsDataType { case BOOLEAN: - if v, err := s.CurTsBlock.GetColumn(index).GetBoolean(s.TsBlockIndex); err != nil { + if v, err := s.curTsBlock.GetColumn(index).GetBoolean(s.tsBlockIndex); err != nil { return "", nil } else { return strconv.FormatBool(v), nil } case INT32: - if v, err := s.CurTsBlock.GetColumn(index).GetInt(s.TsBlockIndex); err != nil { + if v, err := s.curTsBlock.GetColumn(index).GetInt(s.tsBlockIndex); err != nil { return "", err } else { return int32ToString(v), nil } - case INT64: - case TIMESTAMP: - if v, err := s.CurTsBlock.GetColumn(index).GetLong(s.TsBlockIndex); err != nil { + case INT64, TIMESTAMP: + if v, err := s.curTsBlock.GetColumn(index).GetLong(s.tsBlockIndex); err != nil { return "", err } else { return int64ToString(v), nil } case FLOAT: - if v, err := s.CurTsBlock.GetColumn(index).GetFloat(s.TsBlockIndex); err != nil { + if v, err := s.curTsBlock.GetColumn(index).GetFloat(s.tsBlockIndex); err != nil { return "", err } else { return float32ToString(v), nil } case DOUBLE: - if v, err := s.CurTsBlock.GetColumn(index).GetDouble(s.TsBlockIndex); err != nil { + if v, err := s.curTsBlock.GetColumn(index).GetDouble(s.tsBlockIndex); err != nil { return "", err } else { return float64ToString(v), nil } - case TEXT: - case STRING: - if v, err := s.CurTsBlock.GetColumn(index).GetBinary(s.TsBlockIndex); err != nil { + case TEXT, STRING: + if v, err := s.curTsBlock.GetColumn(index).GetBinary(s.tsBlockIndex); err != nil { return "", err } else { return v.GetStringValue(), nil } case BLOB: - if v, err := s.CurTsBlock.GetColumn(index).GetBinary(s.TsBlockIndex); err != nil { + if v, err := s.curTsBlock.GetColumn(index).GetBinary(s.tsBlockIndex); err != nil { return "", err } else { return bytesToHexString(v.values), nil } case DATE: - v, err := s.CurTsBlock.GetColumn(index).GetInt(s.TsBlockIndex) + v, err := s.curTsBlock.GetColumn(index).GetInt(s.tsBlockIndex) if err != nil { return "", err } @@ -524,14 +533,14 @@ func (s *IoTDBRpcDataSet) findColumnNameByIndex(columnIndex int32) (string, erro if columnIndex <= 0 { return "", fmt.Errorf("column index should start from 1") } - if columnIndex > int32(len(s.ColumnNameList)) { - return "", fmt.Errorf("column index %d out of range %d", columnIndex, len(s.ColumnNameList)) + if columnIndex > int32(len(s.columnNameList)) { + return "", fmt.Errorf("column index %d out of range %d", columnIndex, len(s.columnNameList)) } - return s.ColumnNameList[columnIndex-1], nil + return s.columnNameList[columnIndex-1], nil } func (s *IoTDBRpcDataSet) checkRecord() (err error) { - if s.QueryResultIndex > s.QueryResultSize || s.TsBlockIndex >= s.TsBlockSize || s.QueryResult == nil || s.CurTsBlock == nil { + if s.queryResultIndex > s.queryResultSize || s.tsBlockIndex >= s.tsBlockSize || s.queryResult == nil || s.curTsBlock == nil { err = fmt.Errorf("no record remains") } return err diff --git a/client/session.go b/client/session.go index 33800e6..9f9534e 100644 --- a/client/session.go +++ b/client/session.go @@ -424,13 +424,13 @@ func (s *Session) ExecuteStatement(sql string) (*SessionDataSet, error) { StatementId: s.requestStatementId, FetchSize: &s.config.FetchSize, } - resp, err := s.client.ExecuteStatement(context.Background(), &request) + resp, err := s.client.ExecuteStatementV2(context.Background(), &request) if err != nil && resp == nil { if s.reconnect() { request.SessionId = s.sessionId request.StatementId = s.requestStatementId - resp, err = s.client.ExecuteStatement(context.Background(), &request) + resp, err = s.client.ExecuteStatementV2(context.Background(), &request) } } @@ -444,13 +444,13 @@ func (s *Session) ExecuteNonQueryStatement(sql string) (r *common.TSStatus, err StatementId: s.requestStatementId, FetchSize: &s.config.FetchSize, } - resp, err := s.client.ExecuteStatement(context.Background(), &request) + resp, err := s.client.ExecuteStatementV2(context.Background(), &request) if err != nil && resp == nil { if s.reconnect() { request.SessionId = s.sessionId request.StatementId = s.requestStatementId - resp, err = s.client.ExecuteStatement(context.Background(), &request) + resp, err = s.client.ExecuteStatementV2(context.Background(), &request) } } @@ -487,7 +487,7 @@ func (s *Session) ExecuteAggregationQuery(paths []string, aggregations []common. request := rpc.TSAggregationQueryReq{SessionId: s.sessionId, StatementId: s.requestStatementId, Paths: paths, Aggregations: aggregations, StartTime: startTime, EndTime: endTime, Interval: interval, FetchSize: &s.config.FetchSize, Timeout: timeoutMs} - if resp, err := s.client.ExecuteAggregationQuery(context.Background(), &request); err == nil { + if resp, err := s.client.ExecuteAggregationQueryV2(context.Background(), &request); err == nil { if statusErr := VerifySuccess(resp.Status); statusErr == nil { return NewSessionDataSet("", resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, *timeoutMs, *resp.MoreData, s.config.FetchSize) } else { @@ -496,7 +496,7 @@ func (s *Session) ExecuteAggregationQuery(paths []string, aggregations []common. } else { if s.reconnect() { request.SessionId = s.sessionId - resp, err = s.client.ExecuteAggregationQuery(context.Background(), &request) + resp, err = s.client.ExecuteAggregationQueryV2(context.Background(), &request) if statusErr := VerifySuccess(resp.Status); statusErr == nil { return NewSessionDataSet("", resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, *timeoutMs, *resp.MoreData, s.config.FetchSize) } else { @@ -514,7 +514,7 @@ func (s *Session) ExecuteAggregationQueryWithLegalNodes(paths []string, aggregat request := rpc.TSAggregationQueryReq{SessionId: s.sessionId, StatementId: s.requestStatementId, Paths: paths, Aggregations: aggregations, StartTime: startTime, EndTime: endTime, Interval: interval, FetchSize: &s.config.FetchSize, Timeout: timeoutMs, LegalPathNodes: legalNodes} - if resp, err := s.client.ExecuteAggregationQuery(context.Background(), &request); err == nil { + if resp, err := s.client.ExecuteAggregationQueryV2(context.Background(), &request); err == nil { if statusErr := VerifySuccess(resp.Status); statusErr == nil { return NewSessionDataSet("", resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, *timeoutMs, *resp.MoreData, s.config.FetchSize) } else { @@ -523,7 +523,7 @@ func (s *Session) ExecuteAggregationQueryWithLegalNodes(paths []string, aggregat } else { if s.reconnect() { request.SessionId = s.sessionId - resp, err = s.client.ExecuteAggregationQuery(context.Background(), &request) + resp, err = s.client.ExecuteAggregationQueryV2(context.Background(), &request) if statusErr := VerifySuccess(resp.Status); statusErr == nil { return NewSessionDataSet("", resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, *timeoutMs, *resp.MoreData, s.config.FetchSize) } else { @@ -818,13 +818,13 @@ func (s *Session) ExecuteRawDataQuery(paths []string, startTime int64, endTime i EndTime: endTime, StatementId: s.requestStatementId, } - resp, err := s.client.ExecuteRawDataQuery(context.Background(), &request) + resp, err := s.client.ExecuteRawDataQueryV2(context.Background(), &request) if err != nil && resp == nil { if s.reconnect() { request.SessionId = s.sessionId request.StatementId = s.requestStatementId - resp, err = s.client.ExecuteRawDataQuery(context.Background(), &request) + resp, err = s.client.ExecuteRawDataQueryV2(context.Background(), &request) } } @@ -838,13 +838,13 @@ func (s *Session) ExecuteUpdateStatement(sql string) (*SessionDataSet, error) { StatementId: s.requestStatementId, FetchSize: &s.config.FetchSize, } - resp, err := s.client.ExecuteUpdateStatement(context.Background(), &request) + resp, err := s.client.ExecuteUpdateStatementV2(context.Background(), &request) if err != nil && resp == nil { if s.reconnect() { request.SessionId = s.sessionId request.StatementId = s.requestStatementId - resp, err = s.client.ExecuteUpdateStatement(context.Background(), &request) + resp, err = s.client.ExecuteUpdateStatementV2(context.Background(), &request) } } diff --git a/client/sessiondataset.go b/client/sessiondataset.go index 2f24308..cc1bdcf 100644 --- a/client/sessiondataset.go +++ b/client/sessiondataset.go @@ -94,9 +94,9 @@ func (s *SessionDataSet) FindColumn(columnName string) int32 { } func (s *SessionDataSet) GetColumnNames() []string { - return s.ioTDBRpcDataSet.ColumnNameList + return s.ioTDBRpcDataSet.columnNameList } func (s *SessionDataSet) GetColumnTypes() []string { - return s.ioTDBRpcDataSet.ColumnTypeList + return s.ioTDBRpcDataSet.columnTypeList } diff --git a/example/session_example.go b/example/session_example.go index 32026c1..1b31514 100644 --- a/example/session_example.go +++ b/example/session_example.go @@ -162,41 +162,22 @@ func connectCluster() { } func printDevice1(sds *client.SessionDataSet) { - showTimestamp := !sds.IsIgnoreTimeStamp() - if showTimestamp { - fmt.Print("Time\t\t\t\t") - } - for _, columnName := range sds.GetColumnNames() { fmt.Printf("%s\t", columnName) } fmt.Println() for next, err := sds.Next(); err == nil && next; next, err = sds.Next() { - if showTimestamp { - fmt.Printf("%s\t", sds.GetText(client.TimestampColumnName)) - } - - var restartCount int32 - var price float64 - var tickCount int64 - var temperature float32 - var description string - var status bool - - // All of iotdb datatypes can be scan into string variables - // var restartCount string - // var price string - // var tickCount string - // var temperature string - // var description string - // var status string - - if err := sds.Scan(&restartCount, &tickCount, &price, &temperature, &description, &status); err != nil { - log.Fatal(err) - } + timestamp, _ := sds.GetStringByIndex(1) + restartCount, _ := sds.GetIntByIndex(2) + tickCount, _ := sds.GetLongByIndex(3) + price, _ := sds.GetDoubleByIndex(4) + temperature, _ := sds.GetFloatByIndex(5) + description, _ := sds.GetStringByIndex(6) + status, _ := sds.GetBooleanByIndex(7) whitespace := "\t\t" + fmt.Printf("%s\t", timestamp) fmt.Printf("%v%s", restartCount, whitespace) fmt.Printf("%v%s", price, whitespace) fmt.Printf("%v%s", tickCount, whitespace) @@ -209,35 +190,34 @@ func printDevice1(sds *client.SessionDataSet) { } func printDataSet0(sessionDataSet *client.SessionDataSet) { - showTimestamp := !sessionDataSet.IsIgnoreTimeStamp() - if showTimestamp { - fmt.Print("Time\t\t\t\t") - } - - for i := 0; i < sessionDataSet.GetColumnCount(); i++ { - fmt.Printf("%s\t", sessionDataSet.GetColumnName(i)) + columns := sessionDataSet.GetColumnNames() + for _, columnName := range columns { + fmt.Printf("%s\t", columnName) } fmt.Println() for next, err := sessionDataSet.Next(); err == nil && next; next, err = sessionDataSet.Next() { - if showTimestamp { - fmt.Printf("%s\t", sessionDataSet.GetText(client.TimestampColumnName)) - } - for i := 0; i < sessionDataSet.GetColumnCount(); i++ { - columnName := sessionDataSet.GetColumnName(i) - switch sessionDataSet.GetColumnDataType(i) { + for i, columnName := range columns { + dataType, _ := client.GetDataTypeByStr(sessionDataSet.GetColumnTypes()[i]) + switch dataType { case client.BOOLEAN: - fmt.Print(sessionDataSet.GetBool(columnName)) + value, _ := sessionDataSet.GetBoolean(columnName) + fmt.Print(value) case client.INT32: - fmt.Print(sessionDataSet.GetInt32(columnName)) + value, _ := sessionDataSet.GetInt(columnName) + fmt.Print(value) case client.INT64, client.TIMESTAMP: - fmt.Print(sessionDataSet.GetInt64(columnName)) + value, _ := sessionDataSet.GetLong(columnName) + fmt.Print(value) case client.FLOAT: - fmt.Print(sessionDataSet.GetFloat(columnName)) + value, _ := sessionDataSet.GetFloat(columnName) + fmt.Print(value) case client.DOUBLE: - fmt.Print(sessionDataSet.GetDouble(columnName)) + value, _ := sessionDataSet.GetDouble(columnName) + fmt.Print(value) case client.TEXT, client.STRING, client.BLOB, client.DATE: - fmt.Print(sessionDataSet.GetText(columnName)) + value, _ := sessionDataSet.GetString(columnName) + fmt.Print(value) default: } fmt.Print("\t\t") @@ -247,58 +227,46 @@ func printDataSet0(sessionDataSet *client.SessionDataSet) { } func printDataSet1(sds *client.SessionDataSet) { - showTimestamp := !sds.IsIgnoreTimeStamp() - if showTimestamp { - fmt.Print("Time\t\t\t\t") - } - - for i := 0; i < sds.GetColumnCount(); i++ { - fmt.Printf("%s\t", sds.GetColumnName(i)) + columnNames := sds.GetColumnNames() + for _, value := range columnNames { + fmt.Printf("%s\t", value) } fmt.Println() for next, err := sds.Next(); err == nil && next; next, err = sds.Next() { - if showTimestamp { - fmt.Printf("%s\t", sds.GetText(client.TimestampColumnName)) - } - for i := 0; i < sds.GetColumnCount(); i++ { - columnName := sds.GetColumnName(i) - v := sds.GetValue(columnName) - if v == nil { - v = "null" + for _, columnName := range columnNames { + isNull, _ := sds.IsNull(columnName) + + if isNull { + fmt.Printf("%v\t\t", "null") + } else { + v, _ := sds.GetString(columnName) + fmt.Printf("%v\t\t", v) } - fmt.Printf("%v\t\t", v) } fmt.Println() } } func printDataSet2(sds *client.SessionDataSet) { - showTimestamp := !sds.IsIgnoreTimeStamp() - if showTimestamp { - fmt.Print("Time\t\t\t\t") - } - - for i := 0; i < sds.GetColumnCount(); i++ { - fmt.Printf("%s\t", sds.GetColumnName(i)) + columnNames := sds.GetColumnNames() + for _, value := range columnNames { + fmt.Printf("%s\t", value) } fmt.Println() for next, err := sds.Next(); err == nil && next; next, err = sds.Next() { - if showTimestamp { - fmt.Printf("%s\t", sds.GetText(client.TimestampColumnName)) - } + for i := int32(0); i < int32(len(columnNames)); i++ { + isNull, _ := sds.IsNullByIndex(i) - if record, err := sds.GetRowRecord(); err == nil { - for _, field := range record.GetFields() { - v := field.GetValue() - if field.IsNull() { - v = "null" - } + if isNull { + fmt.Printf("%v\t\t", "null") + } else { + v, _ := sds.GetStringByIndex(i) fmt.Printf("%v\t\t", v) } - fmt.Println() } + fmt.Println() } } @@ -641,7 +609,7 @@ func executeAggregationQueryStatementWithLegalNodes(paths []string, aggregations } func executeRawDataQuery() { - session.ExecuteUpdateStatement("insert into root.ln.wf02.wt02(time,s5) values(1,true)") + session.ExecuteNonQueryStatement("insert into root.ln.wf02.wt02(time,s5) values(1,true)") var ( paths = []string{"root.ln.wf02.wt02.s5"} startTime int64 = 1 diff --git a/example/session_pool/session_pool_example.go b/example/session_pool/session_pool_example.go index 459393b..6f52ffe 100644 --- a/example/session_pool/session_pool_example.go +++ b/example/session_pool/session_pool_example.go @@ -26,7 +26,6 @@ import ( "log" "math/rand" "strings" - "sync" "time" "github.com/apache/iotdb-client-go/client" @@ -55,18 +54,6 @@ func main() { sessionPool = client.NewSessionPool(config, 3, 60000, 60000, false) defer sessionPool.Close() - var wg sync.WaitGroup - for i := 0; i < 10000; i++ { - var j = i - wg.Add(1) - go func() { - defer wg.Done() - setStorageGroup(fmt.Sprintf("root.ln-%d", j)) - deleteStorageGroup(fmt.Sprintf("root.ln-%d", j)) - - }() - - } //useNodeUrls() setStorageGroup("root.ln1") setStorageGroup("root.ln2") @@ -136,7 +123,6 @@ func main() { insertAlignedTablets() deleteTimeseries("root.ln.device1.*") executeQueryStatement("show timeseries root.**") - wg.Wait() } @@ -604,7 +590,7 @@ func executeRawDataQuery() { log.Print(err) return } - session.ExecuteUpdateStatement("insert into root.ln.wf02.wt02(time,s5) values(1,true)") + session.ExecuteNonQueryStatement("insert into root.ln.wf02.wt02(time,s5) values(1,true)") var ( paths []string = []string{"root.ln.wf02.wt02.s5"} startTime int64 = 1 @@ -631,41 +617,22 @@ func executeBatchStatement() { } func printDevice1(sds *client.SessionDataSet) { - showTimestamp := !sds.IsIgnoreTimeStamp() - if showTimestamp { - fmt.Print("Time\t\t\t\t") - } - for _, columnName := range sds.GetColumnNames() { fmt.Printf("%s\t", columnName) } fmt.Println() for next, err := sds.Next(); err == nil && next; next, err = sds.Next() { - if showTimestamp { - fmt.Printf("%s\t", sds.GetText(client.TimestampColumnName)) - } - - var restartCount int32 - var price float64 - var tickCount int64 - var temperature float32 - var description string - var status bool - - // All of iotdb datatypes can be scan into string variables - // var restartCount string - // var price string - // var tickCount string - // var temperature string - // var description string - // var status string - - if err := sds.Scan(&restartCount, &tickCount, &price, &temperature, &description, &status); err != nil { - log.Fatal(err) - } + timestamp, _ := sds.GetStringByIndex(1) + restartCount, _ := sds.GetIntByIndex(2) + tickCount, _ := sds.GetLongByIndex(3) + price, _ := sds.GetDoubleByIndex(4) + temperature, _ := sds.GetFloatByIndex(5) + description, _ := sds.GetStringByIndex(6) + status, _ := sds.GetBooleanByIndex(7) whitespace := "\t\t" + fmt.Printf("%s\t", timestamp) fmt.Printf("%v%s", restartCount, whitespace) fmt.Printf("%v%s", price, whitespace) fmt.Printf("%v%s", tickCount, whitespace) @@ -678,35 +645,34 @@ func printDevice1(sds *client.SessionDataSet) { } func printDataSet0(sessionDataSet *client.SessionDataSet) { - showTimestamp := !sessionDataSet.IsIgnoreTimeStamp() - if showTimestamp { - fmt.Print("Time\t\t\t\t") - } - - for i := 0; i < sessionDataSet.GetColumnCount(); i++ { - fmt.Printf("%s\t", sessionDataSet.GetColumnName(i)) + columns := sessionDataSet.GetColumnNames() + for _, columnName := range columns { + fmt.Printf("%s\t", columnName) } fmt.Println() for next, err := sessionDataSet.Next(); err == nil && next; next, err = sessionDataSet.Next() { - if showTimestamp { - fmt.Printf("%s\t", sessionDataSet.GetText(client.TimestampColumnName)) - } - for i := 0; i < sessionDataSet.GetColumnCount(); i++ { - columnName := sessionDataSet.GetColumnName(i) - switch sessionDataSet.GetColumnDataType(i) { + for i, columnName := range columns { + dataType, _ := client.GetDataTypeByStr(sessionDataSet.GetColumnTypes()[i]) + switch dataType { case client.BOOLEAN: - fmt.Print(sessionDataSet.GetBool(columnName)) + value, _ := sessionDataSet.GetBoolean(columnName) + fmt.Print(value) case client.INT32: - fmt.Print(sessionDataSet.GetInt32(columnName)) - case client.INT64: - fmt.Print(sessionDataSet.GetInt64(columnName)) + value, _ := sessionDataSet.GetInt(columnName) + fmt.Print(value) + case client.INT64, client.TIMESTAMP: + value, _ := sessionDataSet.GetLong(columnName) + fmt.Print(value) case client.FLOAT: - fmt.Print(sessionDataSet.GetFloat(columnName)) + value, _ := sessionDataSet.GetFloat(columnName) + fmt.Print(value) case client.DOUBLE: - fmt.Print(sessionDataSet.GetDouble(columnName)) - case client.TEXT: - fmt.Print(sessionDataSet.GetText(columnName)) + value, _ := sessionDataSet.GetDouble(columnName) + fmt.Print(value) + case client.TEXT, client.STRING, client.BLOB, client.DATE: + value, _ := sessionDataSet.GetString(columnName) + fmt.Print(value) default: } fmt.Print("\t\t") @@ -716,58 +682,46 @@ func printDataSet0(sessionDataSet *client.SessionDataSet) { } func printDataSet1(sds *client.SessionDataSet) { - showTimestamp := !sds.IsIgnoreTimeStamp() - if showTimestamp { - fmt.Print("Time\t\t\t\t") - } - - for i := 0; i < sds.GetColumnCount(); i++ { - fmt.Printf("%s\t", sds.GetColumnName(i)) + columnNames := sds.GetColumnNames() + for _, value := range columnNames { + fmt.Printf("%s\t", value) } fmt.Println() for next, err := sds.Next(); err == nil && next; next, err = sds.Next() { - if showTimestamp { - fmt.Printf("%s\t", sds.GetText(client.TimestampColumnName)) - } - for i := 0; i < sds.GetColumnCount(); i++ { - columnName := sds.GetColumnName(i) - v := sds.GetValue(columnName) - if v == nil { - v = "null" + for _, columnName := range columnNames { + isNull, _ := sds.IsNull(columnName) + + if isNull { + fmt.Printf("%v\t\t", "null") + } else { + v, _ := sds.GetString(columnName) + fmt.Printf("%v\t\t", v) } - fmt.Printf("%v\t\t", v) } fmt.Println() } } func printDataSet2(sds *client.SessionDataSet) { - showTimestamp := !sds.IsIgnoreTimeStamp() - if showTimestamp { - fmt.Print("Time\t\t\t\t") - } - - for i := 0; i < sds.GetColumnCount(); i++ { - fmt.Printf("%s\t", sds.GetColumnName(i)) + columnNames := sds.GetColumnNames() + for _, value := range columnNames { + fmt.Printf("%s\t", value) } fmt.Println() for next, err := sds.Next(); err == nil && next; next, err = sds.Next() { - if showTimestamp { - fmt.Printf("%s\t", sds.GetText(client.TimestampColumnName)) - } + for i := int32(0); i < int32(len(columnNames)); i++ { + isNull, _ := sds.IsNullByIndex(i) - if record, err := sds.GetRowRecord(); err == nil { - for _, field := range record.GetFields() { - v := field.GetValue() - if field.IsNull() { - v = "null" - } + if isNull { + fmt.Printf("%v\t\t", "null") + } else { + v, _ := sds.GetStringByIndex(i) fmt.Printf("%v\t\t", v) } - fmt.Println() } + fmt.Println() } } From e621cd34277a3ce472e86c1e0276e6fce1b285ef Mon Sep 17 00:00:00 2001 From: shuwenwei Date: Wed, 26 Mar 2025 10:58:33 +0800 Subject: [PATCH 04/16] fix ut --- client/rpcdataset.go | 33 +++++++++++++++++++++++++++--- client/session.go | 14 ++++++------- client/sessiondataset.go | 2 +- client/tablet_test.go | 2 +- test/e2e/e2e_test.go | 43 ++++++++++++++++++++-------------------- 5 files changed, 61 insertions(+), 33 deletions(-) diff --git a/client/rpcdataset.go b/client/rpcdataset.go index 92f98b9..36a74bf 100644 --- a/client/rpcdataset.go +++ b/client/rpcdataset.go @@ -20,7 +20,7 @@ type IoTDBRpcDataSet struct { columnOrdinalMap map[string]int32 columnTypeDeduplicatedList []TSDataType fetchSize int32 - timeout int64 + timeout *int64 hasCachedRecord bool lastReadWasNull bool @@ -42,7 +42,7 @@ type IoTDBRpcDataSet struct { tsBlockIndex int32 // the row index in current tsBlock } -func NewIoTDBRpcDataSet(sql string, columnNameList []string, columnTypeList []string, columnNameIndex map[string]int32, ignoreTimestamp bool, moreData bool, queryId int64, statementId int64, client *rpc.IClientRPCServiceClient, sessionId int64, queryResult [][]byte, fetchSize int32, timeout int64) (rpcDataSet *IoTDBRpcDataSet, err error) { +func NewIoTDBRpcDataSet(sql string, columnNameList []string, columnTypeList []string, columnNameIndex map[string]int32, ignoreTimestamp bool, moreData bool, queryId int64, statementId int64, client *rpc.IClientRPCServiceClient, sessionId int64, queryResult [][]byte, fetchSize int32, timeout *int64) (rpcDataSet *IoTDBRpcDataSet, err error) { ds := &IoTDBRpcDataSet{ sessionId: sessionId, statementId: statementId, @@ -195,7 +195,7 @@ func (s *IoTDBRpcDataSet) fetchResults() (bool, error) { QueryId: s.queryId, IsAlign: true, } - req.Timeout = &s.timeout + req.Timeout = s.timeout resp, err := s.client.FetchResultsV2(context.Background(), &req) @@ -446,6 +446,33 @@ func (s *IoTDBRpcDataSet) GetTimestamp(columnName string) (time.Time, error) { return s.GetTimestampByIndex(s.findColumn(columnName)) } +func (s *IoTDBRpcDataSet) GetDateByIndex(columnIndex int32) (time.Time, error) { + columnName, err := s.findColumnNameByIndex(columnIndex) + if err != nil { + return time.Time{}, err + } + return s.GetDate(columnName) +} + +func (s *IoTDBRpcDataSet) GetDate(columnName string) (time.Time, error) { + err := s.checkRecord() + if err != nil { + return time.Time{}, err + } + index := s.columnOrdinalMap[columnName] - startIndex + if !s.isNull(index, s.tsBlockIndex) { + s.lastReadWasNull = false + if value, err := s.curTsBlock.GetColumn(index).GetInt(s.tsBlockIndex); err != nil { + return time.Time{}, err + } else { + return int32ToDate(value) + } + } else { + s.lastReadWasNull = true + return time.Time{}, nil + } +} + func (s *IoTDBRpcDataSet) findColumn(columnName string) int32 { return s.columnOrdinalMap[columnName] } diff --git a/client/session.go b/client/session.go index 9f9534e..438ae9b 100644 --- a/client/session.go +++ b/client/session.go @@ -462,7 +462,7 @@ func (s *Session) ExecuteQueryStatement(sql string, timeoutMs *int64) (*SessionD FetchSize: &s.config.FetchSize, Timeout: timeoutMs} if resp, err := s.client.ExecuteQueryStatementV2(context.Background(), &request); err == nil { if statusErr := VerifySuccess(resp.Status); statusErr == nil { - return NewSessionDataSet(sql, resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, *timeoutMs, *resp.MoreData, s.config.FetchSize) + return NewSessionDataSet(sql, resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, timeoutMs, *resp.MoreData, s.config.FetchSize) } else { return nil, statusErr } @@ -472,7 +472,7 @@ func (s *Session) ExecuteQueryStatement(sql string, timeoutMs *int64) (*SessionD request.StatementId = s.requestStatementId resp, err = s.client.ExecuteQueryStatementV2(context.Background(), &request) if statusErr := VerifySuccess(resp.Status); statusErr == nil { - return NewSessionDataSet(sql, resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, *timeoutMs, *resp.MoreData, s.config.FetchSize) + return NewSessionDataSet(sql, resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, timeoutMs, *resp.MoreData, s.config.FetchSize) } else { return nil, statusErr } @@ -489,7 +489,7 @@ func (s *Session) ExecuteAggregationQuery(paths []string, aggregations []common. Aggregations: aggregations, StartTime: startTime, EndTime: endTime, Interval: interval, FetchSize: &s.config.FetchSize, Timeout: timeoutMs} if resp, err := s.client.ExecuteAggregationQueryV2(context.Background(), &request); err == nil { if statusErr := VerifySuccess(resp.Status); statusErr == nil { - return NewSessionDataSet("", resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, *timeoutMs, *resp.MoreData, s.config.FetchSize) + return NewSessionDataSet("", resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, timeoutMs, *resp.MoreData, s.config.FetchSize) } else { return nil, statusErr } @@ -498,7 +498,7 @@ func (s *Session) ExecuteAggregationQuery(paths []string, aggregations []common. request.SessionId = s.sessionId resp, err = s.client.ExecuteAggregationQueryV2(context.Background(), &request) if statusErr := VerifySuccess(resp.Status); statusErr == nil { - return NewSessionDataSet("", resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, *timeoutMs, *resp.MoreData, s.config.FetchSize) + return NewSessionDataSet("", resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, timeoutMs, *resp.MoreData, s.config.FetchSize) } else { return nil, statusErr } @@ -516,7 +516,7 @@ func (s *Session) ExecuteAggregationQueryWithLegalNodes(paths []string, aggregat Timeout: timeoutMs, LegalPathNodes: legalNodes} if resp, err := s.client.ExecuteAggregationQueryV2(context.Background(), &request); err == nil { if statusErr := VerifySuccess(resp.Status); statusErr == nil { - return NewSessionDataSet("", resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, *timeoutMs, *resp.MoreData, s.config.FetchSize) + return NewSessionDataSet("", resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, timeoutMs, *resp.MoreData, s.config.FetchSize) } else { return nil, statusErr } @@ -525,7 +525,7 @@ func (s *Session) ExecuteAggregationQueryWithLegalNodes(paths []string, aggregat request.SessionId = s.sessionId resp, err = s.client.ExecuteAggregationQueryV2(context.Background(), &request) if statusErr := VerifySuccess(resp.Status); statusErr == nil { - return NewSessionDataSet("", resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, *timeoutMs, *resp.MoreData, s.config.FetchSize) + return NewSessionDataSet("", resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, timeoutMs, *resp.MoreData, s.config.FetchSize) } else { return nil, statusErr } @@ -859,7 +859,7 @@ func (s *Session) genDataSet(sql string, resp *rpc.TSExecuteStatementResp) (*Ses queryId = *resp.QueryId } return NewSessionDataSet(sql, resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, - queryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, 60000, *resp.MoreData, s.config.FetchSize) + queryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, nil, *resp.MoreData, s.config.FetchSize) } func (s *Session) genInsertTabletsReq(tablets []*Tablet, isAligned bool) (*rpc.TSInsertTabletsReq, error) { diff --git a/client/sessiondataset.go b/client/sessiondataset.go index cc1bdcf..66837f1 100644 --- a/client/sessiondataset.go +++ b/client/sessiondataset.go @@ -9,7 +9,7 @@ type SessionDataSet struct { ioTDBRpcDataSet *IoTDBRpcDataSet } -func NewSessionDataSet(sql string, columnNameList []string, columnTypeList []string, columnNameIndex map[string]int32, queryId int64, statementId int64, client *rpc.IClientRPCServiceClient, sessionId int64, queryResult [][]byte, ignoreTimestamp bool, timeout int64, moreData bool, fetchSize int32) (*SessionDataSet, error) { +func NewSessionDataSet(sql string, columnNameList []string, columnTypeList []string, columnNameIndex map[string]int32, queryId int64, statementId int64, client *rpc.IClientRPCServiceClient, sessionId int64, queryResult [][]byte, ignoreTimestamp bool, timeout *int64, moreData bool, fetchSize int32) (*SessionDataSet, error) { rpcDataSet, err := NewIoTDBRpcDataSet(sql, columnNameList, columnTypeList, columnNameIndex, ignoreTimestamp, moreData, queryId, statementId, client, sessionId, queryResult, fetchSize, timeout) if err != nil { return nil, err diff --git a/client/tablet_test.go b/client/tablet_test.go index e4ecb73..8069b9d 100644 --- a/client/tablet_test.go +++ b/client/tablet_test.go @@ -191,7 +191,7 @@ func TestTablet_SetValueAt(t *testing.T) { columnIndex: 0, rowIndex: 0, }, - wantErr: true, + wantErr: false, }, { name: "columnIndex-1", args: args{ diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index 0311aa2..55a3177 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -43,7 +43,7 @@ func TestE2ETestSuite(t *testing.T) { func (s *e2eTestSuite) SetupSuite() { clusterConfig := client.ClusterConfig{ - NodeUrls: strings.Split("iotdb:6668,iotdb:6667,iotdb:6669", ","), + NodeUrls: strings.Split("127.0.0.1:6667", ","), UserName: "root", Password: "root", } @@ -90,8 +90,8 @@ func (s *e2eTestSuite) Test_CreateTimeseries() { assert.NoError(err) defer ds.Close() assert.True(ds.Next()) - var timeseries string - assert.NoError(ds.Scan(×eries)) + timeseries, err := ds.GetStringByIndex(1) + assert.NoError(err) assert.Equal(timeseries, "root.tsg1.dev1.status") } @@ -123,8 +123,8 @@ func (s *e2eTestSuite) Test_CreateAlignedTimeseries() { assert.NoError(err) defer ds.Close() assert.True(ds.Next()) - var timeseries string - assert.NoError(ds.Scan(×eries)) + timeseries, err := ds.GetStringByIndex(1) + assert.NoError(err) assert.Equal(timeseries, fullPath) } } @@ -144,8 +144,8 @@ func (s *e2eTestSuite) Test_InsertRecords() { assert.NoError(err) defer ds.Close() assert.True(ds.Next()) - var status string - assert.NoError(ds.Scan(&status)) + status, err := ds.GetString("root.tsg1.dev1.status") + assert.NoError(err) assert.Equal(status, "Working") } @@ -164,9 +164,9 @@ func (s *e2eTestSuite) Test_InsertAlignedRecord() { assert.NoError(err) defer ds.Close() assert.True(ds.Next()) - var status string - assert.NoError(ds.Scan(&status)) - assert.Equal(status, "Working") + status, err := ds.GetString("root.tsg2.dev1.status") + assert.NoError(err) + assert.Equal("Working", status) } func (s *e2eTestSuite) Test_InsertAlignedRecords() { @@ -183,8 +183,8 @@ func (s *e2eTestSuite) Test_InsertAlignedRecords() { assert.NoError(err) defer ds.Close() assert.True(ds.Next()) - var temperature string - assert.NoError(ds.Scan(&temperature)) + temperature, err := ds.GetString("root.al1.dev3.temperature") + assert.NoError(err) assert.Equal(temperature, "44") } @@ -215,10 +215,11 @@ func (s *e2eTestSuite) Test_InsertAlignedRecordsOfOneDevice() { assert.NoError(err) defer ds.Close() assert.True(ds.Next()) - var status string - assert.NoError(ds.Scan(&status)) - assert.Equal(status, "2024-04-01") + date, err := ds.GetString("root.al1.dev4.date") + assert.NoError(err) + assert.Equal("2024-04-01", date) } + func (s *e2eTestSuite) Test_InsertAlignedTablet() { var timeseries = []string{"root.ln.device1.**"} s.session.DeleteTimeseries(timeseries) @@ -235,8 +236,8 @@ func (s *e2eTestSuite) Test_InsertAlignedTablet() { assert.NoError(err) defer ds.Close() assert.True(ds.Next()) - var status string - assert.NoError(ds.Scan(&status)) + status, err := ds.GetStringByIndex(1) + assert.NoError(err) assert.Equal(status, "12") s.session.DeleteStorageGroup("root.ln.**") } @@ -257,8 +258,8 @@ func (s *e2eTestSuite) Test_InsertAlignedTabletWithNilValue() { assert.NoError(err) defer ds.Close() assert.True(ds.Next()) - var status string - assert.NoError(ds.Scan(&status)) + status, err := ds.GetStringByIndex(1) + assert.NoError(err) assert.Equal(status, "12") s.session.DeleteStorageGroup("root.ln.**") } @@ -377,8 +378,8 @@ func (s *e2eTestSuite) Test_InsertAlignedTablets() { assert.NoError(err) defer ds.Close() assert.True(ds.Next()) - var status string - assert.NoError(ds.Get(&status)) + status, err := ds.GetStringByIndex(1) + assert.NoError(err) assert.Equal(status, "8") s.session.DeleteStorageGroup("root.ln.**") } From 3a62fa2adbe33094ce35f1cd86051bee2c5742dd Mon Sep 17 00:00:00 2001 From: shuwenwei Date: Wed, 26 Mar 2025 11:08:30 +0800 Subject: [PATCH 05/16] remove file --- client/sessiondataset_test.go | 38 ----------------------------------- 1 file changed, 38 deletions(-) delete mode 100644 client/sessiondataset_test.go diff --git a/client/sessiondataset_test.go b/client/sessiondataset_test.go deleted file mode 100644 index 977099a..0000000 --- a/client/sessiondataset_test.go +++ /dev/null @@ -1,38 +0,0 @@ -package client - -import ( - "log" - "testing" -) - -func TestSessionDataSet_Next(t *testing.T) { - session := NewSession(&Config{ - Host: "127.0.0.1", - Port: "6667", - UserName: "root", - Password: "root", - }) - err := session.Open(false, 40000) - if err != nil { - log.Fatalf("err is %v", err) - return - } - var timeout int64 = 10000 - sessionDataSet, err := session.ExecuteQueryStatement("select * from root.test.d1", &timeout) - if err != nil { - log.Fatalf("err is %v", err) - return - } - for { - hasNext, err := sessionDataSet.Next() - if err != nil { - log.Fatalf("err is %v", err) - } - if !hasNext { - break - } - t, _ := sessionDataSet.GetLong("Time") - log.Printf("time is %v", t) - } - session.Close() -} From c41250d4a33525b519f53d9a4be442ca6e9b0dba Mon Sep 17 00:00:00 2001 From: shuwenwei Date: Wed, 26 Mar 2025 12:28:15 +0800 Subject: [PATCH 06/16] add ut --- client/session.go | 4 ++++ test/e2e/e2e_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/client/session.go b/client/session.go index 438ae9b..746ee57 100644 --- a/client/session.go +++ b/client/session.go @@ -1196,3 +1196,7 @@ func (s *Session) reconnect() bool { } return connectedSuccess } + +func (s *Session) SetFetchSize(fetchSize int32) { + s.config.FetchSize = fetchSize +} diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index 55a3177..3a0a131 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -383,3 +383,28 @@ func (s *e2eTestSuite) Test_InsertAlignedTablets() { assert.Equal(status, "8") s.session.DeleteStorageGroup("root.ln.**") } + +func (s *e2eTestSuite) Test_SmallFetchSize() { + var timeseries = []string{"root.ln.device1.**"} + s.session.SetFetchSize(1000) + s.session.DeleteTimeseries(timeseries) + writeCount := 10000 + tablet1, err := createTablet(writeCount) + if err != nil { + log.Fatal(err) + } + + tablets := []*client.Tablet{tablet1} + s.checkError(s.session.InsertAlignedTablets(tablets, false)) + + ds, err := s.session.ExecuteQueryStatement("select * from root.ln.device1", nil) + count := 0 + for { + if hasNext, err := ds.Next(); err != nil || !hasNext { + break + } + count += 1 + } + s.Assert().Equal(writeCount, count) + s.session.DeleteStorageGroup("root.ln.**") +} From c217167f238742218be5315f3e5d6b5205f6ce72 Mon Sep 17 00:00:00 2001 From: shuwenwei Date: Wed, 26 Mar 2025 18:56:24 +0800 Subject: [PATCH 07/16] add ut --- client/rpcdataset.go | 25 +++++++-- client/session.go | 2 +- client/sessiondataset.go | 16 ++++++ client/tablet.go | 4 +- client/utils.go | 10 ++-- test/e2e/e2e_test.go | 111 ++++++++++++++++++++++++++++++++++++++- 6 files changed, 156 insertions(+), 12 deletions(-) diff --git a/client/rpcdataset.go b/client/rpcdataset.go index 36a74bf..cb17c37 100644 --- a/client/rpcdataset.go +++ b/client/rpcdataset.go @@ -435,15 +435,30 @@ func (s *IoTDBRpcDataSet) getStringByIndex(columnIndex int32) (string, error) { } func (s *IoTDBRpcDataSet) GetTimestampByIndex(columnIndex int32) (time.Time, error) { - longValue, err := s.getLongByIndex(columnIndex) + columnName, err := s.findColumnNameByIndex(columnIndex) if err != nil { return time.Time{}, err } - return time.UnixMilli(longValue), nil + return s.GetTimestamp(columnName) } func (s *IoTDBRpcDataSet) GetTimestamp(columnName string) (time.Time, error) { - return s.GetTimestampByIndex(s.findColumn(columnName)) + err := s.checkRecord() + if err != nil { + return time.Time{}, err + } + index := s.columnOrdinalMap[columnName] - startIndex + if !s.isNull(index, s.tsBlockIndex) { + s.lastReadWasNull = false + if longValue, err := s.curTsBlock.GetColumn(index).GetLong(s.tsBlockIndex); err != nil { + return time.Time{}, err + } else { + return time.UnixMilli(longValue), nil + } + } else { + s.lastReadWasNull = true + return time.Time{}, nil + } } func (s *IoTDBRpcDataSet) GetDateByIndex(columnIndex int32) (time.Time, error) { @@ -465,7 +480,7 @@ func (s *IoTDBRpcDataSet) GetDate(columnName string) (time.Time, error) { if value, err := s.curTsBlock.GetColumn(index).GetInt(s.tsBlockIndex); err != nil { return time.Time{}, err } else { - return int32ToDate(value) + return Int32ToDate(value) } } else { s.lastReadWasNull = true @@ -547,7 +562,7 @@ func (s *IoTDBRpcDataSet) getString(index int32, tsDataType TSDataType) (string, if err != nil { return "", err } - t, err := int32ToDate(v) + t, err := Int32ToDate(v) if err != nil { return "", err } diff --git a/client/session.go b/client/session.go index 746ee57..9aeb786 100644 --- a/client/session.go +++ b/client/session.go @@ -994,7 +994,7 @@ func valuesToBytes(dataTypes []TSDataType, values []interface{}) ([]byte, error) case DATE: switch s := v.(type) { case time.Time: - date, err := dateToInt32(s) + date, err := DateToInt32(s) if err != nil { return nil, err } diff --git a/client/sessiondataset.go b/client/sessiondataset.go index 66837f1..c41246b 100644 --- a/client/sessiondataset.go +++ b/client/sessiondataset.go @@ -89,6 +89,22 @@ func (s *SessionDataSet) GetTimestamp(columnName string) (time.Time, error) { return s.ioTDBRpcDataSet.GetTimestamp(columnName) } +func (s *SessionDataSet) GetDateByIndex(columnIndex int32) (time.Time, error) { + return s.ioTDBRpcDataSet.GetDateByIndex(columnIndex) +} + +func (s *SessionDataSet) GetDate(columnName string) (time.Time, error) { + return s.ioTDBRpcDataSet.GetDate(columnName) +} + +func (s *SessionDataSet) GetBlobByIndex(columnIndex int32) (*Binary, error) { + return s.ioTDBRpcDataSet.getBinaryByIndex(columnIndex) +} + +func (s *SessionDataSet) GetBlob(columnName string) (*Binary, error) { + return s.ioTDBRpcDataSet.getBinary(columnName) +} + func (s *SessionDataSet) FindColumn(columnName string) int32 { return s.ioTDBRpcDataSet.findColumn(columnName) } diff --git a/client/tablet.go b/client/tablet.go index 7b62f89..2268018 100644 --- a/client/tablet.go +++ b/client/tablet.go @@ -195,7 +195,7 @@ func (t *Tablet) SetValueAt(value interface{}, columnIndex, rowIndex int) error values := t.values[columnIndex].([]int32) switch v := value.(type) { case time.Time: - val, err := dateToInt32(v) + val, err := DateToInt32(v) if err != nil { return err } @@ -241,7 +241,7 @@ func (t *Tablet) GetValueAt(columnIndex, rowIndex int) (interface{}, error) { case BLOB: return t.values[columnIndex].([][]byte)[rowIndex], nil case DATE: - return int32ToDate(t.values[columnIndex].([]int32)[rowIndex]) + return Int32ToDate(t.values[columnIndex].([]int32)[rowIndex]) default: return nil, fmt.Errorf("illegal datatype %v", schema.DataType) } diff --git a/client/utils.go b/client/utils.go index 19e9d17..41cc783 100644 --- a/client/utils.go +++ b/client/utils.go @@ -81,7 +81,7 @@ func bytesToHexString(input []byte) string { return hexString } -func dateToInt32(localDate time.Time) (int32, error) { +func DateToInt32(localDate time.Time) (int32, error) { if localDate.IsZero() { return 0, errors.New("date expression is null or empty") } @@ -96,7 +96,7 @@ func dateToInt32(localDate time.Time) (int32, error) { return int32(result), nil } -func int32ToDate(val int32) (time.Time, error) { +func Int32ToDate(val int32) (time.Time, error) { date := int(val) year := date / 10000 month := (date / 100) % 100 @@ -112,7 +112,7 @@ func int32ToDate(val int32) (time.Time, error) { } func bytesToDate(bys []byte) (time.Time, error) { - return int32ToDate(bytesToInt32(bys)) + return Int32ToDate(bytesToInt32(bys)) } func verifySuccesses(statuses []*common.TSStatus) error { @@ -161,3 +161,7 @@ func NewBinary(v []byte) *Binary { func (b *Binary) GetStringValue() string { return string(b.values) } + +func (b *Binary) GetValues() []byte { + return b.values +} diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index 3a0a131..ef4601b 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -384,7 +384,7 @@ func (s *e2eTestSuite) Test_InsertAlignedTablets() { s.session.DeleteStorageGroup("root.ln.**") } -func (s *e2eTestSuite) Test_SmallFetchSize() { +func (s *e2eTestSuite) Test_FetchMoreData() { var timeseries = []string{"root.ln.device1.**"} s.session.SetFetchSize(1000) s.session.DeleteTimeseries(timeseries) @@ -408,3 +408,112 @@ func (s *e2eTestSuite) Test_SmallFetchSize() { s.Assert().Equal(writeCount, count) s.session.DeleteStorageGroup("root.ln.**") } + +func (s *e2eTestSuite) Test_QueryAllDataType() { + measurementSchemas := []*client.MeasurementSchema{ + { + Measurement: "s0", + DataType: client.BOOLEAN, + }, + { + Measurement: "s1", + DataType: client.INT32, + }, + { + Measurement: "s2", + DataType: client.INT64, + }, + { + Measurement: "s3", + DataType: client.FLOAT, + }, + { + Measurement: "s4", + DataType: client.DOUBLE, + }, + { + Measurement: "s5", + DataType: client.TEXT, + }, + { + Measurement: "s6", + DataType: client.TIMESTAMP, + }, + { + Measurement: "s7", + DataType: client.DATE, + }, + { + Measurement: "s8", + DataType: client.BLOB, + }, + { + Measurement: "s9", + DataType: client.STRING, + }, + } + tablet, err := client.NewTablet("root.tsg1.d1", measurementSchemas, 100) + s.NoError(err) + tablet.SetTimestamp(1, 0) + tablet.SetValueAt(true, 0, 0) + tablet.SetValueAt(int32(1), 1, 0) + tablet.SetValueAt(int64(1), 2, 0) + tablet.SetValueAt(float32(1), 3, 0) + tablet.SetValueAt(float64(1), 4, 0) + tablet.SetValueAt("text", 5, 0) + tablet.SetValueAt(int64(1), 6, 0) + expectedDate, _ := client.Int32ToDate(20250326) + tablet.SetValueAt(expectedDate, 7, 0) + tablet.SetValueAt([]byte{1}, 8, 0) + tablet.SetValueAt("string", 9, 0) + tablet.RowSize = 1 + + r, err := s.session.InsertAlignedTablet(tablet, true) + s.checkError(r, err) + + sessionDataSet, err := s.session.ExecuteQueryStatement("select * from root.tsg1.d1 limit 1", nil) + for { + if hasNext, err := sessionDataSet.Next(); err != nil || !hasNext { + break + } + boolValue, err := sessionDataSet.GetBoolean("root.tsg1.d1.s0") + s.NoError(err) + s.Equal(true, boolValue) + + intValue, err := sessionDataSet.GetInt("root.tsg1.d1.s1") + s.NoError(err) + s.Equal(int32(1), intValue) + + longValue, err := sessionDataSet.GetLong("root.tsg1.d1.s2") + s.NoError(err) + s.Equal(int64(1), longValue) + + floatValue, err := sessionDataSet.GetFloat("root.tsg1.d1.s3") + s.NoError(err) + s.Equal(float32(1), floatValue) + + doubleValue, err := sessionDataSet.GetDouble("root.tsg1.d1.s4") + s.NoError(err) + s.Equal(float64(1), doubleValue) + + textValue, err := sessionDataSet.GetString("root.tsg1.d1.s5") + s.NoError(err) + s.Equal("text", textValue) + + timestampValue, err := sessionDataSet.GetTimestamp("root.tsg1.d1.s6") + s.NoError(err) + s.Equal(time.UnixMilli(1), timestampValue) + + dateValue, err := sessionDataSet.GetDate("root.tsg1.d1.s7") + s.NoError(err) + s.Equal(expectedDate, dateValue) + + blobValue, err := sessionDataSet.GetBlob("root.tsg1.d1.s8") + s.NoError(err) + s.Equal([]byte{1}, blobValue.GetValues()) + + stringValue, err := sessionDataSet.GetString("root.tsg1.d1.s9") + s.NoError(err) + s.Equal("string", stringValue) + } +} From 3c832e6abfc0ebf3ba9457ddb952bb748879cac1 Mon Sep 17 00:00:00 2001 From: shuwenwei Date: Thu, 27 Mar 2025 10:50:04 +0800 Subject: [PATCH 08/16] add ut --- client/rpcdataset.go | 4 ++-- test/e2e/e2e_test.go | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/client/rpcdataset.go b/client/rpcdataset.go index cb17c37..fe1014c 100644 --- a/client/rpcdataset.go +++ b/client/rpcdataset.go @@ -259,7 +259,7 @@ func (s *IoTDBRpcDataSet) isNullByIndex(columnIndex int32) (bool, error) { index := s.columnOrdinalMap[columnName] - startIndex // time column will never be null if index < 0 { - return true, nil + return false, nil } return s.isNull(index, s.tsBlockIndex), nil } @@ -268,7 +268,7 @@ func (s *IoTDBRpcDataSet) isNullByColumnName(columnName string) bool { index := s.columnOrdinalMap[columnName] - startIndex // time column will never be null if index < 0 { - return true + return false } return s.isNull(index, s.tsBlockIndex) } diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index ef4601b..4c12e3c 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -472,10 +472,16 @@ func (s *e2eTestSuite) Test_QueryAllDataType() { s.checkError(r, err) sessionDataSet, err := s.session.ExecuteQueryStatement("select * from root.tsg1.d1 limit 1", nil) + defer sessionDataSet.Close() for { if hasNext, err := sessionDataSet.Next(); err != nil || !hasNext { break } + for _, columnName := range sessionDataSet.GetColumnNames() { + isNull, err := sessionDataSet.IsNull(columnName) + s.NoError(err) + s.False(isNull) + } boolValue, err := sessionDataSet.GetBoolean("root.tsg1.d1.s0") s.NoError(err) s.Equal(true, boolValue) From b52a5c5cea6669da80eec3c785d5c37114e3bf1d Mon Sep 17 00:00:00 2001 From: shuwenwei Date: Thu, 27 Mar 2025 11:15:29 +0800 Subject: [PATCH 09/16] add getObject --- client/rpcdataset.go | 52 +++++++++++++++++++++++++++------------ client/sessiondataset.go | 12 +++++++-- test/e2e/e2e_test.go | 53 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 99 insertions(+), 18 deletions(-) diff --git a/client/rpcdataset.go b/client/rpcdataset.go index fe1014c..74964a0 100644 --- a/client/rpcdataset.go +++ b/client/rpcdataset.go @@ -286,8 +286,7 @@ func (s *IoTDBRpcDataSet) getBooleanByIndex(columnIndex int32) (bool, error) { } func (s *IoTDBRpcDataSet) getBoolean(columnName string) (bool, error) { - err := s.checkRecord() - if err != nil { + if err := s.checkRecord(); err != nil { return false, err } index := s.columnOrdinalMap[columnName] - startIndex @@ -309,8 +308,7 @@ func (s *IoTDBRpcDataSet) getDoubleByIndex(columnIndex int32) (float64, error) { } func (s *IoTDBRpcDataSet) getDouble(columnName string) (float64, error) { - err := s.checkRecord() - if err != nil { + if err := s.checkRecord(); err != nil { return 0, err } index := s.columnOrdinalMap[columnName] - startIndex @@ -332,8 +330,7 @@ func (s *IoTDBRpcDataSet) getFloatByIndex(columnIndex int32) (float32, error) { } func (s *IoTDBRpcDataSet) getFloat(columnName string) (float32, error) { - err := s.checkRecord() - if err != nil { + if err := s.checkRecord(); err != nil { return 0, err } index := s.columnOrdinalMap[columnName] - startIndex @@ -355,8 +352,7 @@ func (s *IoTDBRpcDataSet) getIntByIndex(columnIndex int32) (int32, error) { } func (s *IoTDBRpcDataSet) getInt(columnName string) (int32, error) { - err := s.checkRecord() - if err != nil { + if err := s.checkRecord(); err != nil { return 0, err } index := s.columnOrdinalMap[columnName] - startIndex @@ -386,8 +382,7 @@ func (s *IoTDBRpcDataSet) getLongByIndex(columnIndex int32) (int64, error) { } func (s *IoTDBRpcDataSet) getLong(columnName string) (int64, error) { - err := s.checkRecord() - if err != nil { + if err := s.checkRecord(); err != nil { return 0, err } if columnName == TimestampColumnName { @@ -412,8 +407,7 @@ func (s *IoTDBRpcDataSet) getBinaryByIndex(columnIndex int32) (*Binary, error) { } func (s *IoTDBRpcDataSet) getBinary(columnName string) (*Binary, error) { - err := s.checkRecord() - if err != nil { + if err := s.checkRecord(); err != nil { return nil, err } index := s.columnOrdinalMap[columnName] - startIndex @@ -426,6 +420,34 @@ func (s *IoTDBRpcDataSet) getBinary(columnName string) (*Binary, error) { } } +func (s *IoTDBRpcDataSet) getObjectByIndex(columnIndex int32) (interface{}, error) { + columnName, err := s.findColumnNameByIndex(columnIndex) + if err != nil { + return nil, err + } + return s.getObject(columnName) +} + +func (s *IoTDBRpcDataSet) getObject(columnName string) (interface{}, error) { + if err := s.checkRecord(); err != nil { + return nil, err + } + if columnName == TimestampColumnName { + if value, err := s.curTsBlock.GetTimeByIndex(s.tsBlockIndex); err != nil { + return nil, err + } else { + return time.UnixMilli(value), nil + } + } + index := s.columnOrdinalMap[columnName] - startIndex + if index < 0 || index >= int32(len(s.columnTypeDeduplicatedList)) || s.isNull(index, s.tsBlockIndex) { + s.lastReadWasNull = true + return nil, nil + } + s.lastReadWasNull = false + return s.curTsBlock.GetColumn(index).GetObject(s.tsBlockIndex) +} + func (s *IoTDBRpcDataSet) getStringByIndex(columnIndex int32) (string, error) { columnName, err := s.findColumnNameByIndex(columnIndex) if err != nil { @@ -434,15 +456,15 @@ func (s *IoTDBRpcDataSet) getStringByIndex(columnIndex int32) (string, error) { return s.getValueByName(columnName) } -func (s *IoTDBRpcDataSet) GetTimestampByIndex(columnIndex int32) (time.Time, error) { +func (s *IoTDBRpcDataSet) getTimestampByIndex(columnIndex int32) (time.Time, error) { columnName, err := s.findColumnNameByIndex(columnIndex) if err != nil { return time.Time{}, err } - return s.GetTimestamp(columnName) + return s.getTimestamp(columnName) } -func (s *IoTDBRpcDataSet) GetTimestamp(columnName string) (time.Time, error) { +func (s *IoTDBRpcDataSet) getTimestamp(columnName string) (time.Time, error) { err := s.checkRecord() if err != nil { return time.Time{}, err diff --git a/client/sessiondataset.go b/client/sessiondataset.go index c41246b..d177a44 100644 --- a/client/sessiondataset.go +++ b/client/sessiondataset.go @@ -73,6 +73,14 @@ func (s *SessionDataSet) GetLong(columnName string) (int64, error) { return s.ioTDBRpcDataSet.getLong(columnName) } +func (s *SessionDataSet) GetObjectByIndex(columnIndex int32) (interface{}, error) { + return s.ioTDBRpcDataSet.getObjectByIndex(columnIndex) +} + +func (s *SessionDataSet) GetObject(columnName string) (interface{}, error) { + return s.ioTDBRpcDataSet.getObject(columnName) +} + func (s *SessionDataSet) GetStringByIndex(columnIndex int32) (string, error) { return s.ioTDBRpcDataSet.getStringByIndex(columnIndex) } @@ -82,11 +90,11 @@ func (s *SessionDataSet) GetString(columnName string) (string, error) { } func (s *SessionDataSet) GetTimestampByIndex(columnIndex int32) (time.Time, error) { - return s.ioTDBRpcDataSet.GetTimestampByIndex(columnIndex) + return s.ioTDBRpcDataSet.getTimestampByIndex(columnIndex) } func (s *SessionDataSet) GetTimestamp(columnName string) (time.Time, error) { - return s.ioTDBRpcDataSet.GetTimestamp(columnName) + return s.ioTDBRpcDataSet.getTimestamp(columnName) } func (s *SessionDataSet) GetDateByIndex(columnIndex int32) (time.Time, error) { diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index 4c12e3c..a9686fb 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -472,7 +472,6 @@ func (s *e2eTestSuite) Test_QueryAllDataType() { s.checkError(r, err) sessionDataSet, err := s.session.ExecuteQueryStatement("select * from root.tsg1.d1 limit 1", nil) - defer sessionDataSet.Close() for { if hasNext, err := sessionDataSet.Next(); err != nil || !hasNext { break @@ -522,4 +521,56 @@ func (s *e2eTestSuite) Test_QueryAllDataType() { s.NoError(err) s.Equal("string", stringValue) } + sessionDataSet.Close() + + sessionDataSet, err = s.session.ExecuteQueryStatement("select * from root.tsg1.d1 limit 1", nil) + for { + if hasNext, err := sessionDataSet.Next(); err != nil || !hasNext { + break + } + for _, columnName := range sessionDataSet.GetColumnNames() { + isNull, err := sessionDataSet.IsNull(columnName) + s.NoError(err) + s.False(isNull) + } + boolValue, err := sessionDataSet.GetObject("root.tsg1.d1.s0") + s.NoError(err) + s.Equal(true, boolValue) + + intValue, err := sessionDataSet.GetObject("root.tsg1.d1.s1") + s.NoError(err) + s.Equal(int32(1), intValue) + + longValue, err := sessionDataSet.GetObject("root.tsg1.d1.s2") + s.NoError(err) + s.Equal(int64(1), longValue) + + floatValue, err := sessionDataSet.GetObject("root.tsg1.d1.s3") + s.NoError(err) + s.Equal(float32(1), floatValue) + + doubleValue, err := sessionDataSet.GetObject("root.tsg1.d1.s4") + s.NoError(err) + s.Equal(float64(1), doubleValue) + + textValue, err := sessionDataSet.GetObject("root.tsg1.d1.s5") + s.NoError(err) + s.Equal("text", textValue.(*client.Binary).GetStringValue()) + + timestampValue, err := sessionDataSet.GetObject("root.tsg1.d1.s6") + s.NoError(err) + s.Equal(int64(1), timestampValue) + + dateValue, err := sessionDataSet.GetObject("root.tsg1.d1.s7") + s.NoError(err) + s.Equal(int32(20250326), dateValue) + + blobValue, err := sessionDataSet.GetObject("root.tsg1.d1.s8") + s.NoError(err) + s.Equal([]byte{1}, blobValue.(*client.Binary).GetValues()) + + stringValue, err := sessionDataSet.GetObject("root.tsg1.d1.s9") + s.NoError(err) + s.Equal("string", stringValue.(*client.Binary).GetStringValue()) + } } From 0bfd7a67ebcc2d8dc784e308920645f25a5bd616 Mon Sep 17 00:00:00 2001 From: shuwenwei Date: Fri, 28 Mar 2025 11:00:56 +0800 Subject: [PATCH 10/16] fix bug --- client/session.go | 6 +++++- test/e2e/e2e_test.go | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/client/session.go b/client/session.go index 9aeb786..44b48ef 100644 --- a/client/session.go +++ b/client/session.go @@ -858,8 +858,12 @@ func (s *Session) genDataSet(sql string, resp *rpc.TSExecuteStatementResp) (*Ses } else { queryId = *resp.QueryId } + moreData := false + if resp.MoreData != nil { + moreData = *resp.MoreData + } return NewSessionDataSet(sql, resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, - queryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, nil, *resp.MoreData, s.config.FetchSize) + queryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, nil, moreData, s.config.FetchSize) } func (s *Session) genInsertTabletsReq(tablets []*Tablet, isAligned bool) (*rpc.TSInsertTabletsReq, error) { diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index a9686fb..fecf3e7 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -75,6 +75,11 @@ func (s *e2eTestSuite) checkError(status *common.TSStatus, err error) { } } +func (s *e2eTestSuite) Test_NonQuery() { + _, err := s.session.ExecuteStatement("flush") + s.Require().NoError(err) +} + func (s *e2eTestSuite) Test_CreateTimeseries() { var ( path = "root.tsg1.dev1.status" From bef0f2d06732d8b1f0a579b63d07dd2d189678df Mon Sep 17 00:00:00 2001 From: shuwenwei Date: Mon, 31 Mar 2025 16:18:46 +0800 Subject: [PATCH 11/16] modify ut --- test/e2e/e2e_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index fecf3e7..cecbfae 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -43,7 +43,7 @@ func TestE2ETestSuite(t *testing.T) { func (s *e2eTestSuite) SetupSuite() { clusterConfig := client.ClusterConfig{ - NodeUrls: strings.Split("127.0.0.1:6667", ","), + NodeUrls: strings.Split("iotdb:6668,iotdb:6667,iotdb:6669", ","), UserName: "root", Password: "root", } From 55abb7e5c299a95460c8edc0519483560873e398 Mon Sep 17 00:00:00 2001 From: shuwenwei Date: Tue, 1 Apr 2025 10:21:24 +0800 Subject: [PATCH 12/16] remove time.UnixMillis --- client/rpcdataset.go | 4 ++-- test/e2e/e2e_test.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/client/rpcdataset.go b/client/rpcdataset.go index 74964a0..67cc412 100644 --- a/client/rpcdataset.go +++ b/client/rpcdataset.go @@ -436,7 +436,7 @@ func (s *IoTDBRpcDataSet) getObject(columnName string) (interface{}, error) { if value, err := s.curTsBlock.GetTimeByIndex(s.tsBlockIndex); err != nil { return nil, err } else { - return time.UnixMilli(value), nil + return time.Unix(value/1e3, (value%1e3)*1e6), nil } } index := s.columnOrdinalMap[columnName] - startIndex @@ -475,7 +475,7 @@ func (s *IoTDBRpcDataSet) getTimestamp(columnName string) (time.Time, error) { if longValue, err := s.curTsBlock.GetColumn(index).GetLong(s.tsBlockIndex); err != nil { return time.Time{}, err } else { - return time.UnixMilli(longValue), nil + return time.Unix(longValue/1e3, (longValue%1e3)*1e6), nil } } else { s.lastReadWasNull = true diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index daf97f8..8a0c9d1 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -43,7 +43,7 @@ func TestE2ETestSuite(t *testing.T) { func (s *e2eTestSuite) SetupSuite() { clusterConfig := client.ClusterConfig{ - NodeUrls: strings.Split("iotdb:6668,iotdb:6667,iotdb:6669", ","), + NodeUrls: strings.Split("iotdb:6668,localhost:6667,iotdb:6669", ","), UserName: "root", Password: "root", } @@ -522,7 +522,7 @@ func (s *e2eTestSuite) Test_QueryAllDataType() { timestampValue, err := sessionDataSet.GetTimestamp("root.tsg1.d1.s6") s.NoError(err) - s.Equal(time.UnixMilli(1), timestampValue) + s.Equal(time.Unix(0, 1e6), timestampValue) dateValue, err := sessionDataSet.GetDate("root.tsg1.d1.s7") s.NoError(err) From 0d2c5af214ce09fb335661a3bd29c7661071185d Mon Sep 17 00:00:00 2001 From: shuwenwei Date: Tue, 1 Apr 2025 10:25:07 +0800 Subject: [PATCH 13/16] modify nodeUrls --- test/e2e/e2e_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index 8a0c9d1..1b9a78a 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -43,7 +43,7 @@ func TestE2ETestSuite(t *testing.T) { func (s *e2eTestSuite) SetupSuite() { clusterConfig := client.ClusterConfig{ - NodeUrls: strings.Split("iotdb:6668,localhost:6667,iotdb:6669", ","), + NodeUrls: strings.Split("iotdb:6668,iotdb:6667,iotdb:6669", ","), UserName: "root", Password: "root", } From 29743fd2e851ddf57cb3bd5812b7c17fbf0bd3cd Mon Sep 17 00:00:00 2001 From: shuwenwei Date: Thu, 3 Apr 2025 15:09:10 +0800 Subject: [PATCH 14/16] set lastReadWasNull for time column --- client/rpcdataset.go | 33 +++++++++++---------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/client/rpcdataset.go b/client/rpcdataset.go index 67cc412..0629d21 100644 --- a/client/rpcdataset.go +++ b/client/rpcdataset.go @@ -386,6 +386,7 @@ func (s *IoTDBRpcDataSet) getLong(columnName string) (int64, error) { return 0, err } if columnName == TimestampColumnName { + s.lastReadWasNull = false return s.curTsBlock.GetTimeByIndex(s.tsBlockIndex) } index := s.columnOrdinalMap[columnName] - startIndex @@ -433,6 +434,7 @@ func (s *IoTDBRpcDataSet) getObject(columnName string) (interface{}, error) { return nil, err } if columnName == TimestampColumnName { + s.lastReadWasNull = false if value, err := s.curTsBlock.GetTimeByIndex(s.tsBlockIndex); err != nil { return nil, err } else { @@ -465,21 +467,14 @@ func (s *IoTDBRpcDataSet) getTimestampByIndex(columnIndex int32) (time.Time, err } func (s *IoTDBRpcDataSet) getTimestamp(columnName string) (time.Time, error) { - err := s.checkRecord() + longValue, err := s.getLong(columnName) if err != nil { return time.Time{}, err } - index := s.columnOrdinalMap[columnName] - startIndex - if !s.isNull(index, s.tsBlockIndex) { - s.lastReadWasNull = false - if longValue, err := s.curTsBlock.GetColumn(index).GetLong(s.tsBlockIndex); err != nil { - return time.Time{}, err - } else { - return time.Unix(longValue/1e3, (longValue%1e3)*1e6), nil - } + if s.lastReadWasNull { + return time.Time{}, err } else { - s.lastReadWasNull = true - return time.Time{}, nil + return time.Unix(longValue/1e3, (longValue%1e3)*1e6), nil } } @@ -492,21 +487,14 @@ func (s *IoTDBRpcDataSet) GetDateByIndex(columnIndex int32) (time.Time, error) { } func (s *IoTDBRpcDataSet) GetDate(columnName string) (time.Time, error) { - err := s.checkRecord() + intValue, err := s.getInt(columnName) if err != nil { return time.Time{}, err } - index := s.columnOrdinalMap[columnName] - startIndex - if !s.isNull(index, s.tsBlockIndex) { - s.lastReadWasNull = false - if value, err := s.curTsBlock.GetColumn(index).GetInt(s.tsBlockIndex); err != nil { - return time.Time{}, err - } else { - return Int32ToDate(value) - } + if s.lastReadWasNull { + return time.Time{}, err } else { - s.lastReadWasNull = true - return time.Time{}, nil + return Int32ToDate(intValue) } } @@ -520,6 +508,7 @@ func (s *IoTDBRpcDataSet) getValueByName(columnName string) (string, error) { return "", err } if columnName == TimestampColumnName { + s.lastReadWasNull = false if t, err := s.curTsBlock.GetTimeByIndex(s.tsBlockIndex); err != nil { return "", err } else { From 1aa415761165b752bb221a21898802948bb185f2 Mon Sep 17 00:00:00 2001 From: shuwenwei Date: Wed, 16 Apr 2025 17:49:34 +0800 Subject: [PATCH 15/16] modify it --- test/e2e/e2e_test.go | 66 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index 7f2efbf..faf204e 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -488,7 +488,7 @@ func (s *e2eTestSuite) Test_QueryAllDataType() { r, err := s.session.InsertAlignedTablet(tablet, true) s.checkError(r, err) - sessionDataSet, err := s.session.ExecuteQueryStatement("select * from root.tsg1.d1 limit 1", nil) + sessionDataSet, err := s.session.ExecuteQueryStatement("select s0, s1, s2, s3, s4, s5, s6, s7, s8, s9 from root.tsg1.d1 limit 1", nil) for { if hasNext, err := sessionDataSet.Next(); err != nil || !hasNext { break @@ -498,6 +498,65 @@ func (s *e2eTestSuite) Test_QueryAllDataType() { s.NoError(err) s.False(isNull) } + timeValue, err := sessionDataSet.GetLongByIndex(1) + s.NoError(err) + s.Equal(int64(1), timeValue) + boolValue, err := sessionDataSet.GetBooleanByIndex(2) + s.NoError(err) + s.Equal(true, boolValue) + + intValue, err := sessionDataSet.GetIntByIndex(3) + s.NoError(err) + s.Equal(int32(1), intValue) + + longValue, err := sessionDataSet.GetLongByIndex(4) + s.NoError(err) + s.Equal(int64(1), longValue) + + floatValue, err := sessionDataSet.GetFloatByIndex(5) + s.NoError(err) + s.Equal(float32(1), floatValue) + + doubleValue, err := sessionDataSet.GetDoubleByIndex(6) + s.NoError(err) + s.Equal(float64(1), doubleValue) + + textValue, err := sessionDataSet.GetStringByIndex(7) + s.NoError(err) + s.Equal("text", textValue) + + timestampValue, err := sessionDataSet.GetTimestampByIndex(8) + s.NoError(err) + s.Equal(time.Unix(0, 1e6), timestampValue) + + dateValue, err := sessionDataSet.GetDateByIndex(9) + s.NoError(err) + s.Equal(expectedDate, dateValue) + + blobValue, err := sessionDataSet.GetBlobByIndex(10) + s.NoError(err) + s.Equal([]byte{1}, blobValue.GetValues()) + + stringValue, err := sessionDataSet.GetStringByIndex(11) + s.NoError(err) + s.Equal("string", stringValue) + } + sessionDataSet.Close() + + sessionDataSet, err = s.session.ExecuteQueryStatement("select s0, s1, s2, s3, s4, s5, s6, s7, s8, s9 from root.tsg1.d1 limit 1", nil) + for { + if hasNext, err := sessionDataSet.Next(); err != nil || !hasNext { + break + } + for _, columnName := range sessionDataSet.GetColumnNames() { + isNull, err := sessionDataSet.IsNull(columnName) + s.NoError(err) + s.False(isNull) + } + timeValue, err := sessionDataSet.GetLong("Time") + s.NoError(err) + s.Equal(int64(1), timeValue) + boolValue, err := sessionDataSet.GetBoolean("root.tsg1.d1.s0") s.NoError(err) s.Equal(true, boolValue) @@ -550,6 +609,10 @@ func (s *e2eTestSuite) Test_QueryAllDataType() { s.NoError(err) s.False(isNull) } + timeValue, err := sessionDataSet.GetObject("Time") + s.NoError(err) + s.Equal(time.Unix(0, 1*1e6), timeValue) + boolValue, err := sessionDataSet.GetObject("root.tsg1.d1.s0") s.NoError(err) s.Equal(true, boolValue) @@ -591,7 +654,6 @@ func (s *e2eTestSuite) Test_QueryAllDataType() { s.Equal("string", stringValue.(*client.Binary).GetStringValue()) } } - func (s *e2eTestSuite) Test_InvalidSQL() { _, err := s.session.ExecuteStatementWithContext(context.Background(), "select1 from device") assert := s.Require() From 6b9e7c523ec96827067e3d0978044716dd6ac3f2 Mon Sep 17 00:00:00 2001 From: shuwenwei Date: Wed, 16 Apr 2025 18:04:20 +0800 Subject: [PATCH 16/16] fix compile --- client/session.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/session.go b/client/session.go index d0cca85..07023a0 100644 --- a/client/session.go +++ b/client/session.go @@ -550,7 +550,7 @@ func (s *Session) ExecuteGroupByQueryIntervalQuery(database *string, device, mea Timeout: timeoutMs, IsAligned: isAligned} if resp, err := s.client.ExecuteGroupByQueryIntervalQuery(context.Background(), &request); err == nil { if statusErr := VerifySuccess(resp.Status); statusErr == nil { - return NewSessionDataSet("", resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.client, s.sessionId, resp.QueryDataSet, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, s.config.FetchSize, timeoutMs), err + return NewSessionDataSet("", resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, timeoutMs, *resp.MoreData, s.config.FetchSize) } else { return nil, statusErr } @@ -559,7 +559,7 @@ func (s *Session) ExecuteGroupByQueryIntervalQuery(database *string, device, mea request.SessionId = s.sessionId resp, err = s.client.ExecuteGroupByQueryIntervalQuery(context.Background(), &request) if statusErr := VerifySuccess(resp.Status); statusErr == nil { - return NewSessionDataSet("", resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.client, s.sessionId, resp.QueryDataSet, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, s.config.FetchSize, timeoutMs), err + return NewSessionDataSet("", resp.Columns, resp.DataTypeList, resp.ColumnNameIndexMap, *resp.QueryId, s.requestStatementId, s.client, s.sessionId, resp.QueryResult_, resp.IgnoreTimeStamp != nil && *resp.IgnoreTimeStamp, timeoutMs, *resp.MoreData, s.config.FetchSize) } else { return nil, statusErr }