diff --git a/.github/scripts/package-client-cpp-manylinux-glibc217.sh b/.github/scripts/package-client-cpp-manylinux-glibc217.sh
new file mode 100644
index 0000000000000..c359ce8b40aae
--- /dev/null
+++ b/.github/scripts/package-client-cpp-manylinux-glibc217.sh
@@ -0,0 +1,90 @@
+#!/usr/bin/env bash
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership. The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Build client-cpp in manylinux2014 and verify max required GLIBC symbol <= 2.17.
+set -euxo pipefail
+
+MACHINE=$(uname -m)
+case "${MACHINE}" in
+ x86_64)
+ CMAKE_PKG_ARCH=linux-x86_64
+ JDK_API_ARCH=linux/x64
+ DEFAULT_CLASSIFIER=linux-x86_64-glibc217
+ ;;
+ aarch64)
+ CMAKE_PKG_ARCH=linux-aarch64
+ JDK_API_ARCH=linux/aarch64
+ DEFAULT_CLASSIFIER=linux-aarch64-glibc217
+ ;;
+ *)
+ echo "Unsupported architecture: ${MACHINE}" >&2
+ exit 1
+ ;;
+esac
+
+PACKAGE_CLASSIFIER="${PACKAGE_CLASSIFIER:-${DEFAULT_CLASSIFIER}}"
+
+CMAKE_VERSION=3.28.4
+CMAKE_DIR="/opt/cmake-${CMAKE_VERSION}"
+if [[ ! -x "${CMAKE_DIR}/bin/cmake" ]]; then
+ curl -fsSL -o /tmp/cmake.tar.gz "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-${CMAKE_PKG_ARCH}.tar.gz"
+ rm -rf "${CMAKE_DIR}"
+ mkdir -p /opt
+ tar xf /tmp/cmake.tar.gz -C /opt
+ mv "/opt/cmake-${CMAKE_VERSION}-${CMAKE_PKG_ARCH}" "${CMAKE_DIR}"
+fi
+
+JAVA_HOME=/opt/jdk-17
+if [[ ! -x "${JAVA_HOME}/bin/java" ]]; then
+ curl -fsSL -o /tmp/jdk17.tar.gz "https://api.adoptium.net/v3/binary/latest/17/ga/${JDK_API_ARCH}/jdk/hotspot/normal/eclipse?project=jdk"
+ rm -rf /opt/jdk-17*
+ mkdir -p /opt
+ tar xf /tmp/jdk17.tar.gz -C /opt
+ JAVA_HOME=$(find /opt -maxdepth 1 -type d -name 'jdk-17*' -print -quit)
+ ln -sfn "${JAVA_HOME}" /opt/jdk-17
+ JAVA_HOME=/opt/jdk-17
+fi
+
+export PATH="${CMAKE_DIR}/bin:${JAVA_HOME}/bin:${PATH}"
+export JAVA_HOME
+
+gcc --version
+cmake --version
+java -version
+
+cd "${GITHUB_WORKSPACE:?GITHUB_WORKSPACE is not set}"
+./mvnw clean package -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests \
+ -Dspotless.skip=true \
+ -Dclient.cpp.package.classifier="${PACKAGE_CLASSIFIER}"
+
+SO="iotdb-client/client-cpp/target/install/lib/libiotdb_session.so"
+test -f "${SO}"
+
+echo "=== Build host glibc ==="
+ldd --version 2>&1 | sed -n '1p'
+
+echo "=== Highest GLIBC_* symbols in libiotdb_session.so ==="
+objdump -T "${SO}" | grep GLIBC_ | sed "s/.*GLIBC_/GLIBC_/" | sort -Vu | tail -10
+
+max_glibc=$(objdump -T "${SO}" | grep -oE "GLIBC_[0-9.]+" | sed "s/GLIBC_//" | sort -t. -k1,1n -k2,2n -k3,3n | tail -1)
+echo "max_glibc=${max_glibc}"
+
+if awk -v max="${max_glibc}" "BEGIN { exit !(max > 2.17) }"; then
+ echo "ERROR: libiotdb_session.so requires glibc > 2.17 (max=${max_glibc})"
+ exit 1
+fi
+
+echo "glibc compatibility check passed (max=${max_glibc} <= 2.17)"
diff --git a/.github/workflows/client-cpp-package.yml b/.github/workflows/client-cpp-package.yml
index b403dfad9dd41..b8fabcefbe1a0 100644
--- a/.github/workflows/client-cpp-package.yml
+++ b/.github/workflows/client-cpp-package.yml
@@ -1,9 +1,26 @@
-# Manual run; Release published; v* tag pushes; rc/** pushes only when C++-related paths change
-# (job should-package). release events use the workflow file from the default branch.
+# Publish-oriented packaging workflow:
+# - manual runs, release:published, v* tags
+# - rc/** pushes only when C++-related paths change (job should-package)
+# release events always use the workflow file from the default branch.
name: C++ Client package
on:
workflow_dispatch:
+ inputs:
+ variants:
+ description: "Which packages to build"
+ required: false
+ default: all
+ type: choice
+ options:
+ - all
+ - linux
+ - macos
+ - windows
+ - windows-vs2017
+ - windows-vs2019
+ - windows-vs2022
+ - windows-vs2026
release:
types: [published]
push:
@@ -22,6 +39,7 @@ env:
jobs:
should-package:
+ # Keep rc branch cost low: skip full matrix when unrelated files change.
runs-on: ubuntu-latest
outputs:
run: ${{ steps.result.outputs.run }}
@@ -34,10 +52,14 @@ jobs:
with:
filters: |
cpp:
- - 'pom.xml'
- - 'iotdb-client/**'
- - 'iotdb-protocol/**'
+ - 'iotdb-client/client-cpp/**'
+ - 'iotdb-client/pom.xml'
+ - 'example/client-cpp-example/**'
+ - 'iotdb-protocol/thrift-datanode/src/main/thrift/client.thrift'
+ - 'iotdb-protocol/thrift-commons/src/main/thrift/common.thrift'
- '.github/workflows/client-cpp-package.yml'
+ - '.github/workflows/client-cpp-source-build.yml'
+ - '.github/scripts/package-client-cpp-*.sh'
- id: result
shell: bash
run: |
@@ -62,68 +84,183 @@ jobs:
fi
echo "run=false" >> "$GITHUB_OUTPUT"
- package-linux:
- name: Package (${{ matrix.name }})
+ resolve-matrix:
+ name: Resolve package matrix
needs: should-package
if: needs.should-package.outputs.run == 'true'
- strategy:
- fail-fast: false
- matrix:
- include:
- - name: linux-x86_64
- runs-on: ubuntu-22.04
- - name: linux-aarch64
- runs-on: ubuntu-22.04-arm
- runs-on: ${{ matrix.runs-on }}
+ runs-on: ubuntu-latest
+ outputs:
+ run_linux: ${{ steps.filter.outputs.run_linux }}
+ run_macos: ${{ steps.filter.outputs.run_macos }}
+ run_windows: ${{ steps.filter.outputs.run_windows }}
+ windows_matrix: ${{ steps.filter.outputs.windows_matrix }}
+ steps:
+ - id: filter
+ # Resolve workflow_dispatch variants to a compact matrix payload for fromJSON().
+ shell: bash
+ run: |
+ set -euo pipefail
+ VARIANT="${{ github.event.inputs.variants || 'all' }}"
+
+ run_linux=false
+ run_macos=false
+ run_windows=false
+ case "$VARIANT" in
+ all)
+ run_linux=true
+ run_macos=true
+ run_windows=true
+ ;;
+ linux) run_linux=true ;;
+ macos) run_macos=true ;;
+ windows) run_windows=true ;;
+ windows-vs2017|windows-vs2019|windows-vs2022|windows-vs2026)
+ run_windows=true
+ ;;
+ *)
+ echo "Unknown variant: $VARIANT" >&2
+ exit 1
+ ;;
+ esac
+
+ echo "run_linux=${run_linux}" >> "$GITHUB_OUTPUT"
+ echo "run_macos=${run_macos}" >> "$GITHUB_OUTPUT"
+ echo "run_windows=${run_windows}" >> "$GITHUB_OUTPUT"
+
+ # Compact JSON (no leading whitespace); required for GITHUB_OUTPUT + fromJSON().
+ WINDOWS_MATRIX='[{"name":"windows-vs2026","runs-on":"windows-2025-vs2026","boost_choco":"boost-msvc-14.3","boost_choco_version":"","cmake_generator":"Visual Studio 18 2026","package_classifier":"windows-x86_64-vs2026","vs_choco":"","vs_choco_params":""},{"name":"windows-vs2022","runs-on":"windows-2022","boost_choco":"boost-msvc-14.3","boost_choco_version":"","cmake_generator":"","package_classifier":"windows-x86_64-vs2022","vs_choco":"","vs_choco_params":""},{"name":"windows-vs2019","runs-on":"windows-2022","boost_choco":"boost-msvc-14.2","boost_choco_version":"","cmake_generator":"Visual Studio 16 2019","package_classifier":"windows-x86_64-vs2019","vs_choco":"visualstudio2019buildtools","vs_choco_params":"--add Microsoft.VisualStudio.Workload.VCTools --includeRecommended"},{"name":"windows-vs2017","runs-on":"windows-2022","boost_choco":"boost-msvc-14.1","boost_choco_version":"1.74.0","cmake_generator":"Visual Studio 15 2017","package_classifier":"windows-x86_64-vs2017","vs_choco":"visualstudio2017buildtools","vs_choco_params":"--add Microsoft.VisualStudio.Workload.VCTools --includeRecommended"}]'
+
+ write_windows_matrix_output() {
+ local matrix_json="$1"
+ {
+ echo 'windows_matrix<<__MATRIX_EOF__'
+ echo "${matrix_json}"
+ echo '__MATRIX_EOF__'
+ } >> "$GITHUB_OUTPUT"
+ }
+
+ if [[ "$run_windows" == true ]]; then
+ if [[ "$VARIANT" == all || "$VARIANT" == windows ]]; then
+ FILTERED="$WINDOWS_MATRIX"
+ elif [[ "$VARIANT" =~ ^windows-vs ]]; then
+ FILTERED=$(echo "$WINDOWS_MATRIX" | jq -c --arg v "$VARIANT" '[.[] | select(.name == $v)]')
+ else
+ FILTERED='[]'
+ fi
+ if [[ $(echo "$FILTERED" | jq 'length') -eq 0 ]]; then
+ echo "No Windows matrix rows for variant=${VARIANT}" >&2
+ exit 1
+ fi
+ FILTERED=$(echo "$FILTERED" | jq -c '.')
+ write_windows_matrix_output "${FILTERED}"
+ else
+ write_windows_matrix_output '[]'
+ fi
+
+ package-linux-glibc217:
+ name: Package (linux-x86_64-glibc217)
+ needs: [should-package, resolve-matrix]
+ if: needs.should-package.outputs.run == 'true' && needs.resolve-matrix.outputs.run_linux == 'true'
+ # Checkout/cache on host (Node actions need modern glibc); build in manylinux2014 via docker run.
+ runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- - name: Set up JDK 17
- uses: actions/setup-java@v5
+ - name: Cache Maven packages
+ uses: actions/cache@v5
with:
- distribution: temurin
- java-version: "17"
- - name: Install C++ dependencies (Linux)
+ path: ~/.m2
+ key: linux-glibc217-m2-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ linux-glibc217-m2-
+ - name: Package client-cpp (glibc 2.17 baseline)
shell: bash
run: |
set -euxo pipefail
- sudo apt-get update
- sudo apt-get install -y libboost-all-dev openssl libssl-dev wget
- . /etc/os-release
- if [[ "${VERSION_CODENAME}" == "jammy" ]]; then
- wget -qO /tmp/llvm.sh https://apt.llvm.org/llvm.sh
- chmod +x /tmp/llvm.sh
- sudo DEBIAN_FRONTEND=noninteractive /tmp/llvm.sh 17
- # llvm.sh installs clang-17/lldb/lld/clangd but not the clang-format-17 package
- sudo apt-get install -y clang-format-17
- else
- sudo apt-get install -y clang-format-17
+ chmod +x .github/scripts/package-client-cpp-manylinux-glibc217.sh
+ docker run --rm \
+ -v "${{ github.workspace }}:/workspace" \
+ -v "${HOME}/.m2:/root/.m2" \
+ -w /workspace \
+ -e GITHUB_WORKSPACE=/workspace \
+ quay.io/pypa/manylinux2014_x86_64 \
+ bash .github/scripts/package-client-cpp-manylinux-glibc217.sh
+ - name: Restore workspace ownership after container build
+ if: always()
+ run: sudo chown -R "$(id -u):$(id -g)" "${{ github.workspace }}"
+ - name: Resolve package zip
+ id: pkg
+ shell: bash
+ run: |
+ set -euo pipefail
+ shopt -s nullglob
+ zips=(iotdb-client/client-cpp/target/client-cpp-*-linux-x86_64-glibc217.zip)
+ if [ "${#zips[@]}" -ne 1 ]; then
+ echo "Expected exactly one package zip, got: ${zips[*]:-(none)}"
+ exit 1
fi
- sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-17 100
- sudo update-alternatives --set clang-format /usr/bin/clang-format-17
- clang-format --version
+ echo "path=${zips[0]}" >> "$GITHUB_OUTPUT"
+ echo "name=$(basename "${zips[0]}" .zip)" >> "$GITHUB_OUTPUT"
+ - name: Upload zip artifact
+ uses: actions/upload-artifact@v6
+ with:
+ name: ${{ steps.pkg.outputs.name }}
+ path: ${{ steps.pkg.outputs.path }}
+ if-no-files-found: error
+
+ package-linux-aarch64-glibc217:
+ name: Package (linux-aarch64-glibc217)
+ needs: [should-package, resolve-matrix]
+ if: needs.should-package.outputs.run == 'true' && needs.resolve-matrix.outputs.run_linux == 'true'
+ # Checkout/cache on host; build in manylinux2014 aarch64 via docker run (glibc 2.17 baseline).
+ runs-on: ubuntu-22.04-arm
+ steps:
+ - uses: actions/checkout@v5
- name: Cache Maven packages
uses: actions/cache@v5
with:
path: ~/.m2
- key: ${{ runner.os }}-${{ runner.arch }}-m2-${{ hashFiles('**/pom.xml') }}
+ key: linux-aarch64-glibc217-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: |
- ${{ runner.os }}-${{ runner.arch }}-m2-
- - name: Package client-cpp
+ linux-aarch64-glibc217-m2-
+ - name: Package client-cpp (glibc 2.17 baseline)
shell: bash
run: |
set -euxo pipefail
- ./mvnw clean package -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests
+ chmod +x .github/scripts/package-client-cpp-manylinux-glibc217.sh
+ docker run --rm \
+ -v "${{ github.workspace }}:/workspace" \
+ -v "${HOME}/.m2:/root/.m2" \
+ -w /workspace \
+ -e GITHUB_WORKSPACE=/workspace \
+ quay.io/pypa/manylinux2014_aarch64 \
+ bash .github/scripts/package-client-cpp-manylinux-glibc217.sh
+ - name: Restore workspace ownership after container build
+ if: always()
+ run: sudo chown -R "$(id -u):$(id -g)" "${{ github.workspace }}"
+ - name: Resolve package zip
+ id: pkg
+ shell: bash
+ run: |
+ set -euo pipefail
+ shopt -s nullglob
+ zips=(iotdb-client/client-cpp/target/client-cpp-*-linux-aarch64-glibc217.zip)
+ if [ "${#zips[@]}" -ne 1 ]; then
+ echo "Expected exactly one package zip, got: ${zips[*]:-(none)}"
+ exit 1
+ fi
+ echo "path=${zips[0]}" >> "$GITHUB_OUTPUT"
+ echo "name=$(basename "${zips[0]}" .zip)" >> "$GITHUB_OUTPUT"
- name: Upload zip artifact
uses: actions/upload-artifact@v6
with:
- name: client-cpp-${{ matrix.name }}
- path: iotdb-client/client-cpp/target/client-cpp-*-cpp-*.zip
+ name: ${{ steps.pkg.outputs.name }}
+ path: ${{ steps.pkg.outputs.path }}
if-no-files-found: error
package-macos:
name: Package (${{ matrix.name }})
- needs: should-package
- if: needs.should-package.outputs.run == 'true'
+ needs: [should-package, resolve-matrix]
+ if: needs.should-package.outputs.run == 'true' && needs.resolve-matrix.outputs.run_macos == 'true'
strategy:
fail-fast: false
matrix:
@@ -144,49 +281,55 @@ jobs:
shell: bash
run: |
set -euxo pipefail
- brew install boost openssl llvm@17
+ brew install boost openssl llvm@17 bison
ln -sf "$(brew --prefix llvm@17)/bin/clang-format" "$(brew --prefix)/bin/clang-format"
+ echo "$(brew --prefix bison)/bin" >> "$GITHUB_PATH"
echo "$(brew --prefix llvm@17)/bin" >> "$GITHUB_PATH"
clang-format --version
+ bison --version
- name: Cache Maven packages
uses: actions/cache@v5
with:
path: ~/.m2
- key: ${{ runner.os }}-${{ runner.arch }}-m2-${{ hashFiles('**/pom.xml') }}
+ key: macos-${{ matrix.name }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: |
- ${{ runner.os }}-${{ runner.arch }}-m2-
+ macos-${{ matrix.name }}-m2-
- name: Package client-cpp
shell: bash
env:
MACOSX_DEPLOYMENT_TARGET: "12.0"
run: |
set -euxo pipefail
- ./mvnw clean package -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests
+ ./mvnw clean package -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests \
+ -Dspotless.skip=true
+ - name: Resolve package zip
+ id: pkg
+ shell: bash
+ run: |
+ set -euo pipefail
+ shopt -s nullglob
+ zips=(iotdb-client/client-cpp/target/client-cpp-*.zip)
+ if [ "${#zips[@]}" -ne 1 ]; then
+ echo "Expected exactly one package zip, got: ${zips[*]:-(none)}"
+ exit 1
+ fi
+ echo "path=${zips[0]}" >> "$GITHUB_OUTPUT"
+ echo "name=$(basename "${zips[0]}" .zip)" >> "$GITHUB_OUTPUT"
- name: Upload zip artifact
uses: actions/upload-artifact@v6
with:
- name: client-cpp-${{ matrix.name }}
- path: iotdb-client/client-cpp/target/client-cpp-*-cpp-*.zip
+ name: ${{ steps.pkg.outputs.name }}
+ path: ${{ steps.pkg.outputs.path }}
if-no-files-found: error
package-windows:
name: Package (${{ matrix.name }})
- needs: should-package
- if: needs.should-package.outputs.run == 'true'
+ needs: [should-package, resolve-matrix]
+ if: needs.should-package.outputs.run == 'true' && needs.resolve-matrix.outputs.run_windows == 'true'
strategy:
fail-fast: false
matrix:
- include:
- - name: windows-vs2022
- runs-on: windows-2022
- boost_choco: boost-msvc-14.3
- cmake_generator: ""
- iotdb_tools_thrift_version: ""
- - name: windows-vs2026
- runs-on: windows-2025-vs2026
- boost_choco: boost-msvc-14.3
- cmake_generator: Visual Studio 18 2026
- iotdb_tools_thrift_version: ""
+ include: ${{ fromJSON(needs.resolve-matrix.outputs.windows_matrix) }}
runs-on: ${{ matrix.runs-on }}
steps:
- uses: actions/checkout@v5
@@ -195,44 +338,89 @@ jobs:
with:
distribution: temurin
java-version: "17"
+ - name: Install Visual Studio Build Tools (${{ matrix.name }})
+ if: matrix.vs_choco != ''
+ shell: pwsh
+ run: |
+ $params = '${{ matrix.vs_choco_params }}'
+ if ($params) {
+ choco install ${{ matrix.vs_choco }} -y --package-parameters="$params" --no-progress
+ } else {
+ choco install ${{ matrix.vs_choco }} -y --no-progress
+ }
- name: Install C++ dependencies (Windows)
shell: pwsh
run: |
- choco install winflexbison3 -y
- choco install ${{ matrix.boost_choco }} -y
- $boost_path = (Get-ChildItem -Path 'C:\local\' -Filter 'boost_*').FullName
- echo $boost_path >> $env:GITHUB_PATH
- choco install openssl -y
+ choco install winflexbison3 -y --no-progress
+ $boostArgs = @('install', '${{ matrix.boost_choco }}', '-y', '--no-progress')
+ if ('${{ matrix.boost_choco_version }}' -ne '') {
+ $boostArgs += @("--version=${{ matrix.boost_choco_version }}")
+ }
+ & choco @boostArgs
+ if (-not (Test-Path 'C:\local')) {
+ New-Item -ItemType Directory -Path 'C:\local' -Force | Out-Null
+ }
+ $boostDir = Get-ChildItem -Path 'C:\local\' -Filter 'boost_*' -ErrorAction SilentlyContinue | Select-Object -First 1
+ if (-not $boostDir) {
+ throw "Boost not found under C:\local after installing ${{ matrix.boost_choco }}"
+ }
+ echo $boostDir.FullName >> $env:GITHUB_PATH
+ choco install openssl -y --no-progress
$sslPath = (Get-ChildItem 'C:\Program Files\OpenSSL*' -Directory | Select-Object -First 1).FullName
echo "$sslPath\bin" >> $env:GITHUB_PATH
echo "OPENSSL_ROOT_DIR=$sslPath" >> $env:GITHUB_ENV
- choco install llvm --version=17.0.6 --force -y
- clang-format --version
- name: Cache Maven packages
uses: actions/cache@v5
with:
path: ~/.m2
- key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
+ key: windows-${{ matrix.name }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: |
- ${{ runner.os }}-m2-
+ windows-${{ matrix.name }}-m2-
- name: Package client-cpp
shell: bash
env:
CMAKE_GENERATOR: ${{ matrix.cmake_generator }}
- IOTDB_TOOLS_THRIFT_VERSION: ${{ matrix.iotdb_tools_thrift_version }}
+ PACKAGE_CLASSIFIER: ${{ matrix.package_classifier }}
run: |
set -euxo pipefail
- MVN_ARGS=(./mvnw clean package -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests)
+ MVN_ARGS=(./mvnw clean package -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests \
+ -Dspotless.skip=true \
+ "-Dclient.cpp.package.classifier=${PACKAGE_CLASSIFIER}")
if [ -n "${CMAKE_GENERATOR:-}" ]; then
MVN_ARGS+=("-Dcmake.generator=${CMAKE_GENERATOR}")
fi
- if [ -n "${IOTDB_TOOLS_THRIFT_VERSION:-}" ]; then
- MVN_ARGS+=("-Diotdb-tools-thrift.version=${IOTDB_TOOLS_THRIFT_VERSION}")
- fi
"${MVN_ARGS[@]}"
+ - name: Verify Windows SDK is x64
+ # Guard against accidental Win32 generator defaults on legacy VS matrices.
+ shell: pwsh
+ run: |
+ $dll = "iotdb-client/client-cpp/target/install/lib/iotdb_session.dll"
+ if (-not (Test-Path $dll)) {
+ throw "Missing $dll"
+ }
+ $bytes = [System.IO.File]::ReadAllBytes($dll)
+ $peOffset = [BitConverter]::ToInt32($bytes, 0x3C)
+ $machine = [BitConverter]::ToUInt16($bytes, $peOffset + 4)
+ if ($machine -ne 0x8664) {
+ throw "Expected PE32+ x64 (machine=0x8664), got 0x$($machine.ToString('X4'))"
+ }
+ Write-Host "Verified x64 DLL: $dll"
+ - name: Resolve package zip
+ id: pkg
+ shell: bash
+ run: |
+ set -euo pipefail
+ shopt -s nullglob
+ zips=(iotdb-client/client-cpp/target/client-cpp-*-${{ matrix.package_classifier }}.zip)
+ if [ "${#zips[@]}" -ne 1 ]; then
+ echo "Expected exactly one package zip, got: ${zips[*]:-(none)}"
+ exit 1
+ fi
+ echo "path=${zips[0]}" >> "$GITHUB_OUTPUT"
+ echo "name=$(basename "${zips[0]}" .zip)" >> "$GITHUB_OUTPUT"
- name: Upload zip artifact
uses: actions/upload-artifact@v6
with:
- name: client-cpp-${{ matrix.name }}
- path: iotdb-client/client-cpp/target/client-cpp-*-cpp-*.zip
+ name: ${{ steps.pkg.outputs.name }}
+ path: ${{ steps.pkg.outputs.path }}
if-no-files-found: error
diff --git a/.github/workflows/client-cpp-source-build.yml b/.github/workflows/client-cpp-source-build.yml
new file mode 100644
index 0000000000000..6c0ecc28e82a3
--- /dev/null
+++ b/.github/workflows/client-cpp-source-build.yml
@@ -0,0 +1,132 @@
+# Fast signal workflow for source-build viability.
+# Verifies client-cpp can fetch/build dependencies from source on each OS.
+# This complements (not replaces) the packaging matrix workflow.
+name: C++ Client source build
+
+on:
+ push:
+ branches:
+ - master
+ - "rc/*"
+ paths:
+ - "iotdb-client/pom.xml"
+ - "iotdb-client/client-cpp/**"
+ - "example/client-cpp-example/**"
+ - "iotdb-protocol/thrift-datanode/src/main/thrift/client.thrift"
+ - "iotdb-protocol/thrift-commons/src/main/thrift/common.thrift"
+ - ".github/workflows/client-cpp-source-build.yml"
+ - ".github/workflows/client-cpp-package.yml"
+ - ".github/scripts/package-client-cpp-*.sh"
+ pull_request:
+ branches:
+ - master
+ - "rc/*"
+ - "force_ci/**"
+ paths:
+ - "iotdb-client/pom.xml"
+ - "iotdb-client/client-cpp/**"
+ - "example/client-cpp-example/**"
+ - "iotdb-protocol/thrift-datanode/src/main/thrift/client.thrift"
+ - "iotdb-protocol/thrift-commons/src/main/thrift/common.thrift"
+ - ".github/workflows/client-cpp-source-build.yml"
+ - ".github/workflows/client-cpp-package.yml"
+ - ".github/scripts/package-client-cpp-*.sh"
+ workflow_dispatch:
+
+concurrency:
+ group: client-cpp-source-build-${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+env:
+ MAVEN_OPTS: -Dhttp.keepAlive=false -Dmaven.wagon.http.pool=false -Dmaven.wagon.http.retryHandler.class=standard -Dmaven.wagon.http.retryHandler.count=3
+ MAVEN_ARGS: --batch-mode --no-transfer-progress
+
+jobs:
+ source-build:
+ name: Source build (${{ matrix.name }})
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - name: linux
+ runs-on: ubuntu-22.04
+ - name: macos
+ runs-on: macos-latest
+ - name: windows-vs2022
+ runs-on: windows-2022
+ cmake_generator: ""
+ - name: windows-vs2026
+ runs-on: windows-2025-vs2026
+ cmake_generator: Visual Studio 18 2026
+ runs-on: ${{ matrix.runs-on }}
+
+ steps:
+ - uses: actions/checkout@v5
+
+ - name: Set up JDK 17
+ uses: actions/setup-java@v5
+ with:
+ distribution: temurin
+ java-version: "17"
+
+ - name: Install minimal toolchain (Linux)
+ if: runner.os == 'Linux'
+ shell: bash
+ run: |
+ set -euxo pipefail
+ sudo apt-get update
+ # Compiler + CMake only; Boost/flex/bison/m4 come from CMake fetch.
+ sudo apt-get install -y build-essential cmake wget
+
+ - name: Install minimal toolchain (macOS)
+ if: runner.os == 'macOS'
+ shell: bash
+ run: |
+ set -euxo pipefail
+ # Xcode CLT ships bison 2.3 which cannot build Thrift 0.21.0 (%code).
+ brew install bison cmake
+ echo "$(brew --prefix bison)/bin" >> "$GITHUB_PATH"
+ bison --version
+
+ - name: Install minimal toolchain (Windows)
+ if: runner.os == 'Windows'
+ shell: pwsh
+ run: |
+ # No choco boost / winflexbison: CMake downloads into third-party/windows/.
+ Write-Host "Using preinstalled VS + CMake on the runner image."
+
+ - name: Cache Maven packages
+ uses: actions/cache@v5
+ with:
+ path: ~/.m2
+ key: ${{ runner.os }}-${{ runner.arch }}-m2-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ ${{ runner.os }}-${{ runner.arch }}-m2-
+
+ - name: Configure and build (CMake fetch, online)
+ # Keep this job focused on buildability; package workflow validates release classifiers.
+ shell: bash
+ env:
+ CMAKE_GENERATOR: ${{ matrix.cmake_generator }}
+ run: |
+ set -euxo pipefail
+ MVN_ARGS=(./mvnw clean package -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests)
+ MVN_ARGS+=("-Diotdb.offline=OFF" "-Dspotless.skip=true")
+ if [ -n "${CMAKE_GENERATOR:-}" ]; then
+ MVN_ARGS+=("-Dcmake.generator=${CMAKE_GENERATOR}")
+ fi
+ "${MVN_ARGS[@]}"
+
+ - name: Verify install artifacts
+ shell: bash
+ run: |
+ set -euxo pipefail
+ INSTALL="iotdb-client/client-cpp/target/install"
+ if [ "${{ runner.os }}" = "Windows" ]; then
+ test -d "${INSTALL}/include"
+ ls "${INSTALL}/lib/iotdb_session.dll" "${INSTALL}/lib/iotdb_session.lib"
+ else
+ test -f "${INSTALL}/lib/libiotdb_session.so" \
+ || test -f "${INSTALL}/lib/libiotdb_session.dylib"
+ fi
+ ls -la "${INSTALL}/include" | head -20
diff --git a/.github/workflows/cluster-it-1c1d.yml b/.github/workflows/cluster-it-1c1d.yml
index caf1de91c6827..275e5002d4324 100644
--- a/.github/workflows/cluster-it-1c1d.yml
+++ b/.github/workflows/cluster-it-1c1d.yml
@@ -9,6 +9,12 @@ on:
paths-ignore:
- "docs/**"
- "site/**"
+ - "iotdb-client/client-cpp/**"
+ - "example/client-cpp-example/**"
+ - ".github/workflows/client-cpp-package.yml"
+ - ".github/workflows/client-cpp-source-build.yml"
+ - ".github/scripts/package-client-cpp-*.sh"
+ - ".github/workflows/multi-language-client.yml"
pull_request:
branches:
- master
@@ -17,6 +23,12 @@ on:
paths-ignore:
- "docs/**"
- "site/**"
+ - "iotdb-client/client-cpp/**"
+ - "example/client-cpp-example/**"
+ - ".github/workflows/client-cpp-package.yml"
+ - ".github/workflows/client-cpp-source-build.yml"
+ - ".github/scripts/package-client-cpp-*.sh"
+ - ".github/workflows/multi-language-client.yml"
# allow manually run the action:
workflow_dispatch:
diff --git a/.github/workflows/cluster-it-1c1d1a.yml b/.github/workflows/cluster-it-1c1d1a.yml
index 7ee6ca6ace66f..5e132ea3145b2 100644
--- a/.github/workflows/cluster-it-1c1d1a.yml
+++ b/.github/workflows/cluster-it-1c1d1a.yml
@@ -9,6 +9,12 @@ on:
paths-ignore:
- 'docs/**'
- 'site/**'
+ - 'iotdb-client/client-cpp/**'
+ - 'example/client-cpp-example/**'
+ - '.github/workflows/client-cpp-package.yml'
+ - '.github/workflows/client-cpp-source-build.yml'
+ - '.github/scripts/package-client-cpp-*.sh'
+ - '.github/workflows/multi-language-client.yml'
pull_request:
branches:
- master
@@ -18,6 +24,12 @@ on:
paths-ignore:
- 'docs/**'
- 'site/**'
+ - 'iotdb-client/client-cpp/**'
+ - 'example/client-cpp-example/**'
+ - '.github/workflows/client-cpp-package.yml'
+ - '.github/workflows/client-cpp-source-build.yml'
+ - '.github/scripts/package-client-cpp-*.sh'
+ - '.github/workflows/multi-language-client.yml'
# allow manually run the action:
workflow_dispatch:
diff --git a/.github/workflows/cluster-it-1c3d.yml b/.github/workflows/cluster-it-1c3d.yml
index 035403e1695f4..2758b097fcca8 100644
--- a/.github/workflows/cluster-it-1c3d.yml
+++ b/.github/workflows/cluster-it-1c3d.yml
@@ -9,6 +9,12 @@ on:
paths-ignore:
- "docs/**"
- "site/**"
+ - "iotdb-client/client-cpp/**"
+ - "example/client-cpp-example/**"
+ - ".github/workflows/client-cpp-package.yml"
+ - ".github/workflows/client-cpp-source-build.yml"
+ - ".github/scripts/package-client-cpp-*.sh"
+ - ".github/workflows/multi-language-client.yml"
pull_request:
branches:
- master
@@ -18,6 +24,12 @@ on:
paths-ignore:
- "docs/**"
- "site/**"
+ - "iotdb-client/client-cpp/**"
+ - "example/client-cpp-example/**"
+ - ".github/workflows/client-cpp-package.yml"
+ - ".github/workflows/client-cpp-source-build.yml"
+ - ".github/scripts/package-client-cpp-*.sh"
+ - ".github/workflows/multi-language-client.yml"
# allow manually run the action:
workflow_dispatch:
diff --git a/.github/workflows/compile-check.yml b/.github/workflows/compile-check.yml
index 1cf45e07dc0e2..eaac65a47c469 100644
--- a/.github/workflows/compile-check.yml
+++ b/.github/workflows/compile-check.yml
@@ -11,6 +11,12 @@ on:
paths-ignore:
- "docs/**"
- "site/**"
+ - "iotdb-client/client-cpp/**"
+ - "example/client-cpp-example/**"
+ - ".github/workflows/client-cpp-package.yml"
+ - ".github/workflows/client-cpp-source-build.yml"
+ - ".github/scripts/package-client-cpp-*.sh"
+ - ".github/workflows/multi-language-client.yml"
pull_request:
branches:
- master
@@ -20,6 +26,12 @@ on:
paths-ignore:
- "docs/**"
- "site/**"
+ - "iotdb-client/client-cpp/**"
+ - "example/client-cpp-example/**"
+ - ".github/workflows/client-cpp-package.yml"
+ - ".github/workflows/client-cpp-source-build.yml"
+ - ".github/scripts/package-client-cpp-*.sh"
+ - ".github/workflows/multi-language-client.yml"
# allow manually run the action:
workflow_dispatch:
diff --git a/.github/workflows/dependency-check.yml b/.github/workflows/dependency-check.yml
index 4cf6cb202afca..67b2054ec9605 100644
--- a/.github/workflows/dependency-check.yml
+++ b/.github/workflows/dependency-check.yml
@@ -11,6 +11,12 @@ on:
paths-ignore:
- "docs/**"
- "site/**"
+ - "iotdb-client/client-cpp/**"
+ - "example/client-cpp-example/**"
+ - ".github/workflows/client-cpp-package.yml"
+ - ".github/workflows/client-cpp-source-build.yml"
+ - ".github/scripts/package-client-cpp-*.sh"
+ - ".github/workflows/multi-language-client.yml"
pull_request:
branches:
- master
@@ -20,6 +26,12 @@ on:
paths-ignore:
- "docs/**"
- "site/**"
+ - "iotdb-client/client-cpp/**"
+ - "example/client-cpp-example/**"
+ - ".github/workflows/client-cpp-package.yml"
+ - ".github/workflows/client-cpp-source-build.yml"
+ - ".github/scripts/package-client-cpp-*.sh"
+ - ".github/workflows/multi-language-client.yml"
# allow manually run the action:
workflow_dispatch:
diff --git a/.github/workflows/multi-language-client.yml b/.github/workflows/multi-language-client.yml
index a699ce16429f2..0e7ab9119393c 100644
--- a/.github/workflows/multi-language-client.yml
+++ b/.github/workflows/multi-language-client.yml
@@ -1,3 +1,4 @@
+# Shared client CI: run only affected language jobs via paths-filter.
name: Multi-Language Client
on:
push:
@@ -5,7 +6,6 @@ on:
- master
- "rc/*"
paths:
- - 'pom.xml'
- 'iotdb-client/pom.xml'
- 'iotdb-client/client-py/**'
- 'iotdb-client/client-cpp/**'
@@ -13,13 +13,15 @@ on:
- 'iotdb-protocol/thrift-datanode/src/main/thrift/client.thrift'
- 'iotdb-protocol/thrift-commons/src/main/thrift/common.thrift'
- '.github/workflows/multi-language-client.yml'
+ - '.github/workflows/client-cpp-source-build.yml'
+ - '.github/workflows/client-cpp-package.yml'
+ - '.github/scripts/package-client-cpp-*.sh'
pull_request:
branches:
- master
- "rc/*"
- 'force_ci/**'
paths:
- - 'pom.xml'
- 'iotdb-client/pom.xml'
- 'iotdb-client/client-py/**'
- 'iotdb-client/client-cpp/**'
@@ -27,6 +29,9 @@ on:
- 'iotdb-protocol/thrift-datanode/src/main/thrift/client.thrift'
- 'iotdb-protocol/thrift-commons/src/main/thrift/common.thrift'
- '.github/workflows/multi-language-client.yml'
+ - '.github/workflows/client-cpp-source-build.yml'
+ - '.github/workflows/client-cpp-package.yml'
+ - '.github/scripts/package-client-cpp-*.sh'
# allow manually run the action:
workflow_dispatch:
@@ -40,7 +45,52 @@ env:
MAVEN_ARGS: --batch-mode --no-transfer-progress
jobs:
+ # Per-language path filters: a client-cpp-only PR runs cpp, not go/python.
+ changes:
+ runs-on: ubuntu-latest
+ outputs:
+ cpp: ${{ steps.filter.outputs.cpp }}
+ python: ${{ steps.filter.outputs.python }}
+ go: ${{ steps.filter.outputs.go }}
+ steps:
+ - uses: actions/checkout@v5
+ - uses: dorny/paths-filter@v3
+ id: filter
+ with:
+ filters: |
+ cpp:
+ - 'iotdb-client/pom.xml'
+ - 'iotdb-client/client-cpp/**'
+ - 'example/client-cpp-example/**'
+ - 'iotdb-protocol/thrift-datanode/src/main/thrift/client.thrift'
+ - 'iotdb-protocol/thrift-commons/src/main/thrift/common.thrift'
+ - '.github/workflows/multi-language-client.yml'
+ - '.github/workflows/client-cpp-source-build.yml'
+ - '.github/workflows/client-cpp-package.yml'
+ - '.github/scripts/package-client-cpp-*.sh'
+ python:
+ - 'pom.xml'
+ - 'iotdb-client/pom.xml'
+ - 'iotdb-client/client-py/**'
+ - 'docker/src/main/Dockerfile-1c1d'
+ - '.github/workflows/multi-language-client.yml'
+ go:
+ - 'pom.xml'
+ - 'iotdb-core/**'
+ - 'iotdb-api/**'
+ - 'iotdb-protocol/**'
+ - 'distribution/**'
+ - 'integration-test/**'
+ - 'iotdb-client/session/**'
+ - 'iotdb-client/jdbc/**'
+ - 'iotdb-client/cli/**'
+ - 'iotdb-client/service-rpc/**'
+ - '.github/workflows/multi-language-client.yml'
+
cpp:
+ needs: changes
+ # Full client validation (format + server build + verify) for C++ examples and SDK.
+ if: github.event_name == 'workflow_dispatch' || needs.changes.outputs.cpp == 'true'
strategy:
fail-fast: false
max-parallel: 15
@@ -76,11 +126,12 @@ jobs:
if: runner.os == 'macOS'
shell: bash
run: |
- brew install boost
- brew install openssl llvm@17
+ brew install boost openssl llvm@17 bison
ln -sf "$(brew --prefix llvm@17)/bin/clang-format" "$(brew --prefix)/bin/clang-format"
+ echo "$(brew --prefix bison)/bin" >> "$GITHUB_PATH"
echo "$(brew --prefix llvm@17)/bin" >> "$GITHUB_PATH"
clang-format --version
+ bison --version
sudo rm -rf /Applications/Xcode_14.3.1.app
sudo rm -rf /Applications/Xcode_15.0.1.app
sudo rm -rf /Applications/Xcode_15.1.app
@@ -134,6 +185,8 @@ jobs:
retention-days: 1
go:
+ needs: changes
+ if: github.event_name == 'workflow_dispatch' || needs.changes.outputs.go == 'true'
runs-on: ubuntu-latest
steps:
@@ -158,6 +211,8 @@ jobs:
make e2e_test_for_parent_git_repo e2e_test_clean_for_parent_git_repo
python:
+ needs: changes
+ if: github.event_name == 'workflow_dispatch' || needs.changes.outputs.python == 'true'
strategy:
fail-fast: false
max-parallel: 15
diff --git a/.github/workflows/pipe-it.yml b/.github/workflows/pipe-it.yml
index fb2f732560d84..a25072a618950 100644
--- a/.github/workflows/pipe-it.yml
+++ b/.github/workflows/pipe-it.yml
@@ -9,6 +9,12 @@ on:
paths-ignore:
- "docs/**"
- "site/**"
+ - "iotdb-client/client-cpp/**"
+ - "example/client-cpp-example/**"
+ - ".github/workflows/client-cpp-package.yml"
+ - ".github/workflows/client-cpp-source-build.yml"
+ - ".github/scripts/package-client-cpp-*.sh"
+ - ".github/workflows/multi-language-client.yml"
- "iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/**" #queryengine
pull_request:
branches:
@@ -19,6 +25,12 @@ on:
paths-ignore:
- "docs/**"
- "site/**"
+ - "iotdb-client/client-cpp/**"
+ - "example/client-cpp-example/**"
+ - ".github/workflows/client-cpp-package.yml"
+ - ".github/workflows/client-cpp-source-build.yml"
+ - ".github/scripts/package-client-cpp-*.sh"
+ - ".github/workflows/multi-language-client.yml"
- "iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/**" #queryengine
# allow manually run the action:
workflow_dispatch:
diff --git a/.github/workflows/sonar-codecov.yml b/.github/workflows/sonar-codecov.yml
index 4f62c8926fbe0..810cf91b2e561 100644
--- a/.github/workflows/sonar-codecov.yml
+++ b/.github/workflows/sonar-codecov.yml
@@ -12,6 +12,12 @@ on:
paths-ignore:
- "docs/**"
- "site/**"
+ - "iotdb-client/client-cpp/**"
+ - "example/client-cpp-example/**"
+ - ".github/workflows/client-cpp-package.yml"
+ - ".github/workflows/client-cpp-source-build.yml"
+ - ".github/scripts/package-client-cpp-*.sh"
+ - ".github/workflows/multi-language-client.yml"
pull_request:
branches:
- master
@@ -22,6 +28,12 @@ on:
paths-ignore:
- "docs/**"
- "site/**"
+ - "iotdb-client/client-cpp/**"
+ - "example/client-cpp-example/**"
+ - ".github/workflows/client-cpp-package.yml"
+ - ".github/workflows/client-cpp-source-build.yml"
+ - ".github/scripts/package-client-cpp-*.sh"
+ - ".github/workflows/multi-language-client.yml"
# allow manually run the action:
workflow_dispatch:
diff --git a/.github/workflows/table-cluster-it-1c1d.yml b/.github/workflows/table-cluster-it-1c1d.yml
index a0058fe3219a4..f47d84967c5e5 100644
--- a/.github/workflows/table-cluster-it-1c1d.yml
+++ b/.github/workflows/table-cluster-it-1c1d.yml
@@ -9,6 +9,12 @@ on:
paths-ignore:
- "docs/**"
- "site/**"
+ - "iotdb-client/client-cpp/**"
+ - "example/client-cpp-example/**"
+ - ".github/workflows/client-cpp-package.yml"
+ - ".github/workflows/client-cpp-source-build.yml"
+ - ".github/scripts/package-client-cpp-*.sh"
+ - ".github/workflows/multi-language-client.yml"
pull_request:
branches:
- master
@@ -18,6 +24,12 @@ on:
paths-ignore:
- "docs/**"
- "site/**"
+ - "iotdb-client/client-cpp/**"
+ - "example/client-cpp-example/**"
+ - ".github/workflows/client-cpp-package.yml"
+ - ".github/workflows/client-cpp-source-build.yml"
+ - ".github/scripts/package-client-cpp-*.sh"
+ - ".github/workflows/multi-language-client.yml"
# allow manually run the action:
workflow_dispatch:
diff --git a/.github/workflows/table-cluster-it-1c3d.yml b/.github/workflows/table-cluster-it-1c3d.yml
index 99a7469500c97..a8498732d6f7d 100644
--- a/.github/workflows/table-cluster-it-1c3d.yml
+++ b/.github/workflows/table-cluster-it-1c3d.yml
@@ -9,6 +9,12 @@ on:
paths-ignore:
- "docs/**"
- "site/**"
+ - "iotdb-client/client-cpp/**"
+ - "example/client-cpp-example/**"
+ - ".github/workflows/client-cpp-package.yml"
+ - ".github/workflows/client-cpp-source-build.yml"
+ - ".github/scripts/package-client-cpp-*.sh"
+ - ".github/workflows/multi-language-client.yml"
pull_request:
branches:
- master
@@ -18,6 +24,12 @@ on:
paths-ignore:
- "docs/**"
- "site/**"
+ - "iotdb-client/client-cpp/**"
+ - "example/client-cpp-example/**"
+ - ".github/workflows/client-cpp-package.yml"
+ - ".github/workflows/client-cpp-source-build.yml"
+ - ".github/scripts/package-client-cpp-*.sh"
+ - ".github/workflows/multi-language-client.yml"
# allow manually run the action:
workflow_dispatch:
diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml
index ccc0c2ca4b39e..ca4130d901580 100644
--- a/.github/workflows/unit-test.yml
+++ b/.github/workflows/unit-test.yml
@@ -12,6 +12,12 @@ on:
paths-ignore:
- "docs/**"
- "site/**"
+ - "iotdb-client/client-cpp/**"
+ - "example/client-cpp-example/**"
+ - ".github/workflows/client-cpp-package.yml"
+ - ".github/workflows/client-cpp-source-build.yml"
+ - ".github/scripts/package-client-cpp-*.sh"
+ - ".github/workflows/multi-language-client.yml"
pull_request:
branches:
- master
@@ -21,6 +27,12 @@ on:
paths-ignore:
- "docs/**"
- "site/**"
+ - "iotdb-client/client-cpp/**"
+ - "example/client-cpp-example/**"
+ - ".github/workflows/client-cpp-package.yml"
+ - ".github/workflows/client-cpp-source-build.yml"
+ - ".github/scripts/package-client-cpp-*.sh"
+ - ".github/workflows/multi-language-client.yml"
# allow manually run the action:
workflow_dispatch:
diff --git a/.gitignore b/.gitignore
index b6aa947b3e725..961a5b05d7565 100644
--- a/.gitignore
+++ b/.gitignore
@@ -40,7 +40,7 @@ tsfile-jdbc/src/main/resources/output/queryRes.csv
*.txt
!iotdb-client/client-py/requirements.txt
!iotdb-client/client-py/requirements_dev.txt
-!iotdb-client/client-cpp/src/main/CMakeLists.txt
+!iotdb-client/client-cpp/CMakeLists.txt
!iotdb-client/client-cpp/src/test/CMakeLists.txt
!example/rest-client-c-example/CMakeLists.txt
!example/client-cpp-example/src/CMakeLists.txt
@@ -88,6 +88,11 @@ tsfile-jdbc/src/main/resources/output/queryRes.csv
*.tsfile
tsfile/src/test/resources/*.ts
+### clion project
+**/cmake-build-debug/
+**/cmake-build-release/
+iotdb-client/client-cpp/build-*/
+
### Apache release ###
local-snapshots-dir/
venv/
@@ -107,6 +112,7 @@ classes/
### Cmake files ###
*.cmake
+!iotdb-client/client-cpp/cmake/*.cmake
Makefile
**/CMakeFiles/
diff --git a/distribution/src/assembly/client-cpp.xml b/distribution/src/assembly/client-cpp.xml
index 0a4dfffbc061e..cfff5045d673d 100644
--- a/distribution/src/assembly/client-cpp.xml
+++ b/distribution/src/assembly/client-cpp.xml
@@ -28,7 +28,7 @@
apache-iotdb-${project.version}-client-cpp-${os.classifier}-bin
- ${project.basedir}/../iotdb-client/client-cpp/target/client-cpp-${project.version}-cpp-${os.classifier}
+ ${project.basedir}/../iotdb-client/client-cpp/target/client-cpp-${project.version}-${os.classifier}/client-cpp-${project.version}-${os.classifier}
${file.separator}
diff --git a/example/client-c-example/README.md b/example/client-c-example/README.md
deleted file mode 100644
index 8920883ddbcd6..0000000000000
--- a/example/client-c-example/README.md
+++ /dev/null
@@ -1,68 +0,0 @@
-
-
-# How to get a complete C client demo project (SessionC)
-
-Pure **C** examples for the IoTDB Session **C API** (`SessionC.h`): **tree model** (`tree_example`) and **table model** (`table_example`). Default connection: `127.0.0.1:6667`, user `root` / password `root` (edit the macros at the top of each `.c` file).
-
-## Get a project
-
-Using Maven to build this example project (requires **Boost**, same as the C++ client; on Windows see [`iotdb-client/client-cpp/README.md`](../../iotdb-client/client-cpp/README.md)):
-
-* `cd` the root path of the whole project
-* run
- `mvn package -DskipTests -P with-cpp -pl example/client-c-example -am`
- (use `mvn clean package ...` when no other process holds files under `iotdb-client/client-cpp/target`; on Windows add Boost paths, e.g.
- `-D"boost.include.dir=C:\local\boost_1_87_0" -D"boost.library.dir=C:\local\boost_1_87_0\lib64-msvc-14.2"`)
-* `cd example/client-c-example/target`
-
-After a successful build you should have:
-
-* Unpacked C++ client headers and libraries under `client/` and Thrift under `thrift/` (same layout as [client-cpp-example](../client-cpp-example/README.md))
-* CMake-generated binaries, for example on Windows MSVC:
- `Release/tree_example.exe`, `Release/table_example.exe`
- (exact path depends on the CMake generator)
-
-## Run
-
-Start IoTDB first, then:
-
-```text
-# Windows (example)
-Release\tree_example.exe
-Release\table_example.exe
-```
-
-On failure, the programs print to `stderr` and you can inspect `ts_get_last_error()`.
-
-## Source layout
-
-```
-example/client-c-example/
-+-- README.md
-+-- pom.xml
-+-- src/
-| +-- CMakeLists.txt
-| +-- tree_example.c
-| +-- table_example.c
-```
-
-The Maven build copies `src/*.c` and `src/CMakeLists.txt` into `target/` next to the unpacked `client/` and `thrift/` trees, then runs CMake to compile the two executables.
diff --git a/example/client-c-example/pom.xml b/example/client-c-example/pom.xml
deleted file mode 100644
index 3116c0fd0b4f2..0000000000000
--- a/example/client-c-example/pom.xml
+++ /dev/null
@@ -1,150 +0,0 @@
-
-
-
- 4.0.0
-
- org.apache.iotdb
- iotdb-examples
- 2.0.7-SNAPSHOT
-
- client-c-example
- IoTDB: Example: C Client (SessionC)
-
-
- org.apache.iotdb
- client-cpp
- ${project.version}
- pom
- provided
-
-
-
-
-
- com.coderplus.maven.plugins
- copy-rename-maven-plugin
-
-
- copy-c-sources-and-cmake
-
- copy
-
-
-
-
- ${project.basedir}/src/tree_example.c
- ${project.build.directory}/tree_example.c
-
-
- ${project.basedir}/src/table_example.c
- ${project.build.directory}/table_example.c
-
-
- ${project.basedir}/src/CMakeLists.txt
- ${project.build.directory}/CMakeLists.txt
-
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-dependency-plugin
-
-
- unpack-client
-
- unpack
-
- generate-sources
-
-
-
- org.apache.iotdb
- client-cpp
- ${project.version}
- zip
- cpp-${os.classifier}
- true
-
-
- ${project.build.directory}/client
-
-
-
- unpack-thrift
-
- unpack
-
- generate-sources
-
-
-
- org.apache.iotdb.tools
- iotdb-tools-thrift
- ${iotdb-tools-thrift.version}
- ${os.classifier}
- zip
- true
- ${project.build.directory}/thrift
-
-
-
-
-
-
-
- io.github.cmake-maven-plugin
- cmake-maven-plugin
-
-
- cmake-generate
-
- generate
-
- compile
-
- ${cmake.generator}
- ${project.build.directory}
- ${project.build.directory}
-
-
-
-
-
-
- cmake-compile
-
- compile
-
- compile
-
- ${cmake.build.type}
- ${project.build.directory}
-
-
-
-
-
-
-
diff --git a/example/client-c-example/src/table_example.c b/example/client-c-example/src/table_example.c
deleted file mode 100644
index 9ad844ec4c2af..0000000000000
--- a/example/client-c-example/src/table_example.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/*
- * Table model: CREATE DATABASE/TABLE, insert rows via Tablet, SELECT, DROP DATABASE.
- * Requires IoTDB table-SQL support. Edit HOST / PORT / credentials below.
- */
-
-#include
-#include
-#include
-
-#include "SessionC.h"
-
-#define HOST "127.0.0.1"
-#define PORT 6667
-#define USER "root"
-#define PASS "root"
-
-#define DB_NAME "cdemo_db"
-#define TABLE_NAME "cdemo_t0"
-
-static void fail(const char* ctx, CTableSession* s) {
- fprintf(stderr, "[table_example] %s failed: %s\n", ctx, ts_get_last_error());
- if (s) {
- ts_table_session_close(s);
- ts_table_session_destroy(s);
- }
- exit(1);
-}
-
-int main(void) {
- /* Last arg: default database name; empty string leaves it unset (we USE "cdemo_db" via SQL below). */
- CTableSession* session = ts_table_session_new(HOST, PORT, USER, PASS, "");
- if (!session) {
- fprintf(stderr, "[table_example] ts_table_session_new returned NULL: %s\n", ts_get_last_error());
- return 1;
- }
- if (ts_table_session_open(session) != TS_OK) {
- fail("ts_table_session_open", session);
- }
-
- char sql[512];
- snprintf(sql, sizeof(sql), "DROP DATABASE IF EXISTS %s", DB_NAME);
- (void)ts_table_session_execute_non_query(session, sql);
-
- snprintf(sql, sizeof(sql), "CREATE DATABASE %s", DB_NAME);
- if (ts_table_session_execute_non_query(session, sql) != TS_OK) {
- fail("CREATE DATABASE", session);
- }
-
- snprintf(sql, sizeof(sql), "USE \"%s\"", DB_NAME);
- if (ts_table_session_execute_non_query(session, sql) != TS_OK) {
- fail("USE DATABASE", session);
- }
-
- const char* ddl =
- "CREATE TABLE " TABLE_NAME " ("
- "tag1 string tag,"
- "attr1 string attribute,"
- "m1 double field)";
- if (ts_table_session_execute_non_query(session, ddl) != TS_OK) {
- fail("CREATE TABLE", session);
- }
-
- const char* columnNames[] = {"tag1", "attr1", "m1"};
- TSDataType_C dataTypes[] = {TS_TYPE_STRING, TS_TYPE_STRING, TS_TYPE_DOUBLE};
- TSColumnCategory_C colCategories[] = {TS_COL_TAG, TS_COL_ATTRIBUTE, TS_COL_FIELD};
-
- CTablet* tablet = ts_tablet_new_with_category(TABLE_NAME, 3, columnNames, dataTypes, colCategories, 100);
- if (!tablet) {
- fail("ts_tablet_new_with_category", session);
- }
-
- int i;
- for (i = 0; i < 5; i++) {
- if (ts_tablet_add_timestamp(tablet, i, (int64_t)i) != TS_OK) {
- ts_tablet_destroy(tablet);
- fail("ts_tablet_add_timestamp", session);
- }
- if (ts_tablet_add_value_string(tablet, 0, i, "device_A") != TS_OK) {
- ts_tablet_destroy(tablet);
- fail("ts_tablet_add_value_string tag", session);
- }
- if (ts_tablet_add_value_string(tablet, 1, i, "attr_val") != TS_OK) {
- ts_tablet_destroy(tablet);
- fail("ts_tablet_add_value_string attr", session);
- }
- if (ts_tablet_add_value_double(tablet, 2, i, (double)i * 1.5) != TS_OK) {
- ts_tablet_destroy(tablet);
- fail("ts_tablet_add_value_double", session);
- }
- }
- if (ts_tablet_set_row_count(tablet, 5) != TS_OK) {
- ts_tablet_destroy(tablet);
- fail("ts_tablet_set_row_count", session);
- }
-
- if (ts_table_session_insert(session, tablet) != TS_OK) {
- ts_tablet_destroy(tablet);
- fail("ts_table_session_insert", session);
- }
- ts_tablet_destroy(tablet);
-
- CSessionDataSet* dataSet = NULL;
- if (ts_table_session_execute_query(session, "SELECT * FROM " TABLE_NAME, &dataSet) != TS_OK) {
- fail("ts_table_session_execute_query", session);
- }
- if (!dataSet) {
- fprintf(stderr, "[table_example] dataSet is NULL\n");
- ts_table_session_close(session);
- ts_table_session_destroy(session);
- return 1;
- }
- ts_dataset_set_fetch_size(dataSet, 1024);
-
- int count = 0;
- while (ts_dataset_has_next(dataSet)) {
- CRowRecord* record = ts_dataset_next(dataSet);
- if (!record) {
- break;
- }
- printf("[table_example] row %d: time=%lld\n", count, (long long)ts_row_record_get_timestamp(record));
- ts_row_record_destroy(record);
- count++;
- }
- ts_dataset_destroy(dataSet);
- printf("[table_example] SELECT returned %d row(s).\n", count);
-
- snprintf(sql, sizeof(sql), "DROP DATABASE IF EXISTS %s", DB_NAME);
- (void)ts_table_session_execute_non_query(session, sql);
-
- ts_table_session_close(session);
- ts_table_session_destroy(session);
- return 0;
-}
diff --git a/example/client-c-example/src/tree_example.c b/example/client-c-example/src/tree_example.c
deleted file mode 100644
index a98df2831b69e..0000000000000
--- a/example/client-c-example/src/tree_example.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/*
- * Tree model: create one timeseries, insert one row via string values, SELECT, cleanup.
- * Edit HOST / PORT / credentials below to match your IoTDB.
- */
-
-#include
-#include
-#include
-#include
-
-#include "SessionC.h"
-
-#define HOST "127.0.0.1"
-#define PORT 6667
-#define USER "root"
-#define PASS "root"
-
-#define TS_PATH "root.cdemo.d0.s0"
-#define DEVICE "root.cdemo.d0"
-
-static void fail(const char* ctx, CSession* s) {
- fprintf(stderr, "[tree_example] %s failed: %s\n", ctx, ts_get_last_error());
- if (s) {
- ts_session_close(s);
- ts_session_destroy(s);
- }
- exit(1);
-}
-
-int main(void) {
- const char* path = TS_PATH;
- CSession* session = ts_session_new(HOST, PORT, USER, PASS);
- if (!session) {
- fprintf(stderr, "[tree_example] ts_session_new returned NULL: %s\n", ts_get_last_error());
- return 1;
- }
- if (ts_session_open(session) != TS_OK) {
- fail("ts_session_open", session);
- }
-
- bool exists = false;
- if (ts_session_check_timeseries_exists(session, path, &exists) != TS_OK) {
- fail("ts_session_check_timeseries_exists", session);
- }
- if (exists) {
- if (ts_session_delete_timeseries(session, path) != TS_OK) {
- fail("ts_session_delete_timeseries (cleanup old)", session);
- }
- }
- if (ts_session_create_timeseries(session, path, TS_TYPE_INT64, TS_ENCODING_RLE, TS_COMPRESSION_SNAPPY) !=
- TS_OK) {
- fail("ts_session_create_timeseries", session);
- }
-
- const char* measurements[] = {"s0"};
- const char* values[] = {"100"};
- if (ts_session_insert_record_str(session, DEVICE, 1LL, 1, measurements, values) != TS_OK) {
- fail("ts_session_insert_record_str", session);
- }
-
- CSessionDataSet* dataSet = NULL;
- if (ts_session_execute_query(session, "select s0 from root.cdemo.d0", &dataSet) != TS_OK) {
- fail("ts_session_execute_query", session);
- }
- if (!dataSet) {
- fprintf(stderr, "[tree_example] dataSet is NULL\n");
- ts_session_close(session);
- ts_session_destroy(session);
- return 1;
- }
- ts_dataset_set_fetch_size(dataSet, 1024);
-
- int rows = 0;
- while (ts_dataset_has_next(dataSet)) {
- CRowRecord* record = ts_dataset_next(dataSet);
- if (!record) {
- break;
- }
- int64_t v = ts_row_record_get_int64(record, 0);
- printf("[tree_example] row %d: s0 = %lld\n", rows, (long long)v);
- ts_row_record_destroy(record);
- rows++;
- }
- ts_dataset_destroy(dataSet);
-
- printf("[tree_example] done, read %d row(s).\n", rows);
-
- if (ts_session_delete_timeseries(session, path) != TS_OK) {
- fail("ts_session_delete_timeseries", session);
- }
-
- ts_session_close(session);
- ts_session_destroy(session);
- return 0;
-}
diff --git a/example/client-cpp-example/README.md b/example/client-cpp-example/README.md
index f36a084f888e5..77db316f32020 100644
--- a/example/client-cpp-example/README.md
+++ b/example/client-cpp-example/README.md
@@ -19,30 +19,241 @@
-->
-# How to get a complete CPP client demo project
+# IoTDB C++ client examples
-## Get a project
+[中文说明](README_zh.md)
-Using maven to build this example project:
+Sample programs that link against the pre-built **IoTDB C++ Session SDK**
+(`iotdb_session`). Thrift and Boost are **not** required at application compile
+time; they are embedded inside the SDK shared library.
-* cd the root path of the whole project
-* run `mvn clean package -DskipTests -P with-cpp -pl example/client-cpp-example -am`
-* cd example/client-cpp-example/target
+All examples connect to a running IoTDB instance (default `127.0.0.1:6667`,
+user `root` / `root`).
+
+| Example | Description |
+|---------|-------------|
+| `SessionExample` | Tree model: DDL, insert, query, delete |
+| `AlignedTimeseriesSessionExample` | Aligned time series and templates |
+| `TableModelSessionExample` | Table (relational) model |
+| `MultiSvrNodeClient` | Multi-node insert/query loop |
+| `tree_example` | C Session API (tree model) |
+| `table_example` | C Session API (table model) |
+
+## Which SDK zip to use
+
+Release CI ([client-cpp-package.yml](../../.github/workflows/client-cpp-package.yml))
+publishes one zip per platform/toolchain:
+`client-cpp--.zip` (root folder `client-cpp--/` with `include/` and `lib/`).
+
+| Deployment target | Classifier suffix |
+|-------------------|-------------------|
+| Linux x86_64, glibc ≥ 2.17 | `linux-x86_64-glibc217` |
+| Linux aarch64, glibc ≥ 2.17 | `linux-aarch64-glibc217` |
+| macOS x86_64 | `mac-x86_64` |
+| macOS arm64 | `mac-aarch64` |
+| Windows (match your Visual Studio version) | `windows-x86_64-vs2017` … `vs2026` |
+
+The current build compiles Thrift 0.21 from source at CMake configure time.
+Legacy `-Diotdb-tools-thrift.version=...` flags applied to the **old**
+pre-built Thrift workflow only; for glibc 2.17 on x86_64 use the
+`linux-x86_64-glibc217` artifact or build on an old enough host (see
+[client-cpp README](../../iotdb-client/client-cpp/README.md)).
+
+## SDK layout (after unpack)
+
+The SDK zip produced by `client-cpp` contains **public headers only** and one
+shared library:
+
+```
+client/
+├── include/
+│ ├── Session.h
+│ ├── Export.h
+│ └── ... (17 public headers; no thrift/ or boost/)
+└── lib/
+ ├── iotdb_session.dll + iotdb_session.lib (Windows)
+ ├── libiotdb_session.so (Linux)
+ └── libiotdb_session.dylib (macOS)
+```
+
+## Build the examples
+
+### Option A – Maven (recommended in this repo)
+
+From the repository root:
+
+```bash
+mvn clean package -DskipTests -P with-cpp -pl example/client-cpp-example -am
+```
+
+Maven unpacks the SDK zip into `example/client-cpp-example/target/client/` and
+runs CMake in `target/`. Binaries are under `target/` (exact path depends on
+the generator; on Windows with Visual Studio: `target/Release/`).
+
+### Option B – CMake only (manual SDK)
+
+1. Build or download the SDK and unpack it so `client/include` and
+ `client/lib` exist (see layout above).
+2. Copy `src/*.{cpp,c}` and `src/CMakeLists.txt` into one directory (or use
+ `src/` as the source tree and place `client/` beside it).
+3. Configure and build:
+
+```bash
+cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
+cmake --build build
+```
+
+Windows (Visual Studio generator):
+
+```powershell
+cmake -S . -B build -A x64
+cmake --build build --config Release
+```
+
+Each executable is built with the IoTDB runtime library copied **next to the
+`.exe` / binary** (POST_BUILD step). Linux/macOS binaries use `$ORIGIN` rpath
+so they resolve the `.so` / `.dylib` in the same directory.
+
+Optional staging folder for deployment:
+
+```bash
+cmake --build build --target example-dist
+# -> build/dist/ contains all example binaries + libiotdb_session.{so,dll,dylib}
+```
+
+## Run on a clean machine (no compiler, no IoTDB SDK headers)
+
+You only need:
+
+1. A running IoTDB server reachable from the machine.
+2. The **example executable(s)** and the **IoTDB runtime library** in the
+ **same directory** (or on the system library path).
+
+Copy either from `build/.../Release/` (Windows) / `build/` (Ninja/Make) or from
+`build/dist/` after `example-dist`.
+
+### Windows
+
+**Files to copy**
+
+```
+SessionExample.exe
+iotdb_session.dll
+```
+
+(Repeat for the other example names if needed.)
+
+**Prerequisites on the target PC**
+
+- **64-bit Windows** (examples are built x64).
+- **[Microsoft Visual C++ Redistributable for Visual Studio 2015–2022](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist)**
+ (x64). The SDK and examples are built with **`/MD`**; the redistributable
+ supplies `vcruntime140.dll`, `msvcp140.dll`, etc.
+ Installing this package is enough—you do **not** need Visual Studio or the
+ IoTDB SDK on the target machine.
+
+**Run**
+
+```powershell
+.\SessionExample.exe
+```
+
+If you see “The code execution cannot proceed because VCRUNRuntime140.dll was
+missing”, install the VC++ redistributable above.
+
+You do **not** need a separate Thrift or Boost runtime; they are inside
+`iotdb_session.dll`.
+
+### Linux
+
+**Files to copy**
-You can find some files to form a complete project:
```
-+-- client
-| +-- include
-| +-- Session.h
-| +-- IClientRPCService.h
-| +-- rpc_types.h
-| +-- rpc_constants.h
-| +-- thrift
-| +-- thrift_headers...
-| +-- lib
-| +-- libiotdb_session.dylib
-+-- CMakeLists.txt
-+-- SessionExample.cpp
+SessionExample
+libiotdb_session.so
+chmod +x SessionExample
```
+**Prerequisites on the target machine**
+
+- **glibc** on the target must be **≥ the glibc version on the machine that
+ built the SDK** (backward compatible only in that direction).
+
+Check **build machine** (record in release notes):
+
+```bash
+ldd --version | head -1
+# e.g. ldd (Ubuntu GLIBC 2.35-0ubuntu3) 2.35
+```
+
+Check **target machine**:
+
+```bash
+ldd --version | head -1
+# must be >= build glibc (same major.minor or newer)
+```
+
+See which `GLIBC_` symbols the binary needs:
+
+```bash
+objdump -T SessionExample | grep GLIBC_ | sed 's/.*GLIBC_/GLIBC_/' | sort -Vu | tail -5
+objdump -T libiotdb_session.so | grep GLIBC_ | sed 's/.*GLIBC_/GLIBC_/' | sort -Vu | tail -5
+```
+
+If the target glibc is too old, you'll get errors like
+`version 'GLIBC_2.34' not found` at runtime. Rebuild the SDK on an older distro
+(or in an older container) to widen compatibility.
+
+**Run** (with `.so` beside the binary):
+
+```bash
+./SessionExample
+```
+
+If the shared library is not found:
+
+```bash
+export LD_LIBRARY_PATH=.
+./SessionExample
+```
+
+No separate Thrift install is required.
+
+### macOS
+
+Copy the example binary and `libiotdb_session.dylib` together. The target macOS
+version should be **≥ the deployment target used to build the SDK**. Check with:
+
+```bash
+otool -L SessionExample
+```
+
+## Development notes
+
+- **Windows**: Application and SDK both use **`/MD`** (dynamic CRT). This
+ matches a default Visual Studio project; link `iotdb_session.lib`, ship
+ `iotdb_session.dll`.
+- **Linux**: SDK is `libiotdb_session.so`; link it directly. Prefer shipping
+ the `.so` next to your binary or setting `RPATH` to `$ORIGIN`.
+- Examples assume IoTDB is listening on `127.0.0.1:6667`; change host/port in
+ the source if needed.
+
+## Project layout in this module
+
+```
+client-cpp-example/
+├── pom.xml # Maven: unpack SDK + invoke CMake
+├── README.md
+├── README_zh.md
+└── src/
+ ├── CMakeLists.txt
+ ├── SessionExample.cpp
+ ├── AlignedTimeseriesSessionExample.cpp
+ ├── TableModelSessionExample.cpp
+ ├── MultiSvrNodeClient.cpp
+ ├── tree_example.c
+ └── table_example.c
+```
+After `mvn package`, the runnable tree is under `target/` (sources, `client/`,
+and CMake build output).
diff --git a/example/client-cpp-example/README_zh.md b/example/client-cpp-example/README_zh.md
new file mode 100644
index 0000000000000..acdc11df23277
--- /dev/null
+++ b/example/client-cpp-example/README_zh.md
@@ -0,0 +1,252 @@
+
+
+# IoTDB C++ 客户端示例
+
+[English](README.md)
+
+本目录提供链接 **IoTDB C++ Session SDK**(`iotdb_session`)的示例程序。
+应用侧编译 **不需要** 单独安装 Thrift 或 Boost 头文件/库,它们已封装在 SDK
+共享库内部。
+
+所有示例默认连接本机 IoTDB(`127.0.0.1:6667`,用户 `root` / 密码 `root`)。
+
+| 示例 | 说明 |
+|------|------|
+| `SessionExample` | 树模型:建库建序列、写入、查询、删除 |
+| `AlignedTimeseriesSessionExample` | 对齐时间序列与模板 |
+| `TableModelSessionExample` | 表模型(关系型) |
+| `MultiSvrNodeClient` | 多节点写入/查询循环 |
+| `tree_example` | C Session API(树模型) |
+| `table_example` | C Session API(表模型) |
+
+## 选择哪个 SDK 压缩包
+
+CI 发版([client-cpp-package.yml](../../.github/workflows/client-cpp-package.yml))
+会按平台/工具链打出多份 zip,文件名形如
+`client-cpp--.zip`(解压后为 `client-cpp--/`,内含 `include/` 与 `lib/`)。请按目标环境选择:
+
+| 目标环境 | classifier 后缀 |
+|----------|-----------------|
+| Linux x86_64,glibc ≥ 2.17 | `linux-x86_64-glibc217` |
+| Linux aarch64,glibc ≥ 2.17 | `linux-aarch64-glibc217` |
+| macOS x86_64 | `mac-x86_64` |
+| macOS arm64 | `mac-aarch64` |
+| Windows + 与工程相同的 VS 版本 | `windows-x86_64-vs2017` … `vs2026` |
+
+当前 CMake 构建在配置阶段从源码编译 Thrift 0.21,**不再**通过
+`-Diotdb-tools-thrift.version=0.14.1.1-gcc4-SNAPSHOT` 等旧参数控制 glibc;
+x86_64 上若要兼容 glibc 2.17,请使用 `linux-x86_64-glibc217` 包或在
+glibc ≤ 2.17 的系统上本地编译(见 [client-cpp README](../../iotdb-client/client-cpp/README.md))。
+
+## SDK 目录结构(解压后)
+
+`client-cpp` 打出的 SDK 压缩包只包含 **公开头文件** 和 **一个共享库**:
+
+```
+client/
+├── include/
+│ ├── Session.h
+│ ├── Export.h
+│ └── ... (17 个公开头;无 thrift/、boost/)
+└── lib/
+ ├── iotdb_session.dll + iotdb_session.lib (Windows)
+ ├── libiotdb_session.so (Linux)
+ └── libiotdb_session.dylib (macOS)
+```
+
+## 编译示例
+
+### 方式 A:Maven(本仓库推荐)
+
+在仓库根目录执行:
+
+```bash
+mvn clean package -DskipTests -P with-cpp -pl example/client-cpp-example -am
+```
+
+Maven 会将 SDK 解压到 `example/client-cpp-example/target/client/`,并在
+`target/` 下调用 CMake。可执行文件位于 `target/`(具体路径取决于生成器;
+Windows + Visual Studio 一般为 `target/Release/`)。
+
+### 方式 B:仅 CMake(手动准备 SDK)
+
+1. 自行编译或下载 SDK,解压后保证存在 `client/include` 与 `client/lib`(见
+ 上文目录结构)。
+2. 将 `src/*.{cpp,c}` 与 `src/CMakeLists.txt` 放在同一目录(或保留 `src/`
+ 结构,并在同级放置 `client/`)。
+3. 配置并编译:
+
+```bash
+cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
+cmake --build build
+```
+
+Windows(Visual Studio 生成器):
+
+```powershell
+cmake -S . -B build -A x64
+cmake --build build --config Release
+```
+
+编译完成后,IoTDB 运行时库会通过 POST_BUILD 自动复制到 **与可执行文件相同
+的目录**。Linux/macOS 可执行文件还设置了 `$ORIGIN` rpath,可在同目录加载
+`.so` / `.dylib`。
+
+可选:打部署包目录
+
+```bash
+cmake --build build --target example-dist
+# 生成 build/dist/,内含全部示例二进制 + libiotdb_session.{so,dll,dylib}
+```
+
+## 在「干净机器」上运行(无需编译器、无需 SDK 头文件)
+
+目标机器只需:
+
+1. 可访问的 **IoTDB 服务**(已启动)。
+2. **示例可执行文件** 与 **IoTDB 运行时库** 放在 **同一目录**(或位于系统
+ 库搜索路径中)。
+
+可从 `build/.../Release/`(Windows)或 `build/`(Ninja/Make)复制,也可在
+执行 `example-dist` 后直接使用 `build/dist/`。
+
+### Windows
+
+**需要拷贝的文件**
+
+```
+SessionExample.exe
+iotdb_session.dll
+```
+
+(其他示例同理,可执行文件与 `iotdb_session.dll` 成对拷贝。)
+
+**目标机器前置条件**
+
+- **64 位 Windows**(示例为 x64 构建)。
+- 安装 **[Microsoft Visual C++ 2015–2022 可再发行组件包(x64)](https://learn.microsoft.com/zh-cn/cpp/windows/latest-supported-vc-redist)**。
+ SDK 与示例均使用 **`/MD`**(动态 CRT),该安装包提供 `vcruntime140.dll`、
+ `msvcp140.dll` 等运行时。
+ **仅安装此 Redistributable 即可**,目标机 **不需要** Visual Studio,也
+ **不需要** IoTDB SDK 头文件或 Thrift/Boost。
+
+**运行**
+
+```powershell
+.\SessionExample.exe
+```
+
+若提示缺少 `VCRUNTIME140.dll`,请安装上述 VC++ 可再发行包。
+
+Thrift、Boost 已包含在 `iotdb_session.dll` 内,无需单独部署。
+
+### Linux
+
+**需要拷贝的文件**
+
+```
+SessionExample
+libiotdb_session.so
+chmod +x SessionExample
+```
+
+**目标机器前置条件**
+
+- 目标机的 **glibc 版本必须 ≥ 编译 SDK 时的 glibc 版本**(仅向后兼容:
+ 新系统可跑旧库要求,旧系统不能跑需要更高 glibc 的二进制)。
+
+在 **编译机** 上记录版本(建议写入发布说明):
+
+```bash
+ldd --version | head -1
+# 例如:ldd (Ubuntu GLIBC 2.35-0ubuntu3) 2.35
+```
+
+在 **目标机** 上检查:
+
+```bash
+ldd --version | head -1
+# 版本号应 >= 编译机(同主版本次版本或更新)
+```
+
+查看二进制依赖的最高 `GLIBC_` 符号:
+
+```bash
+objdump -T SessionExample | grep GLIBC_ | sed 's/.*GLIBC_/GLIBC_/' | sort -Vu | tail -5
+objdump -T libiotdb_session.so | grep GLIBC_ | sed 's/.*GLIBC_/GLIBC_/' | sort -Vu | tail -5
+```
+
+若目标 glibc 过旧,运行时会报错,例如
+`version 'GLIBC_2.34' not found`。可在更旧的发行版(或旧版容器)上重新编译
+SDK,以扩大兼容范围。
+
+**运行**(`.so` 与可执行文件同目录):
+
+```bash
+./SessionExample
+```
+
+若找不到共享库:
+
+```bash
+export LD_LIBRARY_PATH=.
+./SessionExample
+```
+
+无需单独安装 Thrift。
+
+### macOS
+
+将示例可执行文件与 `libiotdb_session.dylib` 放在同一目录。目标 macOS 版本
+应 **≥ 编译 SDK 时设置的 deployment target**。可用以下命令检查依赖:
+
+```bash
+otool -L SessionExample
+```
+
+## 开发说明
+
+- **Windows**:应用与 SDK 均使用 **`/MD`**,与 Visual Studio 默认工程一致;
+ 链接 `iotdb_session.lib`,部署时携带 `iotdb_session.dll`。
+- **Linux**:直接链接 `libiotdb_session.so`;建议与可执行文件同目录发布,或
+ 设置 `RPATH=$ORIGIN`。
+- 示例默认连接 `127.0.0.1:6667`;如需修改地址/端口,请编辑对应源码。
+
+## 本模块目录结构
+
+```
+client-cpp-example/
+├── pom.xml # Maven:解压 SDK + 调用 CMake
+├── README.md # 英文说明
+├── README_zh.md # 中文说明(本文件)
+└── src/
+ ├── CMakeLists.txt
+ ├── SessionExample.cpp
+ ├── AlignedTimeseriesSessionExample.cpp
+ ├── TableModelSessionExample.cpp
+ ├── MultiSvrNodeClient.cpp
+ ├── tree_example.c
+ └── table_example.c
+```
+
+执行 `mvn package` 后,可在 `target/` 下找到源码、`client/` SDK 与 CMake
+构建产物。
diff --git a/example/client-cpp-example/pom.xml b/example/client-cpp-example/pom.xml
index 9668aee28ebdf..e74c9c504090d 100644
--- a/example/client-cpp-example/pom.xml
+++ b/example/client-cpp-example/pom.xml
@@ -68,6 +68,14 @@
${project.basedir}/src/MultiSvrNodeClient.cpp
${project.build.directory}/MultiSvrNodeClient.cpp
+
+ ${project.basedir}/src/tree_example.c
+ ${project.build.directory}/tree_example.c
+
+
+ ${project.basedir}/src/table_example.c
+ ${project.build.directory}/table_example.c
+
${project.basedir}/src/CMakeLists.txt
${project.build.directory}/CMakeLists.txt
@@ -98,31 +106,17 @@
client-cpp
${project.version}
zip
- cpp-${os.classifier}
- true
-
-
- ${project.build.directory}/client
-
-
-
- unpack-thrift
-
- unpack
-
- generate-sources
-
-
-
- org.apache.iotdb.tools
- iotdb-tools-thrift
- ${iotdb-tools-thrift.version}
${os.classifier}
- zip
true
- ${project.build.directory}/thrift
+
+
+ ^[^/]+/(.*)$
+ $1
+
+
+ ${project.build.directory}/client
@@ -141,9 +135,6 @@
${cmake.generator}
${project.build.directory}
${project.build.directory}
-
-
-
diff --git a/example/client-cpp-example/src/CMakeLists.txt b/example/client-cpp-example/src/CMakeLists.txt
index 1ee249bfb803e..b1ea7d0f79cba 100644
--- a/example/client-cpp-example/src/CMakeLists.txt
+++ b/example/client-cpp-example/src/CMakeLists.txt
@@ -16,21 +16,25 @@
# under the License.
#
-PROJECT(SessionExample)
-CMAKE_MINIMUM_REQUIRED(VERSION 3.7)
+CMAKE_MINIMUM_REQUIRED(VERSION 3.15)
+CMAKE_POLICY(SET CMP0091 NEW)
+
+PROJECT(iotdb_cpp_client_examples)
SET(CMAKE_CXX_STANDARD 11)
SET(CMAKE_CXX_STANDARD_REQUIRED ON)
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
-# Add Thrift include directory
-INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/thrift/include)
-# Add cpp-client include directory
-INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/client/include)
+IF(MSVC)
+ # Match the IoTDB C++ SDK (/MD); same as a default Visual Studio application.
+ SET(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL")
+ENDIF()
+
+set(IOTDB_SDK_ROOT "${CMAKE_SOURCE_DIR}/client"
+ CACHE PATH "Unpacked IoTDB C++ SDK directory (contains include/ and lib/)")
+
+INCLUDE_DIRECTORIES("${IOTDB_SDK_ROOT}/include")
-# =========================
-# SSL option (default OFF)
-# =========================
option(WITH_SSL "Build with SSL support" OFF)
IF(WITH_SSL)
@@ -47,105 +51,78 @@ ELSE()
ADD_DEFINITIONS(-DWITH_SSL=0)
ENDIF()
-FIND_PACKAGE(Boost REQUIRED)
-IF (DEFINED BOOST_INCLUDEDIR)
- INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIR})
-ENDIF()
+if(WIN32)
+ set(_iotdb_link_lib "${IOTDB_SDK_ROOT}/lib/iotdb_session.lib")
+ set(_iotdb_runtime "${IOTDB_SDK_ROOT}/lib/iotdb_session.dll")
+elseif(APPLE)
+ set(_iotdb_link_lib "${IOTDB_SDK_ROOT}/lib/libiotdb_session.dylib")
+ set(_iotdb_runtime "${_iotdb_link_lib}")
+else()
+ set(_iotdb_link_lib "${IOTDB_SDK_ROOT}/lib/libiotdb_session.so")
+ set(_iotdb_runtime "${_iotdb_link_lib}")
+endif()
-# Add the libs for the cpp-client
-LINK_DIRECTORIES(${CMAKE_SOURCE_DIR}/client/lib)
+if(NOT EXISTS "${_iotdb_link_lib}")
+ message(FATAL_ERROR
+ "IoTDB SDK not found at ${IOTDB_SDK_ROOT}. "
+ "Unpack client-cpp--.zip so that ${_iotdb_link_lib} exists.")
+endif()
ADD_EXECUTABLE(SessionExample SessionExample.cpp)
ADD_EXECUTABLE(AlignedTimeseriesSessionExample AlignedTimeseriesSessionExample.cpp)
ADD_EXECUTABLE(TableModelSessionExample TableModelSessionExample.cpp)
ADD_EXECUTABLE(MultiSvrNodeClient MultiSvrNodeClient.cpp)
+ADD_EXECUTABLE(tree_example tree_example.c)
+ADD_EXECUTABLE(table_example table_example.c)
-IF(MSVC)
- IF(WITH_SSL)
- TARGET_LINK_LIBRARIES(SessionExample
- iotdb_session
- "${CMAKE_SOURCE_DIR}/thrift/lib/Release/thriftmd.lib"
- OpenSSL::SSL
- OpenSSL::Crypto
- )
- TARGET_LINK_LIBRARIES(AlignedTimeseriesSessionExample
- iotdb_session
- "${CMAKE_SOURCE_DIR}/thrift/lib/Release/thriftmd.lib"
- OpenSSL::SSL
- OpenSSL::Crypto
- )
- TARGET_LINK_LIBRARIES(TableModelSessionExample
- iotdb_session
- "${CMAKE_SOURCE_DIR}/thrift/lib/Release/thriftmd.lib"
- OpenSSL::SSL
- OpenSSL::Crypto
- )
- TARGET_LINK_LIBRARIES(MultiSvrNodeClient
- iotdb_session
- "${CMAKE_SOURCE_DIR}/thrift/lib/Release/thriftmd.lib"
- OpenSSL::SSL
- OpenSSL::Crypto
- )
- ELSE()
- TARGET_LINK_LIBRARIES(SessionExample
- iotdb_session
- "${CMAKE_SOURCE_DIR}/thrift/lib/Release/thriftmd.lib"
- )
- TARGET_LINK_LIBRARIES(AlignedTimeseriesSessionExample
- iotdb_session
- "${CMAKE_SOURCE_DIR}/thrift/lib/Release/thriftmd.lib"
- )
- TARGET_LINK_LIBRARIES(TableModelSessionExample
- iotdb_session
- "${CMAKE_SOURCE_DIR}/thrift/lib/Release/thriftmd.lib"
- )
- TARGET_LINK_LIBRARIES(MultiSvrNodeClient
- iotdb_session
- "${CMAKE_SOURCE_DIR}/thrift/lib/Release/thriftmd.lib"
- )
- ENDIF()
-ELSE()
- IF(WITH_SSL)
- TARGET_LINK_LIBRARIES(SessionExample
- iotdb_session
- pthread
- OpenSSL::SSL
- OpenSSL::Crypto
- )
- TARGET_LINK_LIBRARIES(AlignedTimeseriesSessionExample
- iotdb_session
- pthread
- OpenSSL::SSL
- OpenSSL::Crypto
- )
- TARGET_LINK_LIBRARIES(TableModelSessionExample
- iotdb_session
- pthread
- OpenSSL::SSL
- OpenSSL::Crypto
- )
- TARGET_LINK_LIBRARIES(MultiSvrNodeClient
- iotdb_session
- pthread
- OpenSSL::SSL
- OpenSSL::Crypto
- )
- ELSE()
- TARGET_LINK_LIBRARIES(SessionExample
- iotdb_session
- pthread
- )
- TARGET_LINK_LIBRARIES(AlignedTimeseriesSessionExample
- iotdb_session
- pthread
- )
- TARGET_LINK_LIBRARIES(TableModelSessionExample
- iotdb_session
- pthread
- )
- TARGET_LINK_LIBRARIES(MultiSvrNodeClient
- iotdb_session
- pthread
- )
- ENDIF()
-ENDIF()
+set(_example_targets
+ SessionExample
+ AlignedTimeseriesSessionExample
+ TableModelSessionExample
+ MultiSvrNodeClient
+ tree_example
+ table_example)
+
+foreach(_t IN LISTS _example_targets)
+ IF(WITH_SSL)
+ TARGET_LINK_LIBRARIES(${_t} PRIVATE "${_iotdb_link_lib}" OpenSSL::SSL OpenSSL::Crypto)
+ ELSE()
+ TARGET_LINK_LIBRARIES(${_t} PRIVATE "${_iotdb_link_lib}")
+ ENDIF()
+ IF(UNIX)
+ TARGET_LINK_LIBRARIES(${_t} PRIVATE pthread)
+ ENDIF()
+
+ # Run from the build output directory without setting LD_LIBRARY_PATH / PATH.
+ if(UNIX)
+ set_target_properties(${_t} PROPERTIES
+ BUILD_RPATH "\$ORIGIN"
+ INSTALL_RPATH "\$ORIGIN")
+ endif()
+
+ if(EXISTS "${_iotdb_runtime}")
+ add_custom_command(TARGET ${_t} POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ "${_iotdb_runtime}" $
+ COMMENT "Copy IoTDB runtime library next to ${_t}")
+ elseif(WIN32)
+ message(WARNING "Missing ${_iotdb_runtime}; copy iotdb_session.dll manually before running ${_t}.")
+ endif()
+endforeach()
+
+# Optional: stage a self-contained folder for copying to another machine (see README).
+set(_example_dist_dir "${CMAKE_BINARY_DIR}/dist")
+add_custom_target(example-dist DEPENDS ${_example_targets}
+ COMMENT "Collect example binaries and IoTDB runtime into ${_example_dist_dir}")
+foreach(_t IN LISTS _example_targets)
+ add_custom_command(TARGET example-dist POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E make_directory "${_example_dist_dir}"
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ $ "${_example_dist_dir}/"
+ COMMENT "Stage ${_t}")
+endforeach()
+if(EXISTS "${_iotdb_runtime}")
+ add_custom_command(TARGET example-dist POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ "${_iotdb_runtime}" "${_example_dist_dir}/")
+endif()
diff --git a/example/client-cpp-example/src/MultiSvrNodeClient.cpp b/example/client-cpp-example/src/MultiSvrNodeClient.cpp
index 06e96ecd31bdf..e7f94a2c778c0 100644
--- a/example/client-cpp-example/src/MultiSvrNodeClient.cpp
+++ b/example/client-cpp-example/src/MultiSvrNodeClient.cpp
@@ -17,9 +17,11 @@
* under the License.
*/
+#include
#include
#include
#include
+#include
#include
#include "Session.h"
@@ -94,12 +96,10 @@ void RunResilienceExample() {
for (int i = 0; i < 60; ++i) { // run ~60 seconds
int64_t timestamp =
std::chrono::system_clock::now().time_since_epoch() / std::chrono::milliseconds(1);
- std::string value = to_string(i);
- const char* value_cstr = value.c_str();
+ std::string value = std::to_string(i);
try {
- session->insertRecord("root.resilience.d1", timestamp, {"s1"}, {TSDataType::INT64},
- {const_cast(value_cstr)});
+ session->insertRecord("root.resilience.d1", timestamp, {"s1"}, {value});
std::cout << "[Insert] ts=" << timestamp << ", value=" << value << std::endl;
auto dataset = session->executeQueryStatement("SELECT s1 FROM root.resilience.d1 LIMIT 1");
diff --git a/example/client-cpp-example/src/table_example.c b/example/client-cpp-example/src/table_example.c
new file mode 100644
index 0000000000000..bc9df9aa82345
--- /dev/null
+++ b/example/client-cpp-example/src/table_example.c
@@ -0,0 +1,153 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * Table model: CREATE DATABASE/TABLE, insert rows via Tablet, SELECT, DROP DATABASE.
+ * Requires IoTDB table-SQL support. Edit HOST / PORT / credentials below.
+ */
+
+#include
+#include
+#include
+
+#include "SessionC.h"
+
+#define HOST "127.0.0.1"
+#define PORT 6667
+#define USER "root"
+#define PASS "root"
+
+#define DB_NAME "cdemo_db"
+#define TABLE_NAME "cdemo_t0"
+
+static void fail(const char* ctx, CTableSession* s) {
+ fprintf(stderr, "[table_example] %s failed: %s\n", ctx, ts_get_last_error());
+ if (s) {
+ ts_table_session_close(s);
+ ts_table_session_destroy(s);
+ }
+ exit(1);
+}
+
+int main(void) {
+ CTableSession* session = ts_table_session_new(HOST, PORT, USER, PASS, "");
+ if (!session) {
+ fprintf(stderr, "[table_example] ts_table_session_new returned NULL: %s\n",
+ ts_get_last_error());
+ return 1;
+ }
+ if (ts_table_session_open(session) != TS_OK) {
+ fail("ts_table_session_open", session);
+ }
+
+ char sql[512];
+ snprintf(sql, sizeof(sql), "DROP DATABASE IF EXISTS %s", DB_NAME);
+ (void)ts_table_session_execute_non_query(session, sql);
+
+ snprintf(sql, sizeof(sql), "CREATE DATABASE %s", DB_NAME);
+ if (ts_table_session_execute_non_query(session, sql) != TS_OK) {
+ fail("CREATE DATABASE", session);
+ }
+
+ snprintf(sql, sizeof(sql), "USE \"%s\"", DB_NAME);
+ if (ts_table_session_execute_non_query(session, sql) != TS_OK) {
+ fail("USE DATABASE", session);
+ }
+
+ const char* ddl = "CREATE TABLE " TABLE_NAME " ("
+ "tag1 string tag,"
+ "attr1 string attribute,"
+ "m1 double field)";
+ if (ts_table_session_execute_non_query(session, ddl) != TS_OK) {
+ fail("CREATE TABLE", session);
+ }
+
+ const char* columnNames[] = {"tag1", "attr1", "m1"};
+ TSDataType_C dataTypes[] = {TS_TYPE_STRING, TS_TYPE_STRING, TS_TYPE_DOUBLE};
+ TSColumnCategory_C colCategories[] = {TS_COL_TAG, TS_COL_ATTRIBUTE, TS_COL_FIELD};
+
+ CTablet* tablet =
+ ts_tablet_new_with_category(TABLE_NAME, 3, columnNames, dataTypes, colCategories, 100);
+ if (!tablet) {
+ fail("ts_tablet_new_with_category", session);
+ }
+
+ int i;
+ for (i = 0; i < 5; i++) {
+ if (ts_tablet_add_timestamp(tablet, i, (int64_t)i) != TS_OK) {
+ ts_tablet_destroy(tablet);
+ fail("ts_tablet_add_timestamp", session);
+ }
+ if (ts_tablet_add_value_string(tablet, 0, i, "device_A") != TS_OK) {
+ ts_tablet_destroy(tablet);
+ fail("ts_tablet_add_value_string tag", session);
+ }
+ if (ts_tablet_add_value_string(tablet, 1, i, "attr_val") != TS_OK) {
+ ts_tablet_destroy(tablet);
+ fail("ts_tablet_add_value_string attr", session);
+ }
+ if (ts_tablet_add_value_double(tablet, 2, i, (double)i * 1.5) != TS_OK) {
+ ts_tablet_destroy(tablet);
+ fail("ts_tablet_add_value_double", session);
+ }
+ }
+ if (ts_tablet_set_row_count(tablet, 5) != TS_OK) {
+ ts_tablet_destroy(tablet);
+ fail("ts_tablet_set_row_count", session);
+ }
+
+ if (ts_table_session_insert(session, tablet) != TS_OK) {
+ ts_tablet_destroy(tablet);
+ fail("ts_table_session_insert", session);
+ }
+ ts_tablet_destroy(tablet);
+
+ CSessionDataSet* dataSet = NULL;
+ if (ts_table_session_execute_query(session, "SELECT * FROM " TABLE_NAME, &dataSet) != TS_OK) {
+ fail("ts_table_session_execute_query", session);
+ }
+ if (!dataSet) {
+ fprintf(stderr, "[table_example] dataSet is NULL\n");
+ ts_table_session_close(session);
+ ts_table_session_destroy(session);
+ return 1;
+ }
+ ts_dataset_set_fetch_size(dataSet, 1024);
+
+ int count = 0;
+ while (ts_dataset_has_next(dataSet)) {
+ CRowRecord* record = ts_dataset_next(dataSet);
+ if (!record) {
+ break;
+ }
+ printf("[table_example] row %d: time=%lld\n", count,
+ (long long)ts_row_record_get_timestamp(record));
+ ts_row_record_destroy(record);
+ count++;
+ }
+ ts_dataset_destroy(dataSet);
+ printf("[table_example] SELECT returned %d row(s).\n", count);
+
+ snprintf(sql, sizeof(sql), "DROP DATABASE IF EXISTS %s", DB_NAME);
+ (void)ts_table_session_execute_non_query(session, sql);
+
+ ts_table_session_close(session);
+ ts_table_session_destroy(session);
+ return 0;
+}
diff --git a/example/client-cpp-example/src/tree_example.c b/example/client-cpp-example/src/tree_example.c
new file mode 100644
index 0000000000000..b1eb53fafb836
--- /dev/null
+++ b/example/client-cpp-example/src/tree_example.c
@@ -0,0 +1,114 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * Tree model: create one timeseries, insert one row via string values, SELECT, cleanup.
+ * Edit HOST / PORT / credentials below to match your IoTDB.
+ */
+
+#include
+#include
+#include
+#include
+
+#include "SessionC.h"
+
+#define HOST "127.0.0.1"
+#define PORT 6667
+#define USER "root"
+#define PASS "root"
+
+#define TS_PATH "root.cdemo.d0.s0"
+#define DEVICE "root.cdemo.d0"
+
+static void fail(const char* ctx, CSession* s) {
+ fprintf(stderr, "[tree_example] %s failed: %s\n", ctx, ts_get_last_error());
+ if (s) {
+ ts_session_close(s);
+ ts_session_destroy(s);
+ }
+ exit(1);
+}
+
+int main(void) {
+ const char* path = TS_PATH;
+ CSession* session = ts_session_new(HOST, PORT, USER, PASS);
+ if (!session) {
+ fprintf(stderr, "[tree_example] ts_session_new returned NULL: %s\n", ts_get_last_error());
+ return 1;
+ }
+ if (ts_session_open(session) != TS_OK) {
+ fail("ts_session_open", session);
+ }
+
+ bool exists = false;
+ if (ts_session_check_timeseries_exists(session, path, &exists) != TS_OK) {
+ fail("ts_session_check_timeseries_exists", session);
+ }
+ if (exists) {
+ if (ts_session_delete_timeseries(session, path) != TS_OK) {
+ fail("ts_session_delete_timeseries (cleanup old)", session);
+ }
+ }
+ if (ts_session_create_timeseries(session, path, TS_TYPE_INT64, TS_ENCODING_RLE,
+ TS_COMPRESSION_SNAPPY) != TS_OK) {
+ fail("ts_session_create_timeseries", session);
+ }
+
+ const char* measurements[] = {"s0"};
+ const char* values[] = {"100"};
+ if (ts_session_insert_record_str(session, DEVICE, 1LL, 1, measurements, values) != TS_OK) {
+ fail("ts_session_insert_record_str", session);
+ }
+
+ CSessionDataSet* dataSet = NULL;
+ if (ts_session_execute_query(session, "select s0 from root.cdemo.d0", &dataSet) != TS_OK) {
+ fail("ts_session_execute_query", session);
+ }
+ if (!dataSet) {
+ fprintf(stderr, "[tree_example] dataSet is NULL\n");
+ ts_session_close(session);
+ ts_session_destroy(session);
+ return 1;
+ }
+ ts_dataset_set_fetch_size(dataSet, 1024);
+
+ int rows = 0;
+ while (ts_dataset_has_next(dataSet)) {
+ CRowRecord* record = ts_dataset_next(dataSet);
+ if (!record) {
+ break;
+ }
+ int64_t v = ts_row_record_get_int64(record, 0);
+ printf("[tree_example] row %d: s0 = %lld\n", rows, (long long)v);
+ ts_row_record_destroy(record);
+ rows++;
+ }
+ ts_dataset_destroy(dataSet);
+
+ printf("[tree_example] done, read %d row(s).\n", rows);
+
+ if (ts_session_delete_timeseries(session, path) != TS_OK) {
+ fail("ts_session_delete_timeseries", session);
+ }
+
+ ts_session_close(session);
+ ts_session_destroy(session);
+ return 0;
+}
diff --git a/example/pom.xml b/example/pom.xml
index a8415b04d0741..8abb5e30d54e1 100644
--- a/example/pom.xml
+++ b/example/pom.xml
@@ -85,7 +85,6 @@
with-cpp
client-cpp-example
- client-c-example
diff --git a/iotdb-client/client-cpp/CMakeLists.txt b/iotdb-client/client-cpp/CMakeLists.txt
new file mode 100644
index 0000000000000..a0d77a1dfc450
--- /dev/null
+++ b/iotdb-client/client-cpp/CMakeLists.txt
@@ -0,0 +1,184 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# =============================================================================
+# Apache IoTDB - C++ Session Client (top-level CMake build)
+# =============================================================================
+
+cmake_minimum_required(VERSION 3.15)
+project(iotdb_session CXX C)
+
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_CXX_EXTENSIONS OFF)
+set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+set(CMAKE_POLICY_DEFAULT_CMP0091 NEW)
+
+if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
+ set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
+endif()
+
+if(NOT MSVC)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -g -O2")
+endif()
+
+if(MSVC)
+ # /MD: matches default Visual Studio projects; CRT lives in the VC redistributable.
+ set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL")
+endif()
+
+option(WITH_SSL "Build with OpenSSL support" OFF)
+option(BUILD_TESTING "Build IT test executables" OFF)
+option(IOTDB_OFFLINE "Disable all network access during configure" OFF)
+
+set(IOTDB_DEPS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third-party"
+ CACHE PATH "Local tarball cache for third-party dependencies (lives under client-cpp/)")
+if(APPLE)
+ set(_iotdb_default_boost_version "1.84.0")
+else()
+ set(_iotdb_default_boost_version "1.60.0")
+endif()
+set(BOOST_VERSION "${_iotdb_default_boost_version}"
+ CACHE STRING "Boost version used when downloading / unpacking (Thrift build only)")
+set(THRIFT_VERSION "0.21.0"
+ CACHE STRING "Apache Thrift version used when downloading / building")
+
+if(WIN32)
+ set(IOTDB_OS_DEPS_DIR "${IOTDB_DEPS_DIR}/windows")
+elseif(APPLE)
+ set(IOTDB_OS_DEPS_DIR "${IOTDB_DEPS_DIR}/mac")
+else()
+ set(IOTDB_OS_DEPS_DIR "${IOTDB_DEPS_DIR}/linux")
+endif()
+file(MAKE_DIRECTORY "${IOTDB_OS_DEPS_DIR}")
+
+if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install"
+ CACHE PATH "Install prefix" FORCE)
+endif()
+
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
+
+include(FetchBoost) # -> BOOST_INCLUDE_DIR (Thrift build only)
+include(FetchBuildTools)
+if(WITH_SSL)
+ include(FetchOpenSSL)
+endif()
+include(FetchThrift)
+include(GenerateThriftSources)
+
+file(GLOB SESSION_PUBLIC_SRCS CONFIGURE_DEPENDS
+ "${CMAKE_CURRENT_SOURCE_DIR}/src/session/*.cpp")
+file(GLOB SESSION_RPC_SRCS CONFIGURE_DEPENDS
+ "${CMAKE_CURRENT_SOURCE_DIR}/src/rpc/*.cpp")
+
+add_library(iotdb_session SHARED
+ ${SESSION_PUBLIC_SRCS}
+ ${SESSION_RPC_SRCS}
+ ${THRIFT_GENERATED_SRCS})
+
+if(WIN32)
+ set_target_properties(iotdb_session PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
+endif()
+
+add_dependencies(iotdb_session iotdb_thrift_external iotdb_thrift_codegen)
+
+target_compile_definitions(iotdb_session PRIVATE THRIFT_STATIC_DEFINE IOTDB_BUILDING_SHARED)
+
+target_include_directories(iotdb_session
+ PUBLIC
+ $
+ $
+ PRIVATE
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/rpc
+ ${THRIFT_GEN_CPP_DIR}
+ ${THRIFT_INCLUDE_DIR}
+ $<$:${BOOST_INCLUDE_DIR}>)
+
+if(APPLE)
+ target_link_libraries(iotdb_session PRIVATE "-Wl,-force_load,${THRIFT_STATIC_LIB_PATH}")
+elseif(UNIX AND NOT MSVC)
+ # whole-archive pulls all Thrift objects into libiotdb_session.so; allow-multiple-definition
+ # avoids libgcc __morestack_* duplicate symbol errors on some GCC/toolchain combos.
+ target_link_libraries(iotdb_session PRIVATE
+ -Wl,--whole-archive
+ ${THRIFT_STATIC_LIB_PATH}
+ -Wl,--no-whole-archive
+ -Wl,--allow-multiple-definition)
+else()
+ target_link_libraries(iotdb_session PRIVATE iotdb_thrift_static)
+endif()
+
+if(WITH_SSL)
+ target_link_libraries(iotdb_session PUBLIC OpenSSL::SSL OpenSSL::Crypto)
+ target_compile_definitions(iotdb_session PUBLIC WITH_SSL=1)
+else()
+ target_compile_definitions(iotdb_session PUBLIC WITH_SSL=0)
+endif()
+
+if(UNIX)
+ target_link_libraries(iotdb_session PUBLIC pthread)
+endif()
+
+include(GNUInstallDirs)
+
+set(IOTDB_PUBLIC_HEADERS
+ Export.h
+ SessionConfig.h
+ Session.h
+ Common.h
+ Optional.h
+ Date.h
+ Status.h
+ Endpoint.h
+ SessionBuilder.h
+ AbstractSessionBuilder.h
+ TableSession.h
+ TableSessionBuilder.h
+ SessionC.h
+ SessionDataSet.h
+ DeviceID.h
+ Column.h
+ ColumnDecoder.h
+ TsBlock.h)
+
+# Windows: RUNTIME = iotdb_session.dll, ARCHIVE = import .lib (both under lib/ in the zip).
+install(TARGETS iotdb_session
+ RUNTIME DESTINATION lib
+ LIBRARY DESTINATION lib
+ ARCHIVE DESTINATION lib)
+
+foreach(_hdr IN LISTS IOTDB_PUBLIC_HEADERS)
+ install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/include/${_hdr}"
+ DESTINATION include)
+endforeach()
+
+if(BUILD_TESTING)
+ enable_testing()
+ add_subdirectory(test)
+endif()
+
+message(STATUS "iotdb_session configuration summary:")
+message(STATUS " WITH_SSL = ${WITH_SSL}")
+message(STATUS " BUILD_TESTING = ${BUILD_TESTING}")
+message(STATUS " IOTDB_OFFLINE = ${IOTDB_OFFLINE}")
+message(STATUS " IOTDB_DEPS_DIR = ${IOTDB_DEPS_DIR}")
+message(STATUS " BOOST_INCLUDE_DIR = ${BOOST_INCLUDE_DIR} (Thrift build only)")
+message(STATUS " THRIFT_INCLUDE_DIR = ${THRIFT_INCLUDE_DIR}")
+message(STATUS " THRIFT_STATIC_LIB = ${THRIFT_STATIC_LIB_PATH}")
+message(STATUS " THRIFT_EXECUTABLE = ${THRIFT_EXECUTABLE}")
+message(STATUS " CMAKE_INSTALL_PREFIX = ${CMAKE_INSTALL_PREFIX}")
diff --git a/iotdb-client/client-cpp/README.md b/iotdb-client/client-cpp/README.md
index 21e251d92a549..22543c743f272 100644
--- a/iotdb-client/client-cpp/README.md
+++ b/iotdb-client/client-cpp/README.md
@@ -18,182 +18,339 @@
under the License.
-->
-# Building C++ Client
+# Apache IoTDB C++ Client
-## Compile and Test:
+The C++ client is built by a single top-level `CMakeLists.txt` in this
+directory. The outer Maven POM is a thin wrapper that invokes CMake; you can
+also build the client standalone with just `cmake` if you don't have Maven
+available.
-### Compile
+## Build layout at a glance
-#### Unix
-To compile the cpp client, use the following command:
-`mvn clean package -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests`
-
-#### Windows
-To compile on Windows, please install Boost first and add following Maven
-settings:
```
--Dboost.include.dir=${your boost header folder} -Dboost.library.dir=${your boost lib (stage) folder}`
+iotdb-client/client-cpp/
+├── CMakeLists.txt # single entry point - manages everything
+├── cmake/ # helpers (FetchBoost / FetchThrift / ...)
+├── third-party/ # local tarball cache (one sub-dir per OS)
+│ ├── linux/ mac/ windows/
+├── src/include/ # public API headers (installed to include/)
+├── src/session/ # Session / Table / C API implementation (.cpp)
+├── src/rpc/ # Thrift RPC layer (private, not installed)
+├── test/ # Catch2-based integration tests
+└── pom.xml # Maven wrapper (cmake-maven-plugin)
```
-The thrift dependency that the cpp client uses is incompatible with MinGW, please use Visual
-Studio. It is highly recommended to use Visual Studio 2022 or later.
-
-##### Visual Studio 2022
-If you are using Visual Studio 2022, you can compile the cpp client with the following command:
-
+During configure CMake will, in order:
+
+1. Resolve Boost headers (`find_package` → local `third-party//` tarball →
+ download from `archives.boost.io` when not in offline mode).
+2. On Linux/macOS, ensure `m4` / `flex` / `bison` are available; if not,
+ build them from local tarballs into `build/tools/bin` (no `sudo`
+ required).
+3. Build a static Apache Thrift from source (tarball cache → download fallback).
+4. Run the produced `thrift` compiler on
+ `iotdb-protocol/thrift-{commons,datanode}/src/main/thrift/*.thrift`.
+5. Compile `iotdb_session` (the C/C++ session library) and, optionally,
+ the Catch2 integration test binaries.
+6. `cmake --install` lays out the SDK under `target/install/{include,lib}`,
+ which Maven's assembly step packages into a zip.
+
+## Build matrix
+
+| Goal | Command |
+|-------------------------------|--------------------------------------------------------------------------------------------------------|
+| Library only (Linux/macOS) | `mvn -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests package` |
+| Library only (Windows / MSVC) | `mvn -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests "-Dboost.include.dir=C:\boost_1_88_0" package` |
+| Library + ITs (Linux/macOS) | `mvn clean install -P with-cpp -pl distribution,iotdb-client/client-cpp -am` then `mvn -P with-cpp -pl iotdb-client/client-cpp -am verify` |
+| Direct CMake (no Maven) | `cmake -S iotdb-client/client-cpp -B build && cmake --build build --target install` |
+
+The Maven build sets `cmake.install.prefix` to `target/install/`. Output zips
+land at `iotdb-client/client-cpp/target/client-cpp--.zip`
+(with `include/` and `lib/` under `client-cpp--/` inside the zip),
+where `` defaults to the OS name (for example `linux-x86_64`) and
+can be overridden with `-Dclient.cpp.package.classifier=...` when building
+multiple toolchains on the same platform.
+
+### Release packages (CI)
+
+The [C++ Client package](../../.github/workflows/client-cpp-package.yml) workflow
+builds one zip per platform/toolchain. Pick the artifact that matches your
+deployment environment:
+
+| Target environment | Zip classifier (suffix) |
+|--------------------|-------------------------|
+| Linux x86_64, glibc ≥ 2.17 | `linux-x86_64-glibc217` |
+| Linux aarch64, glibc ≥ 2.17 | `linux-aarch64-glibc217` |
+| macOS x86_64 | `mac-x86_64` |
+| macOS arm64 | `mac-aarch64` |
+| Windows + Visual Studio 2017 | `windows-x86_64-vs2017` |
+| Windows + Visual Studio 2019 | `windows-x86_64-vs2019` |
+| Windows + Visual Studio 2022 | `windows-x86_64-vs2022` |
+| Windows + Visual Studio 2026 | `windows-x86_64-vs2026` |
+
+Example file name:
+`client-cpp-2.0.7-SNAPSHOT-linux-x86_64-glibc217.zip`.
+
+Thrift **0.21.0** is compiled from source during the CMake configure step (see
+`cmake/FetchThrift.cmake`). Older releases that used pre-built
+`iotdb-tools-thrift` Maven artifacts and `-Diotdb-tools-thrift.version=...`
+for glibc/MSVC compatibility apply only to the **legacy** client-cpp build;
+with the current CMake build, compatibility is determined by the **compiler
+and OS used to build** the SDK, not by that Maven property.
+
+### Local build for a specific classifier
+
+Linux x86_64 (glibc 2.17 baseline — use CentOS 7 + devtoolset-8, or any host
+whose glibc is ≤ your deployment target):
+
+```bash
+mvn -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests \
+ -Dclient.cpp.package.classifier=linux-x86_64-glibc217 package
```
-mvn clean package -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests
--D"boost.include.dir"="D:\boost_1_75_0" -D"boost.library.dir"="D:\boost_1_75_0\stage\lib"
-```
-
-##### Visual Studio 2019
-If you are using Visual Studio 2019, you can compile the cpp client with the following command:
-
-```
-mvn clean package -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests
--D"boost.include.dir"="D:\boost_1_75_0" -D"boost.library.dir"="D:\boost_1_75_0\stage\lib"
--Diotdb-tools-thrift.version=0.14.1.1-msvc142-SNAPSHOT -Dcmake.generator="Visual Studio 16 2019"
-```
-
-#### Visual Studio 2017 or older
-If you are using Visual Studio 2017 or older, the pre-built Thrift library is incompatible. You
-will have to compile the thrift library manually:
-
-1. Install the dependencies of Thrift:
-* flex http://gnuwin32.sourceforge.net/packages/flex.htm
-* bison http://gnuwin32.sourceforge.net/packages/bison.htm
-* openssl https://slproweb.com/products/Win32OpenSSL.html
-
-2. Clone the repository: https://github.com/apache/iotdb-bin-resources.
-3. Enter the "iotdb-tools-thrift" folder in the cloned repository; use the following command to
- compile the thrift library:
+Windows (match the Visual Studio version you use to build your application):
-`mvn install`
+```powershell
+# Visual Studio 2022 (default on recent Windows)
+mvn -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests package
-4. If you encounter a problem like "cannot find 'unistd.h'", please open the file
-"iotdb-bin-resources\iotdb-tools-thrift\target\build\compiler\cpp\thrift\thriftl.cc" and replace
-"#include " with "#include " and "#include "; then, rerun the command
- in the third step;
+# Visual Studio 2019
+mvn -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests `
+ -Dcmake.generator="Visual Studio 16 2019" `
+ -Dclient.cpp.package.classifier=windows-x86_64-vs2019 package
-5. Return to the cpp client repository and compile it with:
-
-```
-mvn clean package -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests
--D"boost.include.dir"="D:\boost_1_75_0" -D"boost.library.dir"="D:\boost_1_75_0\stage\lib"
+# Visual Studio 2017 (CMake uses -A x64 on Windows automatically)
+mvn -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests `
+ -Dcmake.generator="Visual Studio 15 2017" `
+ -Dclient.cpp.package.classifier=windows-x86_64-vs2017 package
```
+On Windows, the build passes `-DCMAKE_GENERATOR_PLATFORM=x64` so Visual Studio
+generators target **x64** (VS2017 otherwise defaults to Win32).
+
+## CMake options
+
+The table below lists CMake cache variables. When building through **Maven**,
+pass them as Maven properties (the POM maps them to `-D` options for CMake):
+
+| CMake variable | Maven property (`-D...`) |
+|----------------|--------------------------|
+| `WITH_SSL` | `with.ssl` (e.g. `-Dwith.ssl=ON`) |
+| `IOTDB_OFFLINE` | `iotdb.offline` |
+| `BUILD_TESTING` | `build.tests` |
+| `IOTDB_DEPS_DIR` | `iotdb.deps.dir` |
+| `BOOST_INCLUDEDIR` | `boost.include.dir` (legacy alias) |
+
+For a **standalone** `cmake` configure, pass `-DWITH_SSL=ON`, `-DIOTDB_OFFLINE=ON`,
+etc. directly.
+
+| Option | Default | Purpose |
+|-----------------------|----------------------------------|----------------------------------------------------------------------------------------------------------|
+| `WITH_SSL` | `OFF` | Link against OpenSSL. See *SSL* below. |
+| `BUILD_TESTING` | `OFF` (Maven sets `ON` for verify) | Build Catch2 IT executables. |
+| `IOTDB_OFFLINE` | `OFF` | Disallow any network access during configure. |
+| `IOTDB_DEPS_DIR` | `/third-party` | Override the local tarball cache directory. |
+| `BOOST_VERSION` | `1.60.0` (`1.84.0` on macOS) | Boost version that CMake will look for / download. |
+| `THRIFT_VERSION` | `0.21.0` | Apache Thrift version to build from source. |
+| `BOOST_ROOT` | (unset) | Existing Boost install to reuse, equivalent to `-Dboost.include.dir=...` from the legacy build. |
+| `OPENSSL_ROOT_DIR` | (unset) | Existing OpenSSL install when `WITH_SSL=ON`. |
+| `CMAKE_INSTALL_PREFIX`| `/install` | Install location. |
+
+## Online build (default)
+
+CMake will download any missing tarball at configure time. The first run is
+slow (≈100 MB download + a Thrift build); subsequent runs reuse the
+extracted artifacts under `build/_deps/`.
+
+```bash
+# Linux / macOS
+mvn -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests package
+
+# Windows (Developer Command Prompt for VS, PowerShell, or cmd)
+mvn -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests "-Dboost.include.dir=C:\boost_1_88_0" package
+```
-### Test
-First build IoTDB server together with the cpp client.
-
-Explicitly using "install" instead of package in order to be sure we're using libs built on this
-machine.
-
-`mvn clean install -P with-cpp -pl distribution,iotdb-client/client-cpp -am -DskipTests`
-
-After run verify
-
-`mvn clean verify -P with-cpp -pl iotdb-client/client-cpp -am`
-
-## Code Formatting
-
-We use `clang-format` as the only formatter for C++ code and trigger it through Maven Spotless.
-
-### Required version
-
-The version is pinned in the root `pom.xml` as property `clang.format.version` (same approach as Apache TsFile). Use **clang-format 17.0.6** locally so Spotless agrees with CI.
-
-**JDK for Maven:** the C++ `clangFormat` step is registered only when running Maven on **JDK 11 or newer** (see the `spotless-cpp` profile in this module and in `client-cpp-example`). The repository root still supports JDK 8 for Java builds, but `spotless:check` / `spotless:apply` for C++ will not apply the clang-format rules if you use JDK 8.
-
-### Install clang-format 17.0.6
-
-- Linux (Ubuntu): On **24.04+**, `sudo apt-get install -y clang-format-17`. On **22.04**, that package is not in the default archive; add the LLVM 17 repo with [apt.llvm.org](https://apt.llvm.org/) (e.g. `sudo ./llvm.sh 17`, as CI does). The script installs `clang-17` and related tools but **not** the `clang-format-17` package, so also run `sudo apt-get install -y clang-format-17`. Then point the default `clang-format` at 17.x (Spotless invokes `clang-format` on `PATH`; some releases default to another major version):
-
- `sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-17 100`
-
- `sudo update-alternatives --set clang-format /usr/bin/clang-format-17`
-
-- macOS: `brew install llvm@17`, then e.g. `ln -sf "$(brew --prefix llvm@17)/bin/clang-format" "$(brew --prefix)/bin/clang-format"` and/or put `$(brew --prefix llvm@17)/bin` on your `PATH`.
-
-- Windows: `choco install llvm --version=17.0.6 --force -y` (CI uses `--force` like TsFile so the expected LLVM is selected).
-
-### Validate only (no changes)
+## Offline build
-`./mvnw -P with-cpp -pl iotdb-client/client-cpp spotless:check`
+1. Pre-populate the platform-specific sub-directory under `third-party/`:
-`./mvnw -P with-cpp -pl example/client-cpp-example spotless:check`
+ | Platform | Required files |
+ |------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+ | `linux/` | `thrift-0.21.0.tar.gz`, `boost_1_60_0.tar.gz`, `m4-1.4.19.tar.gz`, `flex-2.6.4.tar.gz`, `bison-3.8.tar.gz` (and `openssl-3.5.0.tar.gz` when `WITH_SSL=ON`) |
+ | `mac/` | `thrift-0.21.0.tar.gz`, `boost_1_84_0.tar.gz` (newer Boost for Xcode/Clang; Apple ships m4/flex/bison; `openssl-3.5.0.tar.gz` optional) |
+ | `windows/` | `thrift-0.21.0.tar.gz`, `boost_1_60_0.tar.gz` (Boost headers only - no `b2` build required for `iotdb_session`) |
+
+ Reference URLs (the configure step uses the same):
+ - Apache Thrift 0.21.0:
+ - Boost 1.60.0:
+ - GNU m4 1.4.19:
+ - GNU flex 2.6.4:
+ - GNU bison 3.8:
+ - OpenSSL 3.5.0:
+
+2. Run the build with offline mode enabled:
+
+ ```bash
+ mvn -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests \
+ -Diotdb.offline=ON package
+ ```
+
+ or, going straight through CMake:
+
+ ```bash
+ cmake -S iotdb-client/client-cpp -B build -DIOTDB_OFFLINE=ON
+ cmake --build build --config Release --target install
+ ```
+
+CI environments can share a single cache by setting
+`-DIOTDB_DEPS_DIR=/path/to/cache` instead of copying tarballs around.
+
+## Platform-specific notes
+
+### Linux
+
+- Tested with GCC 7+ and Clang 9+. Anything that can compile Apache Thrift
+ 0.21.0 works.
+- Build deps that must already exist on the host (only required when
+ CMake auto-builds m4/flex/bison from tarball): `make`, `autoconf`,
+ `gcc`, plus the standard C/C++ toolchain. `sudo` is **not** required;
+ the helper tools install under `build/tools/`.
+- If you would rather use distro-provided tools (`apt install m4 flex
+ bison`), CMake will pick them up first.
+
+### macOS
+
+- Xcode Command Line Tools provide `m4`, `flex`, `bison`, and `make`,
+ so the auto-build path normally skips them.
+- Homebrew users can `brew install boost` to short-circuit `FetchBoost`.
+
+### Windows
+
+Visual Studio **2017, 2019, 2022, or 2026** is supported for building the SDK.
+Link your application against the zip built with the **same VS generation** you
+use for your project.
+
+Prerequisites:
+
+1. **Boost.** Download and extract
+
+ (any 1.60+ release will work). `iotdb_session` only needs Boost
+ headers, so running `bootstrap.bat` / `b2` is optional. Pass the
+ location with either `-Dboost.include.dir="C:\boost_1_88_0"` (Maven)
+ or `-DBOOST_ROOT="C:\boost_1_88_0"` (raw CMake).
+2. **flex / bison.** Install
+ and rename `win_flex.exe`→`flex.exe`, `win_bison.exe`→`bison.exe` on
+ `PATH`.
+3. **OpenSSL** *(only when `WITH_SSL=ON`)*: run the Win64 OpenSSL
+ installer from , then
+ pass `-DOPENSSL_ROOT_DIR=...` to CMake.
+
+On Windows the SDK ships as **`iotdb_session.dll`** plus an import library
+**`iotdb_session.lib`**, built with **`/MD`** (dynamic CRT, same as a
+default Visual Studio application). Thrift is linked into the DLL; users
+do not install separate Thrift headers or libraries. Place
+`iotdb_session.dll` next to your `.exe` or on `PATH`.
+
+Auto-building m4/flex/bison from tarball is **not** supported on Windows;
+the GNU autotools tarballs assume a POSIX shell environment.
+
+## SSL
+
+Both Thrift and `iotdb_session` build without OpenSSL by default. Enable
+SSL with `-Dwith.ssl=ON` (Maven) or `-DWITH_SSL=ON` (standalone CMake).
+CMake first calls `find_package(OpenSSL)`;
+if nothing is found, it falls back to:
+
+- **Linux / macOS** – use a local `openssl-.tar.gz` (or download it
+ when not in offline mode), configure with `no-shared`, install into
+ `build/_deps/openssl/install`, and link statically.
+- **Windows** – fail with a friendly message that points at the Win64
+ OpenSSL installer. Building OpenSSL from source via MSVC is out of scope.
+
+## Tests
+
+Maven binds `cmake-maven-plugin`'s `test` goal to the `integration-test`
+phase and runs `ctest`. `pre-integration-test` spawns a local IoTDB server
+from `distribution/target/.../sbin/start-standalone.{sh,bat}`, so make sure
+the distribution module is built first:
+
+```bash
+mvn clean install -P with-cpp -pl distribution,iotdb-client/client-cpp -am -DskipTests
+mvn -P with-cpp -pl iotdb-client/client-cpp -am verify
+```
-### Auto-fix formatting
+Running ctest directly (after a `mvn ... package` build) is also supported:
-`./mvnw -P with-cpp -pl iotdb-client/client-cpp spotless:apply`
+```bash
+cd iotdb-client/client-cpp/target/build/test
+ctest --output-on-failure
+```
-`./mvnw -P with-cpp -pl example/client-cpp-example spotless:apply`
+## Code formatting
-### Windows (PowerShell)
+We use `clang-format` (pinned by the root POM as `clang.format.version`)
+through Maven Spotless. **clang-format 17.0.6** is the version CI runs.
-PowerShell may treat a comma in `-pl` as an argument separator. Prefer the two commands above. If you need a single invocation, quote the whole `-pl` value, for example:
+```bash
+mvn -P with-cpp -pl iotdb-client/client-cpp spotless:check
+mvn -P with-cpp -pl iotdb-client/client-cpp spotless:apply
+```
-`./mvnw -P with-cpp "-pl=iotdb-client/client-cpp,example/client-cpp-example" spotless:check`
+On JDK 8 the C++ Spotless profile is skipped automatically (Spotless's
+clang-format integration requires Spotless 2.44+, which itself requires
+JDK 11+).
-## Package Hierarchy
+## Package layout
-If the compilation finishes successfully, the packaged zip file will be placed under
-"client-cpp/target/client-cpp-${project.version}-cpp-${os}.zip".
+A successful `mvn ... package` produces
+`target/client-cpp--.zip` with this layout:
-On macOS, the hierarchy of the package should look like this:
-```
-.
-+-- client
-| +-- include
-| +-- Session.h
-| +-- IClientRPCService.h
-| +-- client_types.h
-| +-- common_types.h
-| +-- thrift
-| +-- thrift_headers...
-| +-- lib
-| +-- Release
-| +-- libiotdb_session.dylib
-| +-- parser.dylib
-| +-- thriftmd.dylib
-| +-- tutorialgencpp.dylib
```
-
-## Using C++ Client:
+client-cpp--/
+├── include/
+│ ├── Session.h
+│ ├── SessionC.h
+│ └── ... (public API headers only; no Thrift/Boost)
+└── lib/
+ ├── libiotdb_session.{so,dylib} (Linux / macOS)
+ ├── iotdb_session.dll (Windows – runtime)
+ └── iotdb_session.lib (Windows – import library for linking)
```
-1. Put the zip file "client-cpp-${project.version}-cpp-${os}.zip" wherever you want;
-2. Unzip the archive using the following command, and then you can get the two directories
-mentioned above, the header file and the dynamic library:
- unzip client-cpp-${project.version}-cpp-${os}.zip
+Thrift is embedded inside `iotdb_session` on all platforms; it is not shipped
+as a separate install artifact.
-3. Write C++ code to call the operation interface of the cpp client to operate IoTDB,
- for detail interface information, please refer to the link: https://iotdb.apache.org/UserGuide/latest/API/Programming-Cpp-Native-API.html
+## Using the C++ client
- E.g:
- #include "include/Session.h"
+```cpp
+#include "Session.h"
#include
#include
int main() {
- std::cout << "open session" << std::endl;
- std::shared_ptr session(new Session("127.0.0.1", 6667, "root", "root"));
+ auto session = std::make_shared("127.0.0.1", 6667, "root", "root");
session->open(false);
-
- std::cout << "setStorageGroup: root.test01" << std::endl;
session->setStorageGroup("root.test01");
-
if (!session->checkTimeseriesExists("root.test01.d0.s0")) {
- session->createTimeseries("root.test01.d0.s0", TSDataType::INT64, TSEncoding::RLE, CompressionType::SNAPPY);
- std::cout << "create Timeseries: root.test01.d0.s0" << std::endl;
- }
-
- std::cout << "session close" << std::endl;
+ session->createTimeseries(
+ "root.test01.d0.s0",
+ TSDataType::INT64,
+ TSEncoding::RLE,
+ CompressionType::SNAPPY);
+ }
session->close();
}
+```
-4. Compile and execute
- clang++ -O2 user-cpp-code.cpp -liotdb_session -L/user-unzip-absolute-path/lib -Wl,-rpath /user-unzip-absolute-path/lib -std=c++11
- ./a.out
+Compile against the produced SDK:
+
+```bash
+clang++ -O2 user-cpp-code.cpp \
+ -I/path/to/sdk/include \
+ -L/path/to/sdk/lib \
+ -liotdb_session -lpthread \
+ -Wl,-rpath,/path/to/sdk/lib \
+ -std=c++11
```
+
+For full API documentation see the [C++ Native API guide](https://iotdb.apache.org/UserGuide/latest/API/Programming-Cpp-Native-API.html).
diff --git a/iotdb-client/client-cpp/cmake/FetchBoost.cmake b/iotdb-client/client-cpp/cmake/FetchBoost.cmake
new file mode 100644
index 0000000000000..d1ab9c18ae1b9
--- /dev/null
+++ b/iotdb-client/client-cpp/cmake/FetchBoost.cmake
@@ -0,0 +1,130 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# =============================================================================
+# FetchBoost.cmake
+#
+# Resolves the location of Boost headers needed at thrift / iotdb_session
+# compile time, in three stages:
+#
+# 1. Use system / user-provided Boost (find_package, BOOST_ROOT, etc.).
+# 2. Fall back to a local tarball under ${IOTDB_OS_DEPS_DIR}/.
+# 3. Otherwise download the tarball from archives.boost.io (unless
+# IOTDB_OFFLINE is ON).
+#
+# Output (cache) variables:
+# BOOST_INCLUDE_DIR - directory containing headers.
+# =============================================================================
+
+if(DEFINED BOOST_INCLUDE_DIR AND EXISTS "${BOOST_INCLUDE_DIR}/boost/version.hpp")
+ message(STATUS "[Boost] reusing cached BOOST_INCLUDE_DIR=${BOOST_INCLUDE_DIR}")
+ return()
+endif()
+
+# ---------------------------------------------------------------------------
+# Stage 1: find_package(Boost) - respects BOOST_ROOT / Boost_INCLUDE_DIR
+# ---------------------------------------------------------------------------
+find_package(Boost QUIET)
+if(Boost_FOUND AND Boost_INCLUDE_DIRS)
+ set(BOOST_INCLUDE_DIR "${Boost_INCLUDE_DIRS}" CACHE PATH "Boost include directory" FORCE)
+ message(STATUS "[Boost] using system Boost at ${BOOST_INCLUDE_DIR}")
+ return()
+endif()
+
+# Allow plain -DBOOST_INCLUDEDIR= / -DBoost_INCLUDE_DIR= as a fast path.
+foreach(_hint Boost_INCLUDE_DIR BOOST_INCLUDEDIR BOOST_ROOT)
+ if(DEFINED ${_hint})
+ set(_candidate "${${_hint}}")
+ if(EXISTS "${_candidate}/boost/version.hpp")
+ set(BOOST_INCLUDE_DIR "${_candidate}" CACHE PATH "Boost include directory" FORCE)
+ message(STATUS "[Boost] using hinted path ${BOOST_INCLUDE_DIR}")
+ return()
+ elseif(EXISTS "${_candidate}/include/boost/version.hpp")
+ set(BOOST_INCLUDE_DIR "${_candidate}/include" CACHE PATH "Boost include directory" FORCE)
+ message(STATUS "[Boost] using hinted path ${BOOST_INCLUDE_DIR}")
+ return()
+ endif()
+ endif()
+endforeach()
+
+# ---------------------------------------------------------------------------
+# Stage 2: local tarball cache
+# ---------------------------------------------------------------------------
+string(REPLACE "." "_" _boost_us "${BOOST_VERSION}")
+set(_boost_dirname "boost_${_boost_us}")
+set(_boost_tarname_gz "${_boost_dirname}.tar.gz")
+set(_boost_tarname_zip "${_boost_dirname}.zip")
+
+set(_boost_tarball "")
+foreach(_name IN ITEMS ${_boost_tarname_gz} ${_boost_tarname_zip})
+ if(EXISTS "${IOTDB_OS_DEPS_DIR}/${_name}")
+ set(_boost_tarball "${IOTDB_OS_DEPS_DIR}/${_name}")
+ break()
+ endif()
+endforeach()
+
+# ---------------------------------------------------------------------------
+# Stage 3: download
+# ---------------------------------------------------------------------------
+if(NOT _boost_tarball)
+ if(IOTDB_OFFLINE)
+ message(FATAL_ERROR
+ "[Boost] IOTDB_OFFLINE=ON but no Boost tarball found in "
+ "${IOTDB_OS_DEPS_DIR}. Expected one of: ${_boost_tarname_gz}, ${_boost_tarname_zip}.")
+ endif()
+
+ set(_boost_url "https://archives.boost.io/release/${BOOST_VERSION}/source/${_boost_tarname_gz}")
+ set(_boost_tarball "${IOTDB_OS_DEPS_DIR}/${_boost_tarname_gz}")
+ message(STATUS "[Boost] downloading ${_boost_url}")
+ file(DOWNLOAD "${_boost_url}" "${_boost_tarball}"
+ SHOW_PROGRESS
+ STATUS _boost_dl_status
+ TLS_VERIFY ON)
+ list(GET _boost_dl_status 0 _boost_dl_code)
+ if(NOT _boost_dl_code EQUAL 0)
+ list(GET _boost_dl_status 1 _boost_dl_msg)
+ file(REMOVE "${_boost_tarball}")
+ message(FATAL_ERROR "[Boost] download failed: ${_boost_dl_msg}")
+ endif()
+endif()
+
+# ---------------------------------------------------------------------------
+# Extract headers-only into ${CMAKE_BINARY_DIR}/_deps/boost
+# ---------------------------------------------------------------------------
+set(_boost_extract_dir "${CMAKE_BINARY_DIR}/_deps/boost")
+set(_boost_marker "${_boost_extract_dir}/.extracted-${BOOST_VERSION}")
+
+if(NOT EXISTS "${_boost_marker}")
+ file(REMOVE_RECURSE "${_boost_extract_dir}")
+ file(MAKE_DIRECTORY "${_boost_extract_dir}")
+ message(STATUS "[Boost] extracting ${_boost_tarball}")
+ file(ARCHIVE_EXTRACT
+ INPUT "${_boost_tarball}"
+ DESTINATION "${_boost_extract_dir}")
+ file(TOUCH "${_boost_marker}")
+endif()
+
+set(BOOST_INCLUDE_DIR "${_boost_extract_dir}/${_boost_dirname}"
+ CACHE PATH "Boost include directory" FORCE)
+
+if(NOT EXISTS "${BOOST_INCLUDE_DIR}/boost/version.hpp")
+ message(FATAL_ERROR
+ "[Boost] Could not locate boost/version.hpp after extraction. "
+ "Looked in: ${BOOST_INCLUDE_DIR}")
+endif()
+
+message(STATUS "[Boost] BOOST_INCLUDE_DIR = ${BOOST_INCLUDE_DIR}")
diff --git a/iotdb-client/client-cpp/cmake/FetchBuildTools.cmake b/iotdb-client/client-cpp/cmake/FetchBuildTools.cmake
new file mode 100644
index 0000000000000..f6031433a8e6f
--- /dev/null
+++ b/iotdb-client/client-cpp/cmake/FetchBuildTools.cmake
@@ -0,0 +1,240 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# =============================================================================
+# FetchBuildTools.cmake
+#
+# Apache Thrift's source build needs a working flex / bison toolchain (m4 too
+# on Unix). When the host already provides them on PATH we use them as-is.
+# Otherwise we provision them locally:
+#
+# * Linux / macOS - configure-make-install each tool from a tarball into
+# ${CMAKE_BINARY_DIR}/tools (no sudo required).
+# * Windows - extract the winflexbison zip and copy
+# win_flex.exe -> flex.exe, win_bison.exe -> bison.exe.
+#
+# Tarballs / zips are resolved with the standard three-stage pattern:
+# 1. ${IOTDB_OS_DEPS_DIR}/ (or any match for an optional GLOB)
+# 2. file(DOWNLOAD) when IOTDB_OFFLINE is OFF
+# 3. FATAL_ERROR otherwise
+# =============================================================================
+
+set(_tools_prefix "${CMAKE_BINARY_DIR}/tools")
+set(_tools_bin "${_tools_prefix}/bin")
+file(MAKE_DIRECTORY "${_tools_bin}")
+
+# Make sure any tool we install locally takes precedence over the system PATH
+# for the remainder of the configure step (and child ExternalProject calls).
+if(WIN32)
+ set(ENV{PATH} "${_tools_bin};$ENV{PATH}")
+else()
+ set(ENV{PATH} "${_tools_bin}:$ENV{PATH}")
+endif()
+
+set(M4_VERSION "1.4.19" CACHE STRING "GNU m4 version to build when missing")
+set(FLEX_VERSION "2.6.4" CACHE STRING "GNU flex version to build when missing")
+set(BISON_VERSION "3.8" CACHE STRING "GNU bison version to build when missing")
+set(WINFLEXBISON_VERSION "2.5.25"
+ CACHE STRING "winflexbison version to download when no local zip is present")
+
+set(_m4_url "https://ftp.gnu.org/gnu/m4/m4-${M4_VERSION}.tar.gz")
+set(_flex_url "https://github.com/westes/flex/releases/download/v${FLEX_VERSION}/flex-${FLEX_VERSION}.tar.gz")
+set(_bison_url "https://ftp.gnu.org/gnu/bison/bison-${BISON_VERSION}.tar.gz")
+set(_winflexbison_url
+ "https://github.com/lexxmark/winflexbison/releases/download/v${WINFLEXBISON_VERSION}/win_flex_bison-${WINFLEXBISON_VERSION}.zip")
+set(_winflexbison_filename "win_flex_bison-${WINFLEXBISON_VERSION}.zip")
+
+include(ProcessorCount)
+ProcessorCount(_jobs)
+if(_jobs LESS 1)
+ set(_jobs 1)
+endif()
+
+# Resolve tarball: prefer the exact filename in ${IOTDB_OS_DEPS_DIR}/, then
+# any path matching GLOB_PATTERN (caller-supplied wildcard for relaxed naming,
+# e.g. win_flex_bison*.zip), and finally fall back to a download.
+function(_iotdb_resolve_tarball OUT_VAR FILENAME URL)
+ cmake_parse_arguments(ARG "" "GLOB_PATTERN" "" ${ARGN})
+
+ set(_local "${IOTDB_OS_DEPS_DIR}/${FILENAME}")
+ if(EXISTS "${_local}")
+ set(${OUT_VAR} "${_local}" PARENT_SCOPE)
+ return()
+ endif()
+
+ if(ARG_GLOB_PATTERN)
+ file(GLOB _matches "${IOTDB_OS_DEPS_DIR}/${ARG_GLOB_PATTERN}")
+ if(_matches)
+ list(GET _matches 0 _hit)
+ message(STATUS "[BuildTools] reusing ${_hit}")
+ set(${OUT_VAR} "${_hit}" PARENT_SCOPE)
+ return()
+ endif()
+ endif()
+
+ if(IOTDB_OFFLINE)
+ set(_hint "${FILENAME}")
+ if(ARG_GLOB_PATTERN)
+ set(_hint "${FILENAME} (or any ${ARG_GLOB_PATTERN})")
+ endif()
+ message(FATAL_ERROR
+ "[BuildTools] IOTDB_OFFLINE=ON but ${_hint} is missing in "
+ "${IOTDB_OS_DEPS_DIR}.")
+ endif()
+
+ message(STATUS "[BuildTools] downloading ${URL}")
+ file(DOWNLOAD "${URL}" "${_local}" SHOW_PROGRESS STATUS _st TLS_VERIFY ON)
+ list(GET _st 0 _code)
+ if(NOT _code EQUAL 0)
+ list(GET _st 1 _msg)
+ file(REMOVE "${_local}")
+ message(FATAL_ERROR "[BuildTools] download failed for ${FILENAME}: ${_msg}")
+ endif()
+ set(${OUT_VAR} "${_local}" PARENT_SCOPE)
+endfunction()
+
+# Configure-make-install from into ${_tools_prefix}.
+function(_iotdb_build_autotools NAME TARBALL EXTRACTED_DIRNAME)
+ set(_src_root "${CMAKE_BINARY_DIR}/_deps/${NAME}")
+ set(_marker "${_tools_prefix}/.${NAME}-installed")
+ if(EXISTS "${_marker}")
+ return()
+ endif()
+ file(REMOVE_RECURSE "${_src_root}")
+ file(MAKE_DIRECTORY "${_src_root}")
+ message(STATUS "[BuildTools] extracting ${TARBALL}")
+ file(ARCHIVE_EXTRACT INPUT "${TARBALL}" DESTINATION "${_src_root}")
+ set(_src "${_src_root}/${EXTRACTED_DIRNAME}")
+ if(NOT EXISTS "${_src}/configure")
+ message(FATAL_ERROR
+ "[BuildTools] expected configure script at ${_src}/configure")
+ endif()
+ message(STATUS "[BuildTools] building ${NAME} -> ${_tools_prefix}")
+ execute_process(
+ COMMAND ./configure --prefix=${_tools_prefix}
+ WORKING_DIRECTORY "${_src}"
+ RESULT_VARIABLE _rc)
+ if(NOT _rc EQUAL 0)
+ message(FATAL_ERROR "[BuildTools] configure failed for ${NAME}")
+ endif()
+ execute_process(
+ COMMAND make -j${_jobs}
+ WORKING_DIRECTORY "${_src}"
+ RESULT_VARIABLE _rc)
+ if(NOT _rc EQUAL 0)
+ message(FATAL_ERROR "[BuildTools] make failed for ${NAME}")
+ endif()
+ execute_process(
+ COMMAND make install
+ WORKING_DIRECTORY "${_src}"
+ RESULT_VARIABLE _rc)
+ if(NOT _rc EQUAL 0)
+ message(FATAL_ERROR "[BuildTools] make install failed for ${NAME}")
+ endif()
+ file(TOUCH "${_marker}")
+endfunction()
+
+# =============================================================================
+# Windows branch - winflexbison
+# =============================================================================
+if(WIN32)
+ # Stage 1: pick up an existing flex/bison if the host already provides it.
+ find_program(FLEX_EXECUTABLE NAMES flex win_flex)
+ find_program(BISON_EXECUTABLE NAMES bison win_bison)
+
+ if(FLEX_EXECUTABLE AND BISON_EXECUTABLE)
+ message(STATUS "[BuildTools] using system flex = ${FLEX_EXECUTABLE}")
+ message(STATUS "[BuildTools] using system bison = ${BISON_EXECUTABLE}")
+ set(IOTDB_LOCAL_TOOLS_BIN "${_tools_bin}" CACHE INTERNAL "")
+ return()
+ endif()
+
+ # Stage 2/3: resolve and extract the winflexbison zip into _tools_bin.
+ _iotdb_resolve_tarball(_wfb_zip
+ "${_winflexbison_filename}"
+ "${_winflexbison_url}"
+ GLOB_PATTERN "win_flex_bison*.zip")
+
+ set(_wfb_marker "${_tools_bin}/.winflexbison-installed")
+ if(NOT EXISTS "${_wfb_marker}")
+ message(STATUS "[BuildTools] extracting ${_wfb_zip}")
+ file(ARCHIVE_EXTRACT INPUT "${_wfb_zip}" DESTINATION "${_tools_bin}")
+
+ if(NOT EXISTS "${_tools_bin}/win_flex.exe" OR NOT EXISTS "${_tools_bin}/win_bison.exe")
+ message(FATAL_ERROR
+ "[BuildTools] win_flex.exe / win_bison.exe not found after "
+ "extracting ${_wfb_zip} into ${_tools_bin}.")
+ endif()
+
+ # Copy with renamed targets so thrift's CMakeLists sees flex/bison.
+ execute_process(COMMAND ${CMAKE_COMMAND} -E copy
+ "${_tools_bin}/win_flex.exe" "${_tools_bin}/flex.exe"
+ RESULT_VARIABLE _rc)
+ if(NOT _rc EQUAL 0)
+ message(FATAL_ERROR "[BuildTools] failed to copy win_flex.exe -> flex.exe")
+ endif()
+ execute_process(COMMAND ${CMAKE_COMMAND} -E copy
+ "${_tools_bin}/win_bison.exe" "${_tools_bin}/bison.exe"
+ RESULT_VARIABLE _rc)
+ if(NOT _rc EQUAL 0)
+ message(FATAL_ERROR "[BuildTools] failed to copy win_bison.exe -> bison.exe")
+ endif()
+ file(TOUCH "${_wfb_marker}")
+ endif()
+
+ find_program(FLEX_EXECUTABLE flex PATHS "${_tools_bin}" NO_DEFAULT_PATH REQUIRED)
+ find_program(BISON_EXECUTABLE bison PATHS "${_tools_bin}" NO_DEFAULT_PATH REQUIRED)
+
+ message(STATUS "[BuildTools] flex = ${FLEX_EXECUTABLE}")
+ message(STATUS "[BuildTools] bison = ${BISON_EXECUTABLE}")
+ set(IOTDB_LOCAL_TOOLS_BIN "${_tools_bin}" CACHE INTERNAL "")
+ return()
+endif()
+
+# =============================================================================
+# Linux / macOS branch - m4 / flex / bison from autotools tarballs
+# =============================================================================
+
+# m4 (flex/bison both depend on this)
+find_program(M4_EXECUTABLE m4)
+if(NOT M4_EXECUTABLE)
+ _iotdb_resolve_tarball(_m4_tarball "m4-${M4_VERSION}.tar.gz" "${_m4_url}")
+ _iotdb_build_autotools(m4 "${_m4_tarball}" "m4-${M4_VERSION}")
+ find_program(M4_EXECUTABLE m4 PATHS "${_tools_bin}" NO_DEFAULT_PATH REQUIRED)
+endif()
+message(STATUS "[BuildTools] m4 = ${M4_EXECUTABLE}")
+
+# flex
+find_program(FLEX_EXECUTABLE flex)
+if(NOT FLEX_EXECUTABLE)
+ _iotdb_resolve_tarball(_flex_tarball "flex-${FLEX_VERSION}.tar.gz" "${_flex_url}")
+ _iotdb_build_autotools(flex "${_flex_tarball}" "flex-${FLEX_VERSION}")
+ find_program(FLEX_EXECUTABLE flex PATHS "${_tools_bin}" NO_DEFAULT_PATH REQUIRED)
+endif()
+message(STATUS "[BuildTools] flex = ${FLEX_EXECUTABLE}")
+
+# bison
+find_program(BISON_EXECUTABLE bison)
+if(NOT BISON_EXECUTABLE)
+ _iotdb_resolve_tarball(_bison_tarball "bison-${BISON_VERSION}.tar.gz" "${_bison_url}")
+ _iotdb_build_autotools(bison "${_bison_tarball}" "bison-${BISON_VERSION}")
+ find_program(BISON_EXECUTABLE bison PATHS "${_tools_bin}" NO_DEFAULT_PATH REQUIRED)
+endif()
+message(STATUS "[BuildTools] bison = ${BISON_EXECUTABLE}")
+
+# Expose the bin dir for downstream ExternalProject_Add calls.
+set(IOTDB_LOCAL_TOOLS_BIN "${_tools_bin}" CACHE INTERNAL "")
diff --git a/iotdb-client/client-cpp/cmake/FetchOpenSSL.cmake b/iotdb-client/client-cpp/cmake/FetchOpenSSL.cmake
new file mode 100644
index 0000000000000..575e2803f2bd4
--- /dev/null
+++ b/iotdb-client/client-cpp/cmake/FetchOpenSSL.cmake
@@ -0,0 +1,121 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# =============================================================================
+# FetchOpenSSL.cmake (only included when WITH_SSL=ON)
+#
+# Resolution order:
+# 1. find_package(OpenSSL) - any system / vendor install is taken as-is.
+# 2. On Linux/macOS:
+# use tarball ${IOTDB_OS_DEPS_DIR}/openssl-${OPENSSL_VERSION}.tar.gz
+# or download from openssl.org when not in offline mode, then
+# ./Configure && make && make install_sw into ${CMAKE_BINARY_DIR}/_deps/openssl.
+# 3. On Windows: emit a FATAL_ERROR with instructions to run the bundled
+# Win64OpenSSL installer (or any other prebuilt OpenSSL); building
+# OpenSSL from source on MSVC is out of scope.
+#
+# Side effects:
+# Defines imported targets OpenSSL::SSL / OpenSSL::Crypto via find_package
+# so callers can just link against them.
+# =============================================================================
+
+set(OPENSSL_VERSION "3.5.0" CACHE STRING "OpenSSL version to fetch when missing")
+
+find_package(OpenSSL QUIET)
+if(OpenSSL_FOUND)
+ message(STATUS "[OpenSSL] using system OpenSSL ${OPENSSL_VERSION_MAJOR}.${OPENSSL_VERSION_MINOR}")
+ return()
+endif()
+
+if(WIN32)
+ message(FATAL_ERROR
+ "[OpenSSL] WITH_SSL=ON but no OpenSSL was found on Windows. "
+ "Please run third-party/windows/Win64OpenSSL-3_5_0.exe (or any "
+ "OpenSSL installer), then re-run the configure step with "
+ "-DOPENSSL_ROOT_DIR=.")
+endif()
+
+# --- Linux / macOS fallback: build from source ---------------------------
+set(_ossl_tarname "openssl-${OPENSSL_VERSION}.tar.gz")
+set(_ossl_tarball "${IOTDB_OS_DEPS_DIR}/${_ossl_tarname}")
+
+if(NOT EXISTS "${_ossl_tarball}")
+ if(IOTDB_OFFLINE)
+ message(FATAL_ERROR
+ "[OpenSSL] IOTDB_OFFLINE=ON but ${_ossl_tarname} is missing in ${IOTDB_OS_DEPS_DIR}.")
+ endif()
+ set(_ossl_url "https://www.openssl.org/source/${_ossl_tarname}")
+ message(STATUS "[OpenSSL] downloading ${_ossl_url}")
+ file(DOWNLOAD "${_ossl_url}" "${_ossl_tarball}"
+ SHOW_PROGRESS TLS_VERIFY ON STATUS _st)
+ list(GET _st 0 _code)
+ if(NOT _code EQUAL 0)
+ list(GET _st 1 _msg)
+ file(REMOVE "${_ossl_tarball}")
+ message(FATAL_ERROR "[OpenSSL] download failed: ${_msg}")
+ endif()
+endif()
+
+set(_ossl_root "${CMAKE_BINARY_DIR}/_deps/openssl")
+set(_ossl_src "${_ossl_root}/src/openssl-${OPENSSL_VERSION}")
+set(_ossl_inst "${_ossl_root}/install")
+set(_ossl_stamp "${_ossl_root}/.built-${OPENSSL_VERSION}")
+
+if(NOT EXISTS "${_ossl_stamp}")
+ file(REMOVE_RECURSE "${_ossl_root}/src")
+ file(MAKE_DIRECTORY "${_ossl_root}/src")
+ message(STATUS "[OpenSSL] extracting ${_ossl_tarball}")
+ file(ARCHIVE_EXTRACT INPUT "${_ossl_tarball}" DESTINATION "${_ossl_root}/src")
+
+ include(ProcessorCount)
+ ProcessorCount(_jobs)
+ if(_jobs LESS 1)
+ set(_jobs 1)
+ endif()
+
+ message(STATUS "[OpenSSL] configuring -> ${_ossl_inst}")
+ execute_process(
+ COMMAND ./Configure --prefix=${_ossl_inst} --openssldir=${_ossl_inst}/ssl no-shared
+ WORKING_DIRECTORY "${_ossl_src}"
+ RESULT_VARIABLE _rc)
+ if(NOT _rc EQUAL 0)
+ message(FATAL_ERROR "[OpenSSL] Configure failed (rc=${_rc})")
+ endif()
+
+ message(STATUS "[OpenSSL] building (-j${_jobs})")
+ execute_process(
+ COMMAND make -j${_jobs}
+ WORKING_DIRECTORY "${_ossl_src}"
+ RESULT_VARIABLE _rc)
+ if(NOT _rc EQUAL 0)
+ message(FATAL_ERROR "[OpenSSL] make failed (rc=${_rc})")
+ endif()
+
+ execute_process(
+ COMMAND make install_sw
+ WORKING_DIRECTORY "${_ossl_src}"
+ RESULT_VARIABLE _rc)
+ if(NOT _rc EQUAL 0)
+ message(FATAL_ERROR "[OpenSSL] make install_sw failed (rc=${_rc})")
+ endif()
+ file(TOUCH "${_ossl_stamp}")
+endif()
+
+set(OPENSSL_ROOT_DIR "${_ossl_inst}" CACHE PATH "OpenSSL root" FORCE)
+set(OPENSSL_USE_STATIC_LIBS ON)
+find_package(OpenSSL REQUIRED)
+message(STATUS "[OpenSSL] built locally at ${OPENSSL_ROOT_DIR}")
diff --git a/iotdb-client/client-cpp/cmake/FetchThrift.cmake b/iotdb-client/client-cpp/cmake/FetchThrift.cmake
new file mode 100644
index 0000000000000..390c031ff2203
--- /dev/null
+++ b/iotdb-client/client-cpp/cmake/FetchThrift.cmake
@@ -0,0 +1,260 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# =============================================================================
+# FetchThrift.cmake
+#
+# Downloads (or uses a local copy of) the Apache Thrift source tarball and
+# builds it from source as a static-only, runtime-and-compiler artifact. The
+# build runs at configure time so the thrift compiler is available for the
+# code generation step that follows.
+#
+# Exported variables:
+# THRIFT_EXECUTABLE - path to the thrift binary that just got built
+# THRIFT_INCLUDE_DIR - include directory containing
+# THRIFT_STATIC_LIB_PATH- path to libthrift.a / thriftmd.lib
+# THRIFT_RUNTIME_LIB_DIR- directory containing the static thrift library
+# (and any other build artifacts you may want to
+# bundle with the SDK)
+#
+# Imported targets:
+# iotdb_thrift_static - INTERFACE-compatible IMPORTED target that
+# propagates include dirs and the static lib.
+# iotdb_thrift_external - phony custom target representing the build
+# (use add_dependencies( iotdb_thrift_external)
+# to ensure the thrift build runs first).
+# =============================================================================
+
+include(ExternalProject)
+
+set(_thrift_dirname "thrift-${THRIFT_VERSION}")
+set(_thrift_tarname "${_thrift_dirname}.tar.gz")
+
+# ---------------------------------------------------------------------------
+# Resolve tarball (local cache -> download)
+# ---------------------------------------------------------------------------
+set(_thrift_tarball "${IOTDB_OS_DEPS_DIR}/${_thrift_tarname}")
+if(NOT EXISTS "${_thrift_tarball}")
+ if(IOTDB_OFFLINE)
+ message(FATAL_ERROR
+ "[Thrift] IOTDB_OFFLINE=ON but ${_thrift_tarname} is missing in "
+ "${IOTDB_OS_DEPS_DIR}.")
+ endif()
+ set(_thrift_url "https://archive.apache.org/dist/thrift/${THRIFT_VERSION}/${_thrift_tarname}")
+ message(STATUS "[Thrift] downloading ${_thrift_url}")
+ file(DOWNLOAD "${_thrift_url}" "${_thrift_tarball}"
+ SHOW_PROGRESS TLS_VERIFY ON STATUS _thrift_dl)
+ list(GET _thrift_dl 0 _code)
+ if(NOT _code EQUAL 0)
+ list(GET _thrift_dl 1 _msg)
+ file(REMOVE "${_thrift_tarball}")
+ message(FATAL_ERROR "[Thrift] download failed: ${_msg}")
+ endif()
+endif()
+
+# ---------------------------------------------------------------------------
+# Extract once into ${CMAKE_BINARY_DIR}/_deps/thrift/src
+# ---------------------------------------------------------------------------
+set(_thrift_root "${CMAKE_BINARY_DIR}/_deps/thrift")
+set(_thrift_src "${_thrift_root}/src/${_thrift_dirname}")
+set(_thrift_build "${_thrift_root}/build")
+set(_thrift_install "${_thrift_root}/install")
+set(_thrift_marker "${_thrift_root}/.extracted-${THRIFT_VERSION}")
+
+if(NOT EXISTS "${_thrift_marker}")
+ file(REMOVE_RECURSE "${_thrift_root}/src")
+ file(MAKE_DIRECTORY "${_thrift_root}/src")
+ message(STATUS "[Thrift] extracting ${_thrift_tarball}")
+ file(ARCHIVE_EXTRACT INPUT "${_thrift_tarball}"
+ DESTINATION "${_thrift_root}/src")
+ file(TOUCH "${_thrift_marker}")
+endif()
+
+if(NOT EXISTS "${_thrift_src}/CMakeLists.txt")
+ message(FATAL_ERROR
+ "[Thrift] could not find ${_thrift_src}/CMakeLists.txt after "
+ "extracting ${_thrift_tarball}.")
+endif()
+
+# ---------------------------------------------------------------------------
+# ExternalProject_Add: build thrift at *configure* time so the produced
+# binary / library can immediately drive code generation and linking.
+# ---------------------------------------------------------------------------
+set(_thrift_cmake_args
+ # CMake 4.x rejects Thrift 0.21's cmake_minimum_required(3.0); set policy first.
+ "-DCMAKE_POLICY_VERSION_MINIMUM=3.5"
+ "-DCMAKE_INSTALL_PREFIX=${_thrift_install}"
+ "-DCMAKE_BUILD_TYPE=Release"
+ "-DBUILD_JAVA=OFF"
+ "-DBUILD_NODEJS=OFF"
+ "-DBUILD_JAVASCRIPT=OFF"
+ "-DBUILD_PYTHON=OFF"
+ "-DBUILD_TESTING=OFF"
+ "-DBUILD_TUTORIALS=OFF"
+ "-DBUILD_SHARED_LIBS=OFF"
+ "-DWITH_SHARED_LIB=OFF"
+ "-DWITH_STATIC_LIB=ON"
+ "-DCMAKE_POSITION_INDEPENDENT_CODE=ON"
+ "-DCMAKE_POLICY_DEFAULT_CMP0091=NEW"
+ "-DCMAKE_CXX_STANDARD=11")
+
+if(BOOST_INCLUDE_DIR)
+ list(APPEND _thrift_cmake_args
+ "-DBoost_INCLUDE_DIR=${BOOST_INCLUDE_DIR}"
+ "-DBOOST_INCLUDEDIR=${BOOST_INCLUDE_DIR}")
+endif()
+
+if(MSVC)
+ list(APPEND _thrift_cmake_args
+ "-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDLL")
+else()
+ list(APPEND _thrift_cmake_args
+ "-DCMAKE_C_FLAGS=-fPIC"
+ "-DCMAKE_CXX_FLAGS=-fPIC")
+endif()
+
+if(WITH_SSL)
+ list(APPEND _thrift_cmake_args "-DWITH_OPENSSL=ON")
+else()
+ list(APPEND _thrift_cmake_args "-DWITH_OPENSSL=OFF")
+endif()
+
+# Run the ExternalProject build immediately so the thrift compiler is
+# available for the subsequent code-generation step. We do this by
+# invoking cmake twice via execute_process and only register a phony
+# ExternalProject for dependency ordering.
+
+set(_thrift_stamp "${_thrift_build}/.built-${THRIFT_VERSION}-mdll")
+if(NOT EXISTS "${_thrift_stamp}")
+ file(MAKE_DIRECTORY "${_thrift_build}")
+ message(STATUS "[Thrift] configuring ${_thrift_dirname}")
+
+ # When we built m4/flex/bison locally, make sure CMake passes the
+ # updated PATH down to the nested cmake invocation.
+ if(IOTDB_LOCAL_TOOLS_BIN)
+ set(_thrift_env "PATH=${IOTDB_LOCAL_TOOLS_BIN}:$ENV{PATH}")
+ endif()
+
+ if(CMAKE_GENERATOR_PLATFORM)
+ set(_gen_platform_arg "-A" "${CMAKE_GENERATOR_PLATFORM}")
+ else()
+ set(_gen_platform_arg "")
+ endif()
+
+ execute_process(
+ COMMAND ${CMAKE_COMMAND}
+ -G "${CMAKE_GENERATOR}"
+ ${_gen_platform_arg}
+ ${_thrift_cmake_args}
+ "${_thrift_src}"
+ WORKING_DIRECTORY "${_thrift_build}"
+ RESULT_VARIABLE _rc)
+ if(NOT _rc EQUAL 0)
+ message(FATAL_ERROR "[Thrift] configure step failed (rc=${_rc})")
+ endif()
+
+ message(STATUS "[Thrift] building (Release)")
+ execute_process(
+ COMMAND ${CMAKE_COMMAND} --build . --config Release --target install
+ WORKING_DIRECTORY "${_thrift_build}"
+ RESULT_VARIABLE _rc)
+ if(NOT _rc EQUAL 0)
+ message(FATAL_ERROR "[Thrift] build/install step failed (rc=${_rc})")
+ endif()
+ file(TOUCH "${_thrift_stamp}")
+endif()
+
+# ---------------------------------------------------------------------------
+# Locate produced artifacts
+# ---------------------------------------------------------------------------
+set(THRIFT_INCLUDE_DIR "${_thrift_install}/include" CACHE PATH "" FORCE)
+
+# Thrift binary
+if(WIN32)
+ find_program(THRIFT_EXECUTABLE
+ NAMES thrift
+ HINTS "${_thrift_install}/bin" "${_thrift_build}/bin/Release"
+ "${_thrift_build}/compiler/cpp/Release"
+ "${_thrift_build}/compiler/cpp/bin/Release"
+ NO_DEFAULT_PATH)
+else()
+ find_program(THRIFT_EXECUTABLE
+ NAMES thrift
+ HINTS "${_thrift_install}/bin"
+ "${_thrift_build}/bin"
+ "${_thrift_build}/compiler/cpp/bin"
+ "${_thrift_build}/compiler/cpp"
+ NO_DEFAULT_PATH)
+endif()
+
+if(NOT THRIFT_EXECUTABLE)
+ message(FATAL_ERROR
+ "[Thrift] could not find the thrift binary under ${_thrift_install} or ${_thrift_build}")
+endif()
+message(STATUS "[Thrift] THRIFT_EXECUTABLE = ${THRIFT_EXECUTABLE}")
+
+# Thrift static library (search a few standard install/lib locations).
+set(_thrift_libname_candidates)
+if(MSVC)
+ list(APPEND _thrift_libname_candidates thriftmd.lib thriftmt.lib thrift.lib)
+else()
+ list(APPEND _thrift_libname_candidates libthrift.a)
+endif()
+
+set(THRIFT_STATIC_LIB_PATH "")
+foreach(_dir
+ "${_thrift_install}/lib"
+ "${_thrift_install}/lib64"
+ "${_thrift_build}/lib"
+ "${_thrift_build}/lib/Release"
+ "${_thrift_build}/lib/release")
+ if(THRIFT_STATIC_LIB_PATH)
+ break()
+ endif()
+ foreach(_n ${_thrift_libname_candidates})
+ if(EXISTS "${_dir}/${_n}")
+ set(THRIFT_STATIC_LIB_PATH "${_dir}/${_n}")
+ set(THRIFT_RUNTIME_LIB_DIR "${_dir}")
+ break()
+ endif()
+ endforeach()
+endforeach()
+
+if(NOT THRIFT_STATIC_LIB_PATH)
+ message(FATAL_ERROR
+ "[Thrift] could not locate the thrift static library under ${_thrift_install}/lib")
+endif()
+message(STATUS "[Thrift] THRIFT_STATIC_LIB_PATH = ${THRIFT_STATIC_LIB_PATH}")
+
+# Cache as well so subsequent reconfigures keep the same values.
+set(THRIFT_STATIC_LIB_PATH "${THRIFT_STATIC_LIB_PATH}" CACHE FILEPATH "" FORCE)
+set(THRIFT_RUNTIME_LIB_DIR "${THRIFT_RUNTIME_LIB_DIR}" CACHE PATH "" FORCE)
+
+# ---------------------------------------------------------------------------
+# Imported target wrapping the static library.
+# ---------------------------------------------------------------------------
+if(NOT TARGET iotdb_thrift_static)
+ add_library(iotdb_thrift_static STATIC IMPORTED GLOBAL)
+ set_target_properties(iotdb_thrift_static PROPERTIES
+ IMPORTED_LOCATION "${THRIFT_STATIC_LIB_PATH}"
+ INTERFACE_INCLUDE_DIRECTORIES "${THRIFT_INCLUDE_DIR}")
+endif()
+
+# Phony target so downstream code can express ordering deps.
+if(NOT TARGET iotdb_thrift_external)
+ add_custom_target(iotdb_thrift_external ALL)
+endif()
diff --git a/iotdb-client/client-cpp/cmake/GenerateThriftSources.cmake b/iotdb-client/client-cpp/cmake/GenerateThriftSources.cmake
new file mode 100644
index 0000000000000..6a3685af45847
--- /dev/null
+++ b/iotdb-client/client-cpp/cmake/GenerateThriftSources.cmake
@@ -0,0 +1,126 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# =============================================================================
+# GenerateThriftSources.cmake
+#
+# Generates C++ stubs from the iotdb-protocol Thrift files using the thrift
+# compiler that FetchThrift just built.
+#
+# Inputs (resolved relative to the workspace root):
+# iotdb-protocol/thrift-commons/src/main/thrift/common.thrift
+# iotdb-protocol/thrift-datanode/src/main/thrift/client.thrift
+#
+# Outputs:
+# ${THRIFT_GEN_CPP_DIR}/*.{h,cpp} - generated C++ sources
+# THRIFT_GENERATED_SRCS - list of *.cpp files for linking
+# THRIFT_GENERATED_HDRS - list of *.h files (informational)
+# =============================================================================
+
+if(NOT THRIFT_EXECUTABLE)
+ message(FATAL_ERROR "[GenThrift] THRIFT_EXECUTABLE not set - did FetchThrift run first?")
+endif()
+
+# Anchor the source-of-truth .thrift files via the workspace root. The CMake
+# project lives at /iotdb-client/client-cpp/, so the workspace root is
+# two levels up.
+get_filename_component(_workspace_root "${CMAKE_CURRENT_SOURCE_DIR}/../.." ABSOLUTE)
+
+set(_common_thrift "${_workspace_root}/iotdb-protocol/thrift-commons/src/main/thrift/common.thrift")
+set(_client_thrift "${_workspace_root}/iotdb-protocol/thrift-datanode/src/main/thrift/client.thrift")
+
+foreach(_f IN ITEMS "${_common_thrift}" "${_client_thrift}")
+ if(NOT EXISTS "${_f}")
+ message(FATAL_ERROR "[GenThrift] missing thrift input: ${_f}")
+ endif()
+endforeach()
+
+# Mirror the bash reference script: stage both .thrift files into a flat
+# working directory so `include "common.thrift"` resolves without -I args.
+set(_thrift_proto_dir "${CMAKE_BINARY_DIR}/thrift-protocols")
+file(MAKE_DIRECTORY "${_thrift_proto_dir}")
+configure_file("${_common_thrift}" "${_thrift_proto_dir}/common.thrift" COPYONLY)
+configure_file("${_client_thrift}" "${_thrift_proto_dir}/client.thrift" COPYONLY)
+
+set(THRIFT_GEN_CPP_DIR "${CMAKE_BINARY_DIR}/gen-cpp" CACHE PATH "" FORCE)
+file(MAKE_DIRECTORY "${THRIFT_GEN_CPP_DIR}")
+
+# A stamp file lets us re-run thrift only when one of the inputs changes
+# (handled by add_custom_command at build time) while also making sure we
+# run once at configure time so the initial file(GLOB) finds something.
+set(_thrift_stamp "${THRIFT_GEN_CPP_DIR}/.generated-stamp")
+
+set(_thrift_inputs
+ "${_thrift_proto_dir}/common.thrift"
+ "${_thrift_proto_dir}/client.thrift")
+
+set(_run_thrift FALSE)
+if(NOT EXISTS "${_thrift_stamp}")
+ set(_run_thrift TRUE)
+else()
+ foreach(_in IN LISTS _thrift_inputs)
+ if("${_in}" IS_NEWER_THAN "${_thrift_stamp}")
+ set(_run_thrift TRUE)
+ break()
+ endif()
+ endforeach()
+endif()
+
+if(_run_thrift)
+ message(STATUS "[GenThrift] running ${THRIFT_EXECUTABLE} on common.thrift / client.thrift")
+ foreach(_in IN LISTS _thrift_inputs)
+ execute_process(
+ COMMAND "${THRIFT_EXECUTABLE}" -r --gen cpp:no_skeleton -out "${THRIFT_GEN_CPP_DIR}" "${_in}"
+ WORKING_DIRECTORY "${_thrift_proto_dir}"
+ RESULT_VARIABLE _rc)
+ if(NOT _rc EQUAL 0)
+ message(FATAL_ERROR "[GenThrift] thrift compile failed for ${_in} (rc=${_rc})")
+ endif()
+ endforeach()
+ # Defensive: remove any accidentally produced server skeleton.
+ file(GLOB _skeletons "${THRIFT_GEN_CPP_DIR}/*_server.skeleton.cpp")
+ if(_skeletons)
+ file(REMOVE ${_skeletons})
+ endif()
+ file(TOUCH "${_thrift_stamp}")
+endif()
+
+# Build-time regeneration: whenever the workspace .thrift files change, rerun
+# the thrift compiler. The OUTPUT is the stamp; downstream targets that
+# depend on iotdb_thrift_codegen will get the rebuild for free.
+add_custom_command(
+ OUTPUT "${_thrift_stamp}"
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_common_thrift}" "${_thrift_proto_dir}/common.thrift"
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_client_thrift}" "${_thrift_proto_dir}/client.thrift"
+ COMMAND "${THRIFT_EXECUTABLE}" -r --gen cpp:no_skeleton -out "${THRIFT_GEN_CPP_DIR}" "${_thrift_proto_dir}/common.thrift"
+ COMMAND "${THRIFT_EXECUTABLE}" -r --gen cpp:no_skeleton -out "${THRIFT_GEN_CPP_DIR}" "${_thrift_proto_dir}/client.thrift"
+ COMMAND ${CMAKE_COMMAND} -E touch "${_thrift_stamp}"
+ DEPENDS "${_common_thrift}" "${_client_thrift}" iotdb_thrift_external
+ WORKING_DIRECTORY "${_thrift_proto_dir}"
+ COMMENT "Regenerating thrift C++ stubs"
+ VERBATIM)
+
+add_custom_target(iotdb_thrift_codegen DEPENDS "${_thrift_stamp}")
+
+# Glob results with CONFIGURE_DEPENDS so re-cmake picks up newly produced files.
+file(GLOB THRIFT_GENERATED_SRCS CONFIGURE_DEPENDS "${THRIFT_GEN_CPP_DIR}/*.cpp")
+file(GLOB THRIFT_GENERATED_HDRS CONFIGURE_DEPENDS "${THRIFT_GEN_CPP_DIR}/*.h")
+
+list(FILTER THRIFT_GENERATED_SRCS EXCLUDE REGEX ".*_server\\.skeleton\\.cpp$")
+
+message(STATUS "[GenThrift] generated ${THRIFT_GEN_CPP_DIR} with "
+ "$ cpp files")
diff --git a/iotdb-client/client-cpp/pom.xml b/iotdb-client/client-cpp/pom.xml
index c92fab103684e..b465fb09b1bfb 100644
--- a/iotdb-client/client-cpp/pom.xml
+++ b/iotdb-client/client-cpp/pom.xml
@@ -30,15 +30,33 @@
pom
IoTDB: Client: Client for CPP
C++ client
-
+
- https://github.com/catchorg/Catch2/releases/download/v2.13.7/catch.hpp
Release
-
${project.build.directory}/dependency/cmake/
- ${project.build.directory}/thrift/bin/${thrift.executable}
+ ${project.basedir}
+ ${project.build.directory}/build
+ ${project.build.directory}/install
+ ${project.basedir}/third-party
+ OFF
+ OFF
+
+ ON
${ctest.skip.tests}
- false
+
+
+
+ ${os.classifier}
@@ -50,162 +68,11 @@
-
-
- org.apache.maven.plugins
- maven-resources-plugin
-
-
- copy-cpp-files
-
- copy-resources
-
- validate
-
- ${project.build.directory}/build/main/generated-sources-cpp
-
-
- ${project.basedir}/src/main
-
- **/*.h
- **/*.cpp
- **/*.cc
-
-
-
-
-
-
- copy-test-resources
-
- copy-resources
-
- validate
-
- ${project.build.directory}/build/test
-
-
- ${project.basedir}/src/test
- true
-
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-dependency-plugin
-
-
- get-thrift
-
- unpack
-
- generate-sources
-
-
-
- org.apache.iotdb.tools
- iotdb-tools-thrift
- ${iotdb-tools-thrift.version}
- ${os.classifier}
- zip
- true
- ${project.build.directory}/thrift
-
-
-
-
-
-
-
- com.googlecode.maven-download-plugin
- download-maven-plugin
-
-
-
-
-
-
- com.coderplus.maven.plugins
- copy-rename-maven-plugin
-
-
-
- copy-protocol-thrift-source
-
- copy
-
-
-
-
- ../../iotdb-protocol/thrift-datanode/src/main/thrift/client.thrift
- ${project.build.directory}/protocols/client.thrift
-
-
- ../../iotdb-protocol/thrift-commons/src/main/thrift/common.thrift
- ${project.build.directory}/protocols/common.thrift
-
-
-
-
-
-
-
- copy-cmakelist-file
-
- copy
-
- compile
-
-
-
- ${project.basedir}/src/main/CMakeLists.txt
- ${project.build.directory}/build/main/CMakeLists.txt
-
-
-
-
-
-
-
- org.apache.thrift
- thrift-maven-plugin
-
-
- generate-thrift-sources-cpp
-
- compile
-
-
- generate-resources
-
- cpp:no_skeleton
- ${thrift.exec.absolute.path}
- ${project.build.directory}/protocols
- ${project.build.directory}/build/main/generated-sources-cpp
-
-
-
-
io.github.cmake-maven-plugin
cmake-maven-plugin
-
+
cmake-generate
@@ -214,32 +81,21 @@
compile
${cmake.generator}
- ${project.build.directory}/build/main
- ${project.build.directory}/build/main
+ ${cmake.source.dir}
+ ${cmake.project.dir}
-
+
+
+
-
-
-
-
-
- cmake-generate-test
-
- generate
-
- test-compile
-
- ${cmake.generator}
- ${project.build.directory}/build/test
- ${project.build.directory}/build/test
-
+
+
-
+
-
+
cmake-compile
@@ -248,24 +104,11 @@
compile
${cmake.build.type}
-
- ${project.build.directory}/build/main
-
-
-
-
- cmake-compile-test
-
- compile
-
- test-compile
-
- ${cmake.build.type}
- ${project.build.directory}/build/test
+ ${cmake.project.dir}
+ install
-
-
+
cmake-run-test
@@ -274,37 +117,17 @@
integration-test
${cmake.build.type}
- ${project.build.directory}/build/test
+ ${cmake.project.dir}/test
${maven.test.skip}
-
-
- org.apache.maven.plugins
- maven-assembly-plugin
-
-
- package-client-cpp
-
- single
-
- package
-
- ${project.artifactId}-${project.version}
-
- src/assembly/client-cpp.xml
-
-
-
-
-
+
com.bazaarvoice.maven.plugins
process-exec-maven-plugin
-
start-iotdb
@@ -315,17 +138,13 @@
${ctest.skip.tests}
iotdb-server
false
-
45
-
- ${project.build.directory}/build/test/test.log
+ ${cmake.project.dir}/test.log
-
${project.basedir}/../../distribution/target/apache-iotdb-${project.version}-all-bin/apache-iotdb-${project.version}-all-bin/sbin/${iotdb.start.script}
-
stop-iotdb
@@ -336,10 +155,8 @@
${ctest.skip.tests}
iotdb-server
false
-
5
-
- ${project.build.directory}/build/test/test1.log
+ ${cmake.project.dir}/stop.log
${project.basedir}/../../distribution/target/apache-iotdb-${project.version}-all-bin/apache-iotdb-${project.version}-all-bin/sbin/${iotdb.stop.script}
@@ -347,6 +164,26 @@
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+ package-client-cpp
+
+ single
+
+ package
+
+ ${project.artifactId}-${project.version}
+
+ src/assembly/client-cpp.xml
+
+
+
+
+
@@ -421,12 +258,13 @@
win
+
- .skipTests
+ client-cpp-vs-x64
-
- skipTests
-
+
+ windows
+
@@ -435,16 +273,34 @@
cmake-maven-plugin
- cmake-compile-test
- none
-
+ cmake-generate
+
+
+
+
+
-
+
+ .skipTests
+
+
+ skipTests
+
+
+
+ OFF
+
+
+
spotless-cpp
@@ -466,7 +322,7 @@
src/**/*.cpp
- src/test/catch2/**
+ test/catch2/**
${clang.format.version}
diff --git a/iotdb-client/client-cpp/src/assembly/client-cpp.xml b/iotdb-client/client-cpp/src/assembly/client-cpp.xml
index 729fdadde235a..fc2bf5777d06b 100644
--- a/iotdb-client/client-cpp/src/assembly/client-cpp.xml
+++ b/iotdb-client/client-cpp/src/assembly/client-cpp.xml
@@ -17,51 +17,33 @@
specific language governing permissions and limitations
under the License.
-->
+
- cpp-${os.classifier}
+ ${client.cpp.package.classifier}
zip
dir
- false
+ true
+ ${project.artifactId}-${project.version}-${client.cpp.package.classifier}
- ${project.build.directory}/build/main/generated-sources-cpp
-
- **/*.h
-
- include
-
-
- ${project.build.directory}/thrift/include
+ ${project.build.directory}/install/include
**
include
- ${project.build.directory}/thrift/lib
+ ${project.build.directory}/install/lib
**
lib
-
- ${project.build.directory}/build/main
-
- *.so
- *.dylib
- **/*.dll
- **/*.lib
-
- lib
-
-
- ${project.basedir}/../compile-tools/thrift/target/build/lib/Release
-
- **/*.lib
-
- lib
-
diff --git a/iotdb-client/client-cpp/src/main/AbstractSessionBuilder.h b/iotdb-client/client-cpp/src/include/AbstractSessionBuilder.h
similarity index 85%
rename from iotdb-client/client-cpp/src/main/AbstractSessionBuilder.h
rename to iotdb-client/client-cpp/src/include/AbstractSessionBuilder.h
index 9f59504d3887b..3735dfa227d0c 100644
--- a/iotdb-client/client-cpp/src/main/AbstractSessionBuilder.h
+++ b/iotdb-client/client-cpp/src/include/AbstractSessionBuilder.h
@@ -22,16 +22,18 @@
#include
+#include "SessionConfig.h"
+
class AbstractSessionBuilder {
public:
static constexpr const char* DEFAULT_HOST = "localhost";
static constexpr int DEFAULT_RPC_PORT = 6667;
static constexpr const char* DEFAULT_USERNAME = "root";
static constexpr const char* DEFAULT_PASSWORD = "root";
- static constexpr int DEFAULT_FETCH_SIZE = 10000;
- static constexpr int DEFAULT_CONNECT_TIMEOUT_MS = 3 * 1000;
- static constexpr int DEFAULT_MAX_RETRIES = 3;
- static constexpr int DEFAULT_RETRY_DELAY_MS = 500;
+ static constexpr int DEFAULT_FETCH_SIZE = iotdb::session::DEFAULT_FETCH_SIZE;
+ static constexpr int DEFAULT_CONNECT_TIMEOUT_MS = iotdb::session::DEFAULT_CONNECT_TIMEOUT_MS;
+ static constexpr int DEFAULT_MAX_RETRIES = iotdb::session::DEFAULT_MAX_RETRIES;
+ static constexpr int DEFAULT_RETRY_DELAY_MS = iotdb::session::DEFAULT_RETRY_DELAY_MS;
static constexpr const char* DEFAULT_SQL_DIALECT = "tree";
static constexpr bool DEFAULT_ENABLE_AUTO_FETCH = true;
static constexpr bool DEFAULT_ENABLE_REDIRECTIONS = true;
diff --git a/iotdb-client/client-cpp/src/main/Column.h b/iotdb-client/client-cpp/src/include/Column.h
similarity index 100%
rename from iotdb-client/client-cpp/src/main/Column.h
rename to iotdb-client/client-cpp/src/include/Column.h
diff --git a/iotdb-client/client-cpp/src/main/ColumnDecoder.h b/iotdb-client/client-cpp/src/include/ColumnDecoder.h
similarity index 100%
rename from iotdb-client/client-cpp/src/main/ColumnDecoder.h
rename to iotdb-client/client-cpp/src/include/ColumnDecoder.h
diff --git a/iotdb-client/client-cpp/src/main/Common.h b/iotdb-client/client-cpp/src/include/Common.h
similarity index 74%
rename from iotdb-client/client-cpp/src/main/Common.h
rename to iotdb-client/client-cpp/src/include/Common.h
index 74e3f622d1001..49dca0bca4b14 100644
--- a/iotdb-client/client-cpp/src/main/Common.h
+++ b/iotdb-client/client-cpp/src/include/Common.h
@@ -19,40 +19,21 @@
#ifndef IOTDB_COMMON_H
#define IOTDB_COMMON_H
+#include
+#include
+#include
+#include