dbms: development [#CONV-2944].

This commit is contained in:
Alexey Milovidov 2012-05-16 18:03:00 +00:00
parent c89ff86132
commit bfb5eceea7
7 changed files with 477 additions and 244 deletions

View File

@ -0,0 +1,99 @@
#include <Poco/Net/StreamSocket.h>
#include <DB/Core/Block.h>
#include <DB/Core/Progress.h>
#include <DB/Core/Protocol.h>
#include <DB/Core/QueryProcessingStage.h>
#include <DB/IO/ReadBufferFromPocoSocket.h>
#include <DB/IO/WriteBufferFromPocoSocket.h>
#include <DB/DataTypes/DataTypeFactory.h>
#include <DB/DataStreams/IBlockInputStream.h>
#include <DB/DataStreams/IBlockOutputStream.h>
namespace DB
{
using Poco::SharedPtr;
/** Соединение с сервером БД для использования в клиенте.
* Как использовать - см. Core/Protocol.h
* (Реализацию на стороне сервера - см. Server/TCPHandler.h)
*/
class Connection
{
public:
Connection(const String & host_, UInt16 port_,
DataTypeFactory & data_type_factory_,
Protocol::Compression::Enum compression_ = Protocol::Compression::Enable)
: host(host_), port(port_), socket(), in(socket), out(socket),
query_id(0), compression(compression_), data_type_factory(data_type_factory_)
{
connect();
}
virtual ~Connection() {};
/// Пакет, который может быть получен от сервера.
struct Packet
{
UInt64 type;
Block block;
SharedPtr<Exception> exception;
Progress progress;
Packet() : type(Protocol::Server::Hello) {}
};
void sendQuery(const String & query, UInt64 query_id_ = 0, UInt64 stage = QueryProcessingStage::Complete);
void sendCancel();
void sendData(Block & block);
/// Проверить, если ли данные, которые можно прочитать.
bool poll(size_t timeout_microseconds = 0);
/// Получить пакет от сервера.
Packet receivePacket();
private:
String host;
UInt16 port;
Poco::Net::StreamSocket socket;
ReadBufferFromPocoSocket in;
WriteBufferFromPocoSocket out;
UInt64 query_id;
UInt64 compression; /// Сжимать ли данные при взаимодействии с сервером.
DataTypeFactory & data_type_factory;
/// Откуда читать результат выполнения запроса.
SharedPtr<ReadBuffer> chunked_in;
SharedPtr<ReadBuffer> maybe_compressed_in;
BlockInputStreamPtr block_in;
/// Куда писать данные INSERT-а.
SharedPtr<WriteBuffer> chunked_out;
SharedPtr<WriteBuffer> maybe_compressed_out;
BlockOutputStreamPtr block_out;
void connect();
void sendHello();
void receiveHello();
void forceConnected();
bool ping();
Block receiveData();
SharedPtr<Exception> receiveException();
Progress receiveProgress();
};
}

View File

@ -0,0 +1,36 @@
#pragma once
#include <DB/IO/ReadBuffer.h>
#include <DB/IO/WriteBuffer.h>
#include <DB/IO/ReadHelpers.h>
#include <DB/IO/WriteHelpers.h>
namespace DB
{
/// Прогресс выполнения запроса
struct Progress
{
size_t rows; /// Строк обработано.
size_t bytes; /// Байт обработано.
Progress() : rows(0), bytes(0) {}
Progress(size_t rows_, size_t bytes_) : rows(rows_), bytes(bytes_) {}
void read(ReadBuffer & in)
{
readBinary(rows, in);
readBinary(bytes, in);
}
void write(WriteBuffer & out)
{
writeBinary(rows, out);
writeBinary(bytes, out);
}
};
}

View File

@ -4,6 +4,32 @@ namespace DB
{
/** Протокол взаимодействия с сервером.
*
* Клиент соединяется с сервером и передаёт ему пакет Hello.
* Если версия не устраивает, то сервер может разорвать соединение.
* Сервер отвечает пакетом Hello.
* Если версия не устраивает, то клиент может разорвать соединение.
*
* Далее в цикле.
*
* Клиент отправляет на сервер пакет Query.
*
* Если этот запрос требует передачи данных от клиента, то клиент отправляет один или несколько пакетов Data
* с помощью ChunkedWriteBuffer.
* Конец данных определается по отправленному пустому блоку.
*
* Далее, сервер передаёт набор пакетов одного из следующих видов:
* - Data - данные результата выполнения запроса (один блок);
* - Progress - прогресс выполнения запроса;
* - Exception - ошибка;
* - EndOfStream - конец передачи данных;
*
* Клиент должен читать пакеты до EndOfStream или Exception.
* Также, клиент может передать на сервер пакет Cancel - отмена выполнения запроса.
* В этом случае, сервер может прервать выполнение запроса и вернуть неполные данные;
* но клиент всё равно должен читать все пакеты до EndOfStream.
*
* Между запросами, клиент может отправить Ping, и сервер должен ответить Pong.
*/
namespace Protocol
@ -13,12 +39,12 @@ namespace Protocol
{
enum Enum
{
Hello = 0, /// Имя, версия, ревизия.
Data = 1, /// Идентификатор запроса, признак последнего чанка, размер чанка, часть данных со сжатием или без.
Exception = 2, /// Исключение во время обработки запроса.
Progress = 3, /// Прогресс выполнения запроса: строк считано, байт считано.
Ok = 4, /// Запрос без возвращаемого результата успешно выполнен.
Pong = 5, /// Ответ на Ping.
Hello = 0, /// Имя, версия, ревизия.
Data = 1, /// Идентификатор запроса, признак последнего чанка, размер чанка, часть данных со сжатием или без.
Exception = 2, /// Исключение во время обработки запроса.
Progress = 3, /// Прогресс выполнения запроса: строк считано, байт считано.
Pong = 4, /// Ответ на Ping.
EndOfStream = 5, /// Все пакеты были переданы.
};
}
@ -27,12 +53,14 @@ namespace Protocol
{
enum Enum
{
Query = 0, /** Идентификатор запроса, информация, до какой стадии исполнять запрос,
Hello = 0, /// Имя, версия, ревизия.
Query = 1, /** Идентификатор запроса, информация, до какой стадии исполнять запрос,
* использовать ли сжатие, формат входных данных, формат выходных данных, текст запроса (без данных для INSERT-а).
*/
Data = 1, /// Идентификатор запроса, признак последнего чанка, размер чанка, часть данных со сжатием или без.
Cancel = 2, /// Отменить выполнение запроса.
Ping = 3, /// Проверка живости соединения с сервером.
Data = 2, /// Идентификатор запроса, признак последнего чанка, размер чанка, часть данных со сжатием или без.
Cancel = 3, /// Отменить выполнение запроса.
Ping = 4, /// Проверка живости соединения с сервером.
EndOfStream = 5, /// Все пакеты были переданы.
};
}

View File

@ -18,8 +18,6 @@
#include <Poco/File.h>
#include <Poco/SharedPtr.h>
#include <Poco/Util/Application.h>
#include <Poco/Net/StreamSocket.h>
#include <Poco/Net/NetException.h>
#include <Yandex/Revision.h>
@ -27,15 +25,8 @@
#include <DB/Core/Exception.h>
#include <DB/Core/Types.h>
#include <DB/Core/Protocol.h>
#include <DB/Core/QueryProcessingStage.h>
#include <DB/IO/ReadBufferFromPocoSocket.h>
#include <DB/IO/WriteBufferFromPocoSocket.h>
#include <DB/IO/CompressedReadBuffer.h>
#include <DB/IO/CompressedWriteBuffer.h>
#include <DB/IO/ChunkedReadBuffer.h>
#include <DB/IO/ChunkedWriteBuffer.h>
#include <DB/IO/ReadBufferFromFileDescriptor.h>
#include <DB/IO/WriteBufferFromFileDescriptor.h>
#include <DB/IO/ReadHelpers.h>
@ -46,6 +37,8 @@
#include <DB/Interpreters/Context.h>
#include <DB/Client/Connection.h>
/** Клиент командной строки СУБД ClickHouse.
*/
@ -109,7 +102,7 @@ private:
class Client : public Poco::Util::Application
{
public:
Client() : is_interactive(true), stdin_is_not_tty(false), socket(), in(socket), out(socket), query_id(0), compression(Protocol::Compression::Enable),
Client() : is_interactive(true), stdin_is_not_tty(false), query_id(0),
format_max_block_size(0), std_in(STDIN_FILENO), std_out(STDOUT_FILENO), received_rows(0),
rows_read_on_server(0), bytes_read_on_server(0), written_progress_chars(0), written_first_block(false) {}
@ -120,32 +113,16 @@ private:
bool is_interactive; /// Использовать readline интерфейс или batch режим.
bool stdin_is_not_tty; /// stdin - не терминал.
Poco::Net::StreamSocket socket;
ReadBufferFromPocoSocket in;
WriteBufferFromPocoSocket out;
SharedPtr<Connection> connection; /// Соединение с БД.
String query; /// Текущий запрос.
UInt64 query_id; /// Идентификатор запроса. Его можно использовать, чтобы отменить запрос.
UInt64 compression; /// Сжимать ли данные при взаимодействии с сервером.
String in_format; /// Формат передачи данных (INSERT-а) на сервер.
String out_format; /// Формат приёма данных (результата) от сервера.
String format; /// Формат вывода результата в консоль.
size_t format_max_block_size; /// Максимальный размер блока при выводе в консоль.
String insert_format; /// Формат данных для INSERT-а при чтении их из stdin в batch режиме
size_t insert_format_max_block_size; /// Максимальный размер блока при чтении данных INSERT-а.
Context context;
Block empty_block;
/// Откуда читать результат выполнения запроса.
SharedPtr<ReadBuffer> chunked_in;
SharedPtr<ReadBuffer> maybe_compressed_in;
BlockInputStreamPtr block_in;
/// Куда писать данные INSERT-а.
SharedPtr<WriteBuffer> chunked_out;
SharedPtr<WriteBuffer> maybe_compressed_out;
BlockOutputStreamPtr block_out;
/// Чтение из stdin для batch режима
ReadBufferFromFileDescriptor std_in;
@ -256,17 +233,14 @@ private:
<< "." << Revision::get()
<< "." << std::endl;
compression = config().getBool("compression", true) ? Protocol::Compression::Enable : Protocol::Compression::Disable;
in_format = config().getString("in_format", "Native");
out_format = config().getString("out_format", "Native");
format = config().getString("format", is_interactive ? "PrettyCompact" : "TabSeparated");
format = config().getString("format", is_interactive ? "PrettyCompact" : "TabSeparated");
format_max_block_size = config().getInt("format_max_block_size", DEFAULT_BLOCK_SIZE);
connect();
context.format_factory = new FormatFactory();
context.data_type_factory = new DataTypeFactory();
connect();
if (is_interactive)
{
/// Отключаем tab completion.
@ -298,34 +272,14 @@ private:
{
String host = config().getString("host", "localhost");
UInt16 port = config().getInt("port", 9000);
Protocol::Compression::Enum compression = config().getBool("compression", true)
? Protocol::Compression::Enable
: Protocol::Compression::Disable;
if (is_interactive)
std::cout << "Connecting to " << host << ":" << port << "." << std::endl;
socket.connect(Poco::Net::SocketAddress(host, port));
/// Получить hello пакет.
UInt64 packet_type = 0;
String server_name;
UInt64 server_version_major = 0;
UInt64 server_version_minor = 0;
UInt64 server_revision = 0;
readVarUInt(packet_type, in);
if (packet_type != Protocol::Server::Hello)
throw Exception("Unexpected packet from server", ErrorCodes::UNEXPECTED_PACKET_FROM_SERVER);
readStringBinary(server_name, in);
readVarUInt(server_version_major, in);
readVarUInt(server_version_minor, in);
readVarUInt(server_revision, in);
if (is_interactive)
std::cout << "Connected to " << server_name
<< " server version " << server_version_major
<< "." << server_version_minor
<< "." << server_revision
<< "." << std::endl << std::endl;
connection = new Connection(host, port, *context.data_type_factory, compression);
}
@ -367,6 +321,9 @@ private:
if (exit_strings.end() != exit_strings.find(line))
return false;
block_std_in = NULL;
block_std_out = NULL;
watch.restart();
query = line;
@ -381,9 +338,7 @@ private:
written_progress_chars = 0;
written_first_block = false;
forceConnected();
sendQuery();
connection->sendQuery(query, query_id, QueryProcessingStage::Complete);
sendData();
receiveResult();
@ -392,34 +347,10 @@ private:
<< received_rows << " rows in set. Elapsed: " << watch.elapsedSeconds() << " sec."
<< std::endl << std::endl;
block_in = NULL;
maybe_compressed_in = NULL;
chunked_in = NULL;
return true;
}
void forceConnected()
{
try
{
if (!ping())
{
socket.close();
connect();
}
}
catch (const Poco::Net::NetException & e)
{
if (is_interactive)
std::cout << e.displayText() << std::endl;
connect();
}
}
bool parseQuery()
{
ParserQuery parser;
@ -454,48 +385,6 @@ private:
}
bool ping()
{
UInt64 pong = 0;
writeVarUInt(Protocol::Client::Ping, out);
out.next();
if (in.eof())
return false;
readVarUInt(pong, in);
if (pong != Protocol::Server::Pong)
throw Exception("Unknown packet from server (expected Pong)", ErrorCodes::UNKNOWN_PACKET_FROM_SERVER);
return true;
}
void sendQuery()
{
UInt64 stage = QueryProcessingStage::Complete;
writeVarUInt(Protocol::Client::Query, out);
writeIntBinary(query_id, out);
writeVarUInt(stage, out);
writeVarUInt(compression, out);
writeStringBinary(in_format, out);
writeStringBinary(out_format, out);
writeStringBinary(query, out);
out.next();
}
void sendCancel()
{
writeVarUInt(Protocol::Client::Cancel, out);
out.next();
}
void sendData()
{
/// Если нужно отправить данные INSERT-а.
@ -521,48 +410,16 @@ private:
void sendDataFrom(ReadBuffer & buf)
{
/* if (!block_out)
if (!block_std_in)
{
chunked_out = new ChunkedWriteBuffer(out, query_id);
maybe_compressed_out = compression == Protocol::Compression::Enable
? new CompressedWriteBuffer(*chunked_out)
: chunked_out;
block_out = context.format_factory->getOutput(
in_format,
*maybe_compressed_out,
empty_block,
insert_format_max_block_size,
*context.data_type_factory);
// TODO
}
/// Прочитать из сети один блок и вывести его в консоль
Block block = block_in->read();
if (block)
{
received_rows += block.rows();
if (!block_std_out)
{
String current_format = format;
/// Формат может быть указан в SELECT запросе.
if (ASTSelectQuery * select = dynamic_cast<ASTSelectQuery *>(&*parsed_query))
if (select->format)
if (ASTIdentifier * id = dynamic_cast<ASTIdentifier *>(&*select->format))
current_format = id->name;
block_std_out = context.format_factory->getOutput(current_format, std_out, block);
}
block_std_out->write(block);
std_out.next();
return true;
}
else
return false;*/
}
/** Получает и обрабатывает пакеты из сервера.
* Также следит, не требуется ли прервать выполнение запроса.
*/
void receiveResult()
{
InterruptListener interrupt_listener;
@ -579,12 +436,12 @@ private:
{
if (interrupt_listener.check())
{
sendCancel();
connection->sendCancel();
cancelled = true;
if (is_interactive)
std::cout << "Cancelling query." << std::endl;
}
else if (!in.poll(1000000))
else if (!connection->poll(1000000))
continue; /// Если новых данных в ещё нет, то после таймаута продолжим проверять, не остановлено ли выполнение запроса.
}
@ -594,57 +451,43 @@ private:
if (cancelled && is_interactive)
std::cout << "Query was cancelled." << std::endl;
block_std_out = NULL;
}
/// Получить кусок результата или прогресс выполнения или эксепшен.
/** Получить кусок результата или прогресс выполнения или эксепшен,
* и обработать пакет соответствующим образом.
* Возвращает true, если нужно продолжать чтение пакетов.
*/
bool receivePacket()
{
UInt64 packet_type = 0;
readVarUInt(packet_type, in);
Connection::Packet packet = connection->receivePacket();
switch (packet_type)
switch (packet.type)
{
case Protocol::Server::Data:
return receiveData();
case Protocol::Server::Exception:
receiveException();
return false;
case Protocol::Server::Ok:
receiveOk();
return false;
onData(packet.block);
return true;
case Protocol::Server::Progress:
receiveProgress();
onProgress(packet.progress);
return true;
case Protocol::Server::Exception:
onException(*packet.exception);
return false;
case Protocol::Server::EndOfStream:
onEndOfStream();
return false;
default:
throw Exception("Unknown packet from server", ErrorCodes::UNKNOWN_PACKET_FROM_SERVER);
}
}
bool receiveData()
void onData(Block & block)
{
if (!block_in)
{
chunked_in = new ChunkedReadBuffer(in, query_id);
maybe_compressed_in = compression == Protocol::Compression::Enable
? new CompressedReadBuffer(*chunked_in)
: chunked_in;
block_in = context.format_factory->getInput(
out_format,
*maybe_compressed_in,
empty_block,
format_max_block_size,
*context.data_type_factory);
}
if (written_progress_chars)
{
if (written_first_block)
@ -658,8 +501,6 @@ private:
written_first_block = true;
/// Прочитать из сети один блок и вывести его в консоль
Block block = block_in->read();
if (block)
{
received_rows += block.rows();
@ -679,7 +520,6 @@ private:
block_std_out->write(block);
std_out.next();
return true;
}
else
{
@ -687,37 +527,14 @@ private:
block_std_out->writeSuffix();
std_out.next();
return false;
}
}
void receiveException()
void onProgress(const Progress & progress)
{
Exception e;
readException(e, in);
std::cerr << "Received exception from server:" << std::endl
<< "Code: " << e.code() << ". " << e.displayText();
}
void receiveOk()
{
if (is_interactive)
std::cout << "Ok." << std::endl;
}
void receiveProgress()
{
size_t rows = 0;
size_t bytes = 0;
readVarUInt(rows, in);
readVarUInt(bytes, in);
rows_read_on_server += rows;
bytes_read_on_server += bytes;
rows_read_on_server += progress.rows;
bytes_read_on_server += progress.bytes;
static size_t increment = 0;
static const char * indicators[8] =
@ -734,8 +551,6 @@ private:
if (is_interactive)
{
/*for (size_t i = 0; i < written_progress_chars; ++i)
std::cerr << "\b \b";*/
std::cerr << std::string(written_progress_chars, '\b');
std::stringstream message;
@ -756,6 +571,20 @@ private:
++increment;
}
}
void onException(const Exception & e)
{
std::cerr << "Received exception from server:" << std::endl
<< "Code: " << e.code() << ". " << e.displayText();
}
void onEndOfStream()
{
if (is_interactive && !written_first_block)
std::cout << "Ok." << std::endl;
}
void defineOptions(Poco::Util::OptionSet & options)

View File

@ -0,0 +1,214 @@
#include <Poco/Net/NetException.h>
#include <Yandex/Revision.h>
#include <DB/Core/Defines.h>
#include <DB/IO/CompressedReadBuffer.h>
#include <DB/IO/CompressedWriteBuffer.h>
#include <DB/IO/ChunkedReadBuffer.h>
#include <DB/IO/ChunkedWriteBuffer.h>
#include <DB/IO/ReadHelpers.h>
#include <DB/IO/WriteHelpers.h>
#include <DB/DataStreams/NativeBlockInputStream.h>
#include <DB/DataStreams/NativeBlockOutputStream.h>
#include <DB/Client/Connection.h>
namespace DB
{
void Connection::connect()
{
socket.connect(Poco::Net::SocketAddress(host, port));
sendHello();
receiveHello();
}
void Connection::sendHello()
{
writeVarUInt(Protocol::Client::Hello, out);
writeStringBinary(String(DBMS_NAME) + " client", out);
writeVarUInt(DBMS_VERSION_MAJOR, out);
writeVarUInt(DBMS_VERSION_MINOR, out);
writeVarUInt(Revision::get(), out);
out.next();
}
void Connection::receiveHello()
{
/// Получить hello пакет.
UInt64 packet_type = 0;
String server_name;
UInt64 server_version_major = 0;
UInt64 server_version_minor = 0;
UInt64 server_revision = 0;
readVarUInt(packet_type, in);
if (packet_type != Protocol::Server::Hello)
throw Exception("Unexpected packet from server", ErrorCodes::UNEXPECTED_PACKET_FROM_SERVER);
readStringBinary(server_name, in);
readVarUInt(server_version_major, in);
readVarUInt(server_version_minor, in);
readVarUInt(server_revision, in);
}
void Connection::forceConnected()
{
try
{
if (!ping())
{
socket.close();
connect();
}
}
catch (const Poco::Net::NetException & e)
{
connect();
}
}
bool Connection::ping()
{
UInt64 pong = 0;
writeVarUInt(Protocol::Client::Ping, out);
out.next();
if (in.eof())
return false;
readVarUInt(pong, in);
if (pong != Protocol::Server::Pong)
throw Exception("Unknown packet from server (expected Pong)", ErrorCodes::UNKNOWN_PACKET_FROM_SERVER);
return true;
}
void Connection::sendQuery(const String & query, UInt64 query_id_, UInt64 stage)
{
forceConnected();
query_id = query_id_;
writeVarUInt(Protocol::Client::Query, out);
writeIntBinary(query_id, out);
writeVarUInt(stage, out);
writeVarUInt(compression, out);
writeStringBinary("Native", out);
writeStringBinary("Native", out);
writeStringBinary(query, out);
out.next();
maybe_compressed_in = NULL;
maybe_compressed_out = NULL;
chunked_in = NULL;
chunked_out = NULL;
block_in = NULL;
block_out = NULL;
}
void Connection::sendCancel()
{
writeVarUInt(Protocol::Client::Cancel, out);
out.next();
}
void Connection::sendData(Block & block)
{
if (!block_out)
{
chunked_out = new ChunkedWriteBuffer(out, query_id);
maybe_compressed_out = compression == Protocol::Compression::Enable
? new CompressedWriteBuffer(*chunked_out)
: chunked_out;
block_out = new NativeBlockOutputStream(*maybe_compressed_out);
}
block_out->write(block);
}
bool Connection::poll(size_t timeout_microseconds)
{
return in.poll(timeout_microseconds);
}
Connection::Packet Connection::receivePacket()
{
Packet res;
readVarUInt(res.type, in);
switch (res.type)
{
case Protocol::Server::Data:
res.block = receiveData();
return res;
case Protocol::Server::Exception:
res.exception = receiveException();
return res;
case Protocol::Server::Progress:
res.progress = receiveProgress();
return res;
case Protocol::Server::EndOfStream:
return res;
default:
throw Exception("Unknown packet from server", ErrorCodes::UNKNOWN_PACKET_FROM_SERVER);
}
}
Block Connection::receiveData()
{
if (!block_in)
{
chunked_in = new ChunkedReadBuffer(in, query_id);
maybe_compressed_in = compression == Protocol::Compression::Enable
? new CompressedReadBuffer(*chunked_in)
: chunked_in;
block_in = new NativeBlockInputStream(*maybe_compressed_in, data_type_factory);
}
/// Прочитать из сети один блок
return block_in->read();
}
SharedPtr<Exception> Connection::receiveException()
{
Exception e;
readException(e, in);
return e.clone();
}
Progress Connection::receiveProgress()
{
Progress progress;
progress.read(in);
return progress;
}
}

View File

@ -28,7 +28,7 @@ void TCPHandler::runImpl()
WriteBufferFromPocoSocket out(socket());
WriteBufferFromPocoSocket out_for_chunks(socket());
/// Сразу после соединения, отправляем hello-пакет.
receiveHello(in);
sendHello(out);
while (!in.eof())
@ -68,8 +68,8 @@ void TCPHandler::runImpl()
while (sendData(out, out_for_chunks))
;
}
else
sendOk(out);
sendEndOfStream(out);
}
catch (DB::Exception & e)
{
@ -104,6 +104,32 @@ void TCPHandler::runImpl()
}
void TCPHandler::receiveHello(ReadBuffer & in)
{
/// Получить hello пакет.
UInt64 packet_type = 0;
String client_name;
UInt64 client_version_major = 0;
UInt64 client_version_minor = 0;
UInt64 client_revision = 0;
readVarUInt(packet_type, in);
if (packet_type != Protocol::Client::Hello)
throw Exception("Unexpected packet from client", ErrorCodes::UNEXPECTED_PACKET_FROM_CLIENT);
readStringBinary(client_name, in);
readVarUInt(client_version_major, in);
readVarUInt(client_version_minor, in);
readVarUInt(client_revision, in);
LOG_DEBUG(log, "Connected to " << client_name
<< " client version " << client_version_major
<< "." << client_version_minor
<< "." << client_revision
<< ".")
}
void TCPHandler::sendHello(WriteBuffer & out)
{
writeVarUInt(Protocol::Server::Hello, out);
@ -287,11 +313,11 @@ void TCPHandler::sendException(WriteBuffer & out)
out.next();
}
void TCPHandler::sendOk(WriteBuffer & out)
void TCPHandler::sendEndOfStream(WriteBuffer & out)
{
Poco::ScopedLock<Poco::FastMutex> lock(send_mutex);
writeVarUInt(Protocol::Server::Ok, out);
writeVarUInt(Protocol::Server::EndOfStream, out);
out.next();
}

View File

@ -112,8 +112,9 @@ private:
bool sendData(WriteBuffer & out, WriteBuffer & out_for_chunks);
void sendException(WriteBuffer & out);
void sendProgress(WriteBuffer & out, size_t rows, size_t bytes);
void sendOk(WriteBuffer & out);
void sendEndOfStream(WriteBuffer & out);
void receiveHello(ReadBuffer & in);
bool receivePacket(ReadBuffer & in, WriteBuffer & out);
void receiveQuery(ReadBuffer & in);
bool receiveData(ReadBuffer & in);