From 6156118ba2051613f06018832d0a3eb9799418c0 Mon Sep 17 00:00:00 2001 From: Shaun Struwig <41984034+Blargian@users.noreply.github.com> Date: Tue, 21 Jul 2026 14:08:24 +0200 Subject: [PATCH 1/2] Own and sync ClickHouse documentation --- .github/workflows/docs_sync.yml | 212 ++++++++++++++++++++++++++++++ .github/workflows/docs_verify.yml | 50 +++++++ docs/index.mdx | 169 ++++++++++++++++++++++++ 3 files changed, 431 insertions(+) create mode 100644 .github/workflows/docs_sync.yml create mode 100644 .github/workflows/docs_verify.yml create mode 100644 docs/index.mdx diff --git a/.github/workflows/docs_sync.yml b/.github/workflows/docs_sync.yml new file mode 100644 index 00000000..16ae2e82 --- /dev/null +++ b/.github/workflows/docs_sync.yml @@ -0,0 +1,212 @@ +name: 'Sync docs to ClickHouse/ClickHouse' + +# Opens (or refreshes) a pull request on the aggregator docs repo +# +# It fires on three events: +# * a merged PR carrying the `sync-docs` label -> ship docs immediately, +# without waiting for a release +# * a published release -> ship docs on release, gated +# by RELEASE_SCOPE below (major-only by default); +# * manual dispatch -> force a sync. +# +# A single stable branch is force-pushed each run, so the bot keeps exactly one +# open PR that is always one commit off the target branch. The PR is labelled +# `pr-autogenerated-docs`, which the aggregator's docs check recognizes for the +# autogenerated-region edit guard. The generated body includes the changelog +# metadata required for the target repository's CI to initialize. + +on: + pull_request_target: + types: [closed] + release: + types: [published] + workflow_dispatch: + +# --------------------------------------------------------------------------- +# Configuration -- edit these to reuse this workflow in another client repo. +# --------------------------------------------------------------------------- +env: + # Repo that receives the docs PR, and the branch that PR targets. + TARGET_REPO: ClickHouse/ClickHouse + TARGET_BRANCH: master + # Path inside TARGET_REPO that mirrors this repo's docs. Wiped and replaced on + # every sync so deletions and renames propagate. + TARGET_DOCS_PATH: docs/integrations/language-clients/cpp.mdx + # This repo's docs file or folder (the source of truth). + SOURCE_DOCS_PATH: docs/index.mdx + # Stable branch on TARGET_REPO, force-pushed each run. + SYNC_BRANCH: robot/docs-sync-clickhouse-cpp + # Label the sync PR gets on TARGET_REPO. + PR_LABEL: pr-autogenerated-docs + # Label on a merged PR in THIS repo that triggers the expedited path. + SYNC_LABEL: sync-docs + # Which releases trigger a sync: major (X.0.0), minor (X.Y.0), or all. + RELEASE_SCOPE: all + +# The cross-repo work is done with a GitHub App token (see the sync job); this +# workflow only needs to read its own repository. +permissions: + contents: read + +jobs: + # Gate: decide whether this event should produce a sync, and why. Kept in its + # own job so the (large) checkout/clone in `sync` only runs when needed. + decide: + runs-on: ubuntu-latest + outputs: + run: ${{ steps.gate.outputs.run }} + reason: ${{ steps.gate.outputs.reason }} + steps: + - name: Decide whether to sync + id: gate + env: + EVENT_NAME: ${{ github.event_name }} + PR_MERGED: ${{ github.event.pull_request.merged }} + PR_NUMBER: ${{ github.event.pull_request.number }} + PR_LABELS: ${{ toJSON(github.event.pull_request.labels.*.name) }} + RELEASE_TAG: ${{ github.event.release.tag_name }} + RELEASE_PRERELEASE: ${{ github.event.release.prerelease }} + run: | + set -euo pipefail + run=false + reason="" + case "$EVENT_NAME" in + workflow_dispatch) + # Manual runs always sync -- the operator explicitly asked for it. + run=true + reason="manual dispatch" + ;; + pull_request_target) + # Expedited path: a merged PR that carries the sync label. + if [[ "$PR_MERGED" == "true" ]] \ + && printf '%s' "$PR_LABELS" | jq -e --arg l "$SYNC_LABEL" 'index($l) != null' >/dev/null; then + run=true + reason="merged PR #${PR_NUMBER} labeled '${SYNC_LABEL}'" + fi + ;; + release) + if [[ "$RELEASE_PRERELEASE" == "true" ]]; then + echo "Release ${RELEASE_TAG} is a prerelease; skipping." + elif [[ "${RELEASE_TAG#v}" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+) ]]; then + minor="${BASH_REMATCH[2]}" + patch="${BASH_REMATCH[3]}" + case "$RELEASE_SCOPE" in + all) run=true ;; + minor) [[ "$patch" == "0" ]] && run=true ;; + major|*) [[ "$minor" == "0" && "$patch" == "0" ]] && run=true ;; + esac + [[ "$run" == "true" ]] && reason="release ${RELEASE_TAG} (scope=${RELEASE_SCOPE})" + else + echo "Could not parse release tag '${RELEASE_TAG}'; skipping." + fi + ;; + esac + echo "Decision: run=${run} reason='${reason}'" + { + echo "run=${run}" + echo "reason=${reason}" + } >> "$GITHUB_OUTPUT" + + sync: + needs: decide + if: needs.decide.outputs.run == 'true' + runs-on: ubuntu-latest + steps: + - name: Checkout docs source + uses: actions/checkout@v5 + with: + # On a release, take the docs as of the released tag; otherwise take + # the default checkout (post-merge default branch / dispatched ref). + ref: ${{ github.event_name == 'release' && github.event.release.tag_name || '' }} + + - name: Parse target repo + id: parse + run: | + set -euo pipefail + echo "owner=${TARGET_REPO%%/*}" >> "$GITHUB_OUTPUT" + echo "name=${TARGET_REPO##*/}" >> "$GITHUB_OUTPUT" + + - name: Generate token for target repo + id: app-token + uses: actions/create-github-app-token@v3 + with: + app-id: ${{ secrets.WORKFLOW_AUTH_PUBLIC_APP_ID }} + private-key: ${{ secrets.WORKFLOW_AUTH_PUBLIC_PRIVATE_KEY }} + owner: ${{ steps.parse.outputs.owner }} + repositories: ${{ steps.parse.outputs.name }} + + - name: Sync docs and open/refresh PR + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + REASON: ${{ needs.decide.outputs.reason }} + SOURCE_REPO: ${{ github.repository }} + SOURCE_REF: ${{ github.event_name == 'release' && github.event.release.tag_name || github.ref_name }} + SOURCE_SHA: ${{ github.sha }} + run: | + set -euo pipefail + + # Resolve the absolute source path before we cd elsewhere. + src="$(realpath "$SOURCE_DOCS_PATH")" + + workdir="$(mktemp -d)" + git clone --depth 1 --branch "$TARGET_BRANCH" \ + "https://x-access-token:${GH_TOKEN}@github.com/${TARGET_REPO}.git" "$workdir" + cd "$workdir" + + # Replace the target file or folder with this repo's docs. Wipe first + # so deletions and renames on our side propagate. + target="${workdir:?}/${TARGET_DOCS_PATH}" + rm -rf "$target" + mkdir -p "$(dirname "$target")" + if [[ -d "$src" ]]; then + mkdir -p "$target" + cp -R "${src}/." "${target}/" + else + cp "$src" "$target" + fi + + git config user.name "clickhouse-docs-bot" + git config user.email "clickhouse-docs-bot@users.noreply.github.com" + + # Build the single-commit-off-target branch fresh from the target + # branch so the PR is always exactly one commit ahead. + git checkout -B "$SYNC_BRANCH" + git add -A -- "$TARGET_DOCS_PATH" + if git diff --cached --quiet; then + echo "No docs changes to sync; nothing to do." + exit 0 + fi + + git commit -m "Sync ${SOURCE_REPO} docs (${REASON})" + git push --force origin "$SYNC_BRANCH" + + title="Docs: Sync ${SOURCE_REPO} docs" + body=$(cat < +The library is under active development. While it already supports core ClickHouse functionality, +some features and data types may not yet be fully implemented or supported. + +Your feedback is highly valuable and helps guide the prioritization of new features and +improvements. If you encounter limitations, missing functionality, or unexpected behavior, please +share your observations or feature requests through the issue tracker at  +[https://github.com/ClickHouse/clickhouse-cpp/issues](https://github.com/ClickHouse/clickhouse-cpp/issues) + + +## Including the library into your project {#including-library-into-project} +The simplest way to incorporate the library into your project is using CMake’s `FetchContent` +module. This approach lets you pin an exact library version and build it as part of your normal +CMake workflow. + +```cmake +include(FetchContent) + +set(WITH_OPENSSL YES CACHE BOOL "Enable OpenSSL in clickhouse-cpp" FORCE) +FetchContent_Declare( + clickhouse-cpp + GIT_REPOSITORY https://github.com/ClickHouse/clickhouse-cpp.git + GIT_TAG v2.6.0 # can also be `master` or other banch +) +FetchContent_MakeAvailable(clickhouse-cpp) +``` + +The `WITH_OPENSSL` option enables TLS support in the library and is required when connecting to +ClickHouse Cloud or other SSL-enabled ClickHouse deployments. While it can be omitted for non-TLS +connections, enabling it is generally recommended. + +Building with SSL support requires the OpenSSL development packages to be installed. Install +`libssl-dev` on Debian, Ubuntu or their derivatives; `openssl-devel` for Fedora, Red Hat; or +`openssl` on macOS, using homebrew. + +After the dependency is made available, link your target against the exported library target: +```cmake +target_link_libraries(your-target PRIVATE clickhouse-cpp-lib) +``` + +## Examples {#examples} + +### Setting the client object {#example-setup-client} + +Create a `Client` instance to establish a connection to ClickHouse. The following example +demonstrates connecting to a local ClickHouse instance, where no password is required and SSL isn't +enabled. + +```cpp +#include + +clickhouse::Client client{clickhouse::ClientOptions().SetHost("localhost")}; +``` + +In more advanced setups, additional configuration is required. The following example demonstrates +connecting to a ClickHouse Cloud instance using several additional parameters: + +```cpp +#include + +clickhouse::Client client{ + clickhouse::ClientOptions{} + .SetHost("your.instance.clickhouse.cloud") + .SetUser("default") + .SetPassword("your-password") + .SetSSLOptions({}) // Enable SSL + .SetPort(9440) // for connections over SSL ClickHouse Cloud uses port 9440 + }; +``` + +### Creating tables and running queries without data {#example-create-table} + +To execute a query that doesn't return any data, such as creating tables, use the `Execute` method. +The same approach applies to other statements like `ALTER TABLE`, `DROP`, etc.. + +```cpp +client.Execute(R"( + CREATE TABLE IF NOT EXISTS greetings ( + id UInt64, + message String, + language String) + ENGINE = MergeTree ORDER BY id)"); +``` + +### Inserting Data {#example-insert-data} + +To insert data into a table, construct a `Block` and populate it with column objects matching the +table schema. Data is appended column-by-column and then inserted in a single operation using the +`Insert` method, which is optimized for efficient batch writes. + +```cpp +auto id = std::make_shared(); +auto message = std::make_shared(); +auto language = std::make_shared(); + +id->Append(1); +message->Append("Hello, World!"); +language->Append("English"); + +id->Append(2); +message->Append("¡Hola, Mundo!"); +language->Append("Spanish"); + +id->Append(3); +message->Append("Hallo wereld!"); +language->Append("Dutch"); + +clickhouse::Block block{}; +block.AppendColumn("id", id); +block.AppendColumn("message", message); +block.AppendColumn("language", language); + +client.Insert("greetings", block); +``` + +### Selecting the data {#example-select} + +To execute a query that returns data, use the `Select` method and provide a callback to process the +result. Query results are delivered as `Block` objects, reflecting ClickHouse’s native +column-oriented data representation. + +```cpp +client.Select( + "SELECT id, message, language FROM greetings", + [](const clickhouse::Block & block){ + for (size_t i = 0; i < block.GetRowCount(); ++i) { + auto id = block[0]->AsStrict()->At(i); + auto message = block[1]->AsStrict()->At(i); + auto language = block[2]->AsStrict()->At(i); + std::cout << id << "\t" << message << "\t" << language << "\n"; + } + }); +``` + +## Supported Data Types {#supported-data-types} + +- `UInt8`, `UInt16`, `UInt32`, `UInt64`, `Int8`, `Int16`, `Int32`, `Int64` +- `UInt128`, `Int128` +- `Decimal32`, `Decimal64`, `Decimal128` +- `Float32`, `Float64` +- `Date` +- `DateTime`, `DateTime64` +- `DateTime([timezone])`, `DateTime64(N, [timezone])` +- `UUID` +- `Enum8`, `Enum16` +- `String` +- `FixedString(N)` +- `LowCardinality(String)` and `LowCardinality(FixedString(N))` +- `Nullable(T)` +- `Array(T)` +- `Tuple` +- `Map` +- `IPv4`, `IPv6` +- `Point`, `Ring`, `Polygon`, `MultiPolygon` From c2d973b5c8b4f9c6f450dd08b8d0143035dccdb9 Mon Sep 17 00:00:00 2001 From: Shaun Struwig <41984034+Blargian@users.noreply.github.com> Date: Tue, 21 Jul 2026 14:29:12 +0200 Subject: [PATCH 2/2] Sync C++ docs as a folder --- .github/workflows/docs_sync.yml | 4 ++-- .github/workflows/docs_verify.yml | 2 +- docs/navigation.json | 6 ++++++ 3 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 docs/navigation.json diff --git a/.github/workflows/docs_sync.yml b/.github/workflows/docs_sync.yml index 16ae2e82..b55a7ace 100644 --- a/.github/workflows/docs_sync.yml +++ b/.github/workflows/docs_sync.yml @@ -31,9 +31,9 @@ env: TARGET_BRANCH: master # Path inside TARGET_REPO that mirrors this repo's docs. Wiped and replaced on # every sync so deletions and renames propagate. - TARGET_DOCS_PATH: docs/integrations/language-clients/cpp.mdx + TARGET_DOCS_PATH: docs/integrations/language-clients/cpp # This repo's docs file or folder (the source of truth). - SOURCE_DOCS_PATH: docs/index.mdx + SOURCE_DOCS_PATH: docs # Stable branch on TARGET_REPO, force-pushed each run. SYNC_BRANCH: robot/docs-sync-clickhouse-cpp # Label the sync PR gets on TARGET_REPO. diff --git a/.github/workflows/docs_verify.yml b/.github/workflows/docs_verify.yml index 6cbf0c0e..a64f25ea 100644 --- a/.github/workflows/docs_verify.yml +++ b/.github/workflows/docs_verify.yml @@ -46,5 +46,5 @@ jobs: python3 /tmp/mintlify_docs_check.py \ --repo https://github.com/ClickHouse/ClickHouse.git \ --ref master \ - --replace docs/index.mdx:integrations/language-clients/cpp.mdx \ + --replace docs:integrations/language-clients/cpp \ --scoped diff --git a/docs/navigation.json b/docs/navigation.json new file mode 100644 index 00000000..ee5358fe --- /dev/null +++ b/docs/navigation.json @@ -0,0 +1,6 @@ +{ + "group": "C++", + "icon": "/images/integrations/logos/logo_cpp.svg", + "pages": [], + "root": "integrations/language-clients/cpp/index" +}