{"slug": "clickhouse-c-talk-to-clickhouse-using-its-native-binary-protocol", "title": "ClickHouse C – Talk to ClickHouse using its native binary protocol", "summary": "ClickHouse released clickhouse-c, a header-only C client that talks to ClickHouse over its Native binary protocol and Native Format blocks, with no link-time dependencies beyond libc. The library is designed for embedding inside PostgreSQL extensions using palloc arenas and longjmp, and can decode `clickhouse local` output from a pipe without TCP or compression. Users must set `output_format_native_encode_types_in_binary_format = 0` on the server, otherwise `chc_block_read` returns `CHC_ERR_TYPE`.", "body_md": "Header-only C client for the [ClickHouse](https://clickhouse.com/) Native wire\nformat — the [Native Protocol](https://clickhouse.com/docs/reference/interfaces/specs/NativeProtocol)\nover TCP carrying [Native Format](https://clickhouse.com/docs/reference/interfaces/specs/NativeFormat)\nblocks. One core header, plus optional follow-up headers for TCP,\ncompression, codecs, and I/O backends.\n\nDesigned for embedding inside PostgreSQL extensions (`palloc` arena, `longjmp`)\nbut with no PG-specific code. Including `clickhouse.h` alone gives a pure block\ndecoder over caller-supplied `chc_io`, usable for reading `clickhouse-local`'s\n`FORMAT Native` from a pipe with no TCP, no compression, no link-time deps beyond libc.\n\nDecode a `clickhouse local` query without TCP or compression.\n\n```\n/* demo.c — cc -std=c11 -O2 -I. demo.c -o demo */\n\n#define CHC_PROVIDE_STDLIB_ALLOC\n#define CHC_IMPLEMENTATION\n#include \"clickhouse.h\"\n#include \"clickhouse-posix-io.h\"\n\n#include <stdio.h>\n#include <unistd.h>\n\nint main(void) {\n    /* Spawn `clickhouse local --format Native -q \"...\"` and read its stdout\n       via a pipe; see examples/minimal_decode.c for the full plumbing. */\n    int fd = /* read end of pipe from child */;\n\n    chc_alloc al = chc_alloc_stdlib();\n    chc_posix_io state;\n    chc_io io;\n    chc_posix_io_init(&state, &io, fd, NULL, NULL);\n\n    chc_block_opts opts = {};   /* clickhouse-local: no BlockInfo, no custom serialization */\n\n    /* One persistent reader for the whole stream: chc_block_read keeps\n       bytes read past a block boundary buffered for the next block. */\n    chc_err ierr = {};\n    chc_in in;\n    if (chc_in_init(&in, &io, &al, opts.read_buffer_bytes, &ierr) != CHC_OK) {\n        fprintf(stderr, \"init: %s\\n\", ierr.msg);\n        return 1;\n    }\n\n    for (;;) {\n        chc_block *block = NULL;\n        chc_err err = {};\n        if (chc_block_read(&in, &al, &opts, &block, &err) != CHC_OK) {\n            fprintf(stderr, \"decode: %s\\n\", err.msg);\n            return 1;\n        }\n        if (!block) break;\n\n        for (size_t r = 0; r < chc_block_n_rows(block); r++)\n            for (size_t c = 0; c < chc_block_n_columns(block); c++)\n                /* dispatch on chc_column_layout(chc_block_column(block, c)) */;\n\n        chc_block_destroy(block, &al);\n    }\n    chc_in_free(&in);\n}\n```\n\nRunnable end-to-end version: [examples/minimal_decode.c](https://github.com/ClickHouse/clickhouse-c/blob/main/examples/minimal_decode.c).\n\nRequired server setting (Query packet for TCP, `--` flag for `clickhouse local`):\n\n```\noutput_format_native_encode_types_in_binary_format = 0\n```\n\nWithout it, the server emits binary type tags & `chc_block_read` returns\n`CHC_ERR_TYPE`.\n\n`clickhouse-c` is distributed as a flat set of headers:\neach header contains both declarations & implementation, guarded by\na sentinel macro. Exactly one translation unit per consumer defines the\nimplementation macro & includes headers; everyone else includes for\ndeclarations only.\n\n```\n/* consumer/src/clickhouse.c — the one TU that links the library in */\n#define CHC_IMPLEMENTATION\n#include \"clickhouse.h\"\n#include \"clickhouse-posix-io.h\"\n/* …include clickhouse-client.h, clickhouse-compression.h here for the\n   features you use. */\n```\n\nOther TUs include only the public declarations:\n\n```\n#include \"clickhouse.h\"\n#include \"clickhouse-posix-io.h\"\n/* no CHC_IMPLEMENTATION here */\n```\n\nA stdlib `malloc`/` realloc`/` free` helper is available behind\n`#define CHC_PROVIDE_STDLIB_ALLOC` before including `clickhouse.h`. For\n`palloc`/` repalloc`/` pfree` wiring inside a real PostgreSQL extension, see\n[pg_clickhouse](https://github.com/ClickHouse/pg_clickhouse) or\n[pg_stat_ch](https://github.com/ClickHouse/pg_stat_ch).\n\n| Header | Purpose | Links | \n|---|---|---|\n| [`clickhouse.h`](https://github.com/ClickHouse/clickhouse-c/blob/main/doc/clickhouse.md) | Core: types, errors, `chc_alloc` ,`chc_io` , type-name parser, block reader & writer | — | \n| [`clickhouse-client.h`](https://github.com/ClickHouse/clickhouse-c/blob/main/doc/clickhouse-client.md) | TCP packet loop: Hello / Query / Data / EOS / Exception / Progress / Pong | — | \n| [`clickhouse-async.h`](https://github.com/ClickHouse/clickhouse-c/blob/main/doc/clickhouse-async.md) | Ioless client: same packet loop driven by caller byte submission, no socket | — | \n| [`clickhouse-compression.h`](https://github.com/ClickHouse/clickhouse-c/blob/main/doc/clickhouse-compression.md) | Compressed-frame layout, CityHash128, `chc_codec` dispatch, LZ4 & ZSTD adapters (opt out with`CHC_NO_LZ4` /`CHC_NO_ZSTD` ) | `-llz4 -lzstd` | \n| [`clickhouse-posix-io.h`](https://github.com/ClickHouse/clickhouse-c/blob/main/doc/clickhouse-posix-io.md) | `chc_io` over blocking`read(2)` /`write(2)` with EINTR loop & cancel hook | — | \n| [`clickhouse-openssl.h`](https://github.com/ClickHouse/clickhouse-c/blob/main/doc/clickhouse-openssl.md) | `chc_io` over`SSL_read` /`SSL_write` | `-lssl -lcrypto` | \n\nEach follow-up header is independent; pick what your build needs.\n`clickhouse-client.h` supports ClickHouse 23.3 and newer.\n\nPer-header reference in [doc/](https://github.com/ClickHouse/clickhouse-c/blob/main/doc); inline declarations & comments in\nthe headers themselves. Worked examples in [examples/](https://github.com/ClickHouse/clickhouse-c/blob/main/examples).\n\nUse [`test.sh`](https://github.com/ClickHouse/clickhouse-c/blob/main/test.sh) to run tests:\n\n```\n./test.sh\n```\n\nIf errors report missing headers or linker errors, use `CFLAGS` and `LDFLAGS`\nto point to the appropriate directories, e.g., using [Homebrew](https://brew.sh):\n\n```\nCFLAGS=-I/opt/homebrew/include LDFLAGS=-L/opt/homebrew/lib ./test.sh\n```\n\nThe script runs individual tests in [test](https://github.com/ClickHouse/clickhouse-c/blob/main/test). To run individual tests,\npass their base names (without the trailing `.c`) as arguments:\n\n```\n./test.sh test_cancel test_block_decode\n```\n\n`test_client_tcp` spawns `clickhouse server` from `PATH`. Set `CHC_TEST_PORT`\nto test against a running server instead, eg an older release in docker:\n\n```\ndocker run -d -p 127.0.0.1:19233:9000 clickhouse/clickhouse-server:23.3.22.3\nCHC_TEST_PORT=19233 ./test.sh client_tcp\n```\n\n[`tools/capture.py`](https://github.com/ClickHouse/clickhouse-c/blob/main/tools/capture.py) proxies such a server to record replay\nfixtures like [test/ch23_3_sparse.bin](https://github.com/ClickHouse/clickhouse-c/blob/main/test/ch23_3_sparse.bin).\n\n- HTTP protocol — wrap libcurl directly.\n- DNS, endpoint round-robin, connection pooling, retry/backoff.\n- SSL/TLS context lifecycle. `chc_io` callbacks; caller drives OpenSSL.\n- Threading. Each `chc_client` is single-threaded by design.\n- Async I/O inside the library. The blocking client calls `chc_io.read` synchronously (the callback may do whatever it wants under the hood —\nepoll, io_uring,`WaitLatchOrSocket` ). For an ioless client that performs\nno I/O at all, driven by caller byte submission in an event loop, see[`clickhouse-async.h`](https://github.com/ClickHouse/clickhouse-c/blob/main/doc/clickhouse-async.md) .\n- `Variant` /`Dynamic` /`JSON` /`AggregateFunction` decoding in v1. The\nupstream wire format is still shifting in 25.x / 26.x.", "url": "https://wpnews.pro/news/clickhouse-c-talk-to-clickhouse-using-its-native-binary-protocol", "canonical_source": "https://github.com/ClickHouse/clickhouse-c", "published_at": "2026-10-11 23:08:29+00:00", "updated_at": "2026-10-11 23:35:43.970229+00:00", "lang": "en", "topics": ["developer-tools", "ai-infrastructure"], "entities": ["ClickHouse", "clickhouse-c", "PostgreSQL", "pg_clickhouse", "pg_stat_ch", "Native Protocol", "Native Format"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/clickhouse-c-talk-to-clickhouse-using-its-native-binary-protocol", "markdown": "https://wpnews.pro/news/clickhouse-c-talk-to-clickhouse-using-its-native-binary-protocol.md", "text": "https://wpnews.pro/news/clickhouse-c-talk-to-clickhouse-using-its-native-binary-protocol.txt", "jsonld": "https://wpnews.pro/news/clickhouse-c-talk-to-clickhouse-using-its-native-binary-protocol.jsonld"}}