ChDriver.Protocol.Messages (ch_driver v0.1.1)

Copy Markdown

Byte-level encoding and decoding for each ClickHouse native-protocol message: Hello, Addendum, Query (with its ClientInfo sub-structure), the empty Data packet, Ping, Exception, Progress, and ProfileInfo.

This is internal to the driver. ChDriver.Protocol owns packet-type dispatch and calls into this module for the actual bytes.

Summary

Functions

Builds a ClientHello struct advertising this driver's identity, for the given default_database, user, and password.

This driver's advertised protocol revision (@client_revision).

Decodes a ServerHello packet from the front of binary, including its leading packet-type varint (expected to be 0).

Encodes the Addendum sent immediately after receiving ServerHello, when ChDriver.Protocol.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, signaling "no external tables, no input data" — required even for a plain SELECT.

Encodes a Ping packet. The server replies with a bare Pong and nothing else.

Encodes a Query packet for query_string.

Functions

client_hello(default_database \\ "default", user \\ "default", password \\ "")

@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.

client_revision()

@spec client_revision() :: non_neg_integer()

This driver's advertised protocol revision (@client_revision).

decode_server_hello(binary)

@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).

encode_addendum()

@spec encode_addendum() :: iodata()

Encodes the Addendum sent immediately after receiving ServerHello, when ChDriver.Protocol.addendum_required?/0 is true.

Not a full packet — just a raw length-prefixed string (the quota key, always sent empty here), with no leading packet-type varint. This must be sent before any Query packet; see ChDriver.Protocol.addendum_required?/0.

encode_cancel()

@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.

encode_client_hello(hello)

@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.

encode_empty_data_packet(compression \\ :none)

@spec encode_empty_data_packet(ChDriver.Protocol.Block.Compressed.method()) ::
  iodata()

Encodes the empty Data packet ClickHouse requires right after every Query packet, signaling "no external tables, no input data" — required even for a plain SELECT.

compression (:none (default) or :lz4) must match whatever was negotiated for this query via encode_query/2's :compression opt.

encode_ping()

@spec encode_ping() :: iodata()

Encodes a Ping packet. The server replies with a bare Pong and nothing else.

encode_query(query_string, opts \\ [])

@spec encode_query(
  binary(),
  keyword()
) :: iodata()

Encodes a Query packet for query_string.

opts accepts:

  • :query_id -- defaults to "" (the server generates one).
  • :params -- a list of {name, raw_text} or {name, raw_text, rounds} tuples binding query_string's {name:Type} placeholders. Build these from Elixir values with ChDriver.Params.text/1 and ChDriver.Params.escape_rounds/1. Defaults to [].
  • :compression -- :none (default) or :lz4. Setting this to :lz4 tells the server that both directions of this query's block traffic (Data, ProfileEvents) will be wrapped in a ChDriver.Protocol.Block.Compressed envelope from here on — every packet sent after this one, in either direction, needs to match.