blob: 5eeed48e0d27b9254c5c2850b88a22ec5ad33b49 [file] [log] [blame]
/*
* 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.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Thrift;
namespace Apache.IoTDB.DataStructure
{
public class RpcDataSet : System.IDisposable
{
private const string TimestampColumnName = "Time";
private const string DefaultTimeFormat = "yyyy-MM-dd HH:mm:ss.fff";
private readonly string _sql;
private bool _isClosed;
private readonly Client _client;
public readonly List<string> _columnNameList = new List<string>();
public readonly List<string> _columnTypeList = new List<string>();
private readonly Dictionary<string, int> _columnOrdinalMap = new Dictionary<string, int>();
private readonly Dictionary<string, int> _columnName2TsBlockColumnIndexMap = new Dictionary<string, int>();
private readonly List<int> _columnIndex2TsBlockColumnIndexList = new List<int>();
private readonly TSDataType[] _dataTypeForTsBlockColumn;
private int _fetchSize;
private long _timeout;
private bool _hasCachedRecord;
private bool _lastReadWasNull;
private int _columnSize;
private long _sessionId;
private long _queryId;
private long _statementId;
private long _time;
private bool _ignoreTimestamp;
private bool _moreData;
private List<byte[]> _queryResult;
private TsBlock _curTsBlock;
private int _queryResultSize;
private int _queryResultIndex;
public int _tsBlockSize;
private int _tsBlockIndex;
private TimeZoneInfo _zoneId;
private int _timeFactor;
private string _timePrecision;
private bool disposedValue;
public RpcDataSet(string sql, List<string> columnNameList, List<string> columnTypeList,
Dictionary<string, int> columnNameIndex, bool ignoreTimestamp, bool moreData, long queryId,
long statementId, Client client, long sessionId, List<byte[]> queryResult, int fetchSize,
long timeout, string zoneId, List<int> columnIndex2TsBlockColumnIndexList)
{
_sql = sql;
_client = client;
_fetchSize = fetchSize;
_timeout = timeout;
_moreData = moreData;
_columnSize = columnNameList.Count;
_sessionId = sessionId;
_queryId = queryId;
_statementId = statementId;
_ignoreTimestamp = ignoreTimestamp;
int columnStartIndex = 1;
int resultSetColumnSize = columnNameList.Count;
int startIndexForColumnIndex2TsBlockColumnIndexList = 0;
if (!_ignoreTimestamp)
{
_columnNameList.Add(TimestampColumnName);
_columnTypeList.Add("INT64");
_columnName2TsBlockColumnIndexMap[TimestampColumnName] = -1;
_columnOrdinalMap[TimestampColumnName] = 1;
if (columnIndex2TsBlockColumnIndexList != null)
{
columnIndex2TsBlockColumnIndexList.Insert(0, -1);
startIndexForColumnIndex2TsBlockColumnIndexList = 1;
}
columnStartIndex++;
resultSetColumnSize++;
}
_columnNameList.AddRange(columnNameList);
_columnTypeList.AddRange(columnTypeList);
if (columnIndex2TsBlockColumnIndexList == null)
{
columnIndex2TsBlockColumnIndexList = new List<int>();
if (!_ignoreTimestamp)
{
startIndexForColumnIndex2TsBlockColumnIndexList = 1;
columnIndex2TsBlockColumnIndexList.Add(-1);
}
for (int i = 0; i < columnNameList.Count; i++)
columnIndex2TsBlockColumnIndexList.Add(i);
}
int tsBlockColumnSize = columnIndex2TsBlockColumnIndexList.Max() + 1;
_dataTypeForTsBlockColumn = new TSDataType[tsBlockColumnSize];
for (int i = 0; i < columnNameList.Count; i++)
{
int tsBlockColumnIndex = columnIndex2TsBlockColumnIndexList[startIndexForColumnIndex2TsBlockColumnIndexList + i];
if (tsBlockColumnIndex != -1)
{
TSDataType columnType = Client.GetDataTypeByStr(columnTypeList[i]);
_dataTypeForTsBlockColumn[tsBlockColumnIndex] = columnType;
}
if (!_columnName2TsBlockColumnIndexMap.ContainsKey(columnNameList[i]))
{
_columnOrdinalMap[columnNameList[i]] = i + columnStartIndex;
_columnName2TsBlockColumnIndexMap[columnNameList[i]] = tsBlockColumnIndex;
}
}
_queryResult = queryResult;
_queryResultSize = queryResult?.Count ?? 0;
_queryResultIndex = 0;
_tsBlockSize = 0;
_tsBlockIndex = -1;
_zoneId = TimeZoneInfo.FindSystemTimeZoneById(zoneId);
if (columnIndex2TsBlockColumnIndexList.Count != _columnNameList.Count)
throw new ArgumentException("Column index list size mismatch");
_columnIndex2TsBlockColumnIndexList = columnIndex2TsBlockColumnIndexList;
}
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
try
{
this.Close().Wait();
}
catch
{
}
}
disposedValue = true;
}
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
public async Task Close()
{
if (_isClosed) return;
var closeRequest = new TSCloseOperationReq
{
SessionId = _sessionId,
StatementId = _statementId,
QueryId = _queryId
};
try
{
var status = await _client.ServiceClient.closeOperationAsync(closeRequest);
}
catch (TException e)
{
throw new TException("Operation Handle Close Failed", e);
}
_isClosed = true;
}
public bool Next()
{
if (HasCachedBlock())
{
_lastReadWasNull = false;
ConstructOneRow();
return true;
}
if (HasCachedByteBuffer())
{
ConstructOneTsBlock();
ConstructOneRow();
return true;
}
if (_moreData)
{
bool hasResultSet = FetchResults();
if (hasResultSet && HasCachedByteBuffer())
{
ConstructOneTsBlock();
ConstructOneRow();
return true;
}
}
Close().Wait();
return false;
}
private bool FetchResults()
{
if (_isClosed)
throw new InvalidOperationException("Dataset closed");
var req = new TSFetchResultsReq
{
SessionId = _sessionId,
Statement = _sql,
FetchSize = _fetchSize,
QueryId = _queryId,
IsAlign = true,
Timeout = _timeout
};
try
{
var task = _client.ServiceClient.fetchResultsV2Async(req);
var resp = task.ConfigureAwait(false).GetAwaiter().GetResult();
if (!resp.HasResultSet)
{
Close().Wait();
return false;
}
// return _queryResult != null && _queryResultIndex < _queryResultSize;
_queryResult = resp.QueryResult;
_queryResultIndex = 0;
_queryResultSize = _queryResult?.Count ?? 0;
_tsBlockSize = 0;
_tsBlockIndex = -1;
return true;
}
catch (TException e)
{
throw new TException("Cannot fetch result from server, because of network connection", e);
}
}
private bool HasCachedBlock()
{
return _curTsBlock != null && _tsBlockIndex < _tsBlockSize - 1;
}
public bool HasCachedByteBuffer()
{
return _queryResult != null && _queryResultIndex < _queryResultSize;
}
private void ConstructOneRow()
{
_tsBlockIndex++;
_hasCachedRecord = true;
_time = _curTsBlock.GetTimeByIndex(_tsBlockIndex);
}
private void ConstructOneTsBlock()
{
_lastReadWasNull = false;
byte[] curTsBlockBytes = _queryResult[_queryResultIndex];
_queryResultIndex++;
_curTsBlock = TsBlock.Deserialize(new ByteBuffer(curTsBlockBytes));
_tsBlockIndex = -1;
_tsBlockSize = _curTsBlock.PositionCount;
}
public bool IsIgnoredTimestamp => _ignoreTimestamp;
public bool IsNullByIndex(int columnIndex)
{
int index = GetTsBlockColumnIndexForColumnIndex(columnIndex);
return IsNull(index, _tsBlockIndex);
}
public bool IsNullByColumnName(string columnName)
{
int index = GetTsBlockColumnIndexForColumnName(columnName);
return IsNull(index, _tsBlockIndex);
}
private bool IsNull(int index, int rowNum)
{
return index >= 0 && _curTsBlock.GetColumn(index).IsNull(rowNum);
}
public bool GetBooleanByIndex(int columnIndex)
{
int index = GetTsBlockColumnIndexForColumnIndex(columnIndex);
return GetBooleanByTsBlockColumnIndex(index);
}
public bool GetBoolean(string columnName)
{
int index = GetTsBlockColumnIndexForColumnName(columnName);
return GetBooleanByTsBlockColumnIndex(index);
}
private bool GetBooleanByTsBlockColumnIndex(int tsBlockColumnIndex)
{
CheckRecord();
if (!IsNull(tsBlockColumnIndex, _tsBlockIndex))
{
_lastReadWasNull = false;
return _curTsBlock.GetColumn(tsBlockColumnIndex).GetBoolean(_tsBlockIndex);
}
else
{
_lastReadWasNull = true;
return false;
}
}
public double GetDoubleByIndex(int columnIndex)
{
int index = GetTsBlockColumnIndexForColumnIndex(columnIndex);
return GetDoubleByTsBlockColumnIndex(index);
}
public double GetDouble(string columnName)
{
int index = GetTsBlockColumnIndexForColumnName(columnName);
return GetDoubleByTsBlockColumnIndex(index);
}
private double GetDoubleByTsBlockColumnIndex(int tsBlockColumnIndex)
{
CheckRecord();
if (!IsNull(tsBlockColumnIndex, _tsBlockIndex))
{
_lastReadWasNull = false;
return _curTsBlock.GetColumn(tsBlockColumnIndex).GetDouble(_tsBlockIndex);
}
else
{
_lastReadWasNull = true;
return 0.0;
}
}
public float GetFloatByIndex(int columnIndex)
{
int index = GetTsBlockColumnIndexForColumnIndex(columnIndex);
return GetFloatByTsBlockColumnIndex(index);
}
public float GetFloat(string columnName)
{
int index = GetTsBlockColumnIndexForColumnName(columnName);
return GetFloatByTsBlockColumnIndex(index);
}
private float GetFloatByTsBlockColumnIndex(int tsBlockColumnIndex)
{
CheckRecord();
if (!IsNull(tsBlockColumnIndex, _tsBlockIndex))
{
_lastReadWasNull = false;
return _curTsBlock.GetColumn(tsBlockColumnIndex).GetFloat(_tsBlockIndex);
}
else
{
_lastReadWasNull = true;
return 0.0f;
}
}
public int GetIntByIndex(int columnIndex)
{
int index = GetTsBlockColumnIndexForColumnIndex(columnIndex);
return GetIntByTsBlockColumnIndex(index);
}
public int GetInt(string columnName)
{
int index = GetTsBlockColumnIndexForColumnName(columnName);
return GetIntByTsBlockColumnIndex(index);
}
private int GetIntByTsBlockColumnIndex(int tsBlockColumnIndex)
{
CheckRecord();
if (!IsNull(tsBlockColumnIndex, _tsBlockIndex))
{
_lastReadWasNull = false;
TSDataType dataType = _curTsBlock.GetColumn(tsBlockColumnIndex).GetDataType();
if (dataType == TSDataType.INT64)
{
long v = _curTsBlock.GetColumn(tsBlockColumnIndex).GetLong(_tsBlockIndex);
return (int)v;
}
return _curTsBlock.GetColumn(tsBlockColumnIndex).GetInt(_tsBlockIndex);
}
else
{
_lastReadWasNull = true;
return 0;
}
}
public long GetLongByIndex(int columnIndex)
{
int index = GetTsBlockColumnIndexForColumnIndex(columnIndex);
return GetLongByTsBlockColumnIndex(index);
}
public long GetLong(string columnName)
{
int index = GetTsBlockColumnIndexForColumnName(columnName);
return GetLongByTsBlockColumnIndex(index);
}
private long GetLongByTsBlockColumnIndex(int tsBlockColumnIndex)
{
CheckRecord();
if (!IsNull(tsBlockColumnIndex, _tsBlockIndex))
{
if (tsBlockColumnIndex == -1) return _curTsBlock.GetTimeByIndex(_tsBlockIndex);
_lastReadWasNull = false;
return _curTsBlock.GetColumn(tsBlockColumnIndex).GetLong(_tsBlockIndex);
}
else
{
_lastReadWasNull = true;
return 0L;
}
}
public Binary GetBinaryByIndex(int columnIndex)
{
int index = GetTsBlockColumnIndexForColumnIndex(columnIndex);
return GetBinaryByTsBlockColumnIndex(index);
}
public Binary GetBinary(string columnName)
{
int index = GetTsBlockColumnIndexForColumnName(columnName);
return GetBinaryByTsBlockColumnIndex(index);
}
private Binary GetBinaryByTsBlockColumnIndex(int tsBlockColumnIndex)
{
CheckRecord();
if (!IsNull(tsBlockColumnIndex, _tsBlockIndex))
{
_lastReadWasNull = false;
return _curTsBlock.GetColumn(tsBlockColumnIndex).GetBinary(_tsBlockIndex);
}
else
{
_lastReadWasNull = true;
return null;
}
}
public object GetObjectByIndex(int columnIndex)
{
int index = GetTsBlockColumnIndexForColumnIndex(columnIndex);
return GetObjectByTsBlockIndex(index);
}
public object GetObject(string columnName)
{
int index = GetTsBlockColumnIndexForColumnName(columnName);
return GetObjectByTsBlockIndex(index);
}
private object GetObjectByTsBlockIndex(int tsBlockColumnIndex)
{
CheckRecord();
if (IsNull(tsBlockColumnIndex, _tsBlockIndex))
{
_lastReadWasNull = true;
return null;
}
_lastReadWasNull = false;
TSDataType dataType = GetDataTypeByTsBlockColumnIndex(tsBlockColumnIndex);
switch (dataType)
{
case TSDataType.BOOLEAN:
case TSDataType.INT32:
case TSDataType.INT64:
case TSDataType.FLOAT:
case TSDataType.DOUBLE:
return _curTsBlock.GetColumn(tsBlockColumnIndex).GetObject(_tsBlockIndex);
case TSDataType.TIMESTAMP:
long timestamp = tsBlockColumnIndex == -1
? _curTsBlock.GetTimeByIndex(_tsBlockIndex)
: _curTsBlock.GetColumn(tsBlockColumnIndex).GetLong(_tsBlockIndex);
return ConvertToTimestamp(timestamp, _timeFactor);
case TSDataType.TEXT:
case TSDataType.STRING:
Binary binaryStr = _curTsBlock.GetColumn(tsBlockColumnIndex).GetBinary(_tsBlockIndex);
return binaryStr != null ? Encoding.UTF8.GetString(binaryStr.Data) : null;
case TSDataType.BLOB:
return _curTsBlock.GetColumn(tsBlockColumnIndex).GetBinary(_tsBlockIndex);
case TSDataType.DATE:
int value = _curTsBlock.GetColumn(tsBlockColumnIndex).GetInt(_tsBlockIndex);
return Int32ToDate(value);
default:
return null;
}
}
public string GetStringByIndex(int columnIndex)
{
int index = GetTsBlockColumnIndexForColumnIndex(columnIndex);
return GetStringByTsBlockColumnIndex(index);
}
public string GetString(string columnName)
{
int index = GetTsBlockColumnIndexForColumnName(columnName);
return GetStringByTsBlockColumnIndex(index);
}
private string GetStringByTsBlockColumnIndex(int tsBlockColumnIndex)
{
CheckRecord();
if (tsBlockColumnIndex == -1)
{
long timestamp = _curTsBlock.GetTimeByIndex(_tsBlockIndex);
return timestamp.ToString();
}
if (IsNull(tsBlockColumnIndex, _tsBlockIndex))
{
_lastReadWasNull = true;
Console.WriteLine("null");
return string.Empty;
}
_lastReadWasNull = false;
return GetStringByTsBlockColumnIndexAndDataType(
tsBlockColumnIndex,
GetDataTypeByTsBlockColumnIndex(tsBlockColumnIndex));
}
private string GetStringByTsBlockColumnIndexAndDataType(int index, TSDataType tsDataType)
{
switch (tsDataType)
{
case TSDataType.BOOLEAN:
bool boolVal = _curTsBlock.GetColumn(index).GetBoolean(_tsBlockIndex);
return boolVal.ToString();
case TSDataType.INT32:
int intVal = _curTsBlock.GetColumn(index).GetInt(_tsBlockIndex);
return intVal.ToString();
case TSDataType.INT64:
long longVal = _curTsBlock.GetColumn(index).GetLong(_tsBlockIndex);
return longVal.ToString();
case TSDataType.TIMESTAMP:
long tsValue = _curTsBlock.GetColumn(index).GetLong(_tsBlockIndex);
return FormatDatetime(DefaultTimeFormat, _timePrecision, tsValue, _zoneId);
case TSDataType.FLOAT:
float floatVal = _curTsBlock.GetColumn(index).GetFloat(_tsBlockIndex);
return floatVal.ToString("G9");
case TSDataType.DOUBLE:
double doubleVal = _curTsBlock.GetColumn(index).GetDouble(_tsBlockIndex);
return doubleVal.ToString("G17");
case TSDataType.TEXT:
case TSDataType.STRING:
Binary strBytes = _curTsBlock.GetColumn(index).GetBinary(_tsBlockIndex);
return strBytes != null ? Encoding.UTF8.GetString(strBytes.Data) : "0";
case TSDataType.BLOB:
Binary blobBytes = _curTsBlock.GetColumn(index).GetBinary(_tsBlockIndex);
return blobBytes.ToString().Replace("-", "");
case TSDataType.DATE:
int dateValue = _curTsBlock.GetColumn(index).GetInt(_tsBlockIndex);
DateTime date = Int32ToDate(dateValue);
return date.ToString("yyyy-MM-dd");
default:
return string.Empty;
}
}
public RowRecord GetRow()
{
IReadOnlyList<string> columns = _columnNameList;
int i = 0;
List<object> fieldList = new List<Object>();
long timestamp = 0;
foreach (string columnName in columns)
{
object localfield;
string typeStr = _columnTypeList[i];
TSDataType dataType = Client.GetDataTypeByStr(typeStr);
switch (dataType)
{
case TSDataType.BOOLEAN:
localfield = GetBoolean(columnName);
break;
case TSDataType.INT32:
localfield = GetInt(columnName);
break;
case TSDataType.INT64:
localfield = GetLong(columnName);
break;
case TSDataType.TIMESTAMP:
localfield = null;
timestamp = GetLong(columnName);
break;
case TSDataType.FLOAT:
localfield = GetFloat(columnName);
break;
case TSDataType.DOUBLE:
localfield = GetDouble(columnName);
break;
case TSDataType.TEXT:
case TSDataType.STRING:
case TSDataType.BLOB:
case TSDataType.DATE:
localfield = GetString(columnName);
break;
default:
string err_msg = "value format not supported";
throw new TException(err_msg, null);
}
if (localfield != null)
fieldList.Add(localfield);
i += 1;
}
return new RowRecord(timestamp, fieldList, _columnNameList);
}
public DateTime GetTimestampByIndex(int columnIndex)
{
int index = GetTsBlockColumnIndexForColumnIndex(columnIndex);
return GetTimestampByTsBlockColumnIndex(index);
}
public DateTime GetTimestamp(string columnName)
{
int index = GetTsBlockColumnIndexForColumnName(columnName);
return GetTimestampByTsBlockColumnIndex(index);
}
private DateTime GetTimestampByTsBlockColumnIndex(int tsBlockColumnIndex)
{
long value = GetLongByTsBlockColumnIndex(tsBlockColumnIndex);
return ConvertToTimestamp(value, _timeFactor);
}
public DateTime GetDateByIndex(int columnIndex)
{
int index = GetTsBlockColumnIndexForColumnIndex(columnIndex);
return GetDateByTsBlockColumnIndex(index);
}
public DateTime GetDate(string columnName)
{
int index = GetTsBlockColumnIndexForColumnName(columnName);
return GetDateByTsBlockColumnIndex(index);
}
private DateTime GetDateByTsBlockColumnIndex(int tsBlockColumnIndex)
{
int value = GetIntByTsBlockColumnIndex(tsBlockColumnIndex);
return Int32ToDate(value);
}
public TSDataType GetDataTypeByIndex(int columnIndex)
{
int index = GetTsBlockColumnIndexForColumnIndex(columnIndex);
return GetDataTypeByTsBlockColumnIndex(index);
}
public TSDataType GetDataType(string columnName)
{
if (!_columnName2TsBlockColumnIndexMap.TryGetValue(columnName, out int index))
throw new ArgumentException($"Column {columnName} not found");
return GetDataTypeByTsBlockColumnIndex(index);
}
private TSDataType GetDataTypeByTsBlockColumnIndex(int tsBlockColumnIndex)
{
return tsBlockColumnIndex < 0
? TSDataType.TIMESTAMP
: _dataTypeForTsBlockColumn[tsBlockColumnIndex];
}
private DateTime ConvertToTimestamp(long value, double timeFactor)
{
long timestamp = (long)(value * timeFactor);
return DateTimeOffset.FromUnixTimeMilliseconds(timestamp).DateTime;
}
public static DateTime Int32ToDate(int val)
{
int year = val / 10000;
int remaining = val % 10000;
int month = remaining / 100;
int day = remaining % 100;
if (year < 1 || year > 9999)
throw new ArgumentOutOfRangeException(
paramName: nameof(val),
message: $"Invalid year value: {year}. Year must be between 1-9999"
);
if (month < 1 || month > 12)
throw new ArgumentOutOfRangeException(
paramName: nameof(val),
message: $"Invalid month value: {month}. Month must be between 1-12"
);
int daysInMonth = DateTime.DaysInMonth(year, month);
if (day < 1 || day > daysInMonth)
throw new ArgumentOutOfRangeException(
paramName: nameof(val),
message: $"Invalid day value: {day}. Day must be between 1-{daysInMonth} for {year}-{month}"
);
return new DateTime(year, month, day, 0, 0, 0, DateTimeKind.Utc);
}
private string FormatDatetime(string format, string precision, long value, TimeZoneInfo zone)
{
DateTime dt = ConvertToTimestamp(value, 1); // 假设timeFactor=1
DateTime convertedTime = TimeZoneInfo.ConvertTime(dt, zone);
return convertedTime.ToString(format);
}
private int GetTsBlockColumnIndexForColumnName(string columnName)
{
if (!_columnName2TsBlockColumnIndexMap.TryGetValue(columnName, out int index))
throw new ArgumentException($"Column {columnName} not found");
return index;
}
public int FindColumn(string columnName)
{
if (!_columnOrdinalMap.TryGetValue(columnName, out int ordinal))
throw new ArgumentException($"Column {columnName} not found");
return ordinal;
}
public string FindColumnNameByIndex(int columnIndex)
{
if (columnIndex <= 0)
throw new ArgumentOutOfRangeException(nameof(columnIndex), "Column index should start from 1");
if (columnIndex > _columnNameList.Count)
throw new ArgumentOutOfRangeException(nameof(columnIndex),
$"Column index {columnIndex} out of range {_columnNameList.Count}");
return _columnNameList[columnIndex - 1];
}
private int GetTsBlockColumnIndexForColumnIndex(int columnIndex)
{
int adjustedIndex = columnIndex - 1;
if (adjustedIndex < 0 || adjustedIndex >= _columnIndex2TsBlockColumnIndexList.Count)
throw new ArgumentOutOfRangeException(nameof(columnIndex),
$"Index {adjustedIndex} out of range {_columnIndex2TsBlockColumnIndexList.Count}");
return _columnIndex2TsBlockColumnIndexList[adjustedIndex];
}
private void CheckRecord()
{
if (_queryResultIndex > _queryResultSize ||
_tsBlockIndex >= _tsBlockSize ||
_queryResult == null ||
_curTsBlock == null)
{
throw new InvalidOperationException("No record remains");
}
}
public int GetValueColumnStartIndex() => _ignoreTimestamp ? 0 : 1;
public int GetColumnSize() => _columnNameList.Count;
public List<string> GetColumnTypeList() => new List<string>(_columnTypeList);
public List<string> GetColumnNameTypeList() => new List<string>(_columnTypeList);
public bool IsClosed() => _isClosed;
public int FetchSize
{
get => _fetchSize;
set => _fetchSize = value;
}
public bool HasCachedRecord
{
get => _hasCachedRecord;
set => _hasCachedRecord = value;
}
public bool IsLastReadWasNull() => _lastReadWasNull;
public long GetCurrentRowTime() => _time;
public bool IsIgnoreTimestamp() => _ignoreTimestamp;
}
}