# clickhouse-cpp_1 **Repository Path**: mirrors_ClickHouse/clickhouse-cpp_1 ## Basic Information - **Project Name**: clickhouse-cpp_1 - **Description**: C++ client library for ClickHouse - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2022-08-30 - **Last Updated**: 2026-10-20 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README

ClickHouse C++ Client

C++17 client library for ClickHouse using the native ClickHouse protocol.

`clickhouse-cpp` provides a small, direct API for connecting to ClickHouse, executing SQL queries, inserting and selecting columnar `Block` data, and working with ClickHouse data types from C++. It builds on Linux, macOS, and Windows with CMake or Bazel. It supports TLS and compression.

Linux macOS Windows MSVC Windows mingw Windows mingw

## Building Here is an example with recommended settings; ```sh $ mkdir build . $ cd build $ cmake .. -DCH_USE_3X_API=YES $ make ``` `CH_USE_3X_API` selects the new 3.x API. As the project evolves we bring new changes to the API; sometimes these require breaking changes. When that happens we keep the old API unchanged by default and hide the changes behind specific flags. To enable all of these changes at once, we recommend enabling `CH_USE_3X_API`, which will be the default API in version 3.0. Enabling this option is equivalent to setting the following individual options: | Option | 2.x default | 3.x value | Effect when set to the 3.x value | |------------------------------------|-------------|-----------|-----------------------------------------------------------------------------------------| | `CH_MAP_BOOL_TO_UINT8` | `ON` | `OFF` | ClickHouse `Bool` maps to `clickhouse::ColumnBool` instead of `ColumnUInt8` | | `CH_USE_ABSEIL_FOR_BIGNUM` | `ON` | `OFF` | 128-bit integers use the self-contained implementation instead of Abseil | | `CH_NON_OPTIONAL_CURRENT_ENDPOINT` | `OFF` | `ON` | `Client::GetCurrentEndpoint()` returns `Endpoint` by value instead of `std::optional` | The individual options can still be set one at a time for a gradual migration; however, when `CH_USE_3X_API=ON` is given, setting any of them to a conflicting value is a configuration error. Please refer to the workflows for the reference on dependencies/build options - https://github.com/ClickHouse/clickhouse-cpp/blob/master/.github/workflows/linux.yml - https://github.com/ClickHouse/clickhouse-cpp/blob/master/.github/workflows/windows_msvc.yml - https://github.com/ClickHouse/clickhouse-cpp/blob/master/.github/workflows/windows_mingw.yml - https://github.com/ClickHouse/clickhouse-cpp/blob/master/.github/workflows/macos.yml - https://github.com/ClickHouse/clickhouse-cpp/blob/master/.github/workflows/bazel.yml ## Backwards compatibility We aim to keep the public API compatible across releases within the same major version, so regular source-level upgrades should not require application code changes unless explicitly documented. ABI compatibility is not guaranteed yet, because the library is still actively evolving. If you upgrade clickhouse-cpp, rebuild your application against the new library version, including for minor version updates. ## Including clickhouse-cpp in your project Here a simple example (`app.cpp`) of an application using `clickhouse-cpp` ```cpp #include #include namespace ch = clickhouse; int main() { ch::Client client{ch::ClientOptions{}.SetHost("localhost")}; client.BeginSelect("SELECT 'Hello from ClickHouse :)"); while (auto block = client.NextBlock()) { auto col_msg = block->At(0)->AsStrict(); for (size_t i = 0; i < block->GetRowCount(); ++i) { std::cout << col_msg->At(i) << "\n"; } } } ``` You can include `clickhouse-cpp` into your project by using one of the following methods. ### CMake with a git submodule Add clickhouse-cpp as a submodule, for example under `contrib/clickhouse-cpp`: ```sh git submodule add https://github.com/ClickHouse/clickhouse-cpp.git contrib/clickhouse-cpp ``` Then include it from your `CMakeLists.txt`: ```cmake cmake_minimum_required(VERSION 3.13) project(application-example LANGUAGES CXX) set(CH_USE_3X_API ON) add_subdirectory(contrib/clickhouse-cpp) add_executable(application-example app.cpp) target_link_libraries(application-example PRIVATE clickhouse-cpp-lib) ``` ### CMake with FetchContent You can also let CMake download clickhouse-cpp during configuration: ```cmake cmake_minimum_required(VERSION 3.14) project(application-example LANGUAGES CXX) include(FetchContent) set(CH_USE_3X_API ON) FetchContent_Declare( clickhouse_cpp GIT_REPOSITORY https://github.com/ClickHouse/clickhouse-cpp.git GIT_TAG v2.6.2 ) FetchContent_MakeAvailable(clickhouse_cpp) add_executable(application-example app.cpp) target_link_libraries(application-example PRIVATE clickhouse-cpp-lib) ``` ### Bazel Bazel support is experimental and uses bzlmod. Add clickhouse-cpp to your `MODULE.bazel`: ```bzl bazel_dep(name = "clickhouse-cpp", version = "2.6.2") ``` Then depend on the library from your `BUILD.bazel`: ```bzl cc_binary( name = "application-example", srcs = ["app.cpp"], deps = ["@clickhouse-cpp//:clickhouse"], ) ``` By default, the Bazel build uses BoringSSL for TLS because it builds reliably across platforms on BCR and matches what many Bazel workspaces already link against. Use `--@clickhouse-cpp//:tls=openssl` to build with OpenSSL, or `--@clickhouse-cpp//:tls=no` to build without TLS support. Please keep in mind that Bazel support is currently experimental and is still being refined. This means things might change as we improve and update the setup. Most importantly, the project includes settings that were added for compatibility with older versions of the library and its API, and to preserve old behavior. These settings will not be part of the Bazel configuration. This means that even when only the minor version changes your build still might break. ## Supported data types * Array(T) * Bool * Date * DateTime, DateTime64 * DateTime([timezone]), DateTime64(N, [timezone]) * Decimal32, Decimal64, Decimal128 * Enum8, Enum16 * FixedString(N) * Float32, Float64 * IPv4, IPv6 * Nullable(T) * String * LowCardinality(String) or LowCardinality(FixedString(N)) * Tuple * UInt8, UInt16, UInt32, UInt64, Int8, Int16, Int32, Int64 * UInt128, Int128 * UUID * Map * Point, Ring, Polygon, MultiPolygon * JSON Important notes: - With CMake Bool type is mapped to `clickhouse::ColumnUInt8` by default for backwards compatibility. Use `-DCH_MAP_BOOL_TO_UINT8=OFF` to map Bool to `clickhouse::ColumnBool`. - JSON requires requires setting `output_format_native_write_json_as_string=1 enabled for the query. ## Batch Insertion In addition to the `Insert` method, which inserts all the data in a block in a single call, you can use the `BeginInsert` / `SendInsertBlock` / `EndInsert` pattern to insert batches of data. This can be useful for managing larger data sets without inflating memory with the entire set. To use it pass `BeginInsert` an `INSERT` statement ending in `VALUES` but with no actual values. Use the resulting `Block` to append batches of data, sending each to the sever with `SendInsertBlock`. Finally, call `EndInsert` (or let the client go out of scope) to signal the server that insertion is complete. Example: ```cpp // Start the insertion. auto block = client->BeginInsert("INSERT INTO foo (id, name) VALUES"); // Grab the columns from the block. auto col1 = block[0]->As(); auto col2 = block[1]->As(); // Add a couple of records to the block. col1.Append(1); col1.Append(2); col2.Append("holden"); col2.Append("naomi"); // Send those records. block.RefreshRowCount(); client->SendInsertBlock(block); block.Clear(); // Add another record. col1.Append(3); col2.Append("amos"); // Send it and finish. block.RefreshRowCount(); client->EndInsert(); ``` ## Thread-safety ⚠ Please note that `Client` instance is NOT thread-safe. I.e. you must create a separate `Client` for each thread or utilize some synchronization techniques. ⚠ ## Retries If you wish to implement some retry logic atop of `clickhouse::Client` there are few simple rules to make you life easier: - If previous attempt threw an exception, then make sure to call `clickhouse::Client::ResetConnection()` before the next try. - For `clickhouse::Client::Insert()` you can reuse a block from previous try, no need to rebuild it from scratch. See https://github.com/ClickHouse/clickhouse-cpp/issues/184 for details. ## Asynchronous inserts See https://clickhouse.com/docs/en/cloud/bestpractices/asynchronous-inserts for details. ⚠ The asynchronous setting is different according to the clickhouse-server version. The under example with clickhouse-server version 24.8.4.13. ⚠ > Our strong recommendation is to use async_insert=1,wait_for_async_insert=1 if using asynchronous inserts. Using wait_for_async_insert=0 is very risky because your INSERT client may not be aware if there are errors, and also can cause potential overload if your client continues to write quickly in a situation where the ClickHouse server needs to slow down the writes and create some backpressure in order to ensure reliability of the service. - Only use the SDK, do not need to change the clickhouse-server config. Asynchronous inserts only work if the data is sent as SQL text format. Here is the example. ```cpp // You can specify the asynchronous insert settings by using the SETTINGS clause of insert queries clickhouse::Query query("INSERT INTO default.test SETTINGS async_insert=1,wait_for_async_insert=1,async_insert_busy_timeout_ms=5000,async_insert_use_adaptive_busy_timeout=0,async_insert_max_data_size=104857600 VALUES(10,10)"); client.Execute(query); // Or by SetSetting clickhouse::Query query("INSERT INTO default.test VALUES(10,10)"); query.SetSetting("async_insert", clickhouse::QuerySettingsField{ "1", 1 }); query.SetSetting("wait_for_async_insert", clickhouse::QuerySettingsField{ "1", 1 }); // strong recommendation query.SetSetting("async_insert_busy_timeout_ms", clickhouse::QuerySettingsField{ "5000", 1 }); query.SetSetting("async_insert_max_data_size", clickhouse::QuerySettingsField{ "104857600", 1 }); query.SetSetting("async_insert_use_adaptive_busy_timeout", clickhouse::QuerySettingsField{ "0", 1 }); client.Execute(query); // Not available case. The Insert interface actually use the native data format clickhouse::Block block; client.Insert("default.test", block); ``` - Change the clickhouse-server users.xml, enable asynchronous inserts (available for the native data format). Here is the example. ```xml 1 1 0 5000 104857600 1 ``` - Enabling asynchronous inserts at the user level. Ensure your login account has the privileges about ALTER USER. Then you can use insert_account for asynchronous inserts. ```sql ALTER USER insert_account SETTINGS async_insert=1,wait_for_async_insert=1,async_insert_use_adaptive_busy_timeout=0,async_insert_busy_timeout_ms=5000,async_insert_max_data_size=104857600 ```