Skip to main content
clickhouse-c は、ClickHouse の ネイティブプロトコル 向けのヘッダーオンリー C クライアントです。 ソースコードと各ヘッダーのリファレンスは、GitHub リポジトリ にあります。 上位レベルのクライアントとは異なり、このクライアントは意図的に多くのことを行いません。中核となるヘッダーは、ユーザーが提供する I/O コールバックを介して Native フォーマットのブロックをデコードおよびエンコードします。ソケット、TLS コンテキスト、アロケータ、再試行、接続プーリングはユーザー側で管理します。そのため埋め込みに適した小ささを実現しており、clickhouse.h だけをインクルードしても、リンク時の依存関係は libc を除いて発生しません。
このライブラリは現在も活発に開発されています。v1 では ClickHouse の主要な型をデコードします。 制限事項や不足している機能は、issue tracker から報告してください。 ただし、このライブラリには設計上あえて備えていない機能があることをご理解ください。

ライブラリが行わないこと

以下は、意図的に対象外としている項目です。これらはアプリケーション側、または関連するライブラリで対応してください。
  • HTTPプロトコル。HTTP インターフェイス を使用する場合は、libcurl を直接ラップしてください。
  • DNS 名前解決、エンドポイントのフェイルオーバー、接続プーリング、再試行、バックオフ。
  • TLS コンテキストのライフサイクル。OpenSSL バックエンドは、すでに接続済みの SSL を使用します。
  • スレッド処理。各 chc_client は設計上シングルスレッドです。
  • ライブラリ内部での非同期 I/O。ブロッキングクライアント は chc_io.read を同期的に呼び出します。ライブラリ自身では I/O を行わない event-loop client が必要な場合は、I/O を行わないクライアント を使用してください.

ライブラリの構成

clickhouse-c は、フラットなヘッダーファイル群として提供されます。各ヘッダーには宣言と実装の両方が含まれており、 センチネルマクロで保護されています。ビルドに必要なヘッダーを選択してください。

必須のサーバー設定

デコーダはワイヤ形式から可読な型名を読み取るため、これらはテキストとしてエンコードされている必要があります。ClickHouse はデフォルトでこれらをテキストとして書き込みますが、サーバーまたはセッションのプロファイル でこれがbinaryに設定されていてもデコードできなくならないよう、この設定はクエリで明示的に固定してください:

プロジェクトへの追加

インストールするパッケージはないため、Git submodule またはコピーでヘッダーファイルをソースツリーに取り込んでください。 CHC_IMPLEMENTATION を定義して実装を取り込む翻訳単位は、必ず1つだけにしてください。 それ以外のすべての翻訳単位では、宣言だけを得るために同じヘッダーファイルをインクルードします。
chc_alloc_stdlib を使用するには、clickhouse.h をインクルードする前に CHC_PROVIDE_STDLIB_ALLOC を定義してください。 clickhouse-compression.h で lz4/zstd への依存関係をなくすには、CHC_NO_LZ4 または CHC_NO_ZSTD を定義してください。

TCP 経由で接続する

ClickHouse server と通信するには、自分でソケットを用意し、それを chc_io でラップして chc_client_init に渡します。これにより、Hello ハンドシェイクが同期的に実行されます。DNS、フェイルオーバー、再接続、プーリングはライブラリでは処理しないため、これらは呼び出し側で対応する必要があります。
chc_client はシングルスレッドで動作し、1 つの接続をラップします。ライブラリは chc_io コールバックを同期的に呼び出します。これらのコールバックが内部で何を行うか (epollio_uringWaitLatchOrSocket) は、使用者に委ねられます。

クエリの実行

クエリを送信したら、CHC_PKT_END_OF_STREAM に達するまでパケットを読み続けます。必須のサーバー設定を 指定するには chc_client_send_query_ex を使用してください。chc_client_send_query のみを使用すると空の 設定リストが送信され、サーバーのデフォルト設定がそのまま適用されます。
サーバー例外は CHC_PKT_EXCEPTION パケットとして返され、 chc_client_recv_packet の non-OK の戻り値として返されるわけではありません。non-OK が返るのはトランスポート層の障害時だけです。結果の最初の CHC_PKT_DATA パケットは、スキーマを記述した 0 行のヘッダーブロックで、その後にデータブロックが続きます。 chc_packet_clear はパケット内の block または exception を解放します。代わりに所有権を引き取る場合は、まず パケット上のそれらのフィールドを null にしてください。

カラムデータの読み取り

ブロックはカラム指向です。各カラムには chc_column_layout が返す物理レイアウトがあり、 それに応じて処理を分岐します。宣言上の型は chc_block_column_type から取得します。複合レイアウトは入れ子になるため、 Nullable(Array(String)) を読み取るには、Nullable をアンラップし、配列のオフセットをたどってから、 文字列データを切り出します。 プレーンな数値、文字列、Nullable カラム用のリーダー:
CHC_COL_FIXED データは、送信時のバイト表現ではリトルエンディアンです。ビッグエンディアンのホストでは、多バイト 整数のバイト順を自分で入れ替える必要があります。offsets と LowCardinality のキーは、デコード時点で すでにホストバイトオーダーに変換されています。UUIDs はリトルエンディアンの UInt64 を 2 つ並べたもので、IPv4 は 4 バイトのリトルエンディアン整数、IPv6 は ネットワークバイトオーダーです。DateTime64 の ticks は UTC であり、型に含まれる timezone はメタデータにすぎません。 信頼できないピアから取り込む際は、各カラムを走査する前に chc_column_validate を呼び出して ください。chc_block_read は、配列の offsets や LowCardinality のキーといったフィールド間の不変条件を検証しないため、 そうしないと、偽造された block によって内部カラムの境界を超えて読み取られるおそれがあります。

データの挿入

chc_build_* ヘルパーでカラムを構築し、それらを chc_block_builder に追加してから、 chc_client_send_data に渡します。ビルダーは呼び出し元が用意したストレージを使用し、データをコピーするのではなく ポインターを保持するため、ストレージ、カラムツリー、型、名前、スラブは送信処理が完了するまで有効である必要があります。INSERT では クエリを送信し、サーバーのヘッダーブロックを待ってから、1 つ以上のデータブロックを送信し、最後に 空のブロックを送信してストリームを終了します。
chc_build_fixedn_rows * elem_size の リトルエンディアン バイト列を受け取り、chc_build_string は packed されたスラブ上の、ホストバイトオーダーで表された 排他的な終端 offset の累積値を受け取ります。helpers はカラムノードを値として返します。 型に合わせてそれらをネストしてください。たとえば、fixed または string ノードを chc_build_nullable に渡し、その結果を chc_build_array に渡して、array のルートを append します。Tuple、 LowCardinality、Map、および Geo カラムは同じツリーを使います。Map は Array(Tuple(K, V)) です。 block 内のすべてのカラムは、トップレベルの行数が同じでなければなりません。writer はツリーを parse 済みの ClickHouse 型と照合しますが、呼び出し側は append のたびに各 chc_block_col のストレージサイズを確保する必要があります。 また、chc_block_column から取得したデコード済みのカラムを直接 append して再エンコードすることも、chc_block_col 配列を指定して chc_block_write_cols を呼び出し、builder を省略することもできます。builder を下位レベルの chc_block_write ではなく chc_client_send_data 経由で渡すことで、client はネゴシエートされたリビジョンに基づいて block オプションを設定し、圧縮を適用できます。

圧縮

chc_client_opts に圧縮モードと使用するコーデックを渡します。クライアントは受信した Dataパケットを伸長し、送信するパケットを圧縮します。圧縮ヘッダーには LZ4ZSTD のアダプターが用意されています。 各 init はそれぞれ自身のスロットしか埋めないため、どちらにも対応するには両方を呼び出してください。
このプロジェクトがバインディングを提供していない圧縮ライブラリを使用するには、chc_codec を自分で実装してください; vtable は clickhouse-compression.h で宣言されています。

TLS

clickhouse-openssl.h は、SSL_read/SSL_write を介した chc_io バックエンドを提供します。OpenSSL の制御は利用者側で行います。 このライブラリが SSL_CTX を作成したり、証明書を検証したり、SNI を設定したり、SSL_connect / SSL_shutdown を呼び出したりすることはありません。chc_io.read が発火する時点で、ハンドシェイクは完了している必要があります。
ClickHouse Cloud やその他の TLS 対応デプロイでは、ポート 9440 でネイティブプロトコルを 使用します。どちらのバックエンドも、読み取りの合間にポーリングされる省略可能な check_cancel コールバックと、 chc_openssl_io_set_deadline / chc_posix_io_set_deadline による読み取りデッドラインに対応しています。

Ioless (async) クライアント

clickhouse-async.h は、イベントループ向け TCP クライアントの ioless バリアントです。ソケットには一切触れません。受信したバイト列を渡し、送信したいバイト列を取り出して、epollio_uringWaitLatchOrSocket は自分で駆動します。オプション、パケットタイプ、ブロックビルダーはブロッキングクライアントと同じです。 chc_async_client_init は I/O を行わず、ブロックもできません。その後のハンドシェイクは再開可能なステートマシンとして動作し、送信と受信もすべて同様です。パースが渡したバイト列の範囲を超えると、その呼び出しはブロックする代わりに CHC_WOULD_BLOCK を返します。さらに受信バイト列を渡してもう一度呼び出すと、パーサーはブロックの途中から再開します。
pump は双方向にバイトをやり取りします。Outbound では、chc_async_pending_out がキュー済みのバイトへのポインターと長さを返します。ソケットがその一部を受け付けたら、そのバイト数を指定して chc_async_consume_out を呼び出します。部分書き込みでも問題ありません。Inbound では、ソケットから読み取ったデータを chc_async_submit に渡します。送信ではブロックもバックプレッシャーの適用も発生しないため、pending-out の長さを監視し、大きくなりすぎたら送信の発行を止めてください。 動作する liburing ドライバーは test/test_async_uring.c にあります。

メモリとアロケータ

すべてのエントリポイントは chc_alloc vtable を受け取るため、メモリ割り当てにはホスト側で使われている方式がそのまま使われます。
clickhouse.h をインクルードする前に CHC_PROVIDE_STDLIB_ALLOC を定義し、標準の malloc ベースのアロケータを使用するには chc_alloc_stdlib() を呼び出します。

エラーとサーバー例外

関数は CHC_OK (0) または 0 以外の CHC_ERR_* コードを返します。コードが戻り値であり、 呼び出し元のスタックに確保された chc_err に可読なメッセージが格納されます。ライブラリが エラーをヒープに割り当てることはありません。
サーバー側のクエリエラーは chc_err の失敗ではありません。これらはパケットストリーム上で CHC_PKT_EXCEPTION として届き、サーバーの codedisplay_textstack_trace を伴います。chc_err の確認は、 トランスポート、プロトコル、デコードの失敗に対してのみ行ってください。

サポートされているデータ型

ブロックリーダーは以下をデコードできます。
  • Int8Int256, UInt8UInt256
  • Float32, Float64, BFloat16
  • Bool
  • Decimal32, Decimal64, Decimal128, Decimal256
  • Date, Date32, DateTime, DateTime64, Time, Time64
  • String, FixedString(N)
  • UUID, IPv4, IPv6
  • Enum8, Enum16
  • Nullable(T), Array(T), Tuple(...), Map(K, V), Nested(...)
  • LowCardinality(T)
  • Interval
  • QBit(...)
  • Point, Ring, Polygon, MultiPolygon
  • SimpleAggregateFunction(f, T)。これは内部の T としてデコードされます
  • JSONObject('json')。文字列シリアライゼーションでは String カラムとしてデコードされます (下記を参照)
JSONObject('json') は文字列シリアライゼーションでデコードされます。クエリで output_format_native_write_json_as_string=1 を設定してください。サポートされる各行は CHC_COL_STRING カラム内の 1 つの JSON ドキュメントとして渡されます。同じ構造を chc_build_string で構築します。 writer は、解析された型に必要なプレフィックスを出力します。 VariantDynamicAggregateFunction はまだデコードされず、CHC_ERR_TYPE を返します。 フォールバックとして、これらはサーバー側で String にキャストしてください。
最終更新日 2026年7月23日