ChDriver. Protocol
(ch_driver v0.1.1)
Copy Markdown
Encodes and decodes ClickHouse native-protocol packets.
This is internal to the driver — application code talks to ClickHouse
through ChDriver, not this module directly.
Covers the connection handshake (client_hello/3, encode_client_hello/1,
decode_server_hello/1), building outgoing Query/Ping/Cancel packets, and
dispatching incoming server packets to the right decoder
(decode_packet/2). Per-message byte layouts live in
ChDriver.Protocol.Messages; this module owns packet-type dispatch and
the ClientHello/ServerHello struct definitions.
Summary
Functions
Whether the handshake needs to send an Addendum packet after ServerHello.
Always true for this driver's advertised protocol revision.
Builds a ClientHello struct advertising this driver's identity, for the
given default_database, user, and password.
Decodes a single server response packet from the front of binary.
Decodes a ServerHello packet from the front of binary, including its
leading packet-type varint (expected to be 0).
Encodes the Addendum packet sent right after receiving ServerHello, when
addendum_required?/0 is true.
Encodes a Cancel packet, telling the server to stop running the query
currently in progress on this connection. The caller must keep reading
until :end_of_stream afterward — see ChDriver.Connection.cancel_stream/2.
Encodes a ClientHello struct into the plaintext bytes sent to open a
connection: packet-type varint (0), then client name/version/revision
and the default_database/user/password length-prefixed strings.
Encodes the empty Data packet ClickHouse requires right after every
Query packet, even for a plain SELECT. compression must match
whatever was passed as encode_query/2's :compression for this query.
Encodes a Ping packet. The server replies with a bare Pong and nothing else.
Encodes a Query packet for query_string.
Functions
@spec addendum_required?() :: boolean()
Whether the handshake needs to send an Addendum packet after ServerHello.
Always true for this driver's advertised protocol revision.
@spec client_hello(binary(), binary(), binary()) :: ChDriver.Protocol.ClientHello.t()
Builds a ClientHello struct advertising this driver's identity, for the
given default_database, user, and password.
@spec decode_packet(binary(), ChDriver.Protocol.Block.Compressed.method()) :: {:ok, term(), binary()} | {:incomplete, binary()} | {:error, term()}
Decodes a single server response packet from the front of binary.
Returns {:ok, packet, rest}, {:incomplete, binary} if more bytes are
needed (buffer more and retry), or {:error, reason}.
packet is one of:
{:data, %{table_name:, columns:, rows:}}-- a query result block.{:profile_events, %{table_name:, columns:, rows:}}-- internal query execution metrics, wire-identical to:data.{:progress, %{read_rows:, read_bytes:, total_rows_to_read:, total_bytes_to_read:, written_rows:, written_bytes:, elapsed_ns:}}:pong:end_of_stream{:exception, %ChDriver.Error{}}
compression (:none (default) or :lz4) must match whatever was
negotiated for this query via encode_query/2's :compression opt.
It only affects how Data packets' block bodies are decoded; ProfileEvents
and every other packet type are always plain regardless of compression.
@spec decode_server_hello(binary()) :: {:ok, ChDriver.Protocol.ServerHello.t(), binary()} | {:incomplete, binary()} | {:error, term()}
Decodes a ServerHello packet from the front of binary, including its
leading packet-type varint (expected to be 0).
Returns {:ok, %ServerHello{}, rest}, {:incomplete, binary} if more
bytes are needed, or {:error, reason} if the packet type doesn't match
Hello (e.g. the server sent an Exception instead, most likely due to bad
credentials).
@spec encode_addendum() :: iodata()
Encodes the Addendum packet sent right after receiving ServerHello, when
addendum_required?/0 is true.
@spec encode_cancel() :: iodata()
Encodes a Cancel packet, telling the server to stop running the query
currently in progress on this connection. The caller must keep reading
until :end_of_stream afterward — see ChDriver.Connection.cancel_stream/2.
@spec encode_client_hello(ChDriver.Protocol.ClientHello.t()) :: iodata()
Encodes a ClientHello struct into the plaintext bytes sent to open a
connection: packet-type varint (0), then client name/version/revision
and the default_database/user/password length-prefixed strings.
@spec encode_empty_data_packet(ChDriver.Protocol.Block.Compressed.method()) :: iodata()
Encodes the empty Data packet ClickHouse requires right after every
Query packet, even for a plain SELECT. compression must match
whatever was passed as encode_query/2's :compression for this query.
@spec encode_ping() :: iodata()
Encodes a Ping packet. The server replies with a bare Pong and nothing else.
Encodes a Query packet for query_string.
opts accepts:
:query_id-- defaults to"".:params-- a list of{name, raw_text}or{name, raw_text, rounds}tuples bindingquery_string's{name:Type}placeholders. Build these from Elixir values withChDriver.Params.text/1andChDriver.Params.escape_rounds/1. Defaults to[].:compression--:none(default) or:lz4.