ChDriver.Connection (ch_driver v0.1.1)

Copy Markdown

Opens a TCP connection to ClickHouse and runs queries over it.

This is the low-level connection API that ChDriver.DBConnection wraps to plug into DBConnection's pooling. You'd only call it directly if you're managing a single raw connection yourself.

Packet encoding/decoding itself lives in ChDriver.Protocol; this module owns the socket, buffering incoming bytes, and looping over the response packets a query produces.

Summary

Functions

Stops a stream started by start_stream/3 and leaves the connection ready for the next query.

Closes a socket previously returned by connect/1.

Opens a TCP connection to a ClickHouse server and performs the Hello handshake.

Sends a Ping packet and waits for the server's Pong. Returns :ok on a successful round-trip or {:error, term} on a socket error or an unexpected response.

Runs query_string against the connection returned by connect/1 and collects the full result.

Starts running query_string for block-at-a-time streaming, instead of reading the whole result the way query/3 does.

Fetches the next block of a stream started by start_stream/3.

Functions

cancel_stream(socket, map)

@spec cancel_stream(:gen_tcp.socket(), map()) :: :ok | {:error, term()}

Stops a stream started by start_stream/3 and leaves the connection ready for the next query.

If the stream already ran to completion, this is a no-op. Otherwise (e.g. the caller did Enum.take/2 on a large stream and stopped early) it tells ClickHouse to cancel the query and drains any blocks still in flight, so the socket ends up in a clean state for whatever query you run next.

Returns :ok or {:error, reason}.

close(socket)

@spec close(:gen_tcp.socket()) :: :ok

Closes a socket previously returned by connect/1.

connect(opts \\ [])

@spec connect(keyword()) ::
  {:ok,
   %{
     socket: :gen_tcp.socket(),
     server_info: ChDriver.Protocol.ServerHello.t(),
     compression: ChDriver.Protocol.Block.Compressed.method()
   }}
  | {:error, term()}

Opens a TCP connection to a ClickHouse server and performs the Hello handshake.

Options

  • :hostname - defaults to ~c"localhost"
  • :port - defaults to 9000
  • :database - default_database to advertise, defaults to "default"
  • :username - defaults to "default"
  • :password - defaults to ""
  • :connect_timeout - TCP connect timeout in ms, defaults to 5_000
  • :recv_timeout - :gen_tcp.recv/3 timeout in ms, defaults to 5_000
  • :max_buffer_size - maximum accumulated receive-buffer size in bytes before the handshake fails fast with {:error, %ChDriver.Error{}} instead of growing the buffer without limit, defaults to 67108864 (64MB)
  • :compression - :none (default) or :lz4. Turns on wire compression for this connection's query result blocks. Acts as a per-connection default; query/3's own opts can override it per call. Any other value raises ArgumentError.

Returns {:ok, %{socket: socket, server_info: %ChDriver.Protocol.ServerHello{}, compression: :none | :lz4}} on success, or {:error, reason} on failure. The caller owns the returned socket and is responsible for closing it with close/1.

ping(map, opts \\ [])

@spec ping(
  map(),
  keyword()
) :: :ok | {:error, term()}

Sends a Ping packet and waits for the server's Pong. Returns :ok on a successful round-trip or {:error, term} on a socket error or an unexpected response.

query(conn, query_string, opts \\ [])

@spec query(map(), binary(), keyword()) :: {:ok, map()} | {:error, term()}

Runs query_string against the connection returned by connect/1 and collects the full result.

opts[:params] binds query_string's {name:Type} placeholders — a list of {name, raw_text} or {name, raw_text, escape_rounds} tuples (see ChDriver.Params.text/1 and ChDriver.Params.escape_rounds/1 for building these from Elixir values).

opts[:compression] (:none or :lz4) overrides the connection's default compression setting for this one query.

Returns {:ok, %{columns: [{name, type}], rows: [[term]]}} or {:error, term} — either a socket error, or a %ChDriver.Error{} if ClickHouse rejected the query.

start_stream(conn, query_string, opts \\ [])

@spec start_stream(map(), binary(), keyword()) :: {:ok, map()} | {:error, term()}

Starts running query_string for block-at-a-time streaming, instead of reading the whole result the way query/3 does.

Sends the query and reads just far enough to know the result's column names/types, then returns a stream handle that stream_fetch/2 reads further blocks from on demand.

Returns {:ok, stream} or {:error, reason} (a socket error or a %ChDriver.Error{}, exactly like query/3). stream is opaque — pass it straight to stream_fetch/2 and cancel_stream/2.

stream_fetch(socket, stream)

@spec stream_fetch(:gen_tcp.socket(), map()) ::
  {:cont | :halt, map(), map()} | {:error, term()}

Fetches the next block of a stream started by start_stream/3.

Returns {:cont, %{columns:, rows:}, stream} while more blocks remain, {:halt, %{columns:, rows:}, stream} once the result is exhausted (every further call then returns the same empty :halt immediately), or {:error, reason}.