ChDriver (ch_driver v0.1.1)
Copy MarkdownNative ClickHouse TCP-protocol driver, exposed as a DBConnection pool.
Usage
{:ok, pool} = ChDriver.start_link(hostname: "localhost", port: 9000)
{:ok, %ChDriver.Result{columns: columns, rows: rows}} =
ChDriver.query(pool, "SELECT number FROM system.numbers LIMIT 5")start_link/1, query/2,3,4, query!/2,3,4, and stream/2,3,4 are the
whole public surface. Everything else in this library is internal wiring
(used directly by Ecto.Adapters.ClickHouse, but not meant to be called
from application code).
start_link/1 accepts all of ChDriver.Connection.connect/1's options
(:hostname, :port, :database, :username, :password,
:connect_timeout, :recv_timeout, :compression) plus the usual
DBConnection.start_link/2 pool options (:pool_size, :name, etc.),
and forwards the connection options to every pooled connection.
:compression (:none by default, or :lz4) turns on wire compression
for query result blocks. Set it once at pool start, or override it per
call via query/4's opts.
Summary
Functions
Runs statement against conn and returns its result.
Same as query/4, but returns the %ChDriver.Result{} directly on success
and raises the underlying error instead of returning {:error, reason}.
Starts a pool of ClickHouse connections.
Streams the rows of statement one wire-protocol block at a time, instead
of loading the whole result into memory the way query/2,3,4 does.
Functions
@spec query(DBConnection.conn(), binary(), list(), keyword()) :: {:ok, ChDriver.Result.t()} | {:error, Exception.t()}
Runs statement against conn and returns its result.
statement is a raw SQL string. It can contain plain ? positional
placeholders, or ClickHouse's own {name:Type} named placeholders written
directly.
params is the list of Elixir values to bind, in the same order as the
?s (or {name:Type}s) in statement:
ChDriver.query(pool, "SELECT * FROM events WHERE user_id = ?", [42])conn is a pool started by start_link/1, or any DBConnection-compatible
connection reference.
Returns {:ok, %ChDriver.Result{}} or {:error, reason}.
@spec query!(DBConnection.conn(), binary(), list(), keyword()) :: ChDriver.Result.t()
Same as query/4, but returns the %ChDriver.Result{} directly on success
and raises the underlying error instead of returning {:error, reason}.
Starts a pool of ClickHouse connections.
Returns {:ok, pid} (the pool to pass as conn to query/2,3,4 or
stream/2,3,4) or {:error, reason}.
@spec stream(DBConnection.conn(), binary(), list(), keyword()) :: ChDriver.Stream.t()
Streams the rows of statement one wire-protocol block at a time, instead
of loading the whole result into memory the way query/2,3,4 does.
Returns a %ChDriver.Stream{}, an Enumerable whose elements are
%ChDriver.Result{} structs (one per block), honoring
opts[:decode_mapper] the same way query/2,3,4 does.
conn must already be a checked-out connection, so stream/2,3,4 has to
be called from inside DBConnection.run/3 or DBConnection.transaction/3,
not directly against a pool:
{:ok, result} =
DBConnection.run(pool, fn conn ->
conn
|> ChDriver.stream("SELECT number FROM system.numbers LIMIT 200000")
|> Enum.take(5)
end)Each block is only read off the socket when the consumer asks for the next
one, so Enum.take/2 on a large query genuinely avoids buffering rows you
never asked for.