Example #1
0
 internal ClickHouseDataReader(ClickHouseTable table, ClickHouseTcpClient.Session session, CancellationTokenSource?sessionTokenSource)
 {
     _currentTable              = table ?? throw new ArgumentNullException(nameof(table));
     _session                   = session ?? throw new ArgumentNullException(nameof(session));
     _sessionTokenSource        = sessionTokenSource;
     _reinterpretedColumnsCache = new IClickHouseTableColumn[_currentTable.Columns.Count];
     _recordsAffected           = _currentTable.Header.RowCount;
     _blockHeader               = _currentTable.Header;
     State = ClickHouseDataReaderState.Data;
 }
        public async Task SkipNextResult(ClickHouseDataReaderState readBlock, int expectedCount)
        {
            await using var cn = await OpenConnectionAsync();

            await using var cmd = cn.CreateCommand();
            cmd.Extremes        = true;
            cmd.CommandText     = "select x, sum(y) as v from (SELECT number%3 + 1 as x, number as y FROM numbers(10)) group by x with totals;";

            await using var reader = await cmd.ExecuteReaderAsync();

            Assert.Equal(ClickHouseDataReaderState.Data, reader.State);

            do
            {
                switch (reader.State)
                {
                case ClickHouseDataReaderState.Data:
                case ClickHouseDataReaderState.Totals:
                case ClickHouseDataReaderState.Extremes:
                    if (reader.State == readBlock)
                    {
                        break;
                    }

                    continue;

                default:
                    Assert.True(false, $"Unexpected state: {reader.State}.");
                    break;
                }

                int count = 0;
                while (await reader.ReadAsync())
                {
                    ++count;
                }

                Assert.False(await reader.ReadAsync());
                Assert.Equal(expectedCount, count);
                Assert.True(reader.State == ClickHouseDataReaderState.NextResultPending || reader.State == ClickHouseDataReaderState.Closed);
            } while (await reader.NextResultAsync());

            Assert.Equal(ClickHouseDataReaderState.Closed, reader.State);
        }
Example #3
0
        private async ValueTask Close(bool disposing, bool async)
        {
            if (_session.IsDisposed || _session.IsFailed)
            {
                return;
            }

            if (!(State == ClickHouseDataReaderState.Closed || State == ClickHouseDataReaderState.Broken))
            {
                await _session.SendCancel(async);

                while (true)
                {
                    try
                    {
                        var message = _nextResultMessage ?? await _session.ReadMessage(async, CancellationToken.None);

                        _nextResultMessage = null;

                        switch (message.MessageCode)
                        {
                        case ServerMessageCode.Data:
                        case ServerMessageCode.Totals:
                        case ServerMessageCode.Extremes:
                            var dataMessage = (ServerDataMessage)message;
                            await _session.SkipTable(dataMessage, async, CancellationToken.None);

                            continue;

                        case ServerMessageCode.Error:
                            State = ClickHouseDataReaderState.Closed;
                            if (disposing)
                            {
                                break;
                            }

                            throw ((ServerErrorMessage)message).Exception;

                        case ServerMessageCode.Progress:
                            var progressMessage = (ServerProgressMessage)message;
                            _recordsAffected = progressMessage.Rows;
                            continue;

                        case ServerMessageCode.EndOfStream:
                            State = ClickHouseDataReaderState.Closed;
                            break;

                        case ServerMessageCode.ProfileInfo:
                            continue;

                        case ServerMessageCode.Pong:
                        case ServerMessageCode.Hello:
                        case ServerMessageCode.Log:
                            throw new ClickHouseException(ClickHouseErrorCodes.ProtocolUnexpectedResponse, $"Unexpected server message: \"{message.MessageCode}\".");

                        default:
                            throw new NotSupportedException($"Internal error. Message code \"{message.MessageCode}\" not supported.");
                        }
                    }
                    catch (ClickHouseHandledException ex)
                    {
                        if (!disposing)
                        {
                            throw;
                        }

                        State = ClickHouseDataReaderState.Broken;
                        await _session.SetFailed(ex.InnerException, false, async);

                        return;
                    }
                    catch (Exception ex)
                    {
                        State = ClickHouseDataReaderState.Broken;
                        var aggrEx = await _session.SetFailed(ex, false, async);

                        if (disposing)
                        {
                            return;
                        }

                        if (aggrEx != null)
                        {
                            throw aggrEx;
                        }

                        throw;
                    }

                    break;
                }
            }

            _session.Dispose();
            _sessionTokenSource?.Dispose();
        }
Example #4
0
        private async ValueTask <bool> Read(bool nextResult, bool async, CancellationToken cancellationToken)
        {
            if (!nextResult)
            {
                if (_rowIndex == _currentTable.Header.RowCount)
                {
                    return(false);
                }

                if (++_rowIndex < _currentTable.Header.RowCount)
                {
                    return(true);
                }
            }

            while (true)
            {
                ClickHouseTable nextTable;

                try
                {
                    var message = _nextResultMessage;
                    if (message == null)
                    {
                        message = await _session.ReadMessage(async, cancellationToken);
                    }
                    else
                    {
                        _nextResultMessage = null;
                    }

                    switch (message.MessageCode)
                    {
                    case ServerMessageCode.Data:
                        switch (State)
                        {
                        case ClickHouseDataReaderState.NextResultPending:
                            State = ClickHouseDataReaderState.Data;
                            goto case ClickHouseDataReaderState.Data;

                        case ClickHouseDataReaderState.Data:
                        {
                            var dataMessage = (ServerDataMessage)message;
                            nextTable = await _session.ReadTable(dataMessage, _columnSettings, async, cancellationToken);

                            break;
                        }

                        case ClickHouseDataReaderState.Totals:
                        case ClickHouseDataReaderState.Extremes:
                        {
                            var dataMessage = (ServerDataMessage)message;
                            var table       = await _session.SkipTable(dataMessage, async, cancellationToken);

                            if (table.RowCount != 0 || table.Columns.Count != 0)
                            {
                                throw new ClickHouseException(ClickHouseErrorCodes.ProtocolUnexpectedResponse, "Unexpected data block after totals or extremes.");
                            }

                            continue;
                        }

                        default:
                            goto UNEXPECTED_RESPONSE;
                        }

                        break;

                    case ServerMessageCode.Error:
                        State = ClickHouseDataReaderState.Closed;
                        _session.Dispose();
                        throw ((ServerErrorMessage)message).Exception;

                    case ServerMessageCode.Progress:
                        var progressMessage = (ServerProgressMessage)message;
                        _recordsAffected = progressMessage.Rows;
                        continue;

                    case ServerMessageCode.EndOfStream:
                        State = ClickHouseDataReaderState.Closed;
                        _session.Dispose();
                        return(false);

                    case ServerMessageCode.ProfileInfo:
                        continue;

                    case ServerMessageCode.Totals:
                        switch (State)
                        {
                        case ClickHouseDataReaderState.NextResultPending:
                            State = ClickHouseDataReaderState.Totals;
                            goto case ClickHouseDataReaderState.Totals;

                        case ClickHouseDataReaderState.Totals:
                            var totalsMessage = (ServerDataMessage)message;
                            nextTable = await _session.ReadTable(totalsMessage, _columnSettings, async, cancellationToken);

                            break;

                        case ClickHouseDataReaderState.Data:
                        case ClickHouseDataReaderState.Extremes:
                            _nextResultMessage = message;
                            State = ClickHouseDataReaderState.NextResultPending;
                            return(false);

                        default:
                            goto UNEXPECTED_RESPONSE;
                        }

                        break;

                    case ServerMessageCode.Extremes:
                        switch (State)
                        {
                        case ClickHouseDataReaderState.NextResultPending:
                            State = ClickHouseDataReaderState.Extremes;
                            goto case ClickHouseDataReaderState.Extremes;

                        case ClickHouseDataReaderState.Extremes:
                            var extremesMessage = (ServerDataMessage)message;
                            nextTable = await _session.ReadTable(extremesMessage, _columnSettings, async, cancellationToken);

                            break;

                        case ClickHouseDataReaderState.Data:
                        case ClickHouseDataReaderState.Totals:
                            _nextResultMessage = message;
                            State = ClickHouseDataReaderState.NextResultPending;
                            return(false);

                        default:
                            goto UNEXPECTED_RESPONSE;
                        }

                        break;

                    case ServerMessageCode.Pong:
                    case ServerMessageCode.Hello:
                    case ServerMessageCode.Log:
UNEXPECTED_RESPONSE:
                        throw new ClickHouseException(ClickHouseErrorCodes.ProtocolUnexpectedResponse, $"Unexpected server message: \"{message.MessageCode}\".");

                    default:
                        throw new NotSupportedException($"Internal error. Message code \"{message.MessageCode}\" not supported.");
                    }
                }
                catch (ClickHouseHandledException)
                {
                    throw;
                }
                catch (ClickHouseServerException)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    State = ClickHouseDataReaderState.Broken;
                    var aggrEx = await _session.SetFailed(ex, true, async);

                    if (aggrEx != null)
                    {
                        throw aggrEx;
                    }

                    throw;
                }

                if (nextTable.Header.RowCount == 0)
                {
                    continue;
                }

                _currentTable = nextTable;
                _reinterpretedColumnsCache = new IClickHouseTableColumn[_currentTable.Columns.Count];
                _recordsAffected          += nextTable.Header.RowCount;
                _rowIndex = nextResult ? -1 : 0;
                return(true);
            }
        }