#pragma once namespace DB { /** Протокол взаимодействия с сервером. * * Клиент соединяется с сервером и передаёт ему пакет Hello. * Если версия не устраивает, то сервер может разорвать соединение. * Сервер отвечает пакетом Hello. * Если версия не устраивает, то клиент может разорвать соединение. * * Далее в цикле. * * 1. Клиент отправляет на сервер пакет Query. * * Если запрос типа INSERT (требует передачи данных от клиента), то сервер передаёт * пакет Data, содержащий пустой блок, который описывает структуру таблицы. * Затем клиент отправляет данные для вставки * - один или несколько пакетов Data. * Конец данных определается по отправленному пустому блоку. * Затем сервер отправляет клиенту пакет EndOfStream. * * Если запрос типа SELECT или другой, то сервер передаёт набор пакетов одного из следующих видов: * - Data - данные результата выполнения запроса (один блок); * - Progress - прогресс выполнения запроса; * - Exception - ошибка; * - EndOfStream - конец передачи данных; * * Клиент должен читать пакеты до EndOfStream или Exception. * Также, клиент может передать на сервер пакет Cancel - отмена выполнения запроса. * В этом случае, сервер может прервать выполнение запроса и вернуть неполные данные; * но клиент всё равно должен читать все пакеты до EndOfStream. * * Перед пакетом EndOfStream, если есть профайлинговая информация и ревизия клиента достаточно новая, * может быть отправлен пакет ProfileInfo. После него передаются данные профайлинга - * сериализованная структура BlockStreamProfileInfo. * * При запросах, которые возвращают данные, сервер, перед обработкой запроса, * отправляет заголовочный блок, содержащий описание столбцов из запроса, но с нулем строк. * Используя этот заголовочный блок, клиент может заранее проинициализировать формат вывода * и вывести префикс таблицы результата. * * 2. Между запросами, клиент может отправить Ping, и сервер должен ответить Pong. */ namespace Protocol { /// То, что передаёт сервер. namespace Server { enum Enum { Hello = 0, /// Имя, версия, ревизия. Data = 1, /// Блок данных со сжатием или без. Exception = 2, /// Исключение во время обработки запроса. Progress = 3, /// Прогресс выполнения запроса: строк считано, байт считано. Pong = 4, /// Ответ на Ping. EndOfStream = 5, /// Все пакеты были переданы. ProfileInfo = 6, /// Пакет с профайлинговой информацией }; inline const char * toString(Enum packet) { static const char * data[] = { "Hello", "Data", "Exception", "Progress", "Pong", "EndOfStream", "ProfileInfo" }; return packet >= 0 && packet < 7 ? data[packet] : "Unknown packet"; } } /// То, что передаёт клиент. namespace Client { enum Enum { Hello = 0, /// Имя, версия, ревизия, БД по-умолчанию. Query = 1, /** Идентификатор запроса, настройки на отдельный запрос, * информация, до какой стадии исполнять запрос, * использовать ли сжатие, текст запроса (без данных для INSERT-а). */ Data = 2, /// Блок данных со сжатием или без. Cancel = 3, /// Отменить выполнение запроса. Ping = 4, /// Проверка живости соединения с сервером. }; inline const char * toString(Enum packet) { static const char * data[] = { "Hello", "Query", "Data", "Cancel", "Ping" }; return packet >= 0 && packet < 5 ? data[packet] : "Unknown packet"; } } /// Использовать ли сжатие. namespace Compression { enum Enum { Disable = 0, Enable = 1, }; } } }