From 13802a0675014c27903710c0c4b958bda9bff559 Mon Sep 17 00:00:00 2001 From: 761417898 <761417898@qq.com> Date: Wed, 20 May 2026 18:23:13 +0800 Subject: [PATCH 01/28] Refactor client-cpp build to single CMake entry with portable third-party cache Move C++ client dependency resolution and compilation into one top-level CMakeLists with Fetch* modules, cache tarballs under third-party// for offline copy-the-repo workflows, and slim the Maven POM to a CMake wrapper. Skip server CI when only client-cpp changes; gate multi-language-client jobs by language via paths-filter. --- .github/workflows/cluster-it-1c1d.yml | 4 + .github/workflows/cluster-it-1c1d1a.yml | 4 + .github/workflows/cluster-it-1c3d.yml | 4 + .github/workflows/compile-check.yml | 4 + .github/workflows/dependency-check.yml | 4 + .github/workflows/multi-language-client.yml | 46 ++ .github/workflows/pipe-it.yml | 4 + .github/workflows/sonar-codecov.yml | 4 + .github/workflows/table-cluster-it-1c1d.yml | 4 + .github/workflows/table-cluster-it-1c3d.yml | 4 + .github/workflows/unit-test.yml | 4 + .gitignore | 7 +- iotdb-client/client-cpp/CMakeLists.txt | 205 +++++++++ iotdb-client/client-cpp/README.md | 395 +++++++++++------- .../client-cpp/cmake/FetchBoost.cmake | 138 ++++++ .../client-cpp/cmake/FetchBuildTools.cmake | 203 +++++++++ .../client-cpp/cmake/FetchOpenSSL.cmake | 121 ++++++ .../client-cpp/cmake/FetchThrift.cmake | 273 ++++++++++++ .../cmake/GenerateThriftSources.cmake | 126 ++++++ .../cmake/IotdbResolveTarball.cmake | 73 ++++ iotdb-client/client-cpp/pom.xml | 307 +++----------- .../client-cpp/src/assembly/client-cpp.xml | 33 +- .../client-cpp/src/main/CMakeLists.txt | 90 ---- .../client-cpp/src/test/CMakeLists.txt | 181 +++----- .../client-cpp/third-party/.gitignore | 7 + iotdb-client/client-cpp/third-party/README.md | 73 ++++ .../client-cpp/third-party/linux/.gitignore | 2 + .../client-cpp/third-party/mac/.gitignore | 2 + .../client-cpp/third-party/windows/.gitignore | 2 + 29 files changed, 1699 insertions(+), 625 deletions(-) create mode 100644 iotdb-client/client-cpp/CMakeLists.txt create mode 100644 iotdb-client/client-cpp/cmake/FetchBoost.cmake create mode 100644 iotdb-client/client-cpp/cmake/FetchBuildTools.cmake create mode 100644 iotdb-client/client-cpp/cmake/FetchOpenSSL.cmake create mode 100644 iotdb-client/client-cpp/cmake/FetchThrift.cmake create mode 100644 iotdb-client/client-cpp/cmake/GenerateThriftSources.cmake create mode 100644 iotdb-client/client-cpp/cmake/IotdbResolveTarball.cmake delete mode 100644 iotdb-client/client-cpp/src/main/CMakeLists.txt create mode 100644 iotdb-client/client-cpp/third-party/.gitignore create mode 100644 iotdb-client/client-cpp/third-party/README.md create mode 100644 iotdb-client/client-cpp/third-party/linux/.gitignore create mode 100644 iotdb-client/client-cpp/third-party/mac/.gitignore create mode 100644 iotdb-client/client-cpp/third-party/windows/.gitignore diff --git a/.github/workflows/cluster-it-1c1d.yml b/.github/workflows/cluster-it-1c1d.yml index caf1de91c6827..48660a2b9cd28 100644 --- a/.github/workflows/cluster-it-1c1d.yml +++ b/.github/workflows/cluster-it-1c1d.yml @@ -9,6 +9,8 @@ on: paths-ignore: - "docs/**" - "site/**" + - "iotdb-client/client-cpp/**" + - "example/client-cpp-example/**" pull_request: branches: - master @@ -17,6 +19,8 @@ on: paths-ignore: - "docs/**" - "site/**" + - "iotdb-client/client-cpp/**" + - "example/client-cpp-example/**" # 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..eab539933dbf0 100644 --- a/.github/workflows/cluster-it-1c1d1a.yml +++ b/.github/workflows/cluster-it-1c1d1a.yml @@ -9,6 +9,8 @@ on: paths-ignore: - 'docs/**' - 'site/**' + - 'iotdb-client/client-cpp/**' + - 'example/client-cpp-example/**' pull_request: branches: - master @@ -18,6 +20,8 @@ on: paths-ignore: - 'docs/**' - 'site/**' + - 'iotdb-client/client-cpp/**' + - 'example/client-cpp-example/**' # 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..77888b0c64fc6 100644 --- a/.github/workflows/cluster-it-1c3d.yml +++ b/.github/workflows/cluster-it-1c3d.yml @@ -9,6 +9,8 @@ on: paths-ignore: - "docs/**" - "site/**" + - "iotdb-client/client-cpp/**" + - "example/client-cpp-example/**" pull_request: branches: - master @@ -18,6 +20,8 @@ on: paths-ignore: - "docs/**" - "site/**" + - "iotdb-client/client-cpp/**" + - "example/client-cpp-example/**" # allow manually run the action: workflow_dispatch: diff --git a/.github/workflows/compile-check.yml b/.github/workflows/compile-check.yml index 1cf45e07dc0e2..5db86d103875f 100644 --- a/.github/workflows/compile-check.yml +++ b/.github/workflows/compile-check.yml @@ -11,6 +11,8 @@ on: paths-ignore: - "docs/**" - "site/**" + - "iotdb-client/client-cpp/**" + - "example/client-cpp-example/**" pull_request: branches: - master @@ -20,6 +22,8 @@ on: paths-ignore: - "docs/**" - "site/**" + - "iotdb-client/client-cpp/**" + - "example/client-cpp-example/**" # allow manually run the action: workflow_dispatch: diff --git a/.github/workflows/dependency-check.yml b/.github/workflows/dependency-check.yml index 4cf6cb202afca..884d0f293ae01 100644 --- a/.github/workflows/dependency-check.yml +++ b/.github/workflows/dependency-check.yml @@ -11,6 +11,8 @@ on: paths-ignore: - "docs/**" - "site/**" + - "iotdb-client/client-cpp/**" + - "example/client-cpp-example/**" pull_request: branches: - master @@ -20,6 +22,8 @@ on: paths-ignore: - "docs/**" - "site/**" + - "iotdb-client/client-cpp/**" + - "example/client-cpp-example/**" # 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..64bdf216c09ca 100644 --- a/.github/workflows/multi-language-client.yml +++ b/.github/workflows/multi-language-client.yml @@ -40,7 +40,49 @@ 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: + - 'pom.xml' + - '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' + 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 + if: github.event_name == 'workflow_dispatch' || needs.changes.outputs.cpp == 'true' strategy: fail-fast: false max-parallel: 15 @@ -134,6 +176,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 +202,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..486a043f50a1c 100644 --- a/.github/workflows/pipe-it.yml +++ b/.github/workflows/pipe-it.yml @@ -9,6 +9,8 @@ on: paths-ignore: - "docs/**" - "site/**" + - "iotdb-client/client-cpp/**" + - "example/client-cpp-example/**" - "iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/**" #queryengine pull_request: branches: @@ -19,6 +21,8 @@ on: paths-ignore: - "docs/**" - "site/**" + - "iotdb-client/client-cpp/**" + - "example/client-cpp-example/**" - "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..a01cbce5242ed 100644 --- a/.github/workflows/sonar-codecov.yml +++ b/.github/workflows/sonar-codecov.yml @@ -12,6 +12,8 @@ on: paths-ignore: - "docs/**" - "site/**" + - "iotdb-client/client-cpp/**" + - "example/client-cpp-example/**" pull_request: branches: - master @@ -22,6 +24,8 @@ on: paths-ignore: - "docs/**" - "site/**" + - "iotdb-client/client-cpp/**" + - "example/client-cpp-example/**" # 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..ef4590b447c96 100644 --- a/.github/workflows/table-cluster-it-1c1d.yml +++ b/.github/workflows/table-cluster-it-1c1d.yml @@ -9,6 +9,8 @@ on: paths-ignore: - "docs/**" - "site/**" + - "iotdb-client/client-cpp/**" + - "example/client-cpp-example/**" pull_request: branches: - master @@ -18,6 +20,8 @@ on: paths-ignore: - "docs/**" - "site/**" + - "iotdb-client/client-cpp/**" + - "example/client-cpp-example/**" # 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..6ec2d4c23ac07 100644 --- a/.github/workflows/table-cluster-it-1c3d.yml +++ b/.github/workflows/table-cluster-it-1c3d.yml @@ -9,6 +9,8 @@ on: paths-ignore: - "docs/**" - "site/**" + - "iotdb-client/client-cpp/**" + - "example/client-cpp-example/**" pull_request: branches: - master @@ -18,6 +20,8 @@ on: paths-ignore: - "docs/**" - "site/**" + - "iotdb-client/client-cpp/**" + - "example/client-cpp-example/**" # allow manually run the action: workflow_dispatch: diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index ccc0c2ca4b39e..28d286c433066 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -12,6 +12,8 @@ on: paths-ignore: - "docs/**" - "site/**" + - "iotdb-client/client-cpp/**" + - "example/client-cpp-example/**" pull_request: branches: - master @@ -21,6 +23,8 @@ on: paths-ignore: - "docs/**" - "site/**" + - "iotdb-client/client-cpp/**" + - "example/client-cpp-example/**" # allow manually run the action: workflow_dispatch: diff --git a/.gitignore b/.gitignore index b6aa947b3e725..2f29ceaed6132 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,10 @@ tsfile-jdbc/src/main/resources/output/queryRes.csv *.tsfile tsfile/src/test/resources/*.ts +### clion project +**/cmake-build-debug/ +**/cmake-build-release/ + ### Apache release ### local-snapshots-dir/ venv/ @@ -107,6 +111,7 @@ classes/ ### Cmake files ### *.cmake +!iotdb-client/client-cpp/cmake/*.cmake Makefile **/CMakeFiles/ diff --git a/iotdb-client/client-cpp/CMakeLists.txt b/iotdb-client/client-cpp/CMakeLists.txt new file mode 100644 index 0000000000000..ec9015cc2c6e0 --- /dev/null +++ b/iotdb-client/client-cpp/CMakeLists.txt @@ -0,0 +1,205 @@ +# 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) +# ============================================================================= +# This is the single entry point that fully manages the C++ client build, +# including third-party dependencies (Boost headers, Apache Thrift, optional +# OpenSSL) and toolchain bootstrap (m4 / flex / bison on Linux & macOS when +# the system PATH does not provide them). +# +# Standalone usage (no Maven required): +# cmake -S iotdb-client/client-cpp -B build [options] +# cmake --build build --config Release --target install +# +# Common options: +# -DWITH_SSL=ON|OFF Enable OpenSSL support (default OFF) +# -DBUILD_TESTING=ON|OFF Build IT executables (default OFF) +# -DIOTDB_OFFLINE=ON|OFF Disable any network access (default OFF). +# Requires tarballs under third-party/{os}/. +# -DIOTDB_DEPS_DIR= Override the third-party cache root. +# Default: /third-party +# (portable: copy the whole IoTDB tree to an +# offline machine after staging tarballs here). +# -DBOOST_ROOT= Existing Boost installation to reuse. +# -DCMAKE_INSTALL_PREFIX=... Install location (defaults to build/install). +# ============================================================================= + +cmake_minimum_required(VERSION 3.16) +project(iotdb_session CXX C) + +# --------------------------------------------------------------------------- +# Global settings +# --------------------------------------------------------------------------- +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) + # Match thrift's MultiThreaded runtime so static libraries link cleanly. + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") +endif() + +# --------------------------------------------------------------------------- +# Cached options +# --------------------------------------------------------------------------- +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/)") +set(BOOST_VERSION "1.60.0" + CACHE STRING "Boost version used when downloading / unpacking") +set(THRIFT_VERSION "0.21.0" + CACHE STRING "Apache Thrift version used when downloading / building") + +# --------------------------------------------------------------------------- +# Platform -> local tarball directory +# --------------------------------------------------------------------------- +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}") + +# Default install prefix lives inside the build tree so Maven's assembly +# step can pick everything up under a stable path. +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") + +# --------------------------------------------------------------------------- +# Fetch / build third-party dependencies +# --------------------------------------------------------------------------- +include(FetchBoost) # -> BOOST_INCLUDE_DIR +include(FetchBuildTools) # -> populates ${CMAKE_BINARY_DIR}/tools/bin and updates ENV{PATH} +if(WITH_SSL) + include(FetchOpenSSL) +endif() +include(FetchThrift) # -> target iotdb_thrift_static, THRIFT_EXECUTABLE, THRIFT_INCLUDE_DIR +include(GenerateThriftSources) # -> THRIFT_GENERATED_SRCS, THRIFT_GENERATED_HDRS + +# --------------------------------------------------------------------------- +# iotdb_session library +# --------------------------------------------------------------------------- +file(GLOB SESSION_HANDWRITTEN_SRCS CONFIGURE_DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/src/main/*.cpp") +file(GLOB SESSION_HANDWRITTEN_HDRS CONFIGURE_DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/src/main/*.h") + +if(MSVC) + add_library(iotdb_session STATIC + ${SESSION_HANDWRITTEN_SRCS} + ${THRIFT_GENERATED_SRCS}) +else() + add_library(iotdb_session SHARED + ${SESSION_HANDWRITTEN_SRCS} + ${THRIFT_GENERATED_SRCS}) +endif() + +add_dependencies(iotdb_session iotdb_thrift_external iotdb_thrift_codegen) + +target_include_directories(iotdb_session + PUBLIC + $ + $ + $ + $) + +if(BOOST_INCLUDE_DIR) + target_include_directories(iotdb_session PUBLIC + $) +endif() + +target_link_libraries(iotdb_session PUBLIC iotdb_thrift_static) + +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() + +# --------------------------------------------------------------------------- +# Install rules - lay out the SDK exactly like the historical zip layout. +# /include/*.h (handwritten + generated cpp headers) +# /include/thrift/... (thrift runtime headers) +# /lib/ +# /lib/ (bundled so downstream users only need one tree) +# --------------------------------------------------------------------------- +include(GNUInstallDirs) + +install(TARGETS iotdb_session + RUNTIME DESTINATION lib + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib) + +install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src/main/" + DESTINATION include + FILES_MATCHING PATTERN "*.h") + +install(DIRECTORY "${THRIFT_GEN_CPP_DIR}/" + DESTINATION include + FILES_MATCHING PATTERN "*.h") + +install(DIRECTORY "${THRIFT_INCLUDE_DIR}/thrift" + DESTINATION include) + +if(THRIFT_STATIC_LIB_PATH AND EXISTS "${THRIFT_STATIC_LIB_PATH}") + install(FILES "${THRIFT_STATIC_LIB_PATH}" DESTINATION lib) +endif() + +# --------------------------------------------------------------------------- +# Tests +# --------------------------------------------------------------------------- +if(BUILD_TESTING) + enable_testing() + add_subdirectory(src/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}") +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..7e55f81bba1e8 100644 --- a/iotdb-client/client-cpp/README.md +++ b/iotdb-client/client-cpp/README.md @@ -18,182 +18,293 @@ 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 - -#### 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}` -``` - -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: +## Build layout at a glance ``` -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" +iotdb-client/client-cpp/ +├── CMakeLists.txt # single entry point - manages everything +├── cmake/ # helpers (FetchBoost / FetchThrift / ...) +├── third-party/ # downloaded tarballs (linux/ mac/ windows/) +├── src/main/ # handwritten C/C++ sources + public headers +├── src/test/ # Catch2-based integration tests +└── pom.xml # Maven wrapper (cmake-maven-plugin) ``` -##### 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" +Third-party tarballs (Boost, Thrift, flex/bison, OpenSSL, ...) are cached +under **`third-party//`** inside this module. That keeps everything +portable: stage dependencies on a networked machine, **copy the whole IoTDB +tree** to an offline host, then build with `-DIOTDB_OFFLINE=ON`. Archives are +git-ignored; see [`third-party/README.md`](third-party/README.md). Override +the cache root with `-DIOTDB_DEPS_DIR=` (Maven: `-Diotdb.deps.dir=...`). + +During configure CMake will, in order: + +1. Resolve Boost headers (`find_package` → local `${IOTDB_DEPS_DIR}//` + 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 (optional `THRIFT_TARBALL` → + `${IOTDB_DEPS_DIR}//` cache with `thrift-*.tar.gz` glob → download + from Apache archive when not in offline mode; **same on Windows**). +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--cpp-.zip`. + +## CMake options + +All of these can be set on the Maven command line (`-DWITH_SSL=ON`, etc.) or +passed directly to `cmake`. + +| Option | Default | Purpose | +|-----------------------|----------------------------------|----------------------------------------------------------------------------------------------------------| +| `WITH_SSL` | `OFF` | Link against OpenSSL. See *SSL* below. | +| `BUILD_TESTING` | `ON` (`OFF` when `-DskipTests`) | Build Catch2 IT executables. | +| `IOTDB_OFFLINE` | `OFF` | Disallow any network access during configure. | +| `IOTDB_DEPS_DIR` | `/third-party` | Override the third-party cache root (`linux/` / `mac/` / `windows/` appended automatically). | +| `BOOST_VERSION` | `1.60.0` | Boost version that CMake will look for / download. | +| `THRIFT_VERSION` | `0.21.0` | Apache Thrift version to build from source. | +| `THRIFT_TARBALL` | (unset) | Path to a pre-downloaded `thrift-*.tar.gz` anywhere on disk (skips the cache lookup). | +| `THRIFT_URL` | (unset) | Override the Apache archive URL used when the thrift tarball is downloaded. | +| `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 into `third-party//` at configure +time. The first run is slow (≈100 MB download + a Thrift build); subsequent +runs reuse both the cached archives and 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 ``` -#### 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. +## Offline build (copy whole IoTDB tree) -3. Enter the "iotdb-tools-thrift" folder in the cloned repository; use the following command to - compile the thrift library: +**Recommended workflow** -`mvn install` +1. On a **networked** machine, run one online configure/build so CMake fills + `iotdb-client/client-cpp/third-party//` (or copy tarballs there + manually — see table below). +2. Copy the **entire IoTDB repository** (including `third-party/`) to the + offline host. +3. Build with `-DIOTDB_OFFLINE=ON` (no downloads attempted). -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; +```bash +# Step 1 (online machine) +cmake -S iotdb-client/client-cpp -B build +# tarballs land in third-party/windows/ (or linux/ / mac/) -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" +# Step 3 (offline machine, after copying the repo) +cmake -S iotdb-client/client-cpp -B build -DIOTDB_OFFLINE=ON +cmake --build build --config Release --target install ``` +### Files to place under `third-party//` -### 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 +| 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_60_0.tar.gz` (Apple already 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`), `win_flex_bison-2.5.25.zip` (any `win_flex_bison*.zip` name is accepted) | -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. +Reference URLs (the configure step uses the same when downloading online): -**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. +- Apache Thrift 0.21.0: +- Boost 1.60.0: +- GNU m4 1.4.19: +- GNU flex 2.6.4: +- GNU bison 3.8: +- winflexbison 2.5.25: +- OpenSSL 3.5.0: -### Install clang-format 17.0.6 +Maven offline equivalent: -- 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) - -`./mvnw -P with-cpp -pl iotdb-client/client-cpp spotless:check` +```bash +mvn -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests \ + -DIOTDB_OFFLINE=ON package +``` -`./mvnw -P with-cpp -pl example/client-cpp-example spotless:check` +Shared CI caches can still use `-DIOTDB_DEPS_DIR=/path/to/cache` if the +tarballs should live outside this module (the `/` sub-folder is still +appended automatically). + +## 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 + +The recommended toolchain is Visual Studio 2019 or 2022. + +Prerequisites: + +1. **Apache Thrift.** Online builds download `thrift-0.21.0.tar.gz` into + `third-party/windows/` automatically (or pass + `-DTHRIFT_TARBALL=D:\path\to\thrift-0.21.0.tar.gz` for a copy elsewhere). + Offline builds require the tarball under `third-party/windows/` (any + `thrift-*.tar.gz` name is accepted) or `-DTHRIFT_TARBALL=...`. +2. **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). +3. **flex / bison.** CMake handles this automatically: + - If the host already has `flex` / `bison` (or `win_flex` / `win_bison`) + on `PATH`, they are reused as-is. + - Otherwise, in online mode the build downloads + + into `third-party/windows/` and extracts it into `build\tools\bin\`, + renaming `win_flex.exe` / `win_bison.exe` to `flex.exe` / `bison.exe`. + - For offline builds pre-stage any `win_flex_bison*.zip` (e.g. + `win_flex_bison-latest.zip`) into `third-party/windows/`; CMake picks + the first match via glob. +4. **OpenSSL** *(only when `WITH_SSL=ON`)*: run the Win64 OpenSSL + installer from , then + pass `-DOPENSSL_ROOT_DIR=...` to CMake. + +Auto-building m4 from the GNU autotools tarball is **not** supported on +Windows; the bundled winflexbison binaries already cover the flex/bison +needs of Apache Thrift's source build. + +## SSL + +Both Thrift and `iotdb_session` build without OpenSSL by default. Enable +SSL support with `-DWITH_SSL=ON`. 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/src/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--cpp-.zip` with the historical 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 +├── include/ +│ ├── Session.h +│ ├── SessionC.h +│ ├── ... (handwritten + generated headers) +│ └── thrift/ +│ └── ... (Thrift runtime headers) +└── lib/ + ├── libiotdb_session.{so,dylib} (or iotdb_session.lib on Windows) + └── libthrift.{a,lib} (or thriftmd.lib on Windows) ``` -## Using C++ Client: +## Using the C++ client + +```cpp +#include "include/Session.h" +#include +#include + +int main() { + auto session = std::make_shared("127.0.0.1", 6667, "root", "root"); + session->open(false); + session->setStorageGroup("root.test01"); + if (!session->checkTimeseriesExists("root.test01.d0.s0")) { + session->createTimeseries( + "root.test01.d0.s0", + TSDataType::INT64, + TSEncoding::RLE, + CompressionType::SNAPPY); + } + session->close(); +} ``` -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 - -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 - - E.g: - #include "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")); - session->open(false); - std::cout << "setStorageGroup: root.test01" << std::endl; - session->setStorageGroup("root.test01"); +Compile against the produced SDK: - 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->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 +```bash +clang++ -O2 user-cpp-code.cpp \ + -I/path/to/sdk/include \ + -L/path/to/sdk/lib \ + -liotdb_session -lthrift -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..6b817cc20eb71 --- /dev/null +++ b/iotdb-client/client-cpp/cmake/FetchBoost.cmake @@ -0,0 +1,138 @@ +# 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 +# --------------------------------------------------------------------------- +# CMP0167 (CMake 3.30+): the bundled FindBoost was removed in favour of +# BoostConfig.cmake shipped by Boost itself. For broad compatibility (we may +# be looking at a Boost source tree that does NOT ship BoostConfig), keep the +# legacy FindBoost behaviour and silence the developer warning. +if(POLICY CMP0167) + cmake_policy(SET CMP0167 OLD) +endif() + +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..802c56728efac --- /dev/null +++ b/iotdb-client/client-cpp/cmake/FetchBuildTools.cmake @@ -0,0 +1,203 @@ +# 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 +# ============================================================================= + +include(IotdbResolveTarball) + +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() + +# 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" + LOG_PREFIX "BuildTools") + + 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}" + LOG_PREFIX "BuildTools") + _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}" + LOG_PREFIX "BuildTools") + _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}" + LOG_PREFIX "BuildTools") + _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..91b8ff2c5108f --- /dev/null +++ b/iotdb-client/client-cpp/cmake/FetchThrift.cmake @@ -0,0 +1,273 @@ +# 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 +# +# Resolves the Apache Thrift source tarball (same three-stage pattern as +# FetchBuildTools / FetchBoost on every platform, including Windows): +# +# 1. Optional -DTHRIFT_TARBALL= to an existing archive anywhere on disk. +# 2. ${IOTDB_OS_DEPS_DIR}/thrift-.tar.gz (or any thrift-*.tar.gz match). +# 3. file(DOWNLOAD) from archive.apache.org when IOTDB_OFFLINE is OFF. +# +# Then builds thrift from source as a static-only runtime + 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) +include(IotdbResolveTarball) + +set(THRIFT_TARBALL "" CACHE FILEPATH + "Optional path to a pre-downloaded thrift tarball (bypasses ${IOTDB_OS_DEPS_DIR})") +set(THRIFT_URL "" CACHE STRING + "Override download URL for the thrift tarball (default: Apache archive)") + +set(_thrift_dirname "thrift-${THRIFT_VERSION}") +set(_thrift_tarname "${_thrift_dirname}.tar.gz") + +# --------------------------------------------------------------------------- +# Resolve tarball (external path -> local cache / GLOB -> download) +# --------------------------------------------------------------------------- +if(THRIFT_TARBALL) + if(NOT EXISTS "${THRIFT_TARBALL}") + message(FATAL_ERROR + "[Thrift] THRIFT_TARBALL points to a missing file: ${THRIFT_TARBALL}") + endif() + set(_thrift_tarball "${THRIFT_TARBALL}") + message(STATUS "[Thrift] using THRIFT_TARBALL=${_thrift_tarball}") +else() + if(THRIFT_URL) + set(_thrift_url "${THRIFT_URL}") + else() + set(_thrift_url + "https://archive.apache.org/dist/thrift/${THRIFT_VERSION}/${_thrift_tarname}") + endif() + _iotdb_resolve_tarball(_thrift_tarball + "${_thrift_tarname}" + "${_thrift_url}" + GLOB_PATTERN "thrift-*.tar.gz" + LOG_PREFIX "Thrift") +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 + "-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" + # Thrift 0.21.0 still declares cmake_minimum_required(VERSION 3.0) + # which CMake 4.x rejects. Bump the floor so the configure step + # passes on both 3.16+ and 4.x toolchains. + "-DCMAKE_POLICY_VERSION_MINIMUM=3.5" + "-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=MultiThreaded") +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}") +if(NOT EXISTS "${_thrift_stamp}") + file(MAKE_DIRECTORY "${_thrift_build}") + message(STATUS "[Thrift] configuring ${_thrift_dirname}") + + # FetchBuildTools already prepended ${IOTDB_LOCAL_TOOLS_BIN} to ENV{PATH}; + # the child cmake / build invocations inherit that environment. + + 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..e2571ef3654d7 --- /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$") + +list(LENGTH THRIFT_GENERATED_SRCS _gen_count) +message(STATUS "[GenThrift] generated ${_gen_count} cpp files in ${THRIFT_GEN_CPP_DIR}") diff --git a/iotdb-client/client-cpp/cmake/IotdbResolveTarball.cmake b/iotdb-client/client-cpp/cmake/IotdbResolveTarball.cmake new file mode 100644 index 0000000000000..69c06bea3f5b7 --- /dev/null +++ b/iotdb-client/client-cpp/cmake/IotdbResolveTarball.cmake @@ -0,0 +1,73 @@ +# 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. +# +# ============================================================================= +# IotdbResolveTarball.cmake +# +# Shared helper used by FetchBuildTools, FetchThrift, etc. +# +# Resolution order: +# 1. Exact filename under ${IOTDB_OS_DEPS_DIR}/ +# 2. Optional GLOB_PATTERN match under ${IOTDB_OS_DEPS_DIR}/ +# 3. file(DOWNLOAD) into ${IOTDB_OS_DEPS_DIR}/ when IOTDB_OFFLINE is OFF +# 4. FATAL_ERROR otherwise +# ============================================================================= + +function(_iotdb_resolve_tarball OUT_VAR FILENAME URL) + cmake_parse_arguments(ARG "" "GLOB_PATTERN;LOG_PREFIX" "" ${ARGN}) + if(NOT ARG_LOG_PREFIX) + set(ARG_LOG_PREFIX "Deps") + endif() + + set(_local "${IOTDB_OS_DEPS_DIR}/${FILENAME}") + if(EXISTS "${_local}") + message(STATUS "[${ARG_LOG_PREFIX}] using ${_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 "[${ARG_LOG_PREFIX}] 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 + "[${ARG_LOG_PREFIX}] IOTDB_OFFLINE=ON but ${_hint} is missing in " + "${IOTDB_OS_DEPS_DIR}.") + endif() + + message(STATUS "[${ARG_LOG_PREFIX}] 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 "[${ARG_LOG_PREFIX}] download failed for ${FILENAME}: ${_msg}") + endif() + message(STATUS "[${ARG_LOG_PREFIX}] cached ${_local}") + set(${OUT_VAR} "${_local}" PARENT_SCOPE) +endfunction() diff --git a/iotdb-client/client-cpp/pom.xml b/iotdb-client/client-cpp/pom.xml index c92fab103684e..3e1dfa154dc0c 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 + + @@ -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.project.dir} + install - - - cmake-compile-test - - compile - - test-compile - - ${cmake.build.type} - ${project.build.directory}/build/test - - - - + cmake-run-test @@ -274,37 +117,17 @@ integration-test ${cmake.build.type} - ${project.build.directory}/build/test + ${cmake.project.dir}/src/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 + + + + + @@ -428,23 +265,15 @@ skipTests - - - - io.github.cmake-maven-plugin - cmake-maven-plugin - - - cmake-compile-test - none - - - - - - + + OFF + - + spotless-cpp diff --git a/iotdb-client/client-cpp/src/assembly/client-cpp.xml b/iotdb-client/client-cpp/src/assembly/client-cpp.xml index 729fdadde235a..60e5f3a29d7bd 100644 --- a/iotdb-client/client-cpp/src/assembly/client-cpp.xml +++ b/iotdb-client/client-cpp/src/assembly/client-cpp.xml @@ -17,6 +17,11 @@ specific language governing permissions and limitations under the License. --> + cpp-${os.classifier} @@ -26,42 +31,18 @@ false - ${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/CMakeLists.txt b/iotdb-client/client-cpp/src/main/CMakeLists.txt deleted file mode 100644 index 8cfed4e7db912..0000000000000 --- a/iotdb-client/client-cpp/src/main/CMakeLists.txt +++ /dev/null @@ -1,90 +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. -# - -CMAKE_MINIMUM_REQUIRED(VERSION 3.7) -PROJECT(iotdb_session CXX) -SET(CMAKE_CXX_STANDARD 11) -SET(CMAKE_CXX_STANDARD_REQUIRED ON) -SET(CMAKE_POSITION_INDEPENDENT_CODE ON) -IF(NOT MSVC) - # Keep GCC/Clang style flags off on MSVC to avoid invalid-option build errors. - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -g -O2") -ENDIF() - -# Add Thrift include directory -INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/../../thrift/include) - -# ========================= -# SSL option (default OFF) -# ========================= -option(WITH_SSL "Build with SSL support" OFF) - -IF(WITH_SSL) - FIND_PACKAGE(OpenSSL REQUIRED) - IF(OpenSSL_FOUND) - MESSAGE(STATUS "OpenSSL found: ${OPENSSL_VERSION}") - INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR}) - ADD_DEFINITIONS(-DWITH_SSL=1) - ELSE() - MESSAGE(FATAL_ERROR "OpenSSL not found, but WITH_SSL is enabled") - ENDIF() -ELSE() - MESSAGE(STATUS "Building without SSL support") - ADD_DEFINITIONS(-DWITH_SSL=0) -ENDIF() - -# Add Boost include path for MacOS -INCLUDE_DIRECTORIES(/usr/local/include) - -# Add Boost library headers for MaxOS -FIND_PACKAGE(Boost REQUIRED) -IF (DEFINED BOOST_INCLUDEDIR) - INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIR}) -ENDIF() - -IF(MSVC) - SET(THRIFT_STATIC_LIB "${CMAKE_SOURCE_DIR}/../../thrift/lib/Release/thriftmd.lib") -ELSE() - SET(THRIFT_STATIC_LIB "${CMAKE_SOURCE_DIR}/../../thrift/lib/libthrift.a") -ENDIF() - -# Add the generated source files to the sources for the library. -AUX_SOURCE_DIRECTORY(./generated-sources-cpp SESSION_SRCS) -IF(MSVC) - ADD_LIBRARY(iotdb_session ${SESSION_SRCS}) -ELSE() - ADD_LIBRARY(iotdb_session SHARED ${SESSION_SRCS}) -ENDIF() - -# ========================= -# Link libraries (SSL optional) -# ========================= -IF(WITH_SSL) - target_link_libraries(iotdb_session - PUBLIC - OpenSSL::SSL - OpenSSL::Crypto - ${THRIFT_STATIC_LIB} - ) -ELSE() - target_link_libraries(iotdb_session - PUBLIC - ${THRIFT_STATIC_LIB} - ) -ENDIF() - diff --git a/iotdb-client/client-cpp/src/test/CMakeLists.txt b/iotdb-client/client-cpp/src/test/CMakeLists.txt index 5a234b4709408..38a05010ff84d 100644 --- a/iotdb-client/client-cpp/src/test/CMakeLists.txt +++ b/iotdb-client/client-cpp/src/test/CMakeLists.txt @@ -15,138 +15,65 @@ # specific language governing permissions and limitations # under the License. # +# ============================================================================= +# C++ client integration tests (driven by ctest). +# The parent CMakeLists.txt include()s this folder when BUILD_TESTING=ON; +# it relies on the iotdb_session target (and iotdb_thrift_static) already +# being defined at the parent scope. +# ============================================================================= -CMAKE_MINIMUM_REQUIRED(VERSION 3.7) -INCLUDE( CTest ) -SET(CMAKE_CXX_STANDARD 11) -SET(CMAKE_CXX_STANDARD_REQUIRED ON) -SET(TARGET_NAME session_tests) -SET(TARGET_NAME_RELATIONAL session_relational_tests) -IF(NOT MSVC) - # Keep GCC/Clang style flags off on MSVC to avoid invalid-option build errors. - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -g -O2") -ENDIF() -ENABLE_TESTING() +include(CTest) -# ========================= -# SSL option (default OFF) -# ========================= -option(WITH_SSL "Build with SSL support" OFF) +set(_test_targets + session_tests + session_relational_tests + session_c_tests + session_c_relational_tests) -IF(WITH_SSL) - FIND_PACKAGE(OpenSSL REQUIRED) - IF(OpenSSL_FOUND) - MESSAGE(STATUS "OpenSSL found: ${OPENSSL_VERSION}") - INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR}) - ADD_DEFINITIONS(-DWITH_SSL=1) - ELSE() - MESSAGE(FATAL_ERROR "OpenSSL not found, but WITH_SSL is enabled") - ENDIF() -ELSE() - MESSAGE(STATUS "Building without SSL support") - ADD_DEFINITIONS(-DWITH_SSL=0) -ENDIF() +add_executable(session_tests main.cpp cpp/sessionIT.cpp) +add_executable(session_relational_tests main_Relational.cpp cpp/sessionRelationalIT.cpp) +add_executable(session_c_tests main_c.cpp cpp/sessionCIT.cpp) +add_executable(session_c_relational_tests main_c_Relational.cpp cpp/sessionCRelationalIT.cpp) -# Add Boost include path for MacOS -INCLUDE_DIRECTORIES(/usr/local/include) -# Add Session related include files -INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/../main/generated-sources-cpp) -# Add Thrift include directory -INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/../../thrift/include) +foreach(_t IN LISTS _test_targets) + target_include_directories(${_t} PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/catch2") + target_link_libraries(${_t} PRIVATE iotdb_session) + if(WITH_SSL) + target_link_libraries(${_t} PRIVATE OpenSSL::SSL OpenSSL::Crypto) + endif() +endforeach() -# Add Boost library headers for MaxOS -FIND_PACKAGE(Boost REQUIRED) -IF (DEFINED BOOST_INCLUDEDIR) - include_directories("${Boost_INCLUDE_DIR}") -ENDIF() - -# Link directories are different for Windows and Linux/Mac -IF(MSVC) - LINK_DIRECTORIES(${CMAKE_SOURCE_DIR}/../main/Release) - SET(THRIFT_STATIC_LIB "${CMAKE_SOURCE_DIR}/../../thrift/lib/Release/thriftmd.lib") -ELSE() - LINK_DIRECTORIES(${CMAKE_SOURCE_DIR}/../main) - SET(THRIFT_STATIC_LIB "${CMAKE_SOURCE_DIR}/../../thrift/lib/libthrift.a") -ENDIF() - -IF(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang" AND NOT MSVC) - add_compile_options(-fsanitize=address -fno-omit-frame-pointer) - add_link_options(-fsanitize=address) -ENDIF() - -SET(TARGET_NAME_C session_c_tests) -SET(TARGET_NAME_C_RELATIONAL session_c_relational_tests) - -ADD_EXECUTABLE(${TARGET_NAME} main.cpp cpp/sessionIT.cpp) -ADD_EXECUTABLE(${TARGET_NAME_RELATIONAL} main_Relational.cpp cpp/sessionRelationalIT.cpp) -ADD_EXECUTABLE(${TARGET_NAME_C} main_c.cpp cpp/sessionCIT.cpp) -ADD_EXECUTABLE(${TARGET_NAME_C_RELATIONAL} main_c_Relational.cpp cpp/sessionCRelationalIT.cpp) - -# Link with shared library iotdb_session and pthread -SET(ALL_TEST_TARGETS ${TARGET_NAME} ${TARGET_NAME_RELATIONAL} ${TARGET_NAME_C} ${TARGET_NAME_C_RELATIONAL}) - -IF(MSVC) - IF(WITH_SSL) - FOREACH(T ${ALL_TEST_TARGETS}) - TARGET_LINK_LIBRARIES(${T} - iotdb_session - ${THRIFT_STATIC_LIB} - OpenSSL::SSL - OpenSSL::Crypto - ) - ENDFOREACH() - ELSE() - FOREACH(T ${ALL_TEST_TARGETS}) - TARGET_LINK_LIBRARIES(${T} - iotdb_session - ${THRIFT_STATIC_LIB} - ) - ENDFOREACH() - ENDIF() -ELSE() - IF(WITH_SSL) - FOREACH(T ${ALL_TEST_TARGETS}) - TARGET_LINK_LIBRARIES(${T} - iotdb_session - pthread - OpenSSL::SSL - OpenSSL::Crypto - ) - ENDFOREACH() - ELSE() - FOREACH(T ${ALL_TEST_TARGETS}) - TARGET_LINK_LIBRARIES(${T} - iotdb_session - pthread - ) - ENDFOREACH() - ENDIF() -ENDIF() - -# Add Catch2 include directory -FOREACH(T ${ALL_TEST_TARGETS}) - TARGET_INCLUDE_DIRECTORIES(${T} PUBLIC ./catch2/) -ENDFOREACH() - -# Add tests to ctest -IF(MSVC) - ADD_TEST(NAME sessionIT CONFIGURATIONS Release COMMAND ${TARGET_NAME}) - ADD_TEST(NAME sessionRelationalIT CONFIGURATIONS Release COMMAND ${TARGET_NAME_RELATIONAL}) - ADD_TEST(NAME sessionCIT CONFIGURATIONS Release COMMAND ${TARGET_NAME_C}) - ADD_TEST(NAME sessionCRelationalIT CONFIGURATIONS Release COMMAND ${TARGET_NAME_C_RELATIONAL}) -ELSE() - ADD_TEST(NAME sessionIT COMMAND ${TARGET_NAME}) - ADD_TEST(NAME sessionRelationalIT COMMAND ${TARGET_NAME_RELATIONAL}) - ADD_TEST(NAME sessionCIT COMMAND ${TARGET_NAME_C}) - ADD_TEST(NAME sessionCRelationalIT COMMAND ${TARGET_NAME_C_RELATIONAL}) -ENDIF() - -# One process at a time: parallel ctest overloads a single local IoTDB on 127.0.0.1:6667. -SET_TESTS_PROPERTIES(sessionIT sessionRelationalIT sessionCIT sessionCRelationalIT PROPERTIES RUN_SERIAL TRUE) +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang" AND NOT MSVC) + foreach(_t IN LISTS _test_targets) + target_compile_options(${_t} PRIVATE -fsanitize=address -fno-omit-frame-pointer) + target_link_options(${_t} PRIVATE -fsanitize=address) + endforeach() +endif() +# Linux: keep iotdb_session in the executable's needed-list even when there +# is no direct symbol reference from main.cpp (the IT helpers pull it in +# transitively); without this, ld may drop the lib at link time. if(UNIX AND NOT APPLE) - target_link_options(session_tests PRIVATE -Wl,--no-as-needed) - target_link_options(session_relational_tests PRIVATE -Wl,--no-as-needed) - target_link_options(session_c_tests PRIVATE -Wl,--no-as-needed) - target_link_options(session_c_relational_tests PRIVATE -Wl,--no-as-needed) + foreach(_t IN LISTS _test_targets) + target_link_options(${_t} PRIVATE -Wl,--no-as-needed) + endforeach() endif() + +# Register ctest cases (multi-config on MSVC). +if(MSVC) + add_test(NAME sessionIT CONFIGURATIONS Release COMMAND session_tests) + add_test(NAME sessionRelationalIT CONFIGURATIONS Release COMMAND session_relational_tests) + add_test(NAME sessionCIT CONFIGURATIONS Release COMMAND session_c_tests) + add_test(NAME sessionCRelationalIT CONFIGURATIONS Release COMMAND session_c_relational_tests) +else() + add_test(NAME sessionIT COMMAND session_tests) + add_test(NAME sessionRelationalIT COMMAND session_relational_tests) + add_test(NAME sessionCIT COMMAND session_c_tests) + add_test(NAME sessionCRelationalIT COMMAND session_c_relational_tests) +endif() + +# Run sequentially: parallel ctest overloads the single local IoTDB instance. +set_tests_properties( + sessionIT sessionRelationalIT sessionCIT sessionCRelationalIT + PROPERTIES RUN_SERIAL TRUE) diff --git a/iotdb-client/client-cpp/third-party/.gitignore b/iotdb-client/client-cpp/third-party/.gitignore new file mode 100644 index 0000000000000..c8badffab8dc0 --- /dev/null +++ b/iotdb-client/client-cpp/third-party/.gitignore @@ -0,0 +1,7 @@ +# Ignore all cached archives; keep directory structure and README tracked. +* +!.gitignore +!README.md +!linux/ +!mac/ +!windows/ diff --git a/iotdb-client/client-cpp/third-party/README.md b/iotdb-client/client-cpp/third-party/README.md new file mode 100644 index 0000000000000..c92733d50c6a8 --- /dev/null +++ b/iotdb-client/client-cpp/third-party/README.md @@ -0,0 +1,73 @@ + +# Third-party dependency cache (`client-cpp/third-party`) + +CMake downloads (or reuses) build-time tarballs and archives here. The +directory ships with the source tree so you can **stage dependencies on a +networked machine, copy the whole IoTDB checkout to an offline host, and +build `client-cpp` with `-DIOTDB_OFFLINE=ON`**. + +Tarballs themselves are **not** committed to Git (see per-platform +`.gitignore` files). Only this README and the empty platform folders are +tracked. + +## Layout + +``` +third-party/ +├── linux/ # tarballs for Linux offline builds +├── mac/ # tarballs for macOS offline builds +└── windows/ # tarballs / zips for Windows offline builds +``` + +Override the root with `-DIOTDB_DEPS_DIR=` (Maven: `-Diotdb.deps.dir=...`). +The platform sub-folder (`linux/`, `mac/`, `windows/`) is selected automatically. + +## Staging dependencies (online machine) + +Run a normal **online** configure once; CMake caches everything under the +matching `/` folder: + +```bash +cmake -S iotdb-client/client-cpp -B build +# or: mvn -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests package +``` + +Alternatively copy files manually from the URLs listed in +[`README.md`](../README.md) (*Offline build* section). + +## Offline machine (copy whole IoTDB tree) + +1. Copy the entire IoTDB repository (including `iotdb-client/client-cpp/third-party//`). +2. Configure with offline mode: + + ```bash + cmake -S iotdb-client/client-cpp -B build -DIOTDB_OFFLINE=ON + cmake --build build --config Release --target install + ``` + +## Per-platform files (offline minimum) + +| Platform | Typical 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` (+ `openssl-3.5.0.tar.gz` when `WITH_SSL=ON`) | +| `mac/` | `thrift-0.21.0.tar.gz`, `boost_1_60_0.tar.gz` (Xcode CLT usually provides m4/flex/bison) | +| `windows/` | `thrift-0.21.0.tar.gz`, `boost_1_60_0.tar.gz`, `win_flex_bison-2.5.25.zip` (or any `win_flex_bison*.zip`; skip if flex/bison already on `PATH`) | + +Download URLs: see the *Offline build* table in [`README.md`](../README.md). diff --git a/iotdb-client/client-cpp/third-party/linux/.gitignore b/iotdb-client/client-cpp/third-party/linux/.gitignore new file mode 100644 index 0000000000000..d6b7ef32c8478 --- /dev/null +++ b/iotdb-client/client-cpp/third-party/linux/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/iotdb-client/client-cpp/third-party/mac/.gitignore b/iotdb-client/client-cpp/third-party/mac/.gitignore new file mode 100644 index 0000000000000..d6b7ef32c8478 --- /dev/null +++ b/iotdb-client/client-cpp/third-party/mac/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/iotdb-client/client-cpp/third-party/windows/.gitignore b/iotdb-client/client-cpp/third-party/windows/.gitignore new file mode 100644 index 0000000000000..d6b7ef32c8478 --- /dev/null +++ b/iotdb-client/client-cpp/third-party/windows/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore From 3e3629df370c06ba79983fa5752009096792bb74 Mon Sep 17 00:00:00 2001 From: 761417898 <761417898@qq.com> Date: Wed, 20 May 2026 18:49:44 +0800 Subject: [PATCH 02/28] Fix macOS client-cpp CI bison version and add source-build workflow Install Homebrew bison on macOS package/IT runners so Thrift 0.21.0 builds (%code requires Bison 2.4+). Add client-cpp-source-build workflow that uses a minimal toolchain and online CMake fetch to verify zero-to-build compilation. --- .github/workflows/client-cpp-package.yml | 4 +- .github/workflows/client-cpp-source-build.yml | 131 ++++++++++++++++++ .github/workflows/multi-language-client.yml | 6 +- 3 files changed, 138 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/client-cpp-source-build.yml diff --git a/.github/workflows/client-cpp-package.yml b/.github/workflows/client-cpp-package.yml index b403dfad9dd41..76f5492015fdc 100644 --- a/.github/workflows/client-cpp-package.yml +++ b/.github/workflows/client-cpp-package.yml @@ -144,10 +144,12 @@ 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: diff --git a/.github/workflows/client-cpp-source-build.yml b/.github/workflows/client-cpp-source-build.yml new file mode 100644 index 0000000000000..028fa39858f77 --- /dev/null +++ b/.github/workflows/client-cpp-source-build.yml @@ -0,0 +1,131 @@ +# Verify client-cpp builds from a minimal toolchain: CMake downloads third-party +# sources into third-party// and compiles Thrift + iotdb_session without +# pre-installed Boost / flex / bison packages (except where the OS image lacks +# a working compiler or CMake). +name: C++ Client source build + +on: + push: + branches: + - master + - "rc/*" + paths: + - "pom.xml" + - "iotdb-client/pom.xml" + - "iotdb-client/client-cpp/**" + - "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" + pull_request: + branches: + - master + - "rc/*" + - "force_ci/**" + paths: + - "pom.xml" + - "iotdb-client/pom.xml" + - "iotdb-client/client-cpp/**" + - "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" + 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) + 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") + 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* "${INSTALL}/lib/"*thrift* + else + test -f "${INSTALL}/lib/libiotdb_session.so" \ + || test -f "${INSTALL}/lib/libiotdb_session.dylib" \ + || test -f "${INSTALL}/lib/libiotdb_session.a" + test -f "${INSTALL}/lib/libthrift.a" \ + || ls "${INSTALL}/lib/"*thrift* 1>/dev/null + fi + ls -la "${INSTALL}/include" | head -20 diff --git a/.github/workflows/multi-language-client.yml b/.github/workflows/multi-language-client.yml index 64bdf216c09ca..7b3e3089a6c6c 100644 --- a/.github/workflows/multi-language-client.yml +++ b/.github/workflows/multi-language-client.yml @@ -61,6 +61,7 @@ jobs: - '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' python: - 'pom.xml' - 'iotdb-client/pom.xml' @@ -118,11 +119,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 From 7696396ee522c7ce1dedd81413e58917cb7b11f9 Mon Sep 17 00:00:00 2001 From: 761417898 <761417898@qq.com> Date: Mon, 25 May 2026 11:07:37 +0800 Subject: [PATCH 03/28] Fix client-cpp-source-build: install clang-format-17 on all runners Align Linux/macOS/Windows toolchain setup with client-cpp-package so Spotless clang-format check during mvn package succeeds. --- .github/workflows/client-cpp-source-build.yml | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/.github/workflows/client-cpp-source-build.yml b/.github/workflows/client-cpp-source-build.yml index 028fa39858f77..3fd02962c40bf 100644 --- a/.github/workflows/client-cpp-source-build.yml +++ b/.github/workflows/client-cpp-source-build.yml @@ -74,6 +74,19 @@ jobs: sudo apt-get update # Compiler + CMake only; Boost/flex/bison/m4 come from CMake fetch. sudo apt-get install -y build-essential cmake wget + # Spotless (compile phase) requires clang-format 17 — same as client-cpp-package. + . /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 + sudo apt-get install -y clang-format-17 + else + sudo apt-get install -y clang-format-17 + 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 - name: Install minimal toolchain (macOS) if: runner.os == 'macOS' @@ -81,16 +94,20 @@ jobs: run: | set -euxo pipefail # Xcode CLT ships bison 2.3 which cannot build Thrift 0.21.0 (%code). - brew install bison cmake + brew install bison cmake llvm@17 + 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" bison --version + clang-format --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." + choco install llvm --version=17.0.6 --force -y + clang-format --version - name: Cache Maven packages uses: actions/cache@v5 From 10371374022c7504559180761e92024c32c2d115 Mon Sep 17 00:00:00 2001 From: 761417898 <761417898@qq.com> Date: Mon, 25 May 2026 11:33:51 +0800 Subject: [PATCH 04/28] Skip Spotless in client-cpp-source-build; drop clang-format install Source-build workflow focuses on minimal-toolchain CMake fetch; pass -Dspotless.skip=true instead of installing clang-format on runners. --- .github/workflows/client-cpp-source-build.yml | 23 +++---------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/.github/workflows/client-cpp-source-build.yml b/.github/workflows/client-cpp-source-build.yml index 3fd02962c40bf..662b75ff6d40f 100644 --- a/.github/workflows/client-cpp-source-build.yml +++ b/.github/workflows/client-cpp-source-build.yml @@ -74,19 +74,6 @@ jobs: sudo apt-get update # Compiler + CMake only; Boost/flex/bison/m4 come from CMake fetch. sudo apt-get install -y build-essential cmake wget - # Spotless (compile phase) requires clang-format 17 — same as client-cpp-package. - . /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 - sudo apt-get install -y clang-format-17 - else - sudo apt-get install -y clang-format-17 - 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 - name: Install minimal toolchain (macOS) if: runner.os == 'macOS' @@ -94,20 +81,16 @@ jobs: run: | set -euxo pipefail # Xcode CLT ships bison 2.3 which cannot build Thrift 0.21.0 (%code). - brew install bison cmake llvm@17 - ln -sf "$(brew --prefix llvm@17)/bin/clang-format" "$(brew --prefix)/bin/clang-format" + brew install bison cmake echo "$(brew --prefix bison)/bin" >> "$GITHUB_PATH" - echo "$(brew --prefix llvm@17)/bin" >> "$GITHUB_PATH" bison --version - clang-format --version - name: Install minimal toolchain (Windows) if: runner.os == 'Windows' shell: pwsh run: | # No choco boost / winflexbison: CMake downloads into third-party/windows/. - choco install llvm --version=17.0.6 --force -y - clang-format --version + Write-Host "Using preinstalled VS + CMake on the runner image." - name: Cache Maven packages uses: actions/cache@v5 @@ -124,7 +107,7 @@ jobs: run: | set -euxo pipefail MVN_ARGS=(./mvnw clean package -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests) - MVN_ARGS+=("-Diotdb.offline=OFF") + MVN_ARGS+=("-Diotdb.offline=OFF" "-Dspotless.skip=true") if [ -n "${CMAKE_GENERATOR:-}" ]; then MVN_ARGS+=("-Dcmake.generator=${CMAKE_GENERATOR}") fi From 2f175f38cbcb3ccb13a765d86b9113b46eee6fff Mon Sep 17 00:00:00 2001 From: 761417898 <761417898@qq.com> Date: Mon, 25 May 2026 19:07:41 +0800 Subject: [PATCH 05/28] Refactor C++ client SDK: isolate Thrift and ship Windows DLL. Reorganize sources into include/session/rpc with PIMPL so public headers no longer pull in Thrift or Boost. Embed Thrift in iotdb_session on all platforms; on Windows build a /MD shared library with import lib. Update examples, CI verification, and documentation for the slimmer SDK layout. --- .github/workflows/client-cpp-source-build.yml | 7 +- .gitignore | 1 + example/client-cpp-example/README.md | 225 +++++++- example/client-cpp-example/README_zh.md | 229 +++++++++ example/client-cpp-example/pom.xml | 23 - example/client-cpp-example/src/CMakeLists.txt | 181 +++---- .../src/MultiSvrNodeClient.cpp | 8 +- iotdb-client/client-cpp/CMakeLists.txt | 152 +++--- iotdb-client/client-cpp/README.md | 151 +++--- .../client-cpp/cmake/FetchBoost.cmake | 8 - .../client-cpp/cmake/FetchBuildTools.cmake | 57 +- .../client-cpp/cmake/FetchThrift.cmake | 65 +-- .../cmake/GenerateThriftSources.cmake | 4 +- iotdb-client/client-cpp/pom.xml | 4 +- .../AbstractSessionBuilder.h | 0 .../client-cpp/src/{main => include}/Column.h | 0 .../src/{main => include}/ColumnDecoder.h | 0 .../client-cpp/src/{main => include}/Common.h | 145 ++---- iotdb-client/client-cpp/src/include/Date.h | 74 +++ .../src/{main => include}/DeviceID.h | 0 .../client-cpp/src/include/Endpoint.h | 43 ++ iotdb-client/client-cpp/src/include/Export.h | 30 ++ .../client-cpp/src/include/Optional.h | 77 +++ .../src/{main => include}/Session.h | 329 +----------- .../src/{main => include}/SessionBuilder.h | 0 .../src/{main => include}/SessionC.h | 0 .../client-cpp/src/include/SessionDataSet.h | 123 +++++ iotdb-client/client-cpp/src/include/Status.h | 30 ++ .../src/{main => include}/TableSession.h | 0 .../{main => include}/TableSessionBuilder.h | 0 .../src/{main => include}/TsBlock.h | 0 .../client-cpp/src/main/SessionDataSet.cpp | 289 ----------- .../client-cpp/src/main/SessionDataSet.h | 124 ----- .../src/{main => rpc}/IoTDBRpcDataSet.cpp | 74 +-- .../src/{main => rpc}/IoTDBRpcDataSet.h | 51 +- .../src/{main => rpc}/NodesSupplier.cpp | 10 +- .../src/{main => rpc}/NodesSupplier.h | 8 +- iotdb-client/client-cpp/src/rpc/RpcCommon.cpp | 214 ++++++++ iotdb-client/client-cpp/src/rpc/RpcCommon.h | 81 +++ .../src/{main => rpc}/SessionConnection.cpp | 34 +- .../src/{main => rpc}/SessionConnection.h | 13 +- .../src/rpc/SessionDataSetFactory.h | 42 ++ iotdb-client/client-cpp/src/rpc/SessionImpl.h | 232 +++++++++ .../src/{main => rpc}/ThriftConnection.cpp | 15 +- .../src/{main => rpc}/ThriftConnection.h | 0 .../client-cpp/src/rpc/ThriftConvert.cpp | 61 +++ .../client-cpp/src/rpc/ThriftConvert.h | 40 ++ .../src/{main => session}/Column.cpp | 0 .../src/{main => session}/ColumnDecoder.cpp | 0 .../src/{main => session}/Common.cpp | 226 +------- iotdb-client/client-cpp/src/session/Date.cpp | 63 +++ .../src/{main => session}/Session.cpp | 486 +++++++++++------- .../src/{main => session}/SessionC.cpp | 0 .../client-cpp/src/session/SessionDataSet.cpp | 320 ++++++++++++ .../src/{main => session}/TableSession.cpp | 0 .../src/{main => session}/TsBlock.cpp | 0 .../client-cpp/src/test/CMakeLists.txt | 13 +- .../client-cpp/src/test/cpp/sessionIT.cpp | 7 +- .../src/test/cpp/sessionRelationalIT.cpp | 7 +- 59 files changed, 2642 insertions(+), 1734 deletions(-) create mode 100644 example/client-cpp-example/README_zh.md rename iotdb-client/client-cpp/src/{main => include}/AbstractSessionBuilder.h (100%) rename iotdb-client/client-cpp/src/{main => include}/Column.h (100%) rename iotdb-client/client-cpp/src/{main => include}/ColumnDecoder.h (100%) rename iotdb-client/client-cpp/src/{main => include}/Common.h (74%) create mode 100644 iotdb-client/client-cpp/src/include/Date.h rename iotdb-client/client-cpp/src/{main => include}/DeviceID.h (100%) create mode 100644 iotdb-client/client-cpp/src/include/Endpoint.h create mode 100644 iotdb-client/client-cpp/src/include/Export.h create mode 100644 iotdb-client/client-cpp/src/include/Optional.h rename iotdb-client/client-cpp/src/{main => include}/Session.h (74%) rename iotdb-client/client-cpp/src/{main => include}/SessionBuilder.h (100%) rename iotdb-client/client-cpp/src/{main => include}/SessionC.h (100%) create mode 100644 iotdb-client/client-cpp/src/include/SessionDataSet.h create mode 100644 iotdb-client/client-cpp/src/include/Status.h rename iotdb-client/client-cpp/src/{main => include}/TableSession.h (100%) rename iotdb-client/client-cpp/src/{main => include}/TableSessionBuilder.h (100%) rename iotdb-client/client-cpp/src/{main => include}/TsBlock.h (100%) delete mode 100644 iotdb-client/client-cpp/src/main/SessionDataSet.cpp delete mode 100644 iotdb-client/client-cpp/src/main/SessionDataSet.h rename iotdb-client/client-cpp/src/{main => rpc}/IoTDBRpcDataSet.cpp (88%) rename iotdb-client/client-cpp/src/{main => rpc}/IoTDBRpcDataSet.h (72%) rename iotdb-client/client-cpp/src/{main => rpc}/NodesSupplier.cpp (97%) rename iotdb-client/client-cpp/src/{main => rpc}/NodesSupplier.h (95%) create mode 100644 iotdb-client/client-cpp/src/rpc/RpcCommon.cpp create mode 100644 iotdb-client/client-cpp/src/rpc/RpcCommon.h rename iotdb-client/client-cpp/src/{main => rpc}/SessionConnection.cpp (93%) rename iotdb-client/client-cpp/src/{main => rpc}/SessionConnection.h (96%) create mode 100644 iotdb-client/client-cpp/src/rpc/SessionDataSetFactory.h create mode 100644 iotdb-client/client-cpp/src/rpc/SessionImpl.h rename iotdb-client/client-cpp/src/{main => rpc}/ThriftConnection.cpp (93%) rename iotdb-client/client-cpp/src/{main => rpc}/ThriftConnection.h (100%) create mode 100644 iotdb-client/client-cpp/src/rpc/ThriftConvert.cpp create mode 100644 iotdb-client/client-cpp/src/rpc/ThriftConvert.h rename iotdb-client/client-cpp/src/{main => session}/Column.cpp (100%) rename iotdb-client/client-cpp/src/{main => session}/ColumnDecoder.cpp (100%) rename iotdb-client/client-cpp/src/{main => session}/Common.cpp (52%) create mode 100644 iotdb-client/client-cpp/src/session/Date.cpp rename iotdb-client/client-cpp/src/{main => session}/Session.cpp (81%) rename iotdb-client/client-cpp/src/{main => session}/SessionC.cpp (100%) create mode 100644 iotdb-client/client-cpp/src/session/SessionDataSet.cpp rename iotdb-client/client-cpp/src/{main => session}/TableSession.cpp (100%) rename iotdb-client/client-cpp/src/{main => session}/TsBlock.cpp (100%) diff --git a/.github/workflows/client-cpp-source-build.yml b/.github/workflows/client-cpp-source-build.yml index 662b75ff6d40f..c8f8e141c8830 100644 --- a/.github/workflows/client-cpp-source-build.yml +++ b/.github/workflows/client-cpp-source-build.yml @@ -120,12 +120,9 @@ jobs: INSTALL="iotdb-client/client-cpp/target/install" if [ "${{ runner.os }}" = "Windows" ]; then test -d "${INSTALL}/include" - ls "${INSTALL}/lib/"*iotdb_session* "${INSTALL}/lib/"*thrift* + 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" \ - || test -f "${INSTALL}/lib/libiotdb_session.a" - test -f "${INSTALL}/lib/libthrift.a" \ - || ls "${INSTALL}/lib/"*thrift* 1>/dev/null + || test -f "${INSTALL}/lib/libiotdb_session.dylib" fi ls -la "${INSTALL}/include" | head -20 diff --git a/.gitignore b/.gitignore index 2f29ceaed6132..961a5b05d7565 100644 --- a/.gitignore +++ b/.gitignore @@ -91,6 +91,7 @@ tsfile/src/test/resources/*.ts ### clion project **/cmake-build-debug/ **/cmake-build-release/ +iotdb-client/client-cpp/build-*/ ### Apache release ### local-snapshots-dir/ diff --git a/example/client-cpp-example/README.md b/example/client-cpp-example/README.md index f36a084f888e5..fbfe98c78a99f 100644 --- a/example/client-cpp-example/README.md +++ b/example/client-cpp-example/README.md @@ -19,30 +19,217 @@ --> -# 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`). -You can find some files to form a complete project: +| 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 | + +## 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` 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** + +``` +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 ``` -+-- client -| +-- include -| +-- Session.h -| +-- IClientRPCService.h -| +-- rpc_types.h -| +-- rpc_constants.h -| +-- thrift -| +-- thrift_headers... -| +-- lib -| +-- libiotdb_session.dylib -+-- CMakeLists.txt -+-- SessionExample.cpp + +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 +``` +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..fc7246da6f4d8 --- /dev/null +++ b/example/client-cpp-example/README_zh.md @@ -0,0 +1,229 @@ + + +# 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` | 多节点写入/查询循环 | + +## 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` 与 `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 +``` + +执行 `mvn package` 后,可在 `target/` 下找到源码、`client/` SDK 与 CMake +构建产物。 diff --git a/example/client-cpp-example/pom.xml b/example/client-cpp-example/pom.xml index 9668aee28ebdf..c19eb69214e18 100644 --- a/example/client-cpp-example/pom.xml +++ b/example/client-cpp-example/pom.xml @@ -105,26 +105,6 @@ ${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 - - - - @@ -141,9 +121,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..b9ea2dfacbd9e 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.16) +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,74 @@ 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--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) -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) + +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/iotdb-client/client-cpp/CMakeLists.txt b/iotdb-client/client-cpp/CMakeLists.txt index ec9015cc2c6e0..7645d55bc3e75 100644 --- a/iotdb-client/client-cpp/CMakeLists.txt +++ b/iotdb-client/client-cpp/CMakeLists.txt @@ -18,34 +18,10 @@ # ============================================================================= # Apache IoTDB - C++ Session Client (top-level CMake build) # ============================================================================= -# This is the single entry point that fully manages the C++ client build, -# including third-party dependencies (Boost headers, Apache Thrift, optional -# OpenSSL) and toolchain bootstrap (m4 / flex / bison on Linux & macOS when -# the system PATH does not provide them). -# -# Standalone usage (no Maven required): -# cmake -S iotdb-client/client-cpp -B build [options] -# cmake --build build --config Release --target install -# -# Common options: -# -DWITH_SSL=ON|OFF Enable OpenSSL support (default OFF) -# -DBUILD_TESTING=ON|OFF Build IT executables (default OFF) -# -DIOTDB_OFFLINE=ON|OFF Disable any network access (default OFF). -# Requires tarballs under third-party/{os}/. -# -DIOTDB_DEPS_DIR= Override the third-party cache root. -# Default: /third-party -# (portable: copy the whole IoTDB tree to an -# offline machine after staging tarballs here). -# -DBOOST_ROOT= Existing Boost installation to reuse. -# -DCMAKE_INSTALL_PREFIX=... Install location (defaults to build/install). -# ============================================================================= cmake_minimum_required(VERSION 3.16) project(iotdb_session CXX C) -# --------------------------------------------------------------------------- -# Global settings -# --------------------------------------------------------------------------- set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) @@ -61,13 +37,10 @@ if(NOT MSVC) endif() if(MSVC) - # Match thrift's MultiThreaded runtime so static libraries link cleanly. - set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") + # /MD: matches default Visual Studio projects; CRT lives in the VC redistributable. + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL") endif() -# --------------------------------------------------------------------------- -# Cached options -# --------------------------------------------------------------------------- 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) @@ -75,13 +48,10 @@ 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/)") set(BOOST_VERSION "1.60.0" - CACHE STRING "Boost version used when downloading / unpacking") + 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") -# --------------------------------------------------------------------------- -# Platform -> local tarball directory -# --------------------------------------------------------------------------- if(WIN32) set(IOTDB_OS_DEPS_DIR "${IOTDB_DEPS_DIR}/windows") elseif(APPLE) @@ -91,8 +61,6 @@ else() endif() file(MAKE_DIRECTORY "${IOTDB_OS_DEPS_DIR}") -# Default install prefix lives inside the build tree so Maven's assembly -# step can pick everything up under a stable path. if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install" CACHE PATH "Install prefix" FORCE) @@ -100,51 +68,51 @@ endif() list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") -# --------------------------------------------------------------------------- -# Fetch / build third-party dependencies -# --------------------------------------------------------------------------- -include(FetchBoost) # -> BOOST_INCLUDE_DIR -include(FetchBuildTools) # -> populates ${CMAKE_BINARY_DIR}/tools/bin and updates ENV{PATH} +include(FetchBoost) # -> BOOST_INCLUDE_DIR (Thrift build only) +include(FetchBuildTools) if(WITH_SSL) include(FetchOpenSSL) endif() -include(FetchThrift) # -> target iotdb_thrift_static, THRIFT_EXECUTABLE, THRIFT_INCLUDE_DIR -include(GenerateThriftSources) # -> THRIFT_GENERATED_SRCS, THRIFT_GENERATED_HDRS +include(FetchThrift) +include(GenerateThriftSources) -# --------------------------------------------------------------------------- -# iotdb_session library -# --------------------------------------------------------------------------- -file(GLOB SESSION_HANDWRITTEN_SRCS CONFIGURE_DEPENDS - "${CMAKE_CURRENT_SOURCE_DIR}/src/main/*.cpp") -file(GLOB SESSION_HANDWRITTEN_HDRS CONFIGURE_DEPENDS - "${CMAKE_CURRENT_SOURCE_DIR}/src/main/*.h") +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") -if(MSVC) - add_library(iotdb_session STATIC - ${SESSION_HANDWRITTEN_SRCS} - ${THRIFT_GENERATED_SRCS}) -else() - add_library(iotdb_session SHARED - ${SESSION_HANDWRITTEN_SRCS} - ${THRIFT_GENERATED_SRCS}) +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 - $ - $ - $ - $) - -if(BOOST_INCLUDE_DIR) - 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) + target_link_libraries(iotdb_session PRIVATE + -Wl,--whole-archive ${THRIFT_STATIC_LIB_PATH} -Wl,--no-as-needed) +else() + target_link_libraries(iotdb_session PRIVATE iotdb_thrift_static) endif() -target_link_libraries(iotdb_session PUBLIC iotdb_thrift_static) - if(WITH_SSL) target_link_libraries(iotdb_session PUBLIC OpenSSL::SSL OpenSSL::Crypto) target_compile_definitions(iotdb_session PUBLIC WITH_SSL=1) @@ -156,38 +124,38 @@ if(UNIX) target_link_libraries(iotdb_session PUBLIC pthread) endif() -# --------------------------------------------------------------------------- -# Install rules - lay out the SDK exactly like the historical zip layout. -# /include/*.h (handwritten + generated cpp headers) -# /include/thrift/... (thrift runtime headers) -# /lib/ -# /lib/ (bundled so downstream users only need one tree) -# --------------------------------------------------------------------------- include(GNUInstallDirs) +set(IOTDB_PUBLIC_HEADERS + Export.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) -install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src/main/" - DESTINATION include - FILES_MATCHING PATTERN "*.h") - -install(DIRECTORY "${THRIFT_GEN_CPP_DIR}/" - DESTINATION include - FILES_MATCHING PATTERN "*.h") - -install(DIRECTORY "${THRIFT_INCLUDE_DIR}/thrift" - DESTINATION include) - -if(THRIFT_STATIC_LIB_PATH AND EXISTS "${THRIFT_STATIC_LIB_PATH}") - install(FILES "${THRIFT_STATIC_LIB_PATH}" DESTINATION lib) -endif() +foreach(_hdr IN LISTS IOTDB_PUBLIC_HEADERS) + install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/include/${_hdr}" + DESTINATION include) +endforeach() -# --------------------------------------------------------------------------- -# Tests -# --------------------------------------------------------------------------- if(BUILD_TESTING) enable_testing() add_subdirectory(src/test) @@ -198,7 +166,7 @@ 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}") +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}") diff --git a/iotdb-client/client-cpp/README.md b/iotdb-client/client-cpp/README.md index 7e55f81bba1e8..c93b50a498ef4 100644 --- a/iotdb-client/client-cpp/README.md +++ b/iotdb-client/client-cpp/README.md @@ -31,29 +31,23 @@ available. iotdb-client/client-cpp/ ├── CMakeLists.txt # single entry point - manages everything ├── cmake/ # helpers (FetchBoost / FetchThrift / ...) -├── third-party/ # downloaded tarballs (linux/ mac/ windows/) -├── src/main/ # handwritten C/C++ sources + public headers +├── 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) ├── src/test/ # Catch2-based integration tests └── pom.xml # Maven wrapper (cmake-maven-plugin) ``` -Third-party tarballs (Boost, Thrift, flex/bison, OpenSSL, ...) are cached -under **`third-party//`** inside this module. That keeps everything -portable: stage dependencies on a networked machine, **copy the whole IoTDB -tree** to an offline host, then build with `-DIOTDB_OFFLINE=ON`. Archives are -git-ignored; see [`third-party/README.md`](third-party/README.md). Override -the cache root with `-DIOTDB_DEPS_DIR=` (Maven: `-Diotdb.deps.dir=...`). - During configure CMake will, in order: -1. Resolve Boost headers (`find_package` → local `${IOTDB_DEPS_DIR}//` - tarball → download from `archives.boost.io` when not in offline mode). +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 (optional `THRIFT_TARBALL` → - `${IOTDB_DEPS_DIR}//` cache with `thrift-*.tar.gz` glob → download - from Apache archive when not in offline mode; **same on Windows**). +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, @@ -81,23 +75,20 @@ passed directly to `cmake`. | Option | Default | Purpose | |-----------------------|----------------------------------|----------------------------------------------------------------------------------------------------------| | `WITH_SSL` | `OFF` | Link against OpenSSL. See *SSL* below. | -| `BUILD_TESTING` | `ON` (`OFF` when `-DskipTests`) | Build Catch2 IT executables. | +| `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 third-party cache root (`linux/` / `mac/` / `windows/` appended automatically). | +| `IOTDB_DEPS_DIR` | `/third-party` | Override the local tarball cache directory. | | `BOOST_VERSION` | `1.60.0` | Boost version that CMake will look for / download. | | `THRIFT_VERSION` | `0.21.0` | Apache Thrift version to build from source. | -| `THRIFT_TARBALL` | (unset) | Path to a pre-downloaded `thrift-*.tar.gz` anywhere on disk (skips the cache lookup). | -| `THRIFT_URL` | (unset) | Override the Apache archive URL used when the thrift tarball is downloaded. | | `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 into `third-party//` at configure -time. The first run is slow (≈100 MB download + a Thrift build); subsequent -runs reuse both the cached archives and the extracted artifacts under -`build/_deps/`. +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 @@ -107,55 +98,40 @@ mvn -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests package mvn -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests "-Dboost.include.dir=C:\boost_1_88_0" package ``` -## Offline build (copy whole IoTDB tree) - -**Recommended workflow** - -1. On a **networked** machine, run one online configure/build so CMake fills - `iotdb-client/client-cpp/third-party//` (or copy tarballs there - manually — see table below). -2. Copy the **entire IoTDB repository** (including `third-party/`) to the - offline host. -3. Build with `-DIOTDB_OFFLINE=ON` (no downloads attempted). - -```bash -# Step 1 (online machine) -cmake -S iotdb-client/client-cpp -B build -# tarballs land in third-party/windows/ (or linux/ / mac/) +## Offline build -# Step 3 (offline machine, after copying the repo) -cmake -S iotdb-client/client-cpp -B build -DIOTDB_OFFLINE=ON -cmake --build build --config Release --target install -``` +1. Pre-populate the platform-specific sub-directory under `third-party/`: -### Files to place under `third-party//` + | 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_60_0.tar.gz` (Apple already 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`) | -| 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_60_0.tar.gz` (Apple already 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`), `win_flex_bison-2.5.25.zip` (any `win_flex_bison*.zip` name is accepted) | + 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: -Reference URLs (the configure step uses the same when downloading online): +2. Run the build with `-DIOTDB_OFFLINE=ON`: -- Apache Thrift 0.21.0: -- Boost 1.60.0: -- GNU m4 1.4.19: -- GNU flex 2.6.4: -- GNU bison 3.8: -- winflexbison 2.5.25: -- OpenSSL 3.5.0: + ```bash + mvn -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests \ + -DIOTDB_OFFLINE=ON package + ``` -Maven offline equivalent: + or, going straight through CMake: -```bash -mvn -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests \ - -DIOTDB_OFFLINE=ON package -``` + ```bash + cmake -S iotdb-client/client-cpp -B build -DIOTDB_OFFLINE=ON + cmake --build build --config Release --target install + ``` -Shared CI caches can still use `-DIOTDB_DEPS_DIR=/path/to/cache` if the -tarballs should live outside this module (the `/` sub-folder is still -appended automatically). +CI environments can share a single cache by setting +`-DIOTDB_DEPS_DIR=/path/to/cache` instead of copying tarballs around. ## Platform-specific notes @@ -182,34 +158,27 @@ The recommended toolchain is Visual Studio 2019 or 2022. Prerequisites: -1. **Apache Thrift.** Online builds download `thrift-0.21.0.tar.gz` into - `third-party/windows/` automatically (or pass - `-DTHRIFT_TARBALL=D:\path\to\thrift-0.21.0.tar.gz` for a copy elsewhere). - Offline builds require the tarball under `third-party/windows/` (any - `thrift-*.tar.gz` name is accepted) or `-DTHRIFT_TARBALL=...`. -2. **Boost.** Download and extract +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). -3. **flex / bison.** CMake handles this automatically: - - If the host already has `flex` / `bison` (or `win_flex` / `win_bison`) - on `PATH`, they are reused as-is. - - Otherwise, in online mode the build downloads - - into `third-party/windows/` and extracts it into `build\tools\bin\`, - renaming `win_flex.exe` / `win_bison.exe` to `flex.exe` / `bison.exe`. - - For offline builds pre-stage any `win_flex_bison*.zip` (e.g. - `win_flex_bison-latest.zip`) into `third-party/windows/`; CMake picks - the first match via glob. -4. **OpenSSL** *(only when `WITH_SSL=ON`)*: run the Win64 OpenSSL +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. -Auto-building m4 from the GNU autotools tarball is **not** supported on -Windows; the bundled winflexbison binaries already cover the flex/bison -needs of Apache Thrift's source build. +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 @@ -266,18 +235,20 @@ A successful `mvn ... package` produces ├── include/ │ ├── Session.h │ ├── SessionC.h -│ ├── ... (handwritten + generated headers) -│ └── thrift/ -│ └── ... (Thrift runtime headers) +│ └── ... (public API headers only; no Thrift/Boost) └── lib/ - ├── libiotdb_session.{so,dylib} (or iotdb_session.lib on Windows) - └── libthrift.{a,lib} (or thriftmd.lib on Windows) + ├── libiotdb_session.{so,dylib} (Linux / macOS) + ├── iotdb_session.dll (Windows – runtime) + └── iotdb_session.lib (Windows – import library for linking) ``` +Thrift is embedded inside `iotdb_session` on all platforms; it is not shipped +as a separate install artifact. + ## Using the C++ client ```cpp -#include "include/Session.h" +#include "Session.h" #include #include @@ -302,7 +273,7 @@ Compile against the produced SDK: clang++ -O2 user-cpp-code.cpp \ -I/path/to/sdk/include \ -L/path/to/sdk/lib \ - -liotdb_session -lthrift -lpthread \ + -liotdb_session -lpthread \ -Wl,-rpath,/path/to/sdk/lib \ -std=c++11 ``` diff --git a/iotdb-client/client-cpp/cmake/FetchBoost.cmake b/iotdb-client/client-cpp/cmake/FetchBoost.cmake index 6b817cc20eb71..d1ab9c18ae1b9 100644 --- a/iotdb-client/client-cpp/cmake/FetchBoost.cmake +++ b/iotdb-client/client-cpp/cmake/FetchBoost.cmake @@ -38,14 +38,6 @@ endif() # --------------------------------------------------------------------------- # Stage 1: find_package(Boost) - respects BOOST_ROOT / Boost_INCLUDE_DIR # --------------------------------------------------------------------------- -# CMP0167 (CMake 3.30+): the bundled FindBoost was removed in favour of -# BoostConfig.cmake shipped by Boost itself. For broad compatibility (we may -# be looking at a Boost source tree that does NOT ship BoostConfig), keep the -# legacy FindBoost behaviour and silence the developer warning. -if(POLICY CMP0167) - cmake_policy(SET CMP0167 OLD) -endif() - find_package(Boost QUIET) if(Boost_FOUND AND Boost_INCLUDE_DIRS) set(BOOST_INCLUDE_DIR "${Boost_INCLUDE_DIRS}" CACHE PATH "Boost include directory" FORCE) diff --git a/iotdb-client/client-cpp/cmake/FetchBuildTools.cmake b/iotdb-client/client-cpp/cmake/FetchBuildTools.cmake index 802c56728efac..f6031433a8e6f 100644 --- a/iotdb-client/client-cpp/cmake/FetchBuildTools.cmake +++ b/iotdb-client/client-cpp/cmake/FetchBuildTools.cmake @@ -33,8 +33,6 @@ # 3. FATAL_ERROR otherwise # ============================================================================= -include(IotdbResolveTarball) - set(_tools_prefix "${CMAKE_BINARY_DIR}/tools") set(_tools_bin "${_tools_prefix}/bin") file(MAKE_DIRECTORY "${_tools_bin}") @@ -66,6 +64,49 @@ 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}") @@ -126,8 +167,7 @@ if(WIN32) _iotdb_resolve_tarball(_wfb_zip "${_winflexbison_filename}" "${_winflexbison_url}" - GLOB_PATTERN "win_flex_bison*.zip" - LOG_PREFIX "BuildTools") + GLOB_PATTERN "win_flex_bison*.zip") set(_wfb_marker "${_tools_bin}/.winflexbison-installed") if(NOT EXISTS "${_wfb_marker}") @@ -172,8 +212,7 @@ endif() # 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}" - LOG_PREFIX "BuildTools") + _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() @@ -182,8 +221,7 @@ 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}" - LOG_PREFIX "BuildTools") + _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() @@ -192,8 +230,7 @@ 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}" - LOG_PREFIX "BuildTools") + _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() diff --git a/iotdb-client/client-cpp/cmake/FetchThrift.cmake b/iotdb-client/client-cpp/cmake/FetchThrift.cmake index 91b8ff2c5108f..98b205b3a93bc 100644 --- a/iotdb-client/client-cpp/cmake/FetchThrift.cmake +++ b/iotdb-client/client-cpp/cmake/FetchThrift.cmake @@ -18,15 +18,9 @@ # ============================================================================= # FetchThrift.cmake # -# Resolves the Apache Thrift source tarball (same three-stage pattern as -# FetchBuildTools / FetchBoost on every platform, including Windows): -# -# 1. Optional -DTHRIFT_TARBALL= to an existing archive anywhere on disk. -# 2. ${IOTDB_OS_DEPS_DIR}/thrift-.tar.gz (or any thrift-*.tar.gz match). -# 3. file(DOWNLOAD) from archive.apache.org when IOTDB_OFFLINE is OFF. -# -# Then builds thrift from source as a static-only runtime + compiler artifact. -# The build runs at configure time so the thrift compiler is available for the +# 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: @@ -46,38 +40,30 @@ # ============================================================================= include(ExternalProject) -include(IotdbResolveTarball) - -set(THRIFT_TARBALL "" CACHE FILEPATH - "Optional path to a pre-downloaded thrift tarball (bypasses ${IOTDB_OS_DEPS_DIR})") -set(THRIFT_URL "" CACHE STRING - "Override download URL for the thrift tarball (default: Apache archive)") set(_thrift_dirname "thrift-${THRIFT_VERSION}") set(_thrift_tarname "${_thrift_dirname}.tar.gz") # --------------------------------------------------------------------------- -# Resolve tarball (external path -> local cache / GLOB -> download) +# Resolve tarball (local cache -> download) # --------------------------------------------------------------------------- -if(THRIFT_TARBALL) - if(NOT EXISTS "${THRIFT_TARBALL}") +set(_thrift_tarball "${IOTDB_OS_DEPS_DIR}/${_thrift_tarname}") +if(NOT EXISTS "${_thrift_tarball}") + if(IOTDB_OFFLINE) message(FATAL_ERROR - "[Thrift] THRIFT_TARBALL points to a missing file: ${THRIFT_TARBALL}") + "[Thrift] IOTDB_OFFLINE=ON but ${_thrift_tarname} is missing in " + "${IOTDB_OS_DEPS_DIR}.") endif() - set(_thrift_tarball "${THRIFT_TARBALL}") - message(STATUS "[Thrift] using THRIFT_TARBALL=${_thrift_tarball}") -else() - if(THRIFT_URL) - set(_thrift_url "${THRIFT_URL}") - else() - set(_thrift_url - "https://archive.apache.org/dist/thrift/${THRIFT_VERSION}/${_thrift_tarname}") + 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() - _iotdb_resolve_tarball(_thrift_tarball - "${_thrift_tarname}" - "${_thrift_url}" - GLOB_PATTERN "thrift-*.tar.gz" - LOG_PREFIX "Thrift") endif() # --------------------------------------------------------------------------- @@ -122,10 +108,6 @@ set(_thrift_cmake_args "-DWITH_STATIC_LIB=ON" "-DCMAKE_POSITION_INDEPENDENT_CODE=ON" "-DCMAKE_POLICY_DEFAULT_CMP0091=NEW" - # Thrift 0.21.0 still declares cmake_minimum_required(VERSION 3.0) - # which CMake 4.x rejects. Bump the floor so the configure step - # passes on both 3.16+ and 4.x toolchains. - "-DCMAKE_POLICY_VERSION_MINIMUM=3.5" "-DCMAKE_CXX_STANDARD=11") if(BOOST_INCLUDE_DIR) @@ -136,7 +118,7 @@ endif() if(MSVC) list(APPEND _thrift_cmake_args - "-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded") + "-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDLL") else() list(APPEND _thrift_cmake_args "-DCMAKE_C_FLAGS=-fPIC" @@ -154,13 +136,16 @@ endif() # invoking cmake twice via execute_process and only register a phony # ExternalProject for dependency ordering. -set(_thrift_stamp "${_thrift_build}/.built-${THRIFT_VERSION}") +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}") - # FetchBuildTools already prepended ${IOTDB_LOCAL_TOOLS_BIN} to ENV{PATH}; - # the child cmake / build invocations inherit that environment. + # 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}") diff --git a/iotdb-client/client-cpp/cmake/GenerateThriftSources.cmake b/iotdb-client/client-cpp/cmake/GenerateThriftSources.cmake index e2571ef3654d7..6a3685af45847 100644 --- a/iotdb-client/client-cpp/cmake/GenerateThriftSources.cmake +++ b/iotdb-client/client-cpp/cmake/GenerateThriftSources.cmake @@ -122,5 +122,5 @@ file(GLOB THRIFT_GENERATED_HDRS CONFIGURE_DEPENDS "${THRIFT_GEN_CPP_DIR}/*.h") list(FILTER THRIFT_GENERATED_SRCS EXCLUDE REGEX ".*_server\\.skeleton\\.cpp$") -list(LENGTH THRIFT_GENERATED_SRCS _gen_count) -message(STATUS "[GenThrift] generated ${_gen_count} cpp files in ${THRIFT_GEN_CPP_DIR}") +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 3e1dfa154dc0c..cb97282671d3f 100644 --- a/iotdb-client/client-cpp/pom.xml +++ b/iotdb-client/client-cpp/pom.xml @@ -46,8 +46,6 @@ ${project.basedir} ${project.build.directory}/build ${project.build.directory}/install - ${project.basedir}/third-party OFF OFF @@ -56,7 +54,7 @@ ${ctest.skip.tests} - + diff --git a/iotdb-client/client-cpp/src/main/AbstractSessionBuilder.h b/iotdb-client/client-cpp/src/include/AbstractSessionBuilder.h similarity index 100% rename from iotdb-client/client-cpp/src/main/AbstractSessionBuilder.h rename to iotdb-client/client-cpp/src/include/AbstractSessionBuilder.h 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..958b9a716b51e 100644 --- a/iotdb-client/client-cpp/src/main/Common.h +++ b/iotdb-client/client-cpp/src/include/Common.h @@ -19,40 +19,20 @@ #ifndef IOTDB_COMMON_H #define IOTDB_COMMON_H +#include +#include +#include #include #include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include "client_types.h" -#include "common_types.h" +#include "Date.h" +#include "Endpoint.h" +#include "Export.h" +#include "Optional.h" +#include "Status.h" using namespace std; -using ::apache::thrift::TException; -using ::apache::thrift::protocol::TBinaryProtocol; -using ::apache::thrift::protocol::TCompactProtocol; -using ::apache::thrift::transport::TBufferedTransport; -using ::apache::thrift::transport::TFramedTransport; -using ::apache::thrift::transport::TSocket; -using ::apache::thrift::transport::TTransport; -using ::apache::thrift::transport::TTransportException; - -using namespace std; - -constexpr int32_t EMPTY_DATE_INT = 10000101; - -int32_t parseDateExpressionToInt(const boost::gregorian::date& date); -boost::gregorian::date parseIntToDate(int32_t dateInt); - std::string getTimePrecision(int32_t timeFactor); std::string formatDatetime(const std::string& format, const std::string& precision, @@ -121,13 +101,11 @@ namespace TSStatusCode { enum TSStatusCode { SUCCESS_STATUS = 200, - // System level INCOMPATIBLE_VERSION = 201, CONFIGURATION_ERROR = 202, START_UP_ERROR = 203, SHUT_DOWN_ERROR = 204, - // General Error UNSUPPORTED_OPERATION = 300, EXECUTE_STATEMENT_ERROR = 301, MULTIPLE_ERROR = 302, @@ -135,10 +113,8 @@ enum TSStatusCode { OVERLAP_WITH_EXISTING_TASK = 304, INTERNAL_SERVER_ERROR = 305, - // Client, REDIRECTION_RECOMMEND = 400, - // Schema Engine DATABASE_NOT_EXIST = 500, DATABASE_ALREADY_EXISTS = 501, SERIES_OVERFLOW = 502, @@ -165,12 +141,10 @@ enum TSStatusCode { PBTREE_FILE_REDO_LOG_BROKEN = 523, TEMPLATE_NOT_ACTIVATED = 524, - // Storage Engine SYSTEM_READ_ONLY = 600, STORAGE_ENGINE_ERROR = 601, STORAGE_ENGINE_NOT_READY = 602, - // Query Engine PLAN_FAILED_NETWORK_PARTITION = 721 }; } @@ -178,13 +152,13 @@ enum TSStatusCode { class Field { public: TSDataType::TSDataType dataType = TSDataType::UNKNOWN; - boost::optional boolV; - boost::optional intV; - boost::optional dateV; - boost::optional longV; - boost::optional floatV; - boost::optional doubleV; - boost::optional stringV; + Optional boolV; + Optional intV; + Optional dateV; + Optional longV; + Optional floatV; + Optional doubleV; + Optional stringV; explicit Field(TSDataType::TSDataType a) { dataType = a; @@ -192,7 +166,6 @@ class Field { Field() = default; - /** True if this field is SQL NULL (optional for the active dataType is unset). Unknown types are treated as null. */ bool isNull() const { switch (dataType) { case TSDataType::BOOLEAN: @@ -229,7 +202,7 @@ class MyStringBuffer { void clear(); bool hasRemaining(); int getInt(); - boost::gregorian::date getDate(); + IoTdbDate getDate(); int64_t getInt64(); float getFloat(); double getDouble(); @@ -238,7 +211,7 @@ class MyStringBuffer { std::string getString(); void putInt(int ins); - void putDate(boost::gregorian::date date); + void putDate(IoTdbDate date); void putInt64(int64_t ins); void putFloat(float ins); void putDouble(double ins); @@ -258,7 +231,7 @@ class MyStringBuffer { private: bool isBigEndian{}; - char numericBuf[8]{}; //only be used by int, long, float, double etc. + char numericBuf[8]{}; }; class BitMap { @@ -347,10 +320,10 @@ class ExecutionException : public IoTDBException { explicit ExecutionException(const std::string& m) : IoTDBException(m) {} - explicit ExecutionException(const std::string& m, const TSStatus& tsStatus) + explicit ExecutionException(const std::string& m, const Status& tsStatus) : IoTDBException(m), status(tsStatus) {} - TSStatus status; + Status status; }; class BatchExecutionException : public IoTDBException { @@ -361,13 +334,13 @@ class BatchExecutionException : public IoTDBException { explicit BatchExecutionException(const std::string& m) : IoTDBException(m) {} - explicit BatchExecutionException(const std::vector& statusList) + explicit BatchExecutionException(const std::vector& statusList) : statusList(statusList) {} - BatchExecutionException(const std::string& m, const std::vector& statusList) + BatchExecutionException(const std::string& m, const std::vector& statusList) : IoTDBException(m), statusList(statusList) {} - std::vector statusList; + std::vector statusList; }; class RedirectException : public IoTDBException { @@ -378,18 +351,18 @@ class RedirectException : public IoTDBException { explicit RedirectException(const std::string& m) : IoTDBException(m) {} - RedirectException(const std::string& m, const TEndPoint& endPoint) + RedirectException(const std::string& m, const Endpoint& endPoint) : IoTDBException(m), endPoint(endPoint) {} - RedirectException(const std::string& m, const map& deviceEndPointMap) + RedirectException(const std::string& m, const map& deviceEndPointMap) : IoTDBException(m), deviceEndPointMap(deviceEndPointMap) {} - RedirectException(const std::string& m, const vector& endPointList) + RedirectException(const std::string& m, const vector& endPointList) : IoTDBException(m), endPointList(endPointList) {} - TEndPoint endPoint; - map deviceEndPointMap; - vector endPointList; + Endpoint endPoint; + map deviceEndPointMap; + vector endPointList; }; class UnSupportedDataTypeException : public IoTDBException { @@ -422,7 +395,7 @@ class StatementExecutionException : public IoTDBException { enum LogLevelType { LEVEL_DEBUG = 0, LEVEL_INFO, LEVEL_WARN, LEVEL_ERROR }; -extern LogLevelType LOG_LEVEL; +extern IOTDB_SESSION_API LogLevelType LOG_LEVEL; #define log_debug(fmt, ...) \ do { \ @@ -453,62 +426,4 @@ extern LogLevelType LOG_LEVEL; } \ } while (0) -class RpcUtils { -public: - std::shared_ptr SUCCESS_STATUS; - - RpcUtils() { - SUCCESS_STATUS = std::make_shared(); - SUCCESS_STATUS->__set_code(TSStatusCode::SUCCESS_STATUS); - } - - static void verifySuccess(const TSStatus& status); - - static void verifySuccessWithRedirection(const TSStatus& status); - - static void verifySuccessWithRedirectionForMultiDevices(const TSStatus& status, - vector devices); - - static void verifySuccess(const std::vector& statuses); - - static TSStatus getStatus(TSStatusCode::TSStatusCode tsStatusCode); - - static TSStatus getStatus(int code, const std::string& message); - - static std::shared_ptr - getTSExecuteStatementResp(TSStatusCode::TSStatusCode tsStatusCode); - - static std::shared_ptr - getTSExecuteStatementResp(TSStatusCode::TSStatusCode tsStatusCode, const std::string& message); - - static std::shared_ptr getTSExecuteStatementResp(const TSStatus& status); - - static std::shared_ptr - getTSFetchResultsResp(TSStatusCode::TSStatusCode tsStatusCode); - - static std::shared_ptr - getTSFetchResultsResp(TSStatusCode::TSStatusCode tsStatusCode, const std::string& appendMessage); - - static std::shared_ptr getTSFetchResultsResp(const TSStatus& status); -}; - -class UrlUtils { -private: - static const std::string PORT_SEPARATOR; - static const std::string ABB_COLON; - - UrlUtils() = delete; - ~UrlUtils() = delete; - -public: - /** - * Parse TEndPoint from a given TEndPointUrl - * example:[D80:0000:0000:0000:ABAA:0000:00C2:0002]:22227 - * - * @param endPointUrl ip:port - * @return TEndPoint with default values if parse error - */ - static TEndPoint parseTEndPointIpv4AndIpv6Url(const std::string& endPointUrl); -}; - #endif diff --git a/iotdb-client/client-cpp/src/include/Date.h b/iotdb-client/client-cpp/src/include/Date.h new file mode 100644 index 0000000000000..e97bef6ad3c3e --- /dev/null +++ b/iotdb-client/client-cpp/src/include/Date.h @@ -0,0 +1,74 @@ +/** + * 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. + */ +#ifndef IOTDB_DATE_H +#define IOTDB_DATE_H + +#include +#include + +constexpr int32_t EMPTY_DATE_INT = 10000101; + +class IoTdbDate { +public: + IoTdbDate() : valid_(false), year_(0), month_(0), day_(0) {} + + IoTdbDate(int year, int month, int day) : valid_(true), year_(year), month_(month), day_(day) {} + + static IoTdbDate notADate() { + return IoTdbDate(); + } + + bool is_not_a_date() const { + return !valid_; + } + + int year() const { + return year_; + } + + int month() const { + return month_; + } + + int day() const { + return day_; + } + + std::string toIsoExtendedString() const; + + friend bool operator==(const IoTdbDate& lhs, const IoTdbDate& rhs) { + return lhs.valid_ == rhs.valid_ && lhs.year_ == rhs.year_ && lhs.month_ == rhs.month_ && + lhs.day_ == rhs.day_; + } + + friend bool operator!=(const IoTdbDate& lhs, const IoTdbDate& rhs) { + return !(lhs == rhs); + } + +private: + bool valid_; + int year_; + int month_; + int day_; +}; + +int32_t parseDateExpressionToInt(const IoTdbDate& date); +IoTdbDate parseIntToDate(int32_t dateInt); + +#endif diff --git a/iotdb-client/client-cpp/src/main/DeviceID.h b/iotdb-client/client-cpp/src/include/DeviceID.h similarity index 100% rename from iotdb-client/client-cpp/src/main/DeviceID.h rename to iotdb-client/client-cpp/src/include/DeviceID.h diff --git a/iotdb-client/client-cpp/src/include/Endpoint.h b/iotdb-client/client-cpp/src/include/Endpoint.h new file mode 100644 index 0000000000000..187e939c0d3ea --- /dev/null +++ b/iotdb-client/client-cpp/src/include/Endpoint.h @@ -0,0 +1,43 @@ +/** + * 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. + */ +#ifndef IOTDB_ENDPOINT_H +#define IOTDB_ENDPOINT_H + +#include +#include +#include + +struct Endpoint { + std::string host; + int32_t port = 0; +}; + +struct EndpointHash { + size_t operator()(const Endpoint& endpoint) const { + return std::hash()(endpoint.host) ^ std::hash()(endpoint.port); + } +}; + +struct EndpointEqual { + bool operator()(const Endpoint& lhs, const Endpoint& rhs) const { + return lhs.host == rhs.host && lhs.port == rhs.port; + } +}; + +#endif diff --git a/iotdb-client/client-cpp/src/include/Export.h b/iotdb-client/client-cpp/src/include/Export.h new file mode 100644 index 0000000000000..71262d0cffb77 --- /dev/null +++ b/iotdb-client/client-cpp/src/include/Export.h @@ -0,0 +1,30 @@ +/** + * 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. + */ +#ifndef IOTDB_EXPORT_H +#define IOTDB_EXPORT_H + +#if defined(_WIN32) && defined(IOTDB_BUILDING_SHARED) +#define IOTDB_SESSION_API __declspec(dllexport) +#elif defined(_WIN32) +#define IOTDB_SESSION_API __declspec(dllimport) +#else +#define IOTDB_SESSION_API +#endif + +#endif // IOTDB_EXPORT_H diff --git a/iotdb-client/client-cpp/src/include/Optional.h b/iotdb-client/client-cpp/src/include/Optional.h new file mode 100644 index 0000000000000..07092859c22a0 --- /dev/null +++ b/iotdb-client/client-cpp/src/include/Optional.h @@ -0,0 +1,77 @@ +/** + * 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. + */ +#ifndef IOTDB_OPTIONAL_H +#define IOTDB_OPTIONAL_H + +#include + +template class Optional { +public: + Optional() : hasValue_(false) {} + + Optional(const T& value) : hasValue_(true), value_(value) {} + + Optional(T&& value) : hasValue_(true), value_(std::move(value)) {} + + static Optional of(const T& value) { + return Optional(value); + } + + static Optional of(T&& value) { + return Optional(std::move(value)); + } + + static Optional none() { + return Optional(); + } + + bool is_initialized() const { + return hasValue_; + } + + bool has_value() const { + return hasValue_; + } + + const T& value() const { + return value_; + } + + T& value() { + return value_; + } + + const T& get() const { + return value_; + } + + T& get() { + return value_; + } + + explicit operator bool() const { + return hasValue_; + } + +private: + bool hasValue_; + T value_{}; +}; + +#endif diff --git a/iotdb-client/client-cpp/src/main/Session.h b/iotdb-client/client-cpp/src/include/Session.h similarity index 74% rename from iotdb-client/client-cpp/src/main/Session.h rename to iotdb-client/client-cpp/src/include/Session.h index cedfaeba1966d..818e49bee994e 100644 --- a/iotdb-client/client-cpp/src/main/Session.h +++ b/iotdb-client/client-cpp/src/include/Session.h @@ -32,19 +32,11 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include "IClientRPCService.h" -#include "NodesSupplier.h" #include "AbstractSessionBuilder.h" -#include "SessionConnection.h" -#include "SessionDataSet.h" -#include "DeviceID.h" #include "Common.h" +#include "Date.h" +#include "DeviceID.h" +#include "SessionDataSet.h" //== For compatible with Windows OS == #ifndef LONG_LONG_MIN @@ -53,15 +45,6 @@ using namespace std; -using ::apache::thrift::TException; -using ::apache::thrift::protocol::TBinaryProtocol; -using ::apache::thrift::protocol::TCompactProtocol; -using ::apache::thrift::transport::TBufferedTransport; -using ::apache::thrift::transport::TFramedTransport; -using ::apache::thrift::transport::TSocket; -using ::apache::thrift::transport::TTransport; -using ::apache::thrift::transport::TTransportException; - template void safe_cast(const T& value, Target& target) { /* Target Allowed Source Types @@ -282,8 +265,7 @@ class Tablet { break; } case TSDataType::DATE: { - safe_cast(value, - ((boost::gregorian::date*)values[schemaId])[rowIndex]); + safe_cast(value, ((IoTdbDate*)values[schemaId])[rowIndex]); break; } case TSDataType::TIMESTAMP: @@ -391,7 +373,7 @@ class Tablet { case TSDataType::INT32: return &(reinterpret_cast(values[schemaId])[rowIndex]); case TSDataType::DATE: - return &(reinterpret_cast(values[schemaId])[rowIndex]); + return &(reinterpret_cast(values[schemaId])[rowIndex]); case TSDataType::TIMESTAMP: case TSDataType::INT64: return &(reinterpret_cast(values[schemaId])[rowIndex]); @@ -574,214 +556,34 @@ class Template { bool is_aligned_; }; +class SessionConnection; +class TableSession; + class Session { -private: - std::string host_; - int rpcPort_; - bool useSSL_ = false; - std::string trustCertFilePath_; - std::vector nodeUrls_; - std::string username_; - std::string password_; - const TSProtocolVersion::type protocolVersion_ = TSProtocolVersion::IOTDB_SERVICE_PROTOCOL_V3; - bool isClosed_ = true; - std::string zoneId_; - int fetchSize_; - const static int DEFAULT_FETCH_SIZE = 10000; - const static int DEFAULT_TIMEOUT_MS = 0; - int connectTimeoutMs_; - Version::Version version; - std::string sqlDialect_ = "tree"; // default sql dialect - std::string database_; - bool enableAutoFetch_ = true; - bool enableRedirection_ = true; - std::shared_ptr nodesSupplier_; + struct Impl; + std::unique_ptr impl_; friend class SessionConnection; friend class TableSession; - std::shared_ptr defaultSessionConnection_; - - TEndPoint defaultEndPoint_; - - struct TEndPointHash { - size_t operator()(const TEndPoint& endpoint) const { - return std::hash()(endpoint.ip) ^ std::hash()(endpoint.port); - } - }; - - struct TEndPointEqual { - bool operator()(const TEndPoint& lhs, const TEndPoint& rhs) const { - return lhs.ip == rhs.ip && lhs.port == rhs.port; - } - }; - - using EndPointSessionMap = - std::unordered_map, TEndPointHash, TEndPointEqual>; - EndPointSessionMap endPointToSessionConnection; - std::unordered_map deviceIdToEndpoint; - std::unordered_map, TEndPoint> tableModelDeviceIdToEndpoint; - -private: - void removeBrokenSessionConnection(shared_ptr sessionConnection); - - static bool checkSorted(const Tablet& tablet); - - static bool checkSorted(const std::vector& times); - - static void sortTablet(Tablet& tablet); - - static void sortIndexByTimestamp(int* index, std::vector& timestamps, int length); - - void appendValues(std::string& buffer, const char* value, int size); - - void putValuesIntoBuffer(const std::vector& types, - const std::vector& values, std::string& buf); - - int8_t getDataTypeNumber(TSDataType::TSDataType type); - - struct TsCompare { - std::vector& timestamps; - - explicit TsCompare(std::vector& inTimestamps) : timestamps(inTimestamps){}; - - bool operator()(int i, int j) { - return (timestamps[i] < timestamps[j]); - }; - }; - - std::string getVersionString(Version::Version version); - - void initZoneId(); - - void initNodesSupplier(const std::vector& nodeUrls = std::vector()); - - void initDefaultSessionConnection(); - - template - void insertByGroup(std::unordered_map, T>& insertGroup, - InsertConsumer insertConsumer); - - template - void insertOnce(std::unordered_map, T>& insertGroup, - InsertConsumer insertConsumer); - - void insertStringRecordsWithLeaderCache(vector deviceIds, vector times, - vector> measurementsList, - vector> valuesList, bool isAligned); - - void insertRecordsWithLeaderCache(vector deviceIds, vector times, - vector> measurementsList, - const vector>& typesList, - vector> valuesList, bool isAligned); - - void insertTabletsWithLeaderCache(unordered_map tablets, bool sorted, - bool isAligned); - - shared_ptr getQuerySessionConnection(); - - shared_ptr getSessionConnection(std::string deviceId); - - shared_ptr getSessionConnection(std::shared_ptr deviceId); - - void handleQueryRedirection(TEndPoint endPoint); - - void handleRedirection(const std::string& deviceId, TEndPoint endPoint); - - void handleRedirection(const std::shared_ptr& deviceId, TEndPoint endPoint); - - void setSqlDialect(const std::string& dialect) { - this->sqlDialect_ = dialect; - } - - void setDatabase(const std::string& database) { - this->database_ = database; - } - - string getDatabase() { - return database_; - } - - void changeDatabase(string database) { - this->database_ = database; - } public: - Session(const std::string& host, int rpcPort) - : username_("root"), password_("root"), version(Version::V_1_0) { - this->host_ = host; - this->rpcPort_ = rpcPort; - initZoneId(); - initNodesSupplier(); - } - - Session(const std::vector& nodeUrls, const std::string& username, - const std::string& password) - : nodeUrls_(nodeUrls), username_(username), password_(password), version(Version::V_1_0) { - initZoneId(); - initNodesSupplier(this->nodeUrls_); - } - + Session(const std::string& host, int rpcPort); + Session(const std::vector& nodeUrls, const std::string& username, + const std::string& password); Session(const std::string& host, int rpcPort, const std::string& username, - const std::string& password) - : fetchSize_(DEFAULT_FETCH_SIZE) { - this->host_ = host; - this->rpcPort_ = rpcPort; - this->username_ = username; - this->password_ = password; - this->version = Version::V_1_0; - initZoneId(); - initNodesSupplier(); - } - + const std::string& password); Session(const std::string& host, int rpcPort, const std::string& username, - const std::string& password, const std::string& zoneId, - int fetchSize = DEFAULT_FETCH_SIZE) { - this->host_ = host; - this->rpcPort_ = rpcPort; - this->username_ = username; - this->password_ = password; - this->zoneId_ = zoneId; - this->fetchSize_ = fetchSize; - this->version = Version::V_1_0; - initZoneId(); - initNodesSupplier(); - } - + const std::string& password, const std::string& zoneId, int fetchSize = 10000); Session(const std::string& host, const std::string& rpcPort, const std::string& username = "user", const std::string& password = "password", const std::string& zoneId = "", - int fetchSize = DEFAULT_FETCH_SIZE) { - this->host_ = host; - this->rpcPort_ = stoi(rpcPort); - this->username_ = username; - this->password_ = password; - this->zoneId_ = zoneId; - this->fetchSize_ = fetchSize; - this->version = Version::V_1_0; - initZoneId(); - initNodesSupplier(); - } - - Session(AbstractSessionBuilder* builder) { - this->host_ = builder->host; - this->rpcPort_ = builder->rpcPort; - this->username_ = builder->username; - this->password_ = builder->password; - this->zoneId_ = builder->zoneId; - this->fetchSize_ = builder->fetchSize; - this->version = Version::V_1_0; - this->sqlDialect_ = builder->sqlDialect; - this->database_ = builder->database; - this->enableAutoFetch_ = builder->enableAutoFetch; - this->enableRedirection_ = builder->enableRedirections; - this->connectTimeoutMs_ = builder->connectTimeoutMs; - this->nodeUrls_ = builder->nodeUrls; - this->useSSL_ = builder->useSSL; - this->trustCertFilePath_ = builder->trustCertFilePath; - initZoneId(); - initNodesSupplier(this->nodeUrls_); - } - + int fetchSize = 10000); + Session(AbstractSessionBuilder* builder); ~Session(); + void setSqlDialect(const std::string& dialect); + void setDatabase(const std::string& database); + std::string getDatabase(); + void changeDatabase(const std::string& database); + void open(); void open(bool enableRPCCompression); @@ -858,20 +660,8 @@ class Session { void insertRelationalTablet(Tablet& tablet); - void insertRelationalTabletOnce( - const std::unordered_map, Tablet>& relationalTabletGroup, - bool sorted); - - void insertRelationalTabletByGroup( - const std::unordered_map, Tablet>& relationalTabletGroup, - bool sorted); - void insertRelationalTablet(Tablet& tablet, bool sorted); - static void buildInsertTabletReq(TSInsertTabletReq& request, Tablet& tablet, bool sorted); - - void insertTablet(TSInsertTabletReq request); - void insertAlignedTablet(Tablet& tablet); void insertAlignedTablet(Tablet& tablet, bool sorted); @@ -1008,79 +798,4 @@ class Session { bool checkTemplateExists(const std::string& template_name); }; -template -void Session::insertByGroup(std::unordered_map, T>& insertGroup, - InsertConsumer insertConsumer) { - std::vector> futures; - - for (auto& entry : insertGroup) { - auto connection = entry.first; - auto& req = entry.second; - futures.emplace_back(std::async(std::launch::async, [=, &req]() mutable { - try { - insertConsumer(connection, req); - } catch (const RedirectException& e) { - for (const auto& deviceEndPoint : e.deviceEndPointMap) { - handleRedirection(deviceEndPoint.first, deviceEndPoint.second); - } - } catch (const IoTDBConnectionException& e) { - if (endPointToSessionConnection.size() > 1) { - removeBrokenSessionConnection(connection); - try { - insertConsumer(defaultSessionConnection_, req); - } catch (const RedirectException&) { - } - } else { - throw; - } - } catch (const std::exception& e) { - log_debug(e.what()); - throw IoTDBException(e.what()); - } - })); - } - - std::string errorMessages; - for (auto& f : futures) { - try { - f.get(); - } catch (const IoTDBConnectionException& e) { - throw; - } catch (const std::exception& e) { - if (!errorMessages.empty()) { - errorMessages += ";"; - } - errorMessages += e.what(); - } - } - - if (!errorMessages.empty()) { - throw StatementExecutionException(errorMessages); - } -} - -template -void Session::insertOnce(std::unordered_map, T>& insertGroup, - InsertConsumer insertConsumer) { - auto connection = insertGroup.begin()->first; - auto req = insertGroup.begin()->second; - try { - insertConsumer(connection, req); - } catch (const RedirectException& e) { - for (const auto& deviceEndPoint : e.deviceEndPointMap) { - handleRedirection(deviceEndPoint.first, deviceEndPoint.second); - } - } catch (const IoTDBConnectionException& e) { - if (endPointToSessionConnection.size() > 1) { - removeBrokenSessionConnection(connection); - try { - insertConsumer(defaultSessionConnection_, req); - } catch (const RedirectException& e) { - } - } else { - throw; - } - } -} - #endif // IOTDB_SESSION_H diff --git a/iotdb-client/client-cpp/src/main/SessionBuilder.h b/iotdb-client/client-cpp/src/include/SessionBuilder.h similarity index 100% rename from iotdb-client/client-cpp/src/main/SessionBuilder.h rename to iotdb-client/client-cpp/src/include/SessionBuilder.h diff --git a/iotdb-client/client-cpp/src/main/SessionC.h b/iotdb-client/client-cpp/src/include/SessionC.h similarity index 100% rename from iotdb-client/client-cpp/src/main/SessionC.h rename to iotdb-client/client-cpp/src/include/SessionC.h diff --git a/iotdb-client/client-cpp/src/include/SessionDataSet.h b/iotdb-client/client-cpp/src/include/SessionDataSet.h new file mode 100644 index 0000000000000..dc0f7dc421de8 --- /dev/null +++ b/iotdb-client/client-cpp/src/include/SessionDataSet.h @@ -0,0 +1,123 @@ +/** +* 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. + */ + +#ifndef IOTDB_SESSION_DATA_SET_H +#define IOTDB_SESSION_DATA_SET_H + +#include +#include +#include +#include +#include + +#include "Column.h" +#include "Date.h" +#include "Optional.h" + +class RowRecord { +public: + int64_t timestamp; + std::vector fields; + + explicit RowRecord(int64_t timestamp); + RowRecord(int64_t timestamp, const std::vector& fields); + explicit RowRecord(const std::vector& fields); + RowRecord(); + + void addField(const Field& f); + std::string toString(); +}; + +class Session; + +class SessionDataSet { + struct Impl; + std::unique_ptr impl_; + SessionDataSet() = default; + friend class Session; + friend std::unique_ptr + createSessionDataSet(const std::string& sql, const std::vector& columnNameList, + const std::vector& columnTypeList, + const std::map& columnNameIndex, int64_t queryId, + int64_t statementId, std::shared_ptr client, + int64_t sessionId, const std::vector& queryResult, + bool ignoreTimestamp, int64_t timeout, bool moreData, int32_t fetchSize, + const std::string& zoneId, int32_t timeFactor, + std::vector& columnIndex2TsBlockColumnIndexList); + +private: + std::shared_ptr constructRowRecordFromValueArray(); + +public: + ~SessionDataSet(); + + bool hasNext(); + std::shared_ptr next(); + + int getFetchSize(); + void setFetchSize(int fetchSize); + + const std::vector& getColumnNames() const; + const std::vector& getColumnTypeList() const; + void closeOperationHandle(bool forceClose = false); + + class DataIterator { + std::shared_ptr impl_; + + public: + explicit DataIterator(std::shared_ptr impl); + + bool next(); + + bool isNull(const std::string& columnName); + bool isNullByIndex(int32_t columnIndex); + + Optional getBooleanByIndex(int32_t columnIndex); + Optional getBoolean(const std::string& columnName); + + Optional getDoubleByIndex(int32_t columnIndex); + Optional getDouble(const std::string& columnName); + + Optional getFloatByIndex(int32_t columnIndex); + Optional getFloat(const std::string& columnName); + + Optional getIntByIndex(int32_t columnIndex); + Optional getInt(const std::string& columnName); + + Optional getLongByIndex(int32_t columnIndex); + Optional getLong(const std::string& columnName); + + Optional getStringByIndex(int32_t columnIndex); + Optional getString(const std::string& columnName); + + Optional getTimestampByIndex(int32_t columnIndex); + Optional getTimestamp(const std::string& columnName); + + Optional getDateByIndex(int32_t columnIndex); + Optional getDate(const std::string& columnName); + + int32_t findColumn(const std::string& columnName); + const std::vector& getColumnNames() const; + const std::vector& getColumnTypeList() const; + }; + + DataIterator getIterator(); +}; + +#endif diff --git a/iotdb-client/client-cpp/src/include/Status.h b/iotdb-client/client-cpp/src/include/Status.h new file mode 100644 index 0000000000000..147c20cffd21c --- /dev/null +++ b/iotdb-client/client-cpp/src/include/Status.h @@ -0,0 +1,30 @@ +/** + * 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. + */ +#ifndef IOTDB_STATUS_H +#define IOTDB_STATUS_H + +#include +#include + +struct Status { + int32_t code = 0; + std::string message; +}; + +#endif diff --git a/iotdb-client/client-cpp/src/main/TableSession.h b/iotdb-client/client-cpp/src/include/TableSession.h similarity index 100% rename from iotdb-client/client-cpp/src/main/TableSession.h rename to iotdb-client/client-cpp/src/include/TableSession.h diff --git a/iotdb-client/client-cpp/src/main/TableSessionBuilder.h b/iotdb-client/client-cpp/src/include/TableSessionBuilder.h similarity index 100% rename from iotdb-client/client-cpp/src/main/TableSessionBuilder.h rename to iotdb-client/client-cpp/src/include/TableSessionBuilder.h diff --git a/iotdb-client/client-cpp/src/main/TsBlock.h b/iotdb-client/client-cpp/src/include/TsBlock.h similarity index 100% rename from iotdb-client/client-cpp/src/main/TsBlock.h rename to iotdb-client/client-cpp/src/include/TsBlock.h diff --git a/iotdb-client/client-cpp/src/main/SessionDataSet.cpp b/iotdb-client/client-cpp/src/main/SessionDataSet.cpp deleted file mode 100644 index 11c2e8f528bd1..0000000000000 --- a/iotdb-client/client-cpp/src/main/SessionDataSet.cpp +++ /dev/null @@ -1,289 +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. - */ - -#include "SessionDataSet.h" -#include -#include - -RowRecord::RowRecord(int64_t timestamp) { - this->timestamp = timestamp; -} - -RowRecord::RowRecord(int64_t timestamp, const std::vector& fields) - : timestamp(timestamp), fields(fields) {} - -RowRecord::RowRecord(const std::vector& fields) : timestamp(-1), fields(fields) {} - -RowRecord::RowRecord() { - this->timestamp = -1; -} - -void RowRecord::addField(const Field& f) { - this->fields.push_back(f); -} - -std::string RowRecord::toString() { - std::string ret; - if (this->timestamp != -1) { - ret.append(std::to_string(timestamp)); - ret.append("\t"); - } - for (size_t i = 0; i < fields.size(); i++) { - if (i != 0) { - ret.append("\t"); - } - const Field& f = fields[i]; - switch (f.dataType) { - case TSDataType::BOOLEAN: - if (f.isNull()) { - ret.append("null"); - } else { - ret.append(f.boolV.value() ? "true" : "false"); - } - break; - case TSDataType::INT32: - if (f.isNull()) { - ret.append("null"); - } else { - ret.append(std::to_string(f.intV.value())); - } - break; - case TSDataType::DATE: - if (f.isNull()) { - ret.append("null"); - } else { - ret.append(boost::gregorian::to_iso_extended_string(f.dateV.value())); - } - break; - case TSDataType::TIMESTAMP: - case TSDataType::INT64: - if (f.isNull()) { - ret.append("null"); - } else { - ret.append(std::to_string(f.longV.value())); - } - break; - case TSDataType::FLOAT: - if (f.isNull()) { - ret.append("null"); - } else { - ret.append(std::to_string(f.floatV.value())); - } - break; - case TSDataType::DOUBLE: - if (f.isNull()) { - ret.append("null"); - } else { - ret.append(std::to_string(f.doubleV.value())); - } - break; - case TSDataType::BLOB: - case TSDataType::STRING: - case TSDataType::TEXT: - if (f.isNull()) { - ret.append("null"); - } else { - ret.append(f.stringV.value()); - } - break; - case TSDataType::OBJECT: - if (!f.stringV.is_initialized()) { - ret.append("null"); - } else { - ret.append(f.stringV.value()); - } - break; - default: - break; - } - } - ret.append("\n"); - return ret; -} - -bool SessionDataSet::hasNext() { - if (iotdbRpcDataSet_->hasCachedRecord()) { - return true; - } - return iotdbRpcDataSet_->next(); -} - -shared_ptr SessionDataSet::next() { - if (!iotdbRpcDataSet_->hasCachedRecord() && !hasNext()) { - return nullptr; - } - iotdbRpcDataSet_->setHasCachedRecord(false); - - return constructRowRecordFromValueArray(); -} - -int SessionDataSet::getFetchSize() { - return iotdbRpcDataSet_->getFetchSize(); -} - -void SessionDataSet::setFetchSize(int fetchSize) { - return iotdbRpcDataSet_->setFetchSize(fetchSize); -} - -const std::vector& SessionDataSet::getColumnNames() const { - return iotdbRpcDataSet_->getColumnNameList(); -} - -const std::vector& SessionDataSet::getColumnTypeList() const { - return iotdbRpcDataSet_->getColumnTypeList(); -} - -void SessionDataSet::closeOperationHandle(bool forceClose) { - iotdbRpcDataSet_->close(forceClose); -} - -bool SessionDataSet::DataIterator::next() { - return iotdbRpcDataSet_->next(); -} - -bool SessionDataSet::DataIterator::isNull(const std::string& columnName) { - return iotdbRpcDataSet_->isNullByColumnName(columnName); -} - -bool SessionDataSet::DataIterator::isNullByIndex(int32_t columnIndex) { - return iotdbRpcDataSet_->isNullByIndex(columnIndex); -} - -boost::optional SessionDataSet::DataIterator::getBooleanByIndex(int32_t columnIndex) { - return iotdbRpcDataSet_->getBooleanByIndex(columnIndex); -} - -boost::optional SessionDataSet::DataIterator::getBoolean(const std::string& columnName) { - return iotdbRpcDataSet_->getBoolean(columnName); -} - -boost::optional SessionDataSet::DataIterator::getDoubleByIndex(int32_t columnIndex) { - return iotdbRpcDataSet_->getDoubleByIndex(columnIndex); -} - -boost::optional SessionDataSet::DataIterator::getDouble(const std::string& columnName) { - return iotdbRpcDataSet_->getDouble(columnName); -} - -boost::optional SessionDataSet::DataIterator::getFloatByIndex(int32_t columnIndex) { - return iotdbRpcDataSet_->getFloatByIndex(columnIndex); -} - -boost::optional SessionDataSet::DataIterator::getFloat(const std::string& columnName) { - return iotdbRpcDataSet_->getFloat(columnName); -} - -boost::optional SessionDataSet::DataIterator::getIntByIndex(int32_t columnIndex) { - return iotdbRpcDataSet_->getIntByIndex(columnIndex); -} - -boost::optional SessionDataSet::DataIterator::getInt(const std::string& columnName) { - return iotdbRpcDataSet_->getInt(columnName); -} - -boost::optional SessionDataSet::DataIterator::getLongByIndex(int32_t columnIndex) { - return iotdbRpcDataSet_->getLongByIndex(columnIndex); -} - -boost::optional SessionDataSet::DataIterator::getLong(const std::string& columnName) { - return iotdbRpcDataSet_->getLong(columnName); -} - -boost::optional SessionDataSet::DataIterator::getStringByIndex(int32_t columnIndex) { - return iotdbRpcDataSet_->getStringByIndex(columnIndex); -} - -boost::optional -SessionDataSet::DataIterator::getString(const std::string& columnName) { - return iotdbRpcDataSet_->getString(columnName); -} - -boost::optional SessionDataSet::DataIterator::getTimestampByIndex(int32_t columnIndex) { - return iotdbRpcDataSet_->getTimestampByIndex(columnIndex); -} - -boost::optional SessionDataSet::DataIterator::getTimestamp(const std::string& columnName) { - return iotdbRpcDataSet_->getTimestamp(columnName); -} - -boost::optional -SessionDataSet::DataIterator::getDateByIndex(int32_t columnIndex) { - return iotdbRpcDataSet_->getDateByIndex(columnIndex); -} - -boost::optional -SessionDataSet::DataIterator::getDate(const std::string& columnName) { - return iotdbRpcDataSet_->getDate(columnName); -} - -int32_t SessionDataSet::DataIterator::findColumn(const std::string& columnName) { - return iotdbRpcDataSet_->findColumn(columnName); -} - -const std::vector& SessionDataSet::DataIterator::getColumnNames() const { - return iotdbRpcDataSet_->getColumnNameList(); -} - -const std::vector& SessionDataSet::DataIterator::getColumnTypeList() const { - return iotdbRpcDataSet_->getColumnTypeList(); -} - -shared_ptr SessionDataSet::constructRowRecordFromValueArray() { - std::vector outFields; - for (int i = iotdbRpcDataSet_->getValueColumnStartIndex(); i < iotdbRpcDataSet_->getColumnSize(); - i++) { - Field field; - std::string columnName = iotdbRpcDataSet_->getColumnNameList().at(i); - if (!iotdbRpcDataSet_->isNullByColumnName(columnName)) { - TSDataType::TSDataType dataType = iotdbRpcDataSet_->getDataType(columnName); - field.dataType = dataType; - switch (dataType) { - case TSDataType::BOOLEAN: - field.boolV = iotdbRpcDataSet_->getBoolean(columnName); - break; - case TSDataType::INT32: - field.intV = iotdbRpcDataSet_->getInt(columnName); - break; - case TSDataType::DATE: - field.dateV = iotdbRpcDataSet_->getDate(columnName); - break; - case TSDataType::INT64: - case TSDataType::TIMESTAMP: - field.longV = iotdbRpcDataSet_->getLong(columnName); - break; - case TSDataType::FLOAT: - field.floatV = iotdbRpcDataSet_->getFloat(columnName); - break; - case TSDataType::DOUBLE: - field.doubleV = iotdbRpcDataSet_->getDouble(columnName); - break; - case TSDataType::TEXT: - case TSDataType::BLOB: - case TSDataType::STRING: - case TSDataType::OBJECT: - field.stringV = iotdbRpcDataSet_->getBinary(columnName)->getStringValue(); - break; - default: - throw UnSupportedDataTypeException("Data type %s is not supported." + dataType); - } - } - outFields.emplace_back(field); - } - return std::make_shared(iotdbRpcDataSet_->getCurrentRowTime(), outFields); -} diff --git a/iotdb-client/client-cpp/src/main/SessionDataSet.h b/iotdb-client/client-cpp/src/main/SessionDataSet.h deleted file mode 100644 index 0f2c018d25661..0000000000000 --- a/iotdb-client/client-cpp/src/main/SessionDataSet.h +++ /dev/null @@ -1,124 +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. - */ - -#ifndef IOTDB_SESSION_DATA_SET_H -#define IOTDB_SESSION_DATA_SET_H - -#include -#include -#include -#include -#include -#include "IoTDBRpcDataSet.h" -#include "Column.h" - -class RowRecord { -public: - int64_t timestamp; - std::vector fields; - - explicit RowRecord(int64_t timestamp); - RowRecord(int64_t timestamp, const std::vector& fields); - explicit RowRecord(const std::vector& fields); - RowRecord(); - - void addField(const Field& f); - std::string toString(); -}; - -class SessionDataSet { -public: - SessionDataSet(const std::string& sql, const std::vector& columnNameList, - const std::vector& columnTypeList, - const std::map& columnNameIndex, int64_t queryId, - int64_t statementId, std::shared_ptr client, - int64_t sessionId, const std::vector& queryResult, - bool ignoreTimestamp, int64_t timeout, bool moreData, int32_t fetchSize, - const std::string& zoneId, int32_t timeFactor, - std::vector& columnIndex2TsBlockColumnIndexList) { - iotdbRpcDataSet_ = std::make_shared( - sql, columnNameList, columnTypeList, columnNameIndex, ignoreTimestamp, moreData, queryId, - statementId, client, sessionId, queryResult, fetchSize, timeout, zoneId, - IoTDBRpcDataSet::DEFAULT_TIME_FORMAT, timeFactor, columnIndex2TsBlockColumnIndexList); - } - - ~SessionDataSet() = default; - - bool hasNext(); - shared_ptr next(); - - int getFetchSize(); - void setFetchSize(int fetchSize); - - const std::vector& getColumnNames() const; - const std::vector& getColumnTypeList() const; - void closeOperationHandle(bool forceClose = false); - - class DataIterator { - std::shared_ptr iotdbRpcDataSet_; - - public: - DataIterator(std::shared_ptr iotdbRpcDataSet) - : iotdbRpcDataSet_(iotdbRpcDataSet) {} - - bool next(); - - bool isNull(const std::string& columnName); - bool isNullByIndex(int32_t columnIndex); - - boost::optional getBooleanByIndex(int32_t columnIndex); - boost::optional getBoolean(const std::string& columnName); - - boost::optional getDoubleByIndex(int32_t columnIndex); - boost::optional getDouble(const std::string& columnName); - - boost::optional getFloatByIndex(int32_t columnIndex); - boost::optional getFloat(const std::string& columnName); - - boost::optional getIntByIndex(int32_t columnIndex); - boost::optional getInt(const std::string& columnName); - - boost::optional getLongByIndex(int32_t columnIndex); - boost::optional getLong(const std::string& columnName); - - boost::optional getStringByIndex(int32_t columnIndex); - boost::optional getString(const std::string& columnName); - - boost::optional getTimestampByIndex(int32_t columnIndex); - boost::optional getTimestamp(const std::string& columnName); - - boost::optional getDateByIndex(int32_t columnIndex); - boost::optional getDate(const std::string& columnName); - - int32_t findColumn(const std::string& columnName); - const std::vector& getColumnNames() const; - const std::vector& getColumnTypeList() const; - }; - - DataIterator getIterator() { - return {iotdbRpcDataSet_}; - }; - -private: - std::shared_ptr constructRowRecordFromValueArray(); - - std::shared_ptr iotdbRpcDataSet_; -}; - -#endif diff --git a/iotdb-client/client-cpp/src/main/IoTDBRpcDataSet.cpp b/iotdb-client/client-cpp/src/rpc/IoTDBRpcDataSet.cpp similarity index 88% rename from iotdb-client/client-cpp/src/main/IoTDBRpcDataSet.cpp rename to iotdb-client/client-cpp/src/rpc/IoTDBRpcDataSet.cpp index 8b02a35607950..b6ca0b52962ea 100644 --- a/iotdb-client/client-cpp/src/main/IoTDBRpcDataSet.cpp +++ b/iotdb-client/client-cpp/src/rpc/IoTDBRpcDataSet.cpp @@ -23,10 +23,15 @@ #include "IoTDBRpcDataSet.h" -#include +#include +#include "RpcCommon.h" +#include "Optional.h" +#include "Date.h" #include "Column.h" +using apache::thrift::transport::TTransportException; + const int32_t IoTDBRpcDataSet::startIndex = 2; const std::string IoTDBRpcDataSet::TimestampColumnName = "Time"; const std::string IoTDBRpcDataSet::DEFAULT_TIME_FORMAT = "default"; @@ -235,12 +240,12 @@ bool IoTDBRpcDataSet::isNull(int32_t index, int32_t rowNum) { return index >= 0 && curTsBlock_->getColumn(index)->isNull(rowNum); } -boost::optional IoTDBRpcDataSet::getBooleanByIndex(int32_t columnIndex) { +Optional IoTDBRpcDataSet::getBooleanByIndex(int32_t columnIndex) { int32_t index = getTsBlockColumnIndexForColumnIndex(columnIndex); return getBooleanByTsBlockColumnIndex(index); } -boost::optional IoTDBRpcDataSet::getBoolean(const std::string& columnName) { +Optional IoTDBRpcDataSet::getBoolean(const std::string& columnName) { int32_t index = getTsBlockColumnIndexForColumnName(columnName); return getBooleanByTsBlockColumnIndex(index); } @@ -249,7 +254,7 @@ boost::optional IoTDBRpcDataSet::getBoolean(const std::string& columnName) // Only getLong and getString support reading the time column directly. // All other typed getters throw IoTDBException to prevent undefined behavior // from accessing valueColumns_ with a negative index. -boost::optional IoTDBRpcDataSet::getBooleanByTsBlockColumnIndex(int32_t tsBlockColumnIndex) { +Optional IoTDBRpcDataSet::getBooleanByTsBlockColumnIndex(int32_t tsBlockColumnIndex) { checkRecord(); if (tsBlockColumnIndex < 0) { throw IoTDBException("Cannot read boolean from time column"); @@ -259,21 +264,21 @@ boost::optional IoTDBRpcDataSet::getBooleanByTsBlockColumnIndex(int32_t ts return curTsBlock_->getColumn(tsBlockColumnIndex)->getBoolean(tsBlockIndex_); } else { lastReadWasNull_ = true; - return boost::none; + return Optional::none(); } } -boost::optional IoTDBRpcDataSet::getDoubleByIndex(int32_t columnIndex) { +Optional IoTDBRpcDataSet::getDoubleByIndex(int32_t columnIndex) { int32_t index = getTsBlockColumnIndexForColumnIndex(columnIndex); return getDoubleByTsBlockColumnIndex(index); } -boost::optional IoTDBRpcDataSet::getDouble(const std::string& columnName) { +Optional IoTDBRpcDataSet::getDouble(const std::string& columnName) { int32_t index = getTsBlockColumnIndexForColumnName(columnName); return getDoubleByTsBlockColumnIndex(index); } -boost::optional IoTDBRpcDataSet::getDoubleByTsBlockColumnIndex(int32_t tsBlockColumnIndex) { +Optional IoTDBRpcDataSet::getDoubleByTsBlockColumnIndex(int32_t tsBlockColumnIndex) { checkRecord(); if (tsBlockColumnIndex < 0) { throw IoTDBException("Cannot read double from time column"); @@ -283,21 +288,21 @@ boost::optional IoTDBRpcDataSet::getDoubleByTsBlockColumnIndex(int32_t t return curTsBlock_->getColumn(tsBlockColumnIndex)->getDouble(tsBlockIndex_); } else { lastReadWasNull_ = true; - return boost::none; + return Optional::none(); } } -boost::optional IoTDBRpcDataSet::getFloatByIndex(int32_t columnIndex) { +Optional IoTDBRpcDataSet::getFloatByIndex(int32_t columnIndex) { int32_t index = getTsBlockColumnIndexForColumnIndex(columnIndex); return getFloatByTsBlockColumnIndex(index); } -boost::optional IoTDBRpcDataSet::getFloat(const std::string& columnName) { +Optional IoTDBRpcDataSet::getFloat(const std::string& columnName) { int32_t index = getTsBlockColumnIndexForColumnName(columnName); return getFloatByTsBlockColumnIndex(index); } -boost::optional IoTDBRpcDataSet::getFloatByTsBlockColumnIndex(int32_t tsBlockColumnIndex) { +Optional IoTDBRpcDataSet::getFloatByTsBlockColumnIndex(int32_t tsBlockColumnIndex) { checkRecord(); if (tsBlockColumnIndex < 0) { throw IoTDBException("Cannot read float from time column"); @@ -307,21 +312,21 @@ boost::optional IoTDBRpcDataSet::getFloatByTsBlockColumnIndex(int32_t tsB return curTsBlock_->getColumn(tsBlockColumnIndex)->getFloat(tsBlockIndex_); } else { lastReadWasNull_ = true; - return boost::none; + return Optional::none(); } } -boost::optional IoTDBRpcDataSet::getIntByIndex(int32_t columnIndex) { +Optional IoTDBRpcDataSet::getIntByIndex(int32_t columnIndex) { int32_t index = getTsBlockColumnIndexForColumnIndex(columnIndex); return getIntByTsBlockColumnIndex(index); } -boost::optional IoTDBRpcDataSet::getInt(const std::string& columnName) { +Optional IoTDBRpcDataSet::getInt(const std::string& columnName) { int32_t index = getTsBlockColumnIndexForColumnName(columnName); return getIntByTsBlockColumnIndex(index); } -boost::optional IoTDBRpcDataSet::getIntByTsBlockColumnIndex(int32_t tsBlockColumnIndex) { +Optional IoTDBRpcDataSet::getIntByTsBlockColumnIndex(int32_t tsBlockColumnIndex) { checkRecord(); if (tsBlockColumnIndex < 0) { throw IoTDBException("Cannot read int32 from time column"); @@ -336,21 +341,21 @@ boost::optional IoTDBRpcDataSet::getIntByTsBlockColumnIndex(int32_t tsB return curTsBlock_->getColumn(tsBlockColumnIndex)->getInt(tsBlockIndex_); } else { lastReadWasNull_ = true; - return boost::none; + return Optional::none(); } } -boost::optional IoTDBRpcDataSet::getLongByIndex(int32_t columnIndex) { +Optional IoTDBRpcDataSet::getLongByIndex(int32_t columnIndex) { int32_t index = getTsBlockColumnIndexForColumnIndex(columnIndex); return getLongByTsBlockColumnIndex(index); } -boost::optional IoTDBRpcDataSet::getLong(const std::string& columnName) { +Optional IoTDBRpcDataSet::getLong(const std::string& columnName) { int32_t index = getTsBlockColumnIndexForColumnName(columnName); return getLongByTsBlockColumnIndex(index); } -boost::optional IoTDBRpcDataSet::getLongByTsBlockColumnIndex(int32_t tsBlockColumnIndex) { +Optional IoTDBRpcDataSet::getLongByTsBlockColumnIndex(int32_t tsBlockColumnIndex) { checkRecord(); if (tsBlockColumnIndex < 0) { lastReadWasNull_ = false; @@ -366,7 +371,7 @@ boost::optional IoTDBRpcDataSet::getLongByTsBlockColumnIndex(int32_t ts return curTsBlock_->getColumn(tsBlockColumnIndex)->getLong(tsBlockIndex_); } else { lastReadWasNull_ = true; - return boost::none; + return Optional::none(); } } @@ -394,18 +399,17 @@ std::shared_ptr IoTDBRpcDataSet::getBinaryByTsBlockColumnIndex(int32_t t } } -boost::optional IoTDBRpcDataSet::getStringByIndex(int32_t columnIndex) { +Optional IoTDBRpcDataSet::getStringByIndex(int32_t columnIndex) { int32_t index = getTsBlockColumnIndexForColumnIndex(columnIndex); return getStringByTsBlockColumnIndex(index); } -boost::optional IoTDBRpcDataSet::getString(const std::string& columnName) { +Optional IoTDBRpcDataSet::getString(const std::string& columnName) { int32_t index = getTsBlockColumnIndexForColumnName(columnName); return getStringByTsBlockColumnIndex(index); } -boost::optional -IoTDBRpcDataSet::getStringByTsBlockColumnIndex(int32_t tsBlockColumnIndex) { +Optional IoTDBRpcDataSet::getStringByTsBlockColumnIndex(int32_t tsBlockColumnIndex) { checkRecord(); if (tsBlockColumnIndex < 0) { int64_t timestamp = curTsBlock_->getTimeByIndex(tsBlockIndex_); @@ -413,7 +417,7 @@ IoTDBRpcDataSet::getStringByTsBlockColumnIndex(int32_t tsBlockColumnIndex) { } if (isNull(tsBlockColumnIndex, tsBlockIndex_)) { lastReadWasNull_ = true; - return boost::none; + return Optional::none(); } lastReadWasNull_ = false; return getStringByTsBlockColumnIndexAndDataType( @@ -448,43 +452,41 @@ IoTDBRpcDataSet::getStringByTsBlockColumnIndexAndDataType(int32_t index, case TSDataType::DATE: { int32_t value = curTsBlock_->getColumn(index)->getInt(tsBlockIndex_); auto date = parseIntToDate(value); - return boost::gregorian::to_iso_extended_string(date); + return date.toIsoExtendedString(); } default: return ""; } } -boost::optional IoTDBRpcDataSet::getTimestampByIndex(int32_t columnIndex) { +Optional IoTDBRpcDataSet::getTimestampByIndex(int32_t columnIndex) { int32_t index = getTsBlockColumnIndexForColumnIndex(columnIndex); return getTimestampByTsBlockColumnIndex(index); } -boost::optional IoTDBRpcDataSet::getTimestamp(const std::string& columnName) { +Optional IoTDBRpcDataSet::getTimestamp(const std::string& columnName) { int32_t index = getTsBlockColumnIndexForColumnName(columnName); return getTimestampByTsBlockColumnIndex(index); } -boost::optional -IoTDBRpcDataSet::getTimestampByTsBlockColumnIndex(int32_t tsBlockColumnIndex) { +Optional IoTDBRpcDataSet::getTimestampByTsBlockColumnIndex(int32_t tsBlockColumnIndex) { return getLongByTsBlockColumnIndex(tsBlockColumnIndex); } -boost::optional IoTDBRpcDataSet::getDateByIndex(int32_t columnIndex) { +Optional IoTDBRpcDataSet::getDateByIndex(int32_t columnIndex) { int32_t index = getTsBlockColumnIndexForColumnIndex(columnIndex); return getDateByTsBlockColumnIndex(index); } -boost::optional IoTDBRpcDataSet::getDate(const std::string& columnName) { +Optional IoTDBRpcDataSet::getDate(const std::string& columnName) { int32_t index = getTsBlockColumnIndexForColumnName(columnName); return getDateByTsBlockColumnIndex(index); } -boost::optional -IoTDBRpcDataSet::getDateByTsBlockColumnIndex(int32_t tsBlockColumnIndex) { +Optional IoTDBRpcDataSet::getDateByTsBlockColumnIndex(int32_t tsBlockColumnIndex) { auto value = getIntByTsBlockColumnIndex(tsBlockColumnIndex); if (!value.is_initialized()) { - return boost::none; + return Optional::none(); } return parseIntToDate(value.value()); } diff --git a/iotdb-client/client-cpp/src/main/IoTDBRpcDataSet.h b/iotdb-client/client-cpp/src/rpc/IoTDBRpcDataSet.h similarity index 72% rename from iotdb-client/client-cpp/src/main/IoTDBRpcDataSet.h rename to iotdb-client/client-cpp/src/rpc/IoTDBRpcDataSet.h index 0e6855f4049ab..d339edbc91031 100644 --- a/iotdb-client/client-cpp/src/main/IoTDBRpcDataSet.h +++ b/iotdb-client/client-cpp/src/rpc/IoTDBRpcDataSet.h @@ -26,7 +26,8 @@ #include #include #include "IClientRPCService.h" -#include +#include "Date.h" +#include "Optional.h" #include "TsBlock.h" class IoTDBRpcDataSet { @@ -60,24 +61,24 @@ class IoTDBRpcDataSet { bool isNull(int32_t index, int32_t rowNum); bool isNullByIndex(int32_t columnIndex); bool isNullByColumnName(const std::string& columnName); - boost::optional getBooleanByIndex(int32_t columnIndex); - boost::optional getBoolean(const std::string& columnName); - boost::optional getDoubleByIndex(int32_t columnIndex); - boost::optional getDouble(const std::string& columnName); - boost::optional getFloatByIndex(int32_t columnIndex); - boost::optional getFloat(const std::string& columnName); - boost::optional getIntByIndex(int32_t columnIndex); - boost::optional getInt(const std::string& columnName); - boost::optional getLongByIndex(int32_t columnIndex); - boost::optional getLong(const std::string& columnName); + Optional getBooleanByIndex(int32_t columnIndex); + Optional getBoolean(const std::string& columnName); + Optional getDoubleByIndex(int32_t columnIndex); + Optional getDouble(const std::string& columnName); + Optional getFloatByIndex(int32_t columnIndex); + Optional getFloat(const std::string& columnName); + Optional getIntByIndex(int32_t columnIndex); + Optional getInt(const std::string& columnName); + Optional getLongByIndex(int32_t columnIndex); + Optional getLong(const std::string& columnName); std::shared_ptr getBinaryByIndex(int32_t columnIndex); std::shared_ptr getBinary(const std::string& columnName); - boost::optional getStringByIndex(int32_t columnIndex); - boost::optional getString(const std::string& columnName); - boost::optional getTimestampByIndex(int32_t columnIndex); - boost::optional getTimestamp(const std::string& columnName); - boost::optional getDateByIndex(int32_t columnIndex); - boost::optional getDate(const std::string& columnName); + Optional getStringByIndex(int32_t columnIndex); + Optional getString(const std::string& columnName); + Optional getTimestampByIndex(int32_t columnIndex); + Optional getTimestamp(const std::string& columnName); + Optional getDateByIndex(int32_t columnIndex); + Optional getDate(const std::string& columnName); TSDataType::TSDataType getDataTypeByIndex(int32_t columnIndex); TSDataType::TSDataType getDataType(const std::string& columnName); @@ -104,17 +105,17 @@ class IoTDBRpcDataSet { int32_t getTsBlockColumnIndexForColumnIndex(int32_t columnIndex); void checkRecord(); TSDataType::TSDataType getDataTypeByTsBlockColumnIndex(int32_t tsBlockColumnIndex); - boost::optional getBooleanByTsBlockColumnIndex(int32_t tsBlockColumnIndex); + Optional getBooleanByTsBlockColumnIndex(int32_t tsBlockColumnIndex); std::string getStringByTsBlockColumnIndexAndDataType(int32_t index, TSDataType::TSDataType tsDataType); - boost::optional getDoubleByTsBlockColumnIndex(int32_t tsBlockColumnIndex); - boost::optional getFloatByTsBlockColumnIndex(int32_t tsBlockColumnIndex); - boost::optional getIntByTsBlockColumnIndex(int32_t tsBlockColumnIndex); - boost::optional getLongByTsBlockColumnIndex(int32_t tsBlockColumnIndex); + Optional getDoubleByTsBlockColumnIndex(int32_t tsBlockColumnIndex); + Optional getFloatByTsBlockColumnIndex(int32_t tsBlockColumnIndex); + Optional getIntByTsBlockColumnIndex(int32_t tsBlockColumnIndex); + Optional getLongByTsBlockColumnIndex(int32_t tsBlockColumnIndex); std::shared_ptr getBinaryByTsBlockColumnIndex(int32_t tsBlockColumnIndex); - boost::optional getStringByTsBlockColumnIndex(int32_t tsBlockColumnIndex); - boost::optional getDateByTsBlockColumnIndex(int32_t tsBlockColumnIndex); - boost::optional getTimestampByTsBlockColumnIndex(int32_t tsBlockColumnIndex); + Optional getStringByTsBlockColumnIndex(int32_t tsBlockColumnIndex); + Optional getDateByTsBlockColumnIndex(int32_t tsBlockColumnIndex); + Optional getTimestampByTsBlockColumnIndex(int32_t tsBlockColumnIndex); std::string sql_; bool isClosed_; diff --git a/iotdb-client/client-cpp/src/main/NodesSupplier.cpp b/iotdb-client/client-cpp/src/rpc/NodesSupplier.cpp similarity index 97% rename from iotdb-client/client-cpp/src/main/NodesSupplier.cpp rename to iotdb-client/client-cpp/src/rpc/NodesSupplier.cpp index 3f3a807dae8db..848274619f8da 100644 --- a/iotdb-client/client-cpp/src/main/NodesSupplier.cpp +++ b/iotdb-client/client-cpp/src/rpc/NodesSupplier.cpp @@ -50,14 +50,14 @@ StaticNodesSupplier::StaticNodesSupplier(const std::vector& nodes, NodeSelectionPolicy policy) : availableNodes_(nodes), policy_(std::move(policy)) {} -boost::optional StaticNodesSupplier::getQueryEndPoint() { +Optional StaticNodesSupplier::getQueryEndPoint() { try { if (availableNodes_.empty()) { - return boost::none; + return Optional::none(); } return policy_(availableNodes_); } catch (const IoTDBException& e) { - return boost::none; + return Optional::none(); } } @@ -112,11 +112,11 @@ TEndPoint NodesSupplier::selectQueryEndpoint() { } } -boost::optional NodesSupplier::getQueryEndPoint() { +Optional NodesSupplier::getQueryEndPoint() { try { return selectQueryEndpoint(); } catch (const IoTDBException& e) { - return boost::none; + return Optional::none(); } } diff --git a/iotdb-client/client-cpp/src/main/NodesSupplier.h b/iotdb-client/client-cpp/src/rpc/NodesSupplier.h similarity index 95% rename from iotdb-client/client-cpp/src/main/NodesSupplier.h rename to iotdb-client/client-cpp/src/rpc/NodesSupplier.h index 7c56f8e75ba86..af9e4dfec624e 100644 --- a/iotdb-client/client-cpp/src/main/NodesSupplier.h +++ b/iotdb-client/client-cpp/src/rpc/NodesSupplier.h @@ -21,7 +21,7 @@ #include #include -#include +#include "Optional.h" #include #include #include @@ -41,7 +41,7 @@ class RoundRobinPolicy { class INodesSupplier { public: virtual ~INodesSupplier() = default; - virtual boost::optional getQueryEndPoint() = 0; + virtual Optional getQueryEndPoint() = 0; virtual std::vector getEndPointList() = 0; using NodeSelectionPolicy = std::function&)>; }; @@ -51,7 +51,7 @@ class StaticNodesSupplier : public INodesSupplier { explicit StaticNodesSupplier(const std::vector& nodes, NodeSelectionPolicy policy = RoundRobinPolicy::select); - boost::optional getQueryEndPoint() override; + Optional getQueryEndPoint() override; std::vector getEndPointList() override; @@ -97,7 +97,7 @@ class NodesSupplier : public INodesSupplier { std::vector getEndPointList() override; - boost::optional getQueryEndPoint() override; + Optional getQueryEndPoint() override; ~NodesSupplier() override; diff --git a/iotdb-client/client-cpp/src/rpc/RpcCommon.cpp b/iotdb-client/client-cpp/src/rpc/RpcCommon.cpp new file mode 100644 index 0000000000000..c83b39a5fb58d --- /dev/null +++ b/iotdb-client/client-cpp/src/rpc/RpcCommon.cpp @@ -0,0 +1,214 @@ +/** + * 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. + */ + +#include "RpcCommon.h" + +#include +#include +#include + +#include "ThriftConvert.h" +#include "client_types.h" +#include "common_types.h" + +using namespace std; + +RpcUtils::RpcUtils() { + SUCCESS_STATUS = std::make_shared(); + SUCCESS_STATUS->__set_code(TSStatusCode::SUCCESS_STATUS); +} + +void RpcUtils::verifySuccess(const TSStatus& status) { + if (status.code == TSStatusCode::MULTIPLE_ERROR) { + verifySuccess(status.subStatus); + return; + } + if (status.code != TSStatusCode::SUCCESS_STATUS && + status.code != TSStatusCode::REDIRECTION_RECOMMEND) { + throw ExecutionException(to_string(status.code) + ": " + status.message, + statusFromThrift(status)); + } +} + +void RpcUtils::verifySuccessWithRedirection(const TSStatus& status) { + verifySuccess(status); + if (status.__isset.redirectNode) { + throw RedirectException(to_string(status.code) + ": " + status.message, + endpointFromThrift(status.redirectNode)); + } + if (status.__isset.subStatus) { + auto statusSubStatus = status.subStatus; + vector endPointList(statusSubStatus.size()); + int count = 0; + for (const TSStatus& subStatus : statusSubStatus) { + if (subStatus.__isset.redirectNode) { + endPointList[count++] = subStatus.redirectNode; + } else { + TEndPoint endPoint; + endPointList[count++] = endPoint; + } + } + if (!endPointList.empty()) { + throw RedirectException(to_string(status.code) + ": " + status.message, + endpointListFromThrift(endPointList)); + } + } +} + +void RpcUtils::verifySuccessWithRedirectionForMultiDevices(const TSStatus& status, + vector devices) { + verifySuccess(status); + + if (status.code == TSStatusCode::MULTIPLE_ERROR || + status.code == TSStatusCode::REDIRECTION_RECOMMEND) { + map deviceEndPointMap; + const vector& statusSubStatus = status.subStatus; + for (size_t i = 0; i < statusSubStatus.size() && i < devices.size(); i++) { + const TSStatus& subStatus = statusSubStatus[i]; + if (subStatus.__isset.redirectNode) { + deviceEndPointMap.insert(make_pair(devices[i], subStatus.redirectNode)); + } + } + throw RedirectException(to_string(status.code) + ": " + status.message, + endpointMapFromThrift(deviceEndPointMap)); + } + + if (status.__isset.redirectNode) { + throw RedirectException(to_string(status.code) + ": " + status.message, + endpointFromThrift(status.redirectNode)); + } + if (status.__isset.subStatus) { + auto statusSubStatus = status.subStatus; + vector endPointList(statusSubStatus.size()); + int count = 0; + for (const TSStatus& subStatus : statusSubStatus) { + if (subStatus.__isset.redirectNode) { + endPointList[count++] = subStatus.redirectNode; + } else { + TEndPoint endPoint; + endPointList[count++] = endPoint; + } + } + if (!endPointList.empty()) { + throw RedirectException(to_string(status.code) + ": " + status.message, + endpointListFromThrift(endPointList)); + } + } +} + +void RpcUtils::verifySuccess(const vector& statuses) { + for (const TSStatus& status : statuses) { + if (status.code != TSStatusCode::SUCCESS_STATUS) { + vector publicStatuses; + publicStatuses.reserve(statuses.size()); + for (const TSStatus& s : statuses) { + publicStatuses.push_back(statusFromThrift(s)); + } + throw BatchExecutionException(status.message, publicStatuses); + } + } +} + +TSStatus RpcUtils::getStatus(TSStatusCode::TSStatusCode tsStatusCode) { + TSStatus status; + status.__set_code(tsStatusCode); + return status; +} + +TSStatus RpcUtils::getStatus(int code, const string& message) { + TSStatus status; + status.__set_code(code); + status.__set_message(message); + return status; +} + +shared_ptr +RpcUtils::getTSExecuteStatementResp(TSStatusCode::TSStatusCode tsStatusCode) { + TSStatus status = getStatus(tsStatusCode); + return getTSExecuteStatementResp(status); +} + +shared_ptr +RpcUtils::getTSExecuteStatementResp(TSStatusCode::TSStatusCode tsStatusCode, + const string& message) { + TSStatus status = getStatus(tsStatusCode, message); + return getTSExecuteStatementResp(status); +} + +shared_ptr RpcUtils::getTSExecuteStatementResp(const TSStatus& status) { + shared_ptr resp(new TSExecuteStatementResp()); + resp->__set_status(status); + return resp; +} + +shared_ptr +RpcUtils::getTSFetchResultsResp(TSStatusCode::TSStatusCode tsStatusCode) { + TSStatus status = getStatus(tsStatusCode); + return getTSFetchResultsResp(status); +} + +shared_ptr +RpcUtils::getTSFetchResultsResp(TSStatusCode::TSStatusCode tsStatusCode, + const string& appendMessage) { + TSStatus status = getStatus(tsStatusCode, appendMessage); + return getTSFetchResultsResp(status); +} + +shared_ptr RpcUtils::getTSFetchResultsResp(const TSStatus& status) { + shared_ptr resp(new TSFetchResultsResp()); + resp->__set_status(status); + return resp; +} + +const string UrlUtils::PORT_SEPARATOR = ":"; +const string UrlUtils::ABB_COLON = "["; + +TEndPoint UrlUtils::parseTEndPointIpv4AndIpv6Url(const string& endPointUrl) { + TEndPoint endPoint; + + if (endPointUrl.empty()) { + return endPoint; + } + + size_t portSeparatorPos = endPointUrl.find_last_of(PORT_SEPARATOR); + + if (portSeparatorPos == string::npos) { + endPoint.__set_ip(endPointUrl); + return endPoint; + } + + string portStr = endPointUrl.substr(portSeparatorPos + 1); + string ip = endPointUrl.substr(0, portSeparatorPos); + + if (ip.find(ABB_COLON) != string::npos) { + if (ip.size() >= 2 && ip.front() == '[' && ip.back() == ']') { + ip = ip.substr(1, ip.size() - 2); + } + } + + try { + int port = stoi(portStr); + endPoint.__set_ip(ip); + endPoint.__set_port(port); + } catch (const exception&) { + endPoint.__set_ip(endPointUrl); + } + + return endPoint; +} diff --git a/iotdb-client/client-cpp/src/rpc/RpcCommon.h b/iotdb-client/client-cpp/src/rpc/RpcCommon.h new file mode 100644 index 0000000000000..721150bd6cadc --- /dev/null +++ b/iotdb-client/client-cpp/src/rpc/RpcCommon.h @@ -0,0 +1,81 @@ +/** + * 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. + */ +#ifndef IOTDB_RPC_COMMON_H +#define IOTDB_RPC_COMMON_H + +#include +#include +#include + +#include "Common.h" + +class TSStatus; +class TSExecuteStatementResp; +class TSFetchResultsResp; +class TEndPoint; + +class RpcUtils { +public: + std::shared_ptr SUCCESS_STATUS; + + RpcUtils(); + + static void verifySuccess(const TSStatus& status); + + static void verifySuccessWithRedirection(const TSStatus& status); + + static void verifySuccessWithRedirectionForMultiDevices(const TSStatus& status, + std::vector devices); + + static void verifySuccess(const std::vector& statuses); + + static TSStatus getStatus(TSStatusCode::TSStatusCode tsStatusCode); + + static TSStatus getStatus(int code, const std::string& message); + + static std::shared_ptr + getTSExecuteStatementResp(TSStatusCode::TSStatusCode tsStatusCode); + + static std::shared_ptr + getTSExecuteStatementResp(TSStatusCode::TSStatusCode tsStatusCode, const std::string& message); + + static std::shared_ptr getTSExecuteStatementResp(const TSStatus& status); + + static std::shared_ptr + getTSFetchResultsResp(TSStatusCode::TSStatusCode tsStatusCode); + + static std::shared_ptr + getTSFetchResultsResp(TSStatusCode::TSStatusCode tsStatusCode, const std::string& appendMessage); + + static std::shared_ptr getTSFetchResultsResp(const TSStatus& status); +}; + +class UrlUtils { +private: + static const std::string PORT_SEPARATOR; + static const std::string ABB_COLON; + + UrlUtils() = delete; + ~UrlUtils() = delete; + +public: + static TEndPoint parseTEndPointIpv4AndIpv6Url(const std::string& endPointUrl); +}; + +#endif diff --git a/iotdb-client/client-cpp/src/main/SessionConnection.cpp b/iotdb-client/client-cpp/src/rpc/SessionConnection.cpp similarity index 93% rename from iotdb-client/client-cpp/src/main/SessionConnection.cpp rename to iotdb-client/client-cpp/src/rpc/SessionConnection.cpp index a7fa3beb6ffc4..dfdb0198e3872 100644 --- a/iotdb-client/client-cpp/src/main/SessionConnection.cpp +++ b/iotdb-client/client-cpp/src/rpc/SessionConnection.cpp @@ -17,19 +17,25 @@ * under the License. */ #include "SessionConnection.h" -#include "Session.h" +#include "SessionImpl.h" +#include "RpcCommon.h" #include "common_types.h" +#include #include +#include +#include +#include #include #include "SessionDataSet.h" +#include "SessionDataSetFactory.h" using namespace apache::thrift; using namespace apache::thrift::protocol; using namespace apache::thrift::transport; -SessionConnection::SessionConnection(Session* session_ptr, const TEndPoint& endpoint, +SessionConnection::SessionConnection(Session::Impl* session_ptr, const TEndPoint& endpoint, const std::string& zoneId, std::shared_ptr nodeSupplier, int fetchSize, int maxRetries, int64_t retryInterval, @@ -189,10 +195,10 @@ std::unique_ptr SessionConnection::executeQueryStatement(const s RpcUtils::verifySuccess(resp.status); } - return std::unique_ptr(new SessionDataSet( - sql, resp.columns, resp.dataTypeList, resp.columnNameIndexMap, resp.queryId, statementId, - client, sessionId, resp.queryResult, resp.ignoreTimeStamp, timeoutInMs, resp.moreData, - fetchSize, zoneId, timeFactor, resp.columnIndex2TsBlockColumnIndexList)); + return createSessionDataSet(sql, resp.columns, resp.dataTypeList, resp.columnNameIndexMap, + resp.queryId, statementId, client, sessionId, resp.queryResult, + resp.ignoreTimeStamp, timeoutInMs, resp.moreData, fetchSize, zoneId, + timeFactor, resp.columnIndex2TsBlockColumnIndexList); } std::unique_ptr @@ -218,10 +224,10 @@ SessionConnection::executeRawDataQuery(const std::vector& paths, in } else { RpcUtils::verifySuccess(resp.status); } - return std::unique_ptr(new SessionDataSet( - "", resp.columns, resp.dataTypeList, resp.columnNameIndexMap, resp.queryId, statementId, - client, sessionId, resp.queryResult, resp.ignoreTimeStamp, connectionTimeoutInMs, - resp.moreData, fetchSize, zoneId, timeFactor, resp.columnIndex2TsBlockColumnIndexList)); + return createSessionDataSet("", resp.columns, resp.dataTypeList, resp.columnNameIndexMap, + resp.queryId, statementId, client, sessionId, resp.queryResult, + resp.ignoreTimeStamp, connectionTimeoutInMs, resp.moreData, fetchSize, + zoneId, timeFactor, resp.columnIndex2TsBlockColumnIndexList); } std::unique_ptr @@ -246,10 +252,10 @@ SessionConnection::executeLastDataQuery(const std::vector& paths, i } else { RpcUtils::verifySuccess(resp.status); } - return std::unique_ptr(new SessionDataSet( - "", resp.columns, resp.dataTypeList, resp.columnNameIndexMap, resp.queryId, statementId, - client, sessionId, resp.queryResult, resp.ignoreTimeStamp, connectionTimeoutInMs, - resp.moreData, fetchSize, zoneId, timeFactor, resp.columnIndex2TsBlockColumnIndexList)); + return createSessionDataSet("", resp.columns, resp.dataTypeList, resp.columnNameIndexMap, + resp.queryId, statementId, client, sessionId, resp.queryResult, + resp.ignoreTimeStamp, connectionTimeoutInMs, resp.moreData, fetchSize, + zoneId, timeFactor, resp.columnIndex2TsBlockColumnIndexList); } void SessionConnection::executeNonQueryStatement(const string& sql) { diff --git a/iotdb-client/client-cpp/src/main/SessionConnection.h b/iotdb-client/client-cpp/src/rpc/SessionConnection.h similarity index 96% rename from iotdb-client/client-cpp/src/main/SessionConnection.h rename to iotdb-client/client-cpp/src/rpc/SessionConnection.h index 45d1b55cc56c6..7579d7fb1fc2f 100644 --- a/iotdb-client/client-cpp/src/main/SessionConnection.h +++ b/iotdb-client/client-cpp/src/rpc/SessionConnection.h @@ -31,15 +31,16 @@ #include "common_types.h" #include "NodesSupplier.h" #include "Common.h" +#include "RpcCommon.h" +#include "Session.h" class SessionDataSet; -class Session; class SessionConnection : public std::enable_shared_from_this { public: - SessionConnection(Session* session_ptr, const TEndPoint& endpoint, const std::string& zoneId, - std::shared_ptr nodeSupplier, int fetchSize = 10000, - int maxRetries = 3, int64_t retryInterval = 500, + SessionConnection(Session::Impl* session_ptr, const TEndPoint& endpoint, + const std::string& zoneId, std::shared_ptr nodeSupplier, + int fetchSize = 10000, int maxRetries = 3, int64_t retryInterval = 500, int64_t connectionTimeoutMs = 3 * 1000, std::string dialect = "tree", std::string db = ""); @@ -183,9 +184,9 @@ class SessionConnection : public std::enable_shared_from_this std::shared_ptr socketFactory_ = std::make_shared(); #endif - std::shared_ptr transport; + std::shared_ptr transport; std::shared_ptr client; - Session* session; + Session::Impl* session; int64_t sessionId; int64_t statementId; int64_t connectionTimeoutInMs; diff --git a/iotdb-client/client-cpp/src/rpc/SessionDataSetFactory.h b/iotdb-client/client-cpp/src/rpc/SessionDataSetFactory.h new file mode 100644 index 0000000000000..520aaf0f5208a --- /dev/null +++ b/iotdb-client/client-cpp/src/rpc/SessionDataSetFactory.h @@ -0,0 +1,42 @@ +/** + * 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. + */ +#ifndef IOTDB_SESSION_DATA_SET_FACTORY_H +#define IOTDB_SESSION_DATA_SET_FACTORY_H + +#include +#include +#include +#include +#include + +#include "IClientRPCService.h" + +class SessionDataSet; + +std::unique_ptr +createSessionDataSet(const std::string& sql, const std::vector& columnNameList, + const std::vector& columnTypeList, + const std::map& columnNameIndex, int64_t queryId, + int64_t statementId, std::shared_ptr client, + int64_t sessionId, const std::vector& queryResult, + bool ignoreTimestamp, int64_t timeout, bool moreData, int32_t fetchSize, + const std::string& zoneId, int32_t timeFactor, + std::vector& columnIndex2TsBlockColumnIndexList); + +#endif diff --git a/iotdb-client/client-cpp/src/rpc/SessionImpl.h b/iotdb-client/client-cpp/src/rpc/SessionImpl.h new file mode 100644 index 0000000000000..b849fb976e91d --- /dev/null +++ b/iotdb-client/client-cpp/src/rpc/SessionImpl.h @@ -0,0 +1,232 @@ +/** + * 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. + */ +#ifndef IOTDB_SESSION_IMPL_H +#define IOTDB_SESSION_IMPL_H + +#include +#include +#include +#include +#include +#include + +#include "AbstractSessionBuilder.h" +#include "Common.h" +#include "DeviceID.h" +#include "Endpoint.h" +#include "NodesSupplier.h" +#include "Session.h" +#include "SessionConnection.h" +#include "ThriftConvert.h" +#include "client_types.h" +#include "common_types.h" + +class Session::Impl { +public: + std::string host_; + int rpcPort_ = 6667; + bool useSSL_ = false; + std::string trustCertFilePath_; + std::vector nodeUrls_; + std::string username_ = "root"; + std::string password_ = "root"; + const TSProtocolVersion::type protocolVersion_ = TSProtocolVersion::IOTDB_SERVICE_PROTOCOL_V3; + bool isClosed_ = true; + std::string zoneId_; + int fetchSize_ = 10000; + static const int DEFAULT_FETCH_SIZE = 10000; + static const int DEFAULT_TIMEOUT_MS = 0; + int connectTimeoutMs_ = 3000; + Version::Version version = Version::V_1_0; + std::string sqlDialect_ = "tree"; + std::string database_; + bool enableAutoFetch_ = true; + bool enableRedirection_ = true; + std::shared_ptr nodesSupplier_; + std::shared_ptr defaultSessionConnection_; + + TEndPoint defaultEndPoint_; + + struct TEndPointHash { + size_t operator()(const TEndPoint& endpoint) const { + return std::hash()(endpoint.ip) ^ std::hash()(endpoint.port); + } + }; + + struct TEndPointEqual { + bool operator()(const TEndPoint& lhs, const TEndPoint& rhs) const { + return lhs.ip == rhs.ip && lhs.port == rhs.port; + } + }; + + using EndPointSessionMap = std::unordered_map, + TEndPointHash, TEndPointEqual>; + EndPointSessionMap endPointToSessionConnection; + std::unordered_map deviceIdToEndpoint; + std::unordered_map, TEndPoint> tableModelDeviceIdToEndpoint; + + void removeBrokenSessionConnection(std::shared_ptr sessionConnection); + + static bool checkSorted(const Tablet& tablet); + static bool checkSorted(const std::vector& times); + static void sortTablet(Tablet& tablet); + static void sortIndexByTimestamp(int* index, std::vector& timestamps, int length); + + void appendValues(std::string& buffer, const char* value, int size); + void putValuesIntoBuffer(const std::vector& types, + const std::vector& values, std::string& buf); + int8_t getDataTypeNumber(TSDataType::TSDataType type); + + struct TsCompare { + std::vector& timestamps; + explicit TsCompare(std::vector& inTimestamps) : timestamps(inTimestamps) {} + bool operator()(int i, int j) { + return timestamps[i] < timestamps[j]; + } + }; + + std::string getVersionString(Version::Version version); + + void initZoneId(); + void initNodesSupplier(const std::vector& nodeUrls = std::vector()); + void initDefaultSessionConnection(); + + template + void insertByGroup(std::unordered_map, T>& insertGroup, + InsertConsumer insertConsumer); + + template + void insertOnce(std::unordered_map, T>& insertGroup, + InsertConsumer insertConsumer); + + void insertStringRecordsWithLeaderCache(std::vector deviceIds, + std::vector times, + std::vector> measurementsList, + std::vector> valuesList, + bool isAligned); + + void + insertRecordsWithLeaderCache(std::vector deviceIds, std::vector times, + std::vector> measurementsList, + const std::vector>& typesList, + std::vector> valuesList, bool isAligned); + + void insertTabletsWithLeaderCache(std::unordered_map& tablets, bool sorted, + bool isAligned); + + std::shared_ptr getQuerySessionConnection(); + std::shared_ptr getSessionConnection(std::string deviceId); + std::shared_ptr + getSessionConnection(std::shared_ptr deviceId); + + void handleQueryRedirection(TEndPoint endPoint); + void handleRedirection(const std::string& deviceId, TEndPoint endPoint); + void handleRedirection(const std::shared_ptr& deviceId, TEndPoint endPoint); + + static void buildInsertTabletReq(TSInsertTabletReq& request, Tablet& tablet, bool sorted); + void insertTablet(TSInsertTabletReq request); + void insertRelationalTabletOnce( + const std::unordered_map, Tablet>& relationalTabletGroup, + bool sorted); + void insertRelationalTabletByGroup( + const std::unordered_map, Tablet>& relationalTabletGroup, + bool sorted); +}; + +template +void Session::Impl::insertByGroup( + std::unordered_map, T>& insertGroup, + InsertConsumer insertConsumer) { + std::vector> futures; + + for (auto& entry : insertGroup) { + auto connection = entry.first; + auto& req = entry.second; + futures.emplace_back(std::async(std::launch::async, [=, &req]() mutable { + try { + insertConsumer(connection, req); + } catch (const RedirectException& e) { + for (const auto& deviceEndPoint : e.deviceEndPointMap) { + handleRedirection(deviceEndPoint.first, endpointToThrift(deviceEndPoint.second)); + } + } catch (const IoTDBConnectionException&) { + if (endPointToSessionConnection.size() > 1) { + removeBrokenSessionConnection(connection); + try { + insertConsumer(defaultSessionConnection_, req); + } catch (const RedirectException&) { + } + } else { + throw; + } + } catch (const std::exception& e) { + log_debug(e.what()); + throw IoTDBException(e.what()); + } + })); + } + + std::string errorMessages; + for (auto& f : futures) { + try { + f.get(); + } catch (const IoTDBConnectionException&) { + throw; + } catch (const std::exception& e) { + if (!errorMessages.empty()) { + errorMessages += ";"; + } + errorMessages += e.what(); + } + } + + if (!errorMessages.empty()) { + throw StatementExecutionException(errorMessages); + } +} + +template +void Session::Impl::insertOnce( + std::unordered_map, T>& insertGroup, + InsertConsumer insertConsumer) { + auto connection = insertGroup.begin()->first; + auto req = insertGroup.begin()->second; + try { + insertConsumer(connection, req); + } catch (const RedirectException& e) { + for (const auto& deviceEndPoint : e.deviceEndPointMap) { + handleRedirection(deviceEndPoint.first, endpointToThrift(deviceEndPoint.second)); + } + } catch (const IoTDBConnectionException&) { + if (endPointToSessionConnection.size() > 1) { + removeBrokenSessionConnection(connection); + try { + insertConsumer(defaultSessionConnection_, req); + } catch (const RedirectException&) { + } + } else { + throw; + } + } catch (const std::exception& e) { + log_debug(e.what()); + throw IoTDBException(e.what()); + } +} + +#endif diff --git a/iotdb-client/client-cpp/src/main/ThriftConnection.cpp b/iotdb-client/client-cpp/src/rpc/ThriftConnection.cpp similarity index 93% rename from iotdb-client/client-cpp/src/main/ThriftConnection.cpp rename to iotdb-client/client-cpp/src/rpc/ThriftConnection.cpp index b02cb03c45402..fadfc18dffb1a 100644 --- a/iotdb-client/client-cpp/src/main/ThriftConnection.cpp +++ b/iotdb-client/client-cpp/src/rpc/ThriftConnection.cpp @@ -19,10 +19,19 @@ #include "ThriftConnection.h" #include #include +#include +#include +#include #include +#include -#include "Session.h" +#include "RpcCommon.h" #include "SessionDataSet.h" +#include "SessionDataSetFactory.h" + +using namespace apache::thrift; +using namespace apache::thrift::protocol; +using namespace apache::thrift::transport; const int ThriftConnection::THRIFT_DEFAULT_BUFFER_SIZE = 4096; const int ThriftConnection::THRIFT_MAX_FRAME_SIZE = 1048576; @@ -141,10 +150,10 @@ std::unique_ptr ThriftConnection::executeQueryStatement(const st throw IoTDBException(e.what()); } std::shared_ptr queryDataSet(new TSQueryDataSet(resp.queryDataSet)); - return std::unique_ptr(new SessionDataSet( + return createSessionDataSet( "", resp.columns, resp.dataTypeList, resp.columnNameIndexMap, resp.queryId, statementId_, client_, sessionId_, resp.queryResult, resp.ignoreTimeStamp, connectionTimeoutInMs_, - resp.moreData, fetchSize_, zoneId_, timeFactor_, resp.columnIndex2TsBlockColumnIndexList)); + resp.moreData, fetchSize_, zoneId_, timeFactor_, resp.columnIndex2TsBlockColumnIndexList); } void ThriftConnection::close() { diff --git a/iotdb-client/client-cpp/src/main/ThriftConnection.h b/iotdb-client/client-cpp/src/rpc/ThriftConnection.h similarity index 100% rename from iotdb-client/client-cpp/src/main/ThriftConnection.h rename to iotdb-client/client-cpp/src/rpc/ThriftConnection.h diff --git a/iotdb-client/client-cpp/src/rpc/ThriftConvert.cpp b/iotdb-client/client-cpp/src/rpc/ThriftConvert.cpp new file mode 100644 index 0000000000000..3dd01e68157c2 --- /dev/null +++ b/iotdb-client/client-cpp/src/rpc/ThriftConvert.cpp @@ -0,0 +1,61 @@ +/** + * 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. + */ + +#include "ThriftConvert.h" + +#include "common_types.h" + +Status statusFromThrift(const TSStatus& tsStatus) { + Status status; + status.code = tsStatus.code; + status.message = tsStatus.message; + return status; +} + +Endpoint endpointFromThrift(const TEndPoint& endPoint) { + Endpoint endpoint; + endpoint.host = endPoint.ip; + endpoint.port = endPoint.port; + return endpoint; +} + +TEndPoint endpointToThrift(const Endpoint& endpoint) { + TEndPoint endPoint; + endPoint.__set_ip(endpoint.host); + endPoint.__set_port(endpoint.port); + return endPoint; +} + +std::map +endpointMapFromThrift(const std::map& deviceEndPointMap) { + std::map result; + for (const auto& entry : deviceEndPointMap) { + result.emplace(entry.first, endpointFromThrift(entry.second)); + } + return result; +} + +std::vector endpointListFromThrift(const std::vector& endPointList) { + std::vector result; + result.reserve(endPointList.size()); + for (const auto& endPoint : endPointList) { + result.push_back(endpointFromThrift(endPoint)); + } + return result; +} diff --git a/iotdb-client/client-cpp/src/rpc/ThriftConvert.h b/iotdb-client/client-cpp/src/rpc/ThriftConvert.h new file mode 100644 index 0000000000000..66ce790363495 --- /dev/null +++ b/iotdb-client/client-cpp/src/rpc/ThriftConvert.h @@ -0,0 +1,40 @@ +/** + * 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. + */ +#ifndef IOTDB_THRIFT_CONVERT_H +#define IOTDB_THRIFT_CONVERT_H + +#include +#include +#include + +#include "Endpoint.h" +#include "Status.h" + +class TEndPoint; +class TSStatus; + +Status statusFromThrift(const TSStatus& tsStatus); +Endpoint endpointFromThrift(const TEndPoint& endPoint); +TEndPoint endpointToThrift(const Endpoint& endpoint); + +std::map +endpointMapFromThrift(const std::map& deviceEndPointMap); +std::vector endpointListFromThrift(const std::vector& endPointList); + +#endif diff --git a/iotdb-client/client-cpp/src/main/Column.cpp b/iotdb-client/client-cpp/src/session/Column.cpp similarity index 100% rename from iotdb-client/client-cpp/src/main/Column.cpp rename to iotdb-client/client-cpp/src/session/Column.cpp diff --git a/iotdb-client/client-cpp/src/main/ColumnDecoder.cpp b/iotdb-client/client-cpp/src/session/ColumnDecoder.cpp similarity index 100% rename from iotdb-client/client-cpp/src/main/ColumnDecoder.cpp rename to iotdb-client/client-cpp/src/session/ColumnDecoder.cpp diff --git a/iotdb-client/client-cpp/src/main/Common.cpp b/iotdb-client/client-cpp/src/session/Common.cpp similarity index 52% rename from iotdb-client/client-cpp/src/main/Common.cpp rename to iotdb-client/client-cpp/src/session/Common.cpp index 38b913c2270ca..06be4790123f6 100644 --- a/iotdb-client/client-cpp/src/main/Common.cpp +++ b/iotdb-client/client-cpp/src/session/Common.cpp @@ -18,9 +18,13 @@ */ #include "Common.h" -#include + +#include +#include #include +LogLevelType LOG_LEVEL = LEVEL_WARN; + std::string extractExceptionMessage(const std::exception& exception) { const char* what = exception.what(); if (what != nullptr) { @@ -45,35 +49,6 @@ std::string extractExceptionMessage(const std::exception_ptr& exceptionPtr) { } } -int32_t parseDateExpressionToInt(const boost::gregorian::date& date) { - if (date.is_not_a_date()) { - throw IoTDBException("Date expression is null or empty."); - } - - const int year = date.year(); - if (year < 1000 || year > 9999) { - throw DateTimeParseException("Year must be between 1000 and 9999.", - boost::gregorian::to_iso_extended_string(date), 0); - } - - const int64_t result = static_cast(year) * 10000 + date.month() * 100 + date.day(); - if (result > INT32_MAX || result < INT32_MIN) { - throw DateTimeParseException("Date value overflow. ", - boost::gregorian::to_iso_extended_string(date), 0); - } - return static_cast(result); -} - -boost::gregorian::date parseIntToDate(int32_t dateInt) { - if (dateInt == EMPTY_DATE_INT) { - return boost::gregorian::date(boost::date_time::not_a_date_time); - } - int year = dateInt / 10000; - int month = (dateInt % 10000) / 100; - int day = dateInt % 100; - return boost::gregorian::date(year, month, day); -} - std::string getTimePrecision(int32_t timeFactor) { if (timeFactor >= 1000000) return "us"; @@ -84,7 +59,8 @@ std::string getTimePrecision(int32_t timeFactor) { std::string formatDatetime(const std::string& format, const std::string& precision, int64_t timestamp, const std::string& zoneId) { - // Simplified implementation - in real code you'd use proper timezone handling + (void)precision; + (void)zoneId; std::time_t time = static_cast(timestamp); std::tm* tm = std::localtime(&time); char buffer[80]; @@ -124,144 +100,10 @@ TSDataType::TSDataType getDataTypeByStr(const std::string& typeStr) { } std::tm int32ToDate(int32_t value) { - // Convert days since epoch (1970-01-01) to tm struct - std::time_t time = static_cast(value) * 86400; // seconds per day + std::time_t time = static_cast(value) * 86400; return *std::localtime(&time); } -void RpcUtils::verifySuccess(const TSStatus& status) { - if (status.code == TSStatusCode::MULTIPLE_ERROR) { - verifySuccess(status.subStatus); - return; - } - if (status.code != TSStatusCode::SUCCESS_STATUS && - status.code != TSStatusCode::REDIRECTION_RECOMMEND) { - throw ExecutionException(to_string(status.code) + ": " + status.message, status); - } -} - -void RpcUtils::verifySuccessWithRedirection(const TSStatus& status) { - verifySuccess(status); - if (status.__isset.redirectNode) { - throw RedirectException(to_string(status.code) + ": " + status.message, status.redirectNode); - } - if (status.__isset.subStatus) { - auto statusSubStatus = status.subStatus; - vector endPointList(statusSubStatus.size()); - int count = 0; - for (TSStatus subStatus : statusSubStatus) { - if (subStatus.__isset.redirectNode) { - endPointList[count++] = subStatus.redirectNode; - } else { - TEndPoint endPoint; - endPointList[count++] = endPoint; - } - } - if (!endPointList.empty()) { - throw RedirectException(to_string(status.code) + ": " + status.message, endPointList); - } - } -} - -void RpcUtils::verifySuccessWithRedirectionForMultiDevices(const TSStatus& status, - vector devices) { - verifySuccess(status); - - if (status.code == TSStatusCode::MULTIPLE_ERROR || - status.code == TSStatusCode::REDIRECTION_RECOMMEND) { - map deviceEndPointMap; - vector statusSubStatus; - for (int i = 0; i < statusSubStatus.size(); i++) { - TSStatus subStatus = statusSubStatus[i]; - if (subStatus.__isset.redirectNode) { - deviceEndPointMap.insert(make_pair(devices[i], subStatus.redirectNode)); - } - } - throw RedirectException(to_string(status.code) + ": " + status.message, deviceEndPointMap); - } - - if (status.__isset.redirectNode) { - throw RedirectException(to_string(status.code) + ": " + status.message, status.redirectNode); - } - if (status.__isset.subStatus) { - auto statusSubStatus = status.subStatus; - vector endPointList(statusSubStatus.size()); - int count = 0; - for (TSStatus subStatus : statusSubStatus) { - if (subStatus.__isset.redirectNode) { - endPointList[count++] = subStatus.redirectNode; - } else { - TEndPoint endPoint; - endPointList[count++] = endPoint; - } - } - if (!endPointList.empty()) { - throw RedirectException(to_string(status.code) + ": " + status.message, endPointList); - } - } -} - -void RpcUtils::verifySuccess(const vector& statuses) { - for (const TSStatus& status : statuses) { - if (status.code != TSStatusCode::SUCCESS_STATUS) { - throw BatchExecutionException(status.message, statuses); - } - } -} - -TSStatus RpcUtils::getStatus(TSStatusCode::TSStatusCode tsStatusCode) { - TSStatus status; - status.__set_code(tsStatusCode); - return status; -} - -TSStatus RpcUtils::getStatus(int code, const string& message) { - TSStatus status; - status.__set_code(code); - status.__set_message(message); - return status; -} - -shared_ptr -RpcUtils::getTSExecuteStatementResp(TSStatusCode::TSStatusCode tsStatusCode) { - TSStatus status = getStatus(tsStatusCode); - return getTSExecuteStatementResp(status); -} - -shared_ptr -RpcUtils::getTSExecuteStatementResp(TSStatusCode::TSStatusCode tsStatusCode, - const string& message) { - TSStatus status = getStatus(tsStatusCode, message); - return getTSExecuteStatementResp(status); -} - -shared_ptr RpcUtils::getTSExecuteStatementResp(const TSStatus& status) { - shared_ptr resp(new TSExecuteStatementResp()); - TSStatus tsStatus(status); - resp->__set_status(status); - return resp; -} - -shared_ptr -RpcUtils::getTSFetchResultsResp(TSStatusCode::TSStatusCode tsStatusCode) { - TSStatus status = getStatus(tsStatusCode); - return getTSFetchResultsResp(status); -} - -shared_ptr -RpcUtils::getTSFetchResultsResp(TSStatusCode::TSStatusCode tsStatusCode, - const string& appendMessage) { - TSStatus status = getStatus(tsStatusCode, appendMessage); - return getTSFetchResultsResp(status); -} - -shared_ptr RpcUtils::getTSFetchResultsResp(const TSStatus& status) { - shared_ptr resp(new TSFetchResultsResp()); - TSStatus tsStatus(status); - resp->__set_status(tsStatus); - return resp; -} - MyStringBuffer::MyStringBuffer() : pos(0) { checkBigEndian(); } @@ -287,7 +129,7 @@ int MyStringBuffer::getInt() { return *(int*)getOrderedByte(4); } -boost::gregorian::date MyStringBuffer::getDate() { +IoTdbDate MyStringBuffer::getDate() { return parseIntToDate(getInt()); } @@ -357,7 +199,7 @@ void MyStringBuffer::putInt(int ins) { putOrderedByte((char*)&ins, 4); } -void MyStringBuffer::putDate(boost::gregorian::date date) { +void MyStringBuffer::putDate(IoTdbDate date) { putInt(parseDateExpressionToInt(date)); } @@ -392,7 +234,7 @@ void MyStringBuffer::concat(const std::string& ins) { } void MyStringBuffer::checkBigEndian() { - static int chk = 0x0201; //used to distinguish CPU's type (BigEndian or LittleEndian) + static int chk = 0x0201; isBigEndian = (0x01 != *(char*)(&chk)); } @@ -432,7 +274,7 @@ BitMap::BitMap(size_t size) { void BitMap::resize(size_t size) { this->size = size; - this->bits.resize((size >> 3) + 1); // equal to "size/8 + 1" + this->bits.resize((size >> 3) + 1); reset(); } @@ -504,47 +346,3 @@ const std::vector& BitMap::getByteArray() const { size_t BitMap::getSize() const { return this->size; } - -const std::string UrlUtils::PORT_SEPARATOR = ":"; -const std::string UrlUtils::ABB_COLON = "["; - -TEndPoint UrlUtils::parseTEndPointIpv4AndIpv6Url(const std::string& endPointUrl) { - TEndPoint endPoint; - - // Return default TEndPoint if input is empty - if (endPointUrl.empty()) { - return endPoint; - } - - size_t portSeparatorPos = endPointUrl.find_last_of(PORT_SEPARATOR); - - // If no port separator found, treat entire string as IP - if (portSeparatorPos == std::string::npos) { - endPoint.__set_ip(endPointUrl); - return endPoint; - } - - // Extract port part - std::string portStr = endPointUrl.substr(portSeparatorPos + 1); - - // Extract IP part - std::string ip = endPointUrl.substr(0, portSeparatorPos); - - // Handle IPv6 addresses with brackets - if (ip.find(ABB_COLON) != std::string::npos) { - // Remove surrounding square brackets for IPv6 - if (ip.size() >= 2 && ip.front() == '[' && ip.back() == ']') { - ip = ip.substr(1, ip.size() - 2); - } - } - - try { - int port = std::stoi(portStr); - endPoint.__set_ip(ip); - endPoint.__set_port(port); - } catch (const std::exception& e) { - endPoint.__set_ip(endPointUrl); - } - - return endPoint; -} diff --git a/iotdb-client/client-cpp/src/session/Date.cpp b/iotdb-client/client-cpp/src/session/Date.cpp new file mode 100644 index 0000000000000..afb8288d8ab1d --- /dev/null +++ b/iotdb-client/client-cpp/src/session/Date.cpp @@ -0,0 +1,63 @@ +/** + * 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. + */ + +#include "Date.h" + +#include +#include +#include + +#include "Common.h" + +std::string IoTdbDate::toIsoExtendedString() const { + if (!valid_) { + return ""; + } + char buf[16]; + std::snprintf(buf, sizeof(buf), "%04d-%02d-%02d", year_, month_, day_); + return std::string(buf); +} + +int32_t parseDateExpressionToInt(const IoTdbDate& date) { + if (date.is_not_a_date()) { + throw IoTDBException("Date expression is null or empty."); + } + + const int year = date.year(); + if (year < 1000 || year > 9999) { + throw DateTimeParseException("Year must be between 1000 and 9999.", date.toIsoExtendedString(), + 0); + } + + const int64_t result = static_cast(year) * 10000 + date.month() * 100 + date.day(); + if (result > INT32_MAX || result < INT32_MIN) { + throw DateTimeParseException("Date value overflow. ", date.toIsoExtendedString(), 0); + } + return static_cast(result); +} + +IoTdbDate parseIntToDate(int32_t dateInt) { + if (dateInt == EMPTY_DATE_INT) { + return IoTdbDate::notADate(); + } + const int year = dateInt / 10000; + const int month = (dateInt % 10000) / 100; + const int day = dateInt % 100; + return IoTdbDate(year, month, day); +} diff --git a/iotdb-client/client-cpp/src/main/Session.cpp b/iotdb-client/client-cpp/src/session/Session.cpp similarity index 81% rename from iotdb-client/client-cpp/src/main/Session.cpp rename to iotdb-client/client-cpp/src/session/Session.cpp index b6f6afad0faca..0964a5d859810 100644 --- a/iotdb-client/client-cpp/src/main/Session.cpp +++ b/iotdb-client/client-cpp/src/session/Session.cpp @@ -20,11 +20,16 @@ #include "Session.h" #include #include +#include #include #include #include -#include "NodesSupplier.h" +#include +#include "SessionImpl.h" #include "SessionDataSet.h" +#include "ThriftConvert.h" + +using apache::thrift::transport::TTransportException; using namespace std; @@ -35,8 +40,6 @@ using namespace std; */ static const int64_t QUERY_TIMEOUT_MS = -1; -LogLevelType LOG_LEVEL = LEVEL_DEBUG; - TSDataType::TSDataType getTSDataTypeFromString(const string& str) { // BOOLEAN, INT32, INT64, FLOAT, DOUBLE, TEXT, STRING, BLOB, TIMESTAMP, DATE, NULLTYPE if (str == "BOOLEAN") { @@ -73,7 +76,7 @@ void Tablet::createColumns() { values[i] = new bool[maxRowNumber]; break; case TSDataType::DATE: - values[i] = new boost::gregorian::date[maxRowNumber]; + values[i] = new IoTdbDate[maxRowNumber]; break; case TSDataType::INT32: values[i] = new int[maxRowNumber]; @@ -118,7 +121,7 @@ void Tablet::deleteColumns() { break; } case TSDataType::DATE: { - boost::gregorian::date* valueBuf = (boost::gregorian::date*)(values[i]); + IoTdbDate* valueBuf = (IoTdbDate*)(values[i]); delete[] valueBuf; break; } @@ -180,9 +183,9 @@ void Tablet::deepCopyTabletColValue(void* const* srcPtr, void** destPtr, memcpy(*destPtr, src, maxRowNumber * sizeof(double)); break; case TSDataType::DATE: { - *destPtr = new boost::gregorian::date[maxRowNumber]; - boost::gregorian::date* srcDate = static_cast(src); - boost::gregorian::date* destDate = static_cast(*destPtr); + *destPtr = new IoTdbDate[maxRowNumber]; + IoTdbDate* srcDate = static_cast(src); + IoTdbDate* destDate = static_cast(*destPtr); for (size_t j = 0; j < maxRowNumber; ++j) { destDate[j] = srcDate[j]; } @@ -319,7 +322,7 @@ string SessionUtils::getValue(const Tablet& tablet) { break; } case TSDataType::DATE: { - boost::gregorian::date* valueBuf = (boost::gregorian::date*)(tablet.values[i]); + IoTdbDate* valueBuf = (IoTdbDate*)(tablet.values[i]); for (size_t index = 0; index < tablet.rowSize; index++) { if (!bitMap.isMarked(index)) { valueBuffer.putDate(valueBuf[index]); @@ -420,7 +423,7 @@ string MeasurementNode::serialize() const { string Template::serialize() const { MyStringBuffer buffer; - stack>> stack; + std::stack>> nodeStack; unordered_set alignedPrefix; buffer.putString(getName()); buffer.putBool(isAligned()); @@ -429,12 +432,12 @@ string Template::serialize() const { } for (const auto& child : children_) { - stack.push(make_pair("", child.second)); + nodeStack.push(make_pair("", child.second)); } - while (!stack.empty()) { - auto cur = stack.top(); - stack.pop(); + while (!nodeStack.empty()) { + auto cur = nodeStack.top(); + nodeStack.pop(); string prefix = cur.first; shared_ptr cur_node_ptr = cur.second; @@ -449,7 +452,7 @@ string Template::serialize() const { alignedPrefix.emplace(fullPath); } for (const auto& child : cur_node_ptr->getChildren()) { - stack.push(make_pair(fullPath, child.second)); + nodeStack.push(make_pair(fullPath, child.second)); } } else { buffer.putString(prefix); @@ -461,6 +464,104 @@ string Template::serialize() const { return buffer.str; } +Session::Session(const std::string& host, int rpcPort) : impl_(new Impl()) { + impl_->username_ = "root"; + impl_->password_ = "root"; + impl_->version = Version::V_1_0; + impl_->host_ = host; + impl_->rpcPort_ = rpcPort; + impl_->initZoneId(); + impl_->initNodesSupplier(); +} + +Session::Session(const std::vector& nodeUrls, const std::string& username, + const std::string& password) + : impl_(new Impl()) { + impl_->nodeUrls_ = nodeUrls; + impl_->username_ = username; + impl_->password_ = password; + impl_->version = Version::V_1_0; + impl_->initZoneId(); + impl_->initNodesSupplier(impl_->nodeUrls_); +} + +Session::Session(const std::string& host, int rpcPort, const std::string& username, + const std::string& password) + : impl_(new Impl()) { + impl_->host_ = host; + impl_->rpcPort_ = rpcPort; + impl_->username_ = username; + impl_->password_ = password; + impl_->fetchSize_ = Impl::DEFAULT_FETCH_SIZE; + impl_->version = Version::V_1_0; + impl_->initZoneId(); + impl_->initNodesSupplier(); +} + +Session::Session(const std::string& host, int rpcPort, const std::string& username, + const std::string& password, const std::string& zoneId, int fetchSize) + : impl_(new Impl()) { + impl_->host_ = host; + impl_->rpcPort_ = rpcPort; + impl_->username_ = username; + impl_->password_ = password; + impl_->zoneId_ = zoneId; + impl_->fetchSize_ = fetchSize; + impl_->version = Version::V_1_0; + impl_->initZoneId(); + impl_->initNodesSupplier(); +} + +Session::Session(const std::string& host, const std::string& rpcPort, const std::string& username, + const std::string& password, const std::string& zoneId, int fetchSize) + : impl_(new Impl()) { + impl_->host_ = host; + impl_->rpcPort_ = stoi(rpcPort); + impl_->username_ = username; + impl_->password_ = password; + impl_->zoneId_ = zoneId; + impl_->fetchSize_ = fetchSize; + impl_->version = Version::V_1_0; + impl_->initZoneId(); + impl_->initNodesSupplier(); +} + +Session::Session(AbstractSessionBuilder* builder) : impl_(new Impl()) { + impl_->host_ = builder->host; + impl_->rpcPort_ = builder->rpcPort; + impl_->username_ = builder->username; + impl_->password_ = builder->password; + impl_->zoneId_ = builder->zoneId; + impl_->fetchSize_ = builder->fetchSize; + impl_->version = Version::V_1_0; + impl_->sqlDialect_ = builder->sqlDialect; + impl_->database_ = builder->database; + impl_->enableAutoFetch_ = builder->enableAutoFetch; + impl_->enableRedirection_ = builder->enableRedirections; + impl_->connectTimeoutMs_ = builder->connectTimeoutMs; + impl_->nodeUrls_ = builder->nodeUrls; + impl_->useSSL_ = builder->useSSL; + impl_->trustCertFilePath_ = builder->trustCertFilePath; + impl_->initZoneId(); + impl_->initNodesSupplier(impl_->nodeUrls_); +} + +void Session::setSqlDialect(const std::string& dialect) { + impl_->sqlDialect_ = dialect; +} + +void Session::setDatabase(const std::string& database) { + impl_->database_ = database; +} + +std::string Session::getDatabase() { + return impl_->database_; +} + +void Session::changeDatabase(const std::string& database) { + impl_->database_ = database; +} + /** * When delete variable, make sure release all resource. */ @@ -472,7 +573,7 @@ Session::~Session() { } } -void Session::removeBrokenSessionConnection(shared_ptr sessionConnection) { +void Session::Impl::removeBrokenSessionConnection(shared_ptr sessionConnection) { if (enableRedirection_) { this->endPointToSessionConnection.erase(sessionConnection->getEndPoint()); } @@ -501,7 +602,7 @@ void Session::removeBrokenSessionConnection(shared_ptr sessio * * @return whether the batch has been sorted */ -bool Session::checkSorted(const Tablet& tablet) { +bool Session::Impl::checkSorted(const Tablet& tablet) { for (size_t i = 1; i < tablet.rowSize; i++) { if (tablet.timestamps[i] < tablet.timestamps[i - 1]) { return false; @@ -510,7 +611,7 @@ bool Session::checkSorted(const Tablet& tablet) { return true; } -bool Session::checkSorted(const vector& times) { +bool Session::Impl::checkSorted(const vector& times) { for (size_t i = 1; i < times.size(); i++) { if (times[i] < times[i - 1]) { return false; @@ -539,7 +640,7 @@ template void sortValuesList(T* valueList, const int* index, size_t delete[] sortedValues; } -void Session::sortTablet(Tablet& tablet) { +void Session::Impl::sortTablet(Tablet& tablet) { /* * following part of code sort the batch data by time, * so we can insert continuous data in value list to get a better performance @@ -564,7 +665,7 @@ void Session::sortTablet(Tablet& tablet) { break; } case TSDataType::DATE: { - sortValuesList((boost::gregorian::date*)(tablet.values[i]), index, tablet.rowSize); + sortValuesList((IoTdbDate*)(tablet.values[i]), index, tablet.rowSize); break; } case TSDataType::TIMESTAMP: @@ -596,7 +697,7 @@ void Session::sortTablet(Tablet& tablet) { delete[] index; } -void Session::sortIndexByTimestamp(int* index, std::vector& timestamps, int length) { +void Session::Impl::sortIndexByTimestamp(int* index, std::vector& timestamps, int length) { if (length <= 1) { return; } @@ -608,7 +709,7 @@ void Session::sortIndexByTimestamp(int* index, std::vector& timestamps, /** * Append value into buffer in Big Endian order to comply with IoTDB server */ -void Session::appendValues(string& buffer, const char* value, int size) { +void Session::Impl::appendValues(string& buffer, const char* value, int size) { static bool hasCheckedEndianFlag = false; static bool localCpuIsBigEndian = false; if (!hasCheckedEndianFlag) { @@ -626,8 +727,8 @@ void Session::appendValues(string& buffer, const char* value, int size) { } } -void Session::putValuesIntoBuffer(const vector& types, - const vector& values, string& buf) { +void Session::Impl::putValuesIntoBuffer(const vector& types, + const vector& values, string& buf) { int32_t date; for (size_t i = 0; i < values.size(); i++) { int8_t typeNum = getDataTypeNumber(types[i]); @@ -640,7 +741,7 @@ void Session::putValuesIntoBuffer(const vector& types, appendValues(buf, values[i], sizeof(int32_t)); break; case TSDataType::DATE: - date = parseDateExpressionToInt(*(boost::gregorian::date*)values[i]); + date = parseDateExpressionToInt(*(IoTdbDate*)values[i]); appendValues(buf, (char*)&date, sizeof(int32_t)); break; case TSDataType::TIMESTAMP: @@ -669,7 +770,7 @@ void Session::putValuesIntoBuffer(const vector& types, } } -int8_t Session::getDataTypeNumber(TSDataType::TSDataType type) { +int8_t Session::Impl::getDataTypeNumber(TSDataType::TSDataType type) { switch (type) { case TSDataType::BOOLEAN: return 0; @@ -698,7 +799,7 @@ int8_t Session::getDataTypeNumber(TSDataType::TSDataType type) { } } -string Session::getVersionString(Version::Version version) { +string Session::Impl::getVersionString(Version::Version version) { switch (version) { case Version::V_0_12: return "V_0_12"; @@ -711,7 +812,7 @@ string Session::getVersionString(Version::Version version) { } } -void Session::initZoneId() { +void Session::Impl::initZoneId() { if (!zoneId_.empty()) { return; } @@ -729,7 +830,7 @@ void Session::initZoneId() { zoneId_ = zoneStr; } -void Session::initNodesSupplier(const std::vector& nodeUrls) { +void Session::Impl::initNodesSupplier(const std::vector& nodeUrls) { std::vector endPoints; std::unordered_set uniqueEndpoints; @@ -775,7 +876,7 @@ void Session::initNodesSupplier(const std::vector& nodeUrls) { } } -void Session::initDefaultSessionConnection() { +void Session::Impl::initDefaultSessionConnection() { // Try all endpoints from supplier until a connection is established. auto endpoints = nodesSupplier_->getEndPointList(); bool connected = false; @@ -807,10 +908,11 @@ void Session::initDefaultSessionConnection() { } } -void Session::insertStringRecordsWithLeaderCache(vector deviceIds, vector times, - vector> measurementsList, - vector> valuesList, - bool isAligned) { +void Session::Impl::insertStringRecordsWithLeaderCache(vector deviceIds, + vector times, + vector> measurementsList, + vector> valuesList, + bool isAligned) { std::unordered_map, TSInsertStringRecordsReq> recordsGroup; for (int i = 0; i < deviceIds.size(); i++) { auto connection = getSessionConnection(deviceIds[i]); @@ -843,10 +945,10 @@ void Session::insertStringRecordsWithLeaderCache(vector deviceIds, vecto } } -void Session::insertRecordsWithLeaderCache(vector deviceIds, vector times, - vector> measurementsList, - const vector>& typesList, - vector> valuesList, bool isAligned) { +void Session::Impl::insertRecordsWithLeaderCache( + vector deviceIds, vector times, vector> measurementsList, + const vector>& typesList, vector> valuesList, + bool isAligned) { std::unordered_map, TSInsertRecordsReq> recordsGroup; for (int i = 0; i < deviceIds.size(); i++) { auto connection = getSessionConnection(deviceIds[i]); @@ -884,8 +986,8 @@ void Session::insertRecordsWithLeaderCache(vector deviceIds, vector tablets, bool sorted, - bool isAligned) { +void Session::Impl::insertTabletsWithLeaderCache(unordered_map& tablets, + bool sorted, bool isAligned) { std::unordered_map, TSInsertTabletsReq> tabletsGroup; if (tablets.empty()) { throw BatchExecutionException("No tablet is inserting!"); @@ -932,38 +1034,39 @@ void Session::insertTabletsWithLeaderCache(unordered_map tablet } void Session::open() { - open(false, DEFAULT_TIMEOUT_MS); + open(false, Impl::DEFAULT_TIMEOUT_MS); } void Session::open(bool enableRPCCompression) { - open(enableRPCCompression, DEFAULT_TIMEOUT_MS); + open(enableRPCCompression, Impl::DEFAULT_TIMEOUT_MS); } void Session::open(bool enableRPCCompression, int connectionTimeoutInMs) { - if (!isClosed_) { + if (!impl_->isClosed_) { return; } try { - initDefaultSessionConnection(); + impl_->initDefaultSessionConnection(); } catch (const exception& e) { log_debug(e.what()); throw IoTDBException(e.what()); } - zoneId_ = defaultSessionConnection_->zoneId; + impl_->zoneId_ = impl_->defaultSessionConnection_->zoneId; - if (enableRedirection_) { - endPointToSessionConnection.insert(make_pair(defaultEndPoint_, defaultSessionConnection_)); + if (impl_->enableRedirection_) { + impl_->endPointToSessionConnection.insert( + make_pair(impl_->defaultEndPoint_, impl_->defaultSessionConnection_)); } - isClosed_ = false; + impl_->isClosed_ = false; } void Session::close() { - if (isClosed_) { + if (impl_->isClosed_) { return; } - isClosed_ = true; + impl_->isClosed_ = true; } void Session::insertRecord(const string& deviceId, int64_t time, const vector& measurements, @@ -975,14 +1078,15 @@ void Session::insertRecord(const string& deviceId, int64_t time, const vectorinsertStringRecord(req); + impl_->getSessionConnection(deviceId)->insertStringRecord(req); } catch (RedirectException& e) { - handleRedirection(deviceId, e.endPoint); + impl_->handleRedirection(deviceId, endpointToThrift(e.endPoint)); } catch (const IoTDBConnectionException& e) { - if (enableRedirection_ && deviceIdToEndpoint.find(deviceId) != deviceIdToEndpoint.end()) { - deviceIdToEndpoint.erase(deviceId); + if (impl_->enableRedirection_ && + impl_->deviceIdToEndpoint.find(deviceId) != impl_->deviceIdToEndpoint.end()) { + impl_->deviceIdToEndpoint.erase(deviceId); try { - defaultSessionConnection_->insertStringRecord(req); + impl_->defaultSessionConnection_->insertStringRecord(req); } catch (RedirectException& e) { } } else { @@ -999,18 +1103,19 @@ void Session::insertRecord(const string& deviceId, int64_t time, const vectorputValuesIntoBuffer(types, values, buffer); req.__set_values(buffer); req.__set_isAligned(false); try { - getSessionConnection(deviceId)->insertRecord(req); + impl_->getSessionConnection(deviceId)->insertRecord(req); } catch (RedirectException& e) { - handleRedirection(deviceId, e.endPoint); + impl_->handleRedirection(deviceId, endpointToThrift(e.endPoint)); } catch (const IoTDBConnectionException& e) { - if (enableRedirection_ && deviceIdToEndpoint.find(deviceId) != deviceIdToEndpoint.end()) { - deviceIdToEndpoint.erase(deviceId); + if (impl_->enableRedirection_ && + impl_->deviceIdToEndpoint.find(deviceId) != impl_->deviceIdToEndpoint.end()) { + impl_->deviceIdToEndpoint.erase(deviceId); try { - defaultSessionConnection_->insertRecord(req); + impl_->defaultSessionConnection_->insertRecord(req); } catch (RedirectException& e) { } } else { @@ -1029,14 +1134,15 @@ void Session::insertAlignedRecord(const string& deviceId, int64_t time, req.__set_values(values); req.__set_isAligned(true); try { - getSessionConnection(deviceId)->insertStringRecord(req); + impl_->getSessionConnection(deviceId)->insertStringRecord(req); } catch (RedirectException& e) { - handleRedirection(deviceId, e.endPoint); + impl_->handleRedirection(deviceId, endpointToThrift(e.endPoint)); } catch (const IoTDBConnectionException& e) { - if (enableRedirection_ && deviceIdToEndpoint.find(deviceId) != deviceIdToEndpoint.end()) { - deviceIdToEndpoint.erase(deviceId); + if (impl_->enableRedirection_ && + impl_->deviceIdToEndpoint.find(deviceId) != impl_->deviceIdToEndpoint.end()) { + impl_->deviceIdToEndpoint.erase(deviceId); try { - defaultSessionConnection_->insertStringRecord(req); + impl_->defaultSessionConnection_->insertStringRecord(req); } catch (RedirectException& e) { } } else { @@ -1054,18 +1160,19 @@ void Session::insertAlignedRecord(const string& deviceId, int64_t time, req.__set_timestamp(time); req.__set_measurements(measurements); string buffer; - putValuesIntoBuffer(types, values, buffer); + impl_->putValuesIntoBuffer(types, values, buffer); req.__set_values(buffer); req.__set_isAligned(false); try { - getSessionConnection(deviceId)->insertRecord(req); + impl_->getSessionConnection(deviceId)->insertRecord(req); } catch (RedirectException& e) { - handleRedirection(deviceId, e.endPoint); + impl_->handleRedirection(deviceId, endpointToThrift(e.endPoint)); } catch (const IoTDBConnectionException& e) { - if (enableRedirection_ && deviceIdToEndpoint.find(deviceId) != deviceIdToEndpoint.end()) { - deviceIdToEndpoint.erase(deviceId); + if (impl_->enableRedirection_ && + impl_->deviceIdToEndpoint.find(deviceId) != impl_->deviceIdToEndpoint.end()) { + impl_->deviceIdToEndpoint.erase(deviceId); try { - defaultSessionConnection_->insertRecord(req); + impl_->defaultSessionConnection_->insertRecord(req); } catch (RedirectException& e) { } } else { @@ -1083,8 +1190,9 @@ void Session::insertRecords(const vector& deviceIds, const vectorenableRedirection_) { + impl_->insertStringRecordsWithLeaderCache(deviceIds, times, measurementsList, valuesList, + false); } else { TSInsertStringRecordsReq request; request.__set_prefixPaths(deviceIds); @@ -1093,7 +1201,7 @@ void Session::insertRecords(const vector& deviceIds, const vectorinsertStringRecords(request); + impl_->defaultSessionConnection_->insertStringRecords(request); } catch (RedirectException& e) { } } @@ -1109,8 +1217,9 @@ void Session::insertRecords(const vector& deviceIds, const vectorenableRedirection_) { + impl_->insertRecordsWithLeaderCache(deviceIds, times, measurementsList, typesList, valuesList, + false); } else { TSInsertRecordsReq request; request.__set_prefixPaths(deviceIds); @@ -1119,13 +1228,13 @@ void Session::insertRecords(const vector& deviceIds, const vector bufferList; for (size_t i = 0; i < valuesList.size(); i++) { string buffer; - putValuesIntoBuffer(typesList[i], valuesList[i], buffer); + impl_->putValuesIntoBuffer(typesList[i], valuesList[i], buffer); bufferList.push_back(buffer); } request.__set_valuesList(bufferList); request.__set_isAligned(false); try { - defaultSessionConnection_->insertRecords(request); + impl_->defaultSessionConnection_->insertRecords(request); } catch (RedirectException& e) { } } @@ -1140,8 +1249,8 @@ void Session::insertAlignedRecords(const vector& deviceIds, const vector throw exception(e); } - if (enableRedirection_) { - insertStringRecordsWithLeaderCache(deviceIds, times, measurementsList, valuesList, true); + if (impl_->enableRedirection_) { + impl_->insertStringRecordsWithLeaderCache(deviceIds, times, measurementsList, valuesList, true); } else { TSInsertStringRecordsReq request; request.__set_prefixPaths(deviceIds); @@ -1150,7 +1259,7 @@ void Session::insertAlignedRecords(const vector& deviceIds, const vector request.__set_valuesList(valuesList); request.__set_isAligned(true); try { - defaultSessionConnection_->insertStringRecords(request); + impl_->defaultSessionConnection_->insertStringRecords(request); } catch (RedirectException& e) { } } @@ -1166,8 +1275,9 @@ void Session::insertAlignedRecords(const vector& deviceIds, const vector throw exception(e); } - if (enableRedirection_) { - insertRecordsWithLeaderCache(deviceIds, times, measurementsList, typesList, valuesList, true); + if (impl_->enableRedirection_) { + impl_->insertRecordsWithLeaderCache(deviceIds, times, measurementsList, typesList, valuesList, + true); } else { TSInsertRecordsReq request; request.__set_prefixPaths(deviceIds); @@ -1176,13 +1286,13 @@ void Session::insertAlignedRecords(const vector& deviceIds, const vector vector bufferList; for (size_t i = 0; i < valuesList.size(); i++) { string buffer; - putValuesIntoBuffer(typesList[i], valuesList[i], buffer); + impl_->putValuesIntoBuffer(typesList[i], valuesList[i], buffer); bufferList.push_back(buffer); } request.__set_valuesList(bufferList); request.__set_isAligned(false); try { - defaultSessionConnection_->insertRecords(request); + impl_->defaultSessionConnection_->insertRecords(request); } catch (RedirectException& e) { } } @@ -1199,13 +1309,13 @@ void Session::insertRecordsOfOneDevice(const string& deviceId, vector& vector>& measurementsList, vector>& typesList, vector>& valuesList, bool sorted) { - if (!checkSorted(times)) { + if (!impl_->checkSorted(times)) { int* index = new int[times.size()]; for (size_t i = 0; i < times.size(); i++) { index[i] = (int)i; } - sortIndexByTimestamp(index, times, (int)(times.size())); + impl_->sortIndexByTimestamp(index, times, (int)(times.size())); times = sortList(times, index, (int)(times.size())); measurementsList = sortList(measurementsList, index, (int)(times.size())); typesList = sortList(typesList, index, (int)(times.size())); @@ -1219,21 +1329,22 @@ void Session::insertRecordsOfOneDevice(const string& deviceId, vector& vector bufferList; for (size_t i = 0; i < valuesList.size(); i++) { string buffer; - putValuesIntoBuffer(typesList[i], valuesList[i], buffer); + impl_->putValuesIntoBuffer(typesList[i], valuesList[i], buffer); bufferList.push_back(buffer); } request.__set_valuesList(bufferList); request.__set_isAligned(false); TSStatus respStatus; try { - getSessionConnection(deviceId)->insertRecordsOfOneDevice(request); + impl_->getSessionConnection(deviceId)->insertRecordsOfOneDevice(request); } catch (RedirectException& e) { - handleRedirection(deviceId, e.endPoint); + impl_->handleRedirection(deviceId, endpointToThrift(e.endPoint)); } catch (const IoTDBConnectionException& e) { - if (enableRedirection_ && deviceIdToEndpoint.find(deviceId) != deviceIdToEndpoint.end()) { - deviceIdToEndpoint.erase(deviceId); + if (impl_->enableRedirection_ && + impl_->deviceIdToEndpoint.find(deviceId) != impl_->deviceIdToEndpoint.end()) { + impl_->deviceIdToEndpoint.erase(deviceId); try { - defaultSessionConnection_->insertRecordsOfOneDevice(request); + impl_->defaultSessionConnection_->insertRecordsOfOneDevice(request); } catch (RedirectException& e) { } } else { @@ -1253,13 +1364,13 @@ void Session::insertAlignedRecordsOfOneDevice(const string& deviceId, vector>& measurementsList, vector>& typesList, vector>& valuesList, bool sorted) { - if (!checkSorted(times)) { + if (!impl_->checkSorted(times)) { int* index = new int[times.size()]; for (size_t i = 0; i < times.size(); i++) { index[i] = (int)i; } - sortIndexByTimestamp(index, times, (int)(times.size())); + impl_->sortIndexByTimestamp(index, times, (int)(times.size())); times = sortList(times, index, (int)(times.size())); measurementsList = sortList(measurementsList, index, (int)(times.size())); typesList = sortList(typesList, index, (int)(times.size())); @@ -1273,21 +1384,22 @@ void Session::insertAlignedRecordsOfOneDevice(const string& deviceId, vector bufferList; for (size_t i = 0; i < valuesList.size(); i++) { string buffer; - putValuesIntoBuffer(typesList[i], valuesList[i], buffer); + impl_->putValuesIntoBuffer(typesList[i], valuesList[i], buffer); bufferList.push_back(buffer); } request.__set_valuesList(bufferList); request.__set_isAligned(true); TSStatus respStatus; try { - getSessionConnection(deviceId)->insertRecordsOfOneDevice(request); + impl_->getSessionConnection(deviceId)->insertRecordsOfOneDevice(request); } catch (RedirectException& e) { - handleRedirection(deviceId, e.endPoint); + impl_->handleRedirection(deviceId, endpointToThrift(e.endPoint)); } catch (const IoTDBConnectionException& e) { - if (enableRedirection_ && deviceIdToEndpoint.find(deviceId) != deviceIdToEndpoint.end()) { - deviceIdToEndpoint.erase(deviceId); + if (impl_->enableRedirection_ && + impl_->deviceIdToEndpoint.find(deviceId) != impl_->deviceIdToEndpoint.end()) { + impl_->deviceIdToEndpoint.erase(deviceId); try { - defaultSessionConnection_->insertRecordsOfOneDevice(request); + impl_->defaultSessionConnection_->insertRecordsOfOneDevice(request); } catch (RedirectException& e) { } } else { @@ -1306,7 +1418,7 @@ void Session::insertTablet(Tablet& tablet) { } } -void Session::buildInsertTabletReq(TSInsertTabletReq& request, Tablet& tablet, bool sorted) { +void Session::Impl::buildInsertTabletReq(TSInsertTabletReq& request, Tablet& tablet, bool sorted) { if ((!sorted) && !checkSorted(tablet)) { sortTablet(tablet); } @@ -1329,12 +1441,12 @@ void Session::buildInsertTabletReq(TSInsertTabletReq& request, Tablet& tablet, b request.__set_isAligned(tablet.isAligned); } -void Session::insertTablet(TSInsertTabletReq request) { +void Session::Impl::insertTablet(TSInsertTabletReq request) { auto deviceId = request.prefixPath; try { getSessionConnection(deviceId)->insertTablet(request); } catch (RedirectException& e) { - handleRedirection(deviceId, e.endPoint); + handleRedirection(deviceId, endpointToThrift(e.endPoint)); } catch (const IoTDBConnectionException& e) { if (enableRedirection_ && deviceIdToEndpoint.find(deviceId) != deviceIdToEndpoint.end()) { deviceIdToEndpoint.erase(deviceId); @@ -1350,20 +1462,21 @@ void Session::insertTablet(TSInsertTabletReq request) { void Session::insertTablet(Tablet& tablet, bool sorted) { TSInsertTabletReq request; - buildInsertTabletReq(request, tablet, sorted); - insertTablet(request); + impl_->buildInsertTabletReq(request, tablet, sorted); + impl_->insertTablet(request); } void Session::insertRelationalTablet(Tablet& tablet, bool sorted) { std::unordered_map, Tablet> relationalTabletGroup; - if (tableModelDeviceIdToEndpoint.empty()) { - relationalTabletGroup.insert(make_pair(defaultSessionConnection_, tablet)); + if (impl_->tableModelDeviceIdToEndpoint.empty()) { + relationalTabletGroup.insert(make_pair(impl_->defaultSessionConnection_, tablet)); } else if (SessionUtils::isTabletContainsSingleDevice(tablet)) { - relationalTabletGroup.insert(make_pair(getSessionConnection(tablet.getDeviceID(0)), tablet)); + relationalTabletGroup.insert( + make_pair(impl_->getSessionConnection(tablet.getDeviceID(0)), tablet)); } else { for (int row = 0; row < tablet.rowSize; row++) { auto iDeviceID = tablet.getDeviceID(row); - std::shared_ptr connection = getSessionConnection(iDeviceID); + std::shared_ptr connection = impl_->getSessionConnection(iDeviceID); auto it = relationalTabletGroup.find(connection); if (it == relationalTabletGroup.end()) { @@ -1400,7 +1513,7 @@ void Session::insertRelationalTablet(Tablet& tablet, bool sorted) { case TSDataType::DATE: { currentTablet.addValue( tablet.schemas[col].first, rowIndex, - *(boost::gregorian::date*)tablet.getValue(col, row, tablet.schemas[col].second)); + *(IoTdbDate*)tablet.getValue(col, row, tablet.schemas[col].second)); break; } case TSDataType::STRING: @@ -1418,9 +1531,9 @@ void Session::insertRelationalTablet(Tablet& tablet, bool sorted) { } } if (relationalTabletGroup.size() == 1) { - insertRelationalTabletOnce(relationalTabletGroup, sorted); + impl_->insertRelationalTabletOnce(relationalTabletGroup, sorted); } else { - insertRelationalTabletByGroup(relationalTabletGroup, sorted); + impl_->insertRelationalTabletByGroup(relationalTabletGroup, sorted); } } @@ -1428,7 +1541,7 @@ void Session::insertRelationalTablet(Tablet& tablet) { insertRelationalTablet(tablet, false); } -void Session::insertRelationalTabletOnce( +void Session::Impl::insertRelationalTabletOnce( const std::unordered_map, Tablet>& relationalTabletGroup, bool sorted) { auto iter = relationalTabletGroup.begin(); @@ -1450,7 +1563,7 @@ void Session::insertRelationalTabletOnce( auto endPointList = e.endPointList; for (int i = 0; i < endPointList.size(); i++) { auto deviceID = tablet.getDeviceID(i); - handleRedirection(deviceID, endPointList[i]); + handleRedirection(deviceID, endpointToThrift(endPointList[i])); } } catch (const IoTDBConnectionException& e) { if (endPointToSessionConnection.size() > 1) { @@ -1476,7 +1589,7 @@ void Session::insertRelationalTabletOnce( } } -void Session::insertRelationalTabletByGroup( +void Session::Impl::insertRelationalTabletByGroup( const std::unordered_map, Tablet>& relationalTabletGroup, bool sorted) { // Create a vector to store future objects for asynchronous operations @@ -1487,32 +1600,33 @@ void Session::insertRelationalTabletByGroup( auto tablet = iter->second; // Launch asynchronous task for each tablet insertion - futures.emplace_back(std::async(std::launch::async, [=]() mutable { - TSInsertTabletReq request; - buildInsertTabletReq(request, tablet, sorted); - request.__set_writeToTable(true); - - std::vector columnCategories; - for (auto& category : tablet.columnTypes) { - columnCategories.push_back(static_cast(category)); - } - request.__set_columnCategories(columnCategories); - - try { - TSStatus respStatus; - connection->getSessionClient()->insertTablet(respStatus, request); - RpcUtils::verifySuccess(respStatus); - } catch (const TTransportException& e) { - log_debug(e.what()); - throw IoTDBConnectionException(e.what()); - } catch (const IoTDBException& e) { - log_debug(e.what()); - throw; - } catch (const exception& e) { - log_debug(e.what()); - throw IoTDBException(e.what()); - } - })); + futures.emplace_back( + std::async(std::launch::async, [this, connection, tablet, sorted]() mutable { + TSInsertTabletReq request; + buildInsertTabletReq(request, tablet, sorted); + request.__set_writeToTable(true); + + std::vector columnCategories; + for (auto& category : tablet.columnTypes) { + columnCategories.push_back(static_cast(category)); + } + request.__set_columnCategories(columnCategories); + + try { + TSStatus respStatus; + connection->getSessionClient()->insertTablet(respStatus, request); + RpcUtils::verifySuccess(respStatus); + } catch (const TTransportException& e) { + log_debug(e.what()); + throw IoTDBConnectionException(e.what()); + } catch (const IoTDBException& e) { + log_debug(e.what()); + throw; + } catch (const exception& e) { + log_debug(e.what()); + throw IoTDBException(e.what()); + } + })); } for (auto& f : futures) { @@ -1551,16 +1665,16 @@ void Session::insertTablets(unordered_map& tablets, bool sorted } auto beginIter = tablets.begin(); bool isAligned = ((*beginIter).second)->isAligned; - if (enableRedirection_) { - insertTabletsWithLeaderCache(tablets, sorted, isAligned); + if (impl_->enableRedirection_) { + impl_->insertTabletsWithLeaderCache(tablets, sorted, isAligned); } else { TSInsertTabletsReq request; for (const auto& item : tablets) { if (isAligned != item.second->isAligned) { throw BatchExecutionException("The tablets should be all aligned or non-aligned!"); } - if (!checkSorted(*(item.second))) { - sortTablet(*(item.second)); + if (!impl_->checkSorted(*(item.second))) { + impl_->sortTablet(*(item.second)); } request.prefixPaths.push_back(item.second->deviceId); vector measurements; @@ -1578,7 +1692,7 @@ void Session::insertTablets(unordered_map& tablets, bool sorted request.__set_isAligned(isAligned); try { TSStatus respStatus; - defaultSessionConnection_->insertTablets(request); + impl_->defaultSessionConnection_->insertTablets(request); RpcUtils::verifySuccess(respStatus); } catch (RedirectException& e) { } @@ -1607,7 +1721,7 @@ void Session::testInsertRecord(const string& deviceId, int64_t time, req.__set_values(values); TSStatus tsStatus; try { - defaultSessionConnection_->testInsertStringRecord(req); + impl_->defaultSessionConnection_->testInsertStringRecord(req); RpcUtils::verifySuccess(tsStatus); } catch (const TTransportException& e) { log_debug(e.what()); @@ -1633,7 +1747,7 @@ void Session::testInsertTablet(const Tablet& tablet) { request.__set_size(tablet.rowSize); try { TSStatus tsStatus; - defaultSessionConnection_->testInsertTablet(request); + impl_->defaultSessionConnection_->testInsertTablet(request); RpcUtils::verifySuccess(tsStatus); } catch (const TTransportException& e) { log_debug(e.what()); @@ -1663,7 +1777,7 @@ void Session::testInsertRecords(const vector& deviceIds, const vectorgetSessionClient()->insertStringRecords(tsStatus, request); + impl_->defaultSessionConnection_->getSessionClient()->insertStringRecords(tsStatus, request); RpcUtils::verifySuccess(tsStatus); } catch (const TTransportException& e) { log_debug(e.what()); @@ -1684,7 +1798,7 @@ void Session::deleteTimeseries(const string& path) { } void Session::deleteTimeseries(const vector& paths) { - defaultSessionConnection_->deleteTimeseries(paths); + impl_->defaultSessionConnection_->deleteTimeseries(paths); } void Session::deleteData(const string& path, int64_t endTime) { @@ -1702,11 +1816,11 @@ void Session::deleteData(const vector& paths, int64_t startTime, int64_t req.__set_paths(paths); req.__set_startTime(startTime); req.__set_endTime(endTime); - defaultSessionConnection_->deleteData(req); + impl_->defaultSessionConnection_->deleteData(req); } void Session::setStorageGroup(const string& storageGroupId) { - defaultSessionConnection_->setStorageGroup(storageGroupId); + impl_->defaultSessionConnection_->setStorageGroup(storageGroupId); } void Session::deleteStorageGroup(const string& storageGroup) { @@ -1716,7 +1830,7 @@ void Session::deleteStorageGroup(const string& storageGroup) { } void Session::deleteStorageGroups(const vector& storageGroups) { - defaultSessionConnection_->deleteStorageGroups(storageGroups); + impl_->defaultSessionConnection_->deleteStorageGroups(storageGroups); } void Session::createDatabase(const string& database) { @@ -1765,7 +1879,7 @@ void Session::createTimeseries(const string& path, TSDataType::TSDataType dataTy if (!measurementAlias.empty()) { req.__set_measurementAlias(measurementAlias); } - defaultSessionConnection_->createTimeseries(req); + impl_->defaultSessionConnection_->createTimeseries(req); } void Session::createMultiTimeseries(const vector& paths, @@ -1814,7 +1928,7 @@ void Session::createMultiTimeseries(const vector& paths, request.__set_measurementAliasList(*measurementAliasList); } - defaultSessionConnection_->createMultiTimeseries(request); + impl_->defaultSessionConnection_->createMultiTimeseries(request); } void Session::createAlignedTimeseries( @@ -1847,7 +1961,7 @@ void Session::createAlignedTimeseries( } request.__set_compressors(compressorsOrdinal); - defaultSessionConnection_->createAlignedTimeseries(request); + impl_->defaultSessionConnection_->createAlignedTimeseries(request); } bool Session::checkTimeseriesExists(const string& path) { @@ -1865,7 +1979,7 @@ bool Session::checkTimeseriesExists(const string& path) { } } -shared_ptr Session::getQuerySessionConnection() { +shared_ptr Session::Impl::getQuerySessionConnection() { auto endPoint = nodesSupplier_->getQueryEndPoint(); if (!endPoint.is_initialized() || endPointToSessionConnection.empty()) { return defaultSessionConnection_; @@ -1884,12 +1998,12 @@ shared_ptr Session::getQuerySessionConnection() { endPointToSessionConnection.emplace(endPoint.value(), newConnection); return newConnection; } catch (exception& e) { - log_debug("Session::getQuerySessionConnection() exception: " + e.what()); + log_debug("Session::Impl::getQuerySessionConnection() exception: " + e.what()); return newConnection; } } -shared_ptr Session::getSessionConnection(std::string deviceId) { +shared_ptr Session::Impl::getSessionConnection(std::string deviceId) { if (!enableRedirection_ || deviceIdToEndpoint.find(deviceId) == deviceIdToEndpoint.end() || endPointToSessionConnection.find(deviceIdToEndpoint[deviceId]) == endPointToSessionConnection.end()) { @@ -1899,7 +2013,7 @@ shared_ptr Session::getSessionConnection(std::string deviceId } shared_ptr -Session::getSessionConnection(std::shared_ptr deviceId) { +Session::Impl::getSessionConnection(std::shared_ptr deviceId) { if (!enableRedirection_ || tableModelDeviceIdToEndpoint.find(deviceId) == tableModelDeviceIdToEndpoint.end() || endPointToSessionConnection.find(tableModelDeviceIdToEndpoint[deviceId]) == @@ -1910,15 +2024,15 @@ Session::getSessionConnection(std::shared_ptr deviceId) { } string Session::getTimeZone() { - auto ret = defaultSessionConnection_->getTimeZone(); + auto ret = impl_->defaultSessionConnection_->getTimeZone(); return ret.timeZone; } void Session::setTimeZone(const string& zoneId) { TSSetTimeZoneReq req; - req.__set_sessionId(defaultSessionConnection_->sessionId); + req.__set_sessionId(impl_->defaultSessionConnection_->sessionId); req.__set_timeZone(zoneId); - defaultSessionConnection_->setTimeZone(req); + impl_->defaultSessionConnection_->setTimeZone(req); } unique_ptr Session::executeQueryStatement(const string& sql) { @@ -1929,7 +2043,7 @@ unique_ptr Session::executeQueryStatement(const string& sql, int return executeQueryStatementMayRedirect(sql, timeoutInMs); } -void Session::handleQueryRedirection(TEndPoint endPoint) { +void Session::Impl::handleQueryRedirection(TEndPoint endPoint) { if (!enableRedirection_) return; shared_ptr newConnection; @@ -1950,7 +2064,7 @@ void Session::handleQueryRedirection(TEndPoint endPoint) { defaultSessionConnection_ = newConnection; } -void Session::handleRedirection(const std::string& deviceId, TEndPoint endPoint) { +void Session::Impl::handleRedirection(const std::string& deviceId, TEndPoint endPoint) { if (!enableRedirection_) return; if (endPoint.ip == "127.0.0.1") @@ -1974,8 +2088,8 @@ void Session::handleRedirection(const std::string& deviceId, TEndPoint endPoint) } } -void Session::handleRedirection(const std::shared_ptr& deviceId, - TEndPoint endPoint) { +void Session::Impl::handleRedirection(const std::shared_ptr& deviceId, + TEndPoint endPoint) { if (!enableRedirection_) return; if (endPoint.ip == "127.0.0.1") @@ -2001,7 +2115,7 @@ void Session::handleRedirection(const std::shared_ptr& devic std::unique_ptr Session::executeQueryStatementMayRedirect(const std::string& sql, int64_t timeoutInMs) { - auto sessionConnection = getQuerySessionConnection(); + auto sessionConnection = impl_->getQuerySessionConnection(); if (!sessionConnection) { log_warn("Session connection not found"); return nullptr; @@ -2010,9 +2124,9 @@ std::unique_ptr Session::executeQueryStatementMayRedirect(const return sessionConnection->executeQueryStatement(sql, timeoutInMs); } catch (RedirectException& e) { log_warn("Session connection redirect exception: " + e.what()); - handleQueryRedirection(e.endPoint); + impl_->handleQueryRedirection(endpointToThrift(e.endPoint)); try { - return defaultSessionConnection_->executeQueryStatement(sql, timeoutInMs); + return impl_->defaultSessionConnection_->executeQueryStatement(sql, timeoutInMs); } catch (exception& e) { log_error("Exception while executing redirected query statement: %s", e.what()); throw ExecutionException(e.what()); @@ -2025,7 +2139,7 @@ std::unique_ptr Session::executeQueryStatementMayRedirect(const void Session::executeNonQueryStatement(const string& sql) { try { - defaultSessionConnection_->executeNonQueryStatement(sql); + impl_->defaultSessionConnection_->executeNonQueryStatement(sql); } catch (const exception& e) { throw IoTDBException(e.what()); } @@ -2033,7 +2147,7 @@ void Session::executeNonQueryStatement(const string& sql) { unique_ptr Session::executeRawDataQuery(const vector& paths, int64_t startTime, int64_t endTime) { - return defaultSessionConnection_->executeRawDataQuery(paths, startTime, endTime); + return impl_->defaultSessionConnection_->executeRawDataQuery(paths, startTime, endTime); } unique_ptr Session::executeLastDataQuery(const vector& paths) { @@ -2042,28 +2156,28 @@ unique_ptr Session::executeLastDataQuery(const vector& p unique_ptr Session::executeLastDataQuery(const vector& paths, int64_t lastTime) { - return defaultSessionConnection_->executeLastDataQuery(paths, lastTime); + return impl_->defaultSessionConnection_->executeLastDataQuery(paths, lastTime); } void Session::createSchemaTemplate(const Template& templ) { TSCreateSchemaTemplateReq req; req.__set_name(templ.getName()); req.__set_serializedTemplate(templ.serialize()); - defaultSessionConnection_->createSchemaTemplate(req); + impl_->defaultSessionConnection_->createSchemaTemplate(req); } void Session::setSchemaTemplate(const string& template_name, const string& prefix_path) { TSSetSchemaTemplateReq req; req.__set_templateName(template_name); req.__set_prefixPath(prefix_path); - defaultSessionConnection_->setSchemaTemplate(req); + impl_->defaultSessionConnection_->setSchemaTemplate(req); } void Session::unsetSchemaTemplate(const string& prefix_path, const string& template_name) { TSUnsetSchemaTemplateReq req; req.__set_templateName(template_name); req.__set_prefixPath(prefix_path); - defaultSessionConnection_->unsetSchemaTemplate(req); + impl_->defaultSessionConnection_->unsetSchemaTemplate(req); } void Session::addAlignedMeasurementsInTemplate( @@ -2097,7 +2211,7 @@ void Session::addAlignedMeasurementsInTemplate( } req.__set_compressors(compressorsOrdinal); - defaultSessionConnection_->appendSchemaTemplate(req); + impl_->defaultSessionConnection_->appendSchemaTemplate(req); } void Session::addAlignedMeasurementsInTemplate(const string& template_name, @@ -2143,7 +2257,7 @@ void Session::addUnalignedMeasurementsInTemplate( } req.__set_compressors(compressorsOrdinal); - defaultSessionConnection_->appendSchemaTemplate(req); + impl_->defaultSessionConnection_->appendSchemaTemplate(req); } void Session::addUnalignedMeasurementsInTemplate(const string& template_name, @@ -2163,14 +2277,14 @@ void Session::deleteNodeInTemplate(const string& template_name, const string& pa TSPruneSchemaTemplateReq req; req.__set_name(template_name); req.__set_path(path); - defaultSessionConnection_->pruneSchemaTemplate(req); + impl_->defaultSessionConnection_->pruneSchemaTemplate(req); } int Session::countMeasurementsInTemplate(const string& template_name) { TSQueryTemplateReq req; req.__set_name(template_name); req.__set_queryType(TemplateQueryType::COUNT_MEASUREMENTS); - TSQueryTemplateResp resp = defaultSessionConnection_->querySchemaTemplate(req); + TSQueryTemplateResp resp = impl_->defaultSessionConnection_->querySchemaTemplate(req); return resp.count; } @@ -2179,7 +2293,7 @@ bool Session::isMeasurementInTemplate(const string& template_name, const string& req.__set_name(template_name); req.__set_measurement(path); req.__set_queryType(TemplateQueryType::IS_MEASUREMENT); - TSQueryTemplateResp resp = defaultSessionConnection_->querySchemaTemplate(req); + TSQueryTemplateResp resp = impl_->defaultSessionConnection_->querySchemaTemplate(req); return resp.result; } @@ -2188,7 +2302,7 @@ bool Session::isPathExistInTemplate(const string& template_name, const string& p req.__set_name(template_name); req.__set_measurement(path); req.__set_queryType(TemplateQueryType::PATH_EXIST); - TSQueryTemplateResp resp = defaultSessionConnection_->querySchemaTemplate(req); + TSQueryTemplateResp resp = impl_->defaultSessionConnection_->querySchemaTemplate(req); return resp.result; } @@ -2197,7 +2311,7 @@ std::vector Session::showMeasurementsInTemplate(const string& templ req.__set_name(template_name); req.__set_measurement(""); req.__set_queryType(TemplateQueryType::SHOW_MEASUREMENTS); - TSQueryTemplateResp resp = defaultSessionConnection_->querySchemaTemplate(req); + TSQueryTemplateResp resp = impl_->defaultSessionConnection_->querySchemaTemplate(req); return resp.measurements; } @@ -2207,7 +2321,7 @@ std::vector Session::showMeasurementsInTemplate(const string& templ req.__set_name(template_name); req.__set_measurement(pattern); req.__set_queryType(TemplateQueryType::SHOW_MEASUREMENTS); - TSQueryTemplateResp resp = defaultSessionConnection_->querySchemaTemplate(req); + TSQueryTemplateResp resp = impl_->defaultSessionConnection_->querySchemaTemplate(req); return resp.measurements; } diff --git a/iotdb-client/client-cpp/src/main/SessionC.cpp b/iotdb-client/client-cpp/src/session/SessionC.cpp similarity index 100% rename from iotdb-client/client-cpp/src/main/SessionC.cpp rename to iotdb-client/client-cpp/src/session/SessionC.cpp diff --git a/iotdb-client/client-cpp/src/session/SessionDataSet.cpp b/iotdb-client/client-cpp/src/session/SessionDataSet.cpp new file mode 100644 index 0000000000000..50ce431b1528a --- /dev/null +++ b/iotdb-client/client-cpp/src/session/SessionDataSet.cpp @@ -0,0 +1,320 @@ +/** +* 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. + */ + +#include "SessionDataSet.h" + +#include + +#include "IoTDBRpcDataSet.h" +#include "SessionDataSetFactory.h" + +using namespace std; + +struct SessionDataSet::Impl { + std::shared_ptr iotdbRpcDataSet_; +}; + +std::unique_ptr +createSessionDataSet(const std::string& sql, const std::vector& columnNameList, + const std::vector& columnTypeList, + const std::map& columnNameIndex, int64_t queryId, + int64_t statementId, std::shared_ptr client, + int64_t sessionId, const std::vector& queryResult, + bool ignoreTimestamp, int64_t timeout, bool moreData, int32_t fetchSize, + const std::string& zoneId, int32_t timeFactor, + std::vector& columnIndex2TsBlockColumnIndexList) { + auto dataSet = std::unique_ptr(new SessionDataSet()); + dataSet->impl_ = std::unique_ptr(new SessionDataSet::Impl()); + dataSet->impl_->iotdbRpcDataSet_ = std::make_shared( + sql, columnNameList, columnTypeList, columnNameIndex, ignoreTimestamp, moreData, queryId, + statementId, client, sessionId, queryResult, fetchSize, timeout, zoneId, + IoTDBRpcDataSet::DEFAULT_TIME_FORMAT, timeFactor, columnIndex2TsBlockColumnIndexList); + return dataSet; +} + +RowRecord::RowRecord(int64_t timestamp) { + this->timestamp = timestamp; +} + +RowRecord::RowRecord(int64_t timestamp, const std::vector& fields) + : timestamp(timestamp), fields(fields) {} + +RowRecord::RowRecord(const std::vector& fields) : timestamp(-1), fields(fields) {} + +RowRecord::RowRecord() { + this->timestamp = -1; +} + +void RowRecord::addField(const Field& f) { + this->fields.push_back(f); +} + +std::string RowRecord::toString() { + std::string ret; + if (this->timestamp != -1) { + ret.append(std::to_string(timestamp)); + ret.append("\t"); + } + for (size_t i = 0; i < fields.size(); i++) { + if (i != 0) { + ret.append("\t"); + } + const Field& f = fields[i]; + switch (f.dataType) { + case TSDataType::BOOLEAN: + if (f.isNull()) { + ret.append("null"); + } else { + ret.append(f.boolV.value() ? "true" : "false"); + } + break; + case TSDataType::INT32: + if (f.isNull()) { + ret.append("null"); + } else { + ret.append(std::to_string(f.intV.value())); + } + break; + case TSDataType::DATE: + if (f.isNull()) { + ret.append("null"); + } else { + ret.append(f.dateV.value().toIsoExtendedString()); + } + break; + case TSDataType::TIMESTAMP: + case TSDataType::INT64: + if (f.isNull()) { + ret.append("null"); + } else { + ret.append(std::to_string(f.longV.value())); + } + break; + case TSDataType::FLOAT: + if (f.isNull()) { + ret.append("null"); + } else { + ret.append(std::to_string(f.floatV.value())); + } + break; + case TSDataType::DOUBLE: + if (f.isNull()) { + ret.append("null"); + } else { + ret.append(std::to_string(f.doubleV.value())); + } + break; + case TSDataType::BLOB: + case TSDataType::STRING: + case TSDataType::TEXT: + if (f.isNull()) { + ret.append("null"); + } else { + ret.append(f.stringV.value()); + } + break; + case TSDataType::OBJECT: + if (!f.stringV.is_initialized()) { + ret.append("null"); + } else { + ret.append(f.stringV.value()); + } + break; + default: + break; + } + } + ret.append("\n"); + return ret; +} + +SessionDataSet::~SessionDataSet() = default; + +bool SessionDataSet::hasNext() { + if (impl_->iotdbRpcDataSet_->hasCachedRecord()) { + return true; + } + return impl_->iotdbRpcDataSet_->next(); +} + +shared_ptr SessionDataSet::next() { + if (!impl_->iotdbRpcDataSet_->hasCachedRecord() && !hasNext()) { + return nullptr; + } + impl_->iotdbRpcDataSet_->setHasCachedRecord(false); + return constructRowRecordFromValueArray(); +} + +int SessionDataSet::getFetchSize() { + return impl_->iotdbRpcDataSet_->getFetchSize(); +} + +void SessionDataSet::setFetchSize(int fetchSize) { + impl_->iotdbRpcDataSet_->setFetchSize(fetchSize); +} + +const std::vector& SessionDataSet::getColumnNames() const { + return impl_->iotdbRpcDataSet_->getColumnNameList(); +} + +const std::vector& SessionDataSet::getColumnTypeList() const { + return impl_->iotdbRpcDataSet_->getColumnTypeList(); +} + +void SessionDataSet::closeOperationHandle(bool forceClose) { + impl_->iotdbRpcDataSet_->close(forceClose); +} + +SessionDataSet::DataIterator::DataIterator(std::shared_ptr impl) : impl_(std::move(impl)) {} + +bool SessionDataSet::DataIterator::next() { + return impl_->iotdbRpcDataSet_->next(); +} + +bool SessionDataSet::DataIterator::isNull(const std::string& columnName) { + return impl_->iotdbRpcDataSet_->isNullByColumnName(columnName); +} + +bool SessionDataSet::DataIterator::isNullByIndex(int32_t columnIndex) { + return impl_->iotdbRpcDataSet_->isNullByIndex(columnIndex); +} + +Optional SessionDataSet::DataIterator::getBooleanByIndex(int32_t columnIndex) { + return impl_->iotdbRpcDataSet_->getBooleanByIndex(columnIndex); +} + +Optional SessionDataSet::DataIterator::getBoolean(const std::string& columnName) { + return impl_->iotdbRpcDataSet_->getBoolean(columnName); +} + +Optional SessionDataSet::DataIterator::getDoubleByIndex(int32_t columnIndex) { + return impl_->iotdbRpcDataSet_->getDoubleByIndex(columnIndex); +} + +Optional SessionDataSet::DataIterator::getDouble(const std::string& columnName) { + return impl_->iotdbRpcDataSet_->getDouble(columnName); +} + +Optional SessionDataSet::DataIterator::getFloatByIndex(int32_t columnIndex) { + return impl_->iotdbRpcDataSet_->getFloatByIndex(columnIndex); +} + +Optional SessionDataSet::DataIterator::getFloat(const std::string& columnName) { + return impl_->iotdbRpcDataSet_->getFloat(columnName); +} + +Optional SessionDataSet::DataIterator::getIntByIndex(int32_t columnIndex) { + return impl_->iotdbRpcDataSet_->getIntByIndex(columnIndex); +} + +Optional SessionDataSet::DataIterator::getInt(const std::string& columnName) { + return impl_->iotdbRpcDataSet_->getInt(columnName); +} + +Optional SessionDataSet::DataIterator::getLongByIndex(int32_t columnIndex) { + return impl_->iotdbRpcDataSet_->getLongByIndex(columnIndex); +} + +Optional SessionDataSet::DataIterator::getLong(const std::string& columnName) { + return impl_->iotdbRpcDataSet_->getLong(columnName); +} + +Optional SessionDataSet::DataIterator::getStringByIndex(int32_t columnIndex) { + return impl_->iotdbRpcDataSet_->getStringByIndex(columnIndex); +} + +Optional SessionDataSet::DataIterator::getString(const std::string& columnName) { + return impl_->iotdbRpcDataSet_->getString(columnName); +} + +Optional SessionDataSet::DataIterator::getTimestampByIndex(int32_t columnIndex) { + return impl_->iotdbRpcDataSet_->getTimestampByIndex(columnIndex); +} + +Optional SessionDataSet::DataIterator::getTimestamp(const std::string& columnName) { + return impl_->iotdbRpcDataSet_->getTimestamp(columnName); +} + +Optional SessionDataSet::DataIterator::getDateByIndex(int32_t columnIndex) { + return impl_->iotdbRpcDataSet_->getDateByIndex(columnIndex); +} + +Optional SessionDataSet::DataIterator::getDate(const std::string& columnName) { + return impl_->iotdbRpcDataSet_->getDate(columnName); +} + +int32_t SessionDataSet::DataIterator::findColumn(const std::string& columnName) { + return impl_->iotdbRpcDataSet_->findColumn(columnName); +} + +const std::vector& SessionDataSet::DataIterator::getColumnNames() const { + return impl_->iotdbRpcDataSet_->getColumnNameList(); +} + +const std::vector& SessionDataSet::DataIterator::getColumnTypeList() const { + return impl_->iotdbRpcDataSet_->getColumnTypeList(); +} + +SessionDataSet::DataIterator SessionDataSet::getIterator() { + return DataIterator(std::shared_ptr(impl_.get(), [](Impl*) {})); +} + +shared_ptr SessionDataSet::constructRowRecordFromValueArray() { + std::vector outFields; + for (int i = impl_->iotdbRpcDataSet_->getValueColumnStartIndex(); + i < impl_->iotdbRpcDataSet_->getColumnSize(); i++) { + Field field; + std::string columnName = impl_->iotdbRpcDataSet_->getColumnNameList().at(i); + if (!impl_->iotdbRpcDataSet_->isNullByColumnName(columnName)) { + TSDataType::TSDataType dataType = impl_->iotdbRpcDataSet_->getDataType(columnName); + field.dataType = dataType; + switch (dataType) { + case TSDataType::BOOLEAN: + field.boolV = impl_->iotdbRpcDataSet_->getBoolean(columnName); + break; + case TSDataType::INT32: + field.intV = impl_->iotdbRpcDataSet_->getInt(columnName); + break; + case TSDataType::DATE: + field.dateV = impl_->iotdbRpcDataSet_->getDate(columnName); + break; + case TSDataType::INT64: + case TSDataType::TIMESTAMP: + field.longV = impl_->iotdbRpcDataSet_->getLong(columnName); + break; + case TSDataType::FLOAT: + field.floatV = impl_->iotdbRpcDataSet_->getFloat(columnName); + break; + case TSDataType::DOUBLE: + field.doubleV = impl_->iotdbRpcDataSet_->getDouble(columnName); + break; + case TSDataType::TEXT: + case TSDataType::BLOB: + case TSDataType::STRING: + case TSDataType::OBJECT: + field.stringV = impl_->iotdbRpcDataSet_->getBinary(columnName)->getStringValue(); + break; + default: + throw UnSupportedDataTypeException("Data type is not supported."); + } + } + outFields.emplace_back(field); + } + return std::make_shared(impl_->iotdbRpcDataSet_->getCurrentRowTime(), outFields); +} diff --git a/iotdb-client/client-cpp/src/main/TableSession.cpp b/iotdb-client/client-cpp/src/session/TableSession.cpp similarity index 100% rename from iotdb-client/client-cpp/src/main/TableSession.cpp rename to iotdb-client/client-cpp/src/session/TableSession.cpp diff --git a/iotdb-client/client-cpp/src/main/TsBlock.cpp b/iotdb-client/client-cpp/src/session/TsBlock.cpp similarity index 100% rename from iotdb-client/client-cpp/src/main/TsBlock.cpp rename to iotdb-client/client-cpp/src/session/TsBlock.cpp diff --git a/iotdb-client/client-cpp/src/test/CMakeLists.txt b/iotdb-client/client-cpp/src/test/CMakeLists.txt index 38a05010ff84d..d26512cba0ae0 100644 --- a/iotdb-client/client-cpp/src/test/CMakeLists.txt +++ b/iotdb-client/client-cpp/src/test/CMakeLists.txt @@ -37,7 +37,13 @@ add_executable(session_c_relational_tests main_c_Relational.cpp cpp/sessionCRela foreach(_t IN LISTS _test_targets) target_include_directories(${_t} PRIVATE - "${CMAKE_CURRENT_SOURCE_DIR}/catch2") + "${CMAKE_CURRENT_SOURCE_DIR}/catch2" + "${CMAKE_CURRENT_SOURCE_DIR}/../rpc" + "${THRIFT_GEN_CPP_DIR}" + "${THRIFT_INCLUDE_DIR}") + if(BOOST_INCLUDE_DIR) + target_include_directories(${_t} PRIVATE "${BOOST_INCLUDE_DIR}") + endif() target_link_libraries(${_t} PRIVATE iotdb_session) if(WITH_SSL) target_link_libraries(${_t} PRIVATE OpenSSL::SSL OpenSSL::Crypto) @@ -66,6 +72,11 @@ if(MSVC) add_test(NAME sessionRelationalIT CONFIGURATIONS Release COMMAND session_relational_tests) add_test(NAME sessionCIT CONFIGURATIONS Release COMMAND session_c_tests) add_test(NAME sessionCRelationalIT CONFIGURATIONS Release COMMAND session_c_relational_tests) + foreach(_t IN LISTS _test_targets) + add_custom_command(TARGET ${_t} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + $ $) + endforeach() else() add_test(NAME sessionIT COMMAND session_tests) add_test(NAME sessionRelationalIT COMMAND session_relational_tests) diff --git a/iotdb-client/client-cpp/src/test/cpp/sessionIT.cpp b/iotdb-client/client-cpp/src/test/cpp/sessionIT.cpp index 1f9abb153efd9..8db819eee61c6 100644 --- a/iotdb-client/client-cpp/src/test/cpp/sessionIT.cpp +++ b/iotdb-client/client-cpp/src/test/cpp/sessionIT.cpp @@ -18,9 +18,12 @@ */ #include "catch.hpp" +#include "Date.h" +#include "RpcCommon.h" #include "Session.h" #include "SessionBuilder.h" #include "TsBlock.h" +#include "common_types.h" using namespace std; @@ -246,7 +249,7 @@ TEST_CASE("Test insertRecord with new datatypes ", "[testTypedInsertRecordNewDat string deviceId = "root.test.d1"; vector measurements = {"s1", "s2", "s3", "s4"}; int64_t value1 = 20250507; - boost::gregorian::date value2 = boost::gregorian::date(2025, 5, 7); + IoTdbDate value2 = IoTdbDate(2025, 5, 7); string value3 = "20250507"; string value4 = "20250507"; @@ -477,7 +480,7 @@ TEST_CASE("Test insertTablet multi datatype", "[testInsertTabletMultiDatatype]") } int64_t s1Value = 20250507; - boost::gregorian::date s2Value(2025, 5, 7); + IoTdbDate s2Value(2025, 5, 7); std::string s3Value("20250507"); std::string s4Value("20250507"); diff --git a/iotdb-client/client-cpp/src/test/cpp/sessionRelationalIT.cpp b/iotdb-client/client-cpp/src/test/cpp/sessionRelationalIT.cpp index 308b07b18e522..aa241a8654f50 100644 --- a/iotdb-client/client-cpp/src/test/cpp/sessionRelationalIT.cpp +++ b/iotdb-client/client-cpp/src/test/cpp/sessionRelationalIT.cpp @@ -20,6 +20,7 @@ #include "TableSession.h" #include "TableSessionBuilder.h" #include "catch.hpp" +#include "Date.h" #include using namespace std; @@ -206,7 +207,7 @@ TEST_CASE("Test RelationalTabletTsblockRead", "[testRelationalTabletTsblockRead] tablet.addValue(4, rowIndex, static_cast(row * 1.1f)); tablet.addValue(5, rowIndex, "text_" + to_string(row)); tablet.addValue(6, rowIndex, static_cast(timestamp)); - tablet.addValue(7, rowIndex, boost::gregorian::date(2025, 5, 15)); + tablet.addValue(7, rowIndex, IoTdbDate(2025, 5, 15)); tablet.addValue(8, rowIndex, "blob_" + to_string(row)); tablet.addValue(9, rowIndex, "string_" + to_string(row)); @@ -254,7 +255,7 @@ TEST_CASE("Test RelationalTabletTsblockRead", "[testRelationalTabletTsblockRead] REQUIRE(fabs(dataIter.getDoubleByIndex(6).value() - rowNum * 1.1f) < 0.1); REQUIRE(dataIter.getStringByIndex(7).value() == "text_" + to_string(rowNum)); REQUIRE(dataIter.getTimestampByIndex(8).value() == static_cast(timestamp)); - REQUIRE(dataIter.getDateByIndex(9).value() == boost::gregorian::date(2025, 5, 15)); + REQUIRE(dataIter.getDateByIndex(9).value() == IoTdbDate(2025, 5, 15)); REQUIRE(dataIter.getStringByIndex(10).value() == "blob_" + to_string(rowNum)); REQUIRE(dataIter.getStringByIndex(11).value() == "string_" + to_string(rowNum)); } @@ -286,7 +287,7 @@ TEST_CASE("Test RelationalTabletTsblockRead", "[testRelationalTabletTsblockRead] REQUIRE(fabs(record->fields[5].doubleV.value() - rowNum * 1.1f) < 0.1); REQUIRE(record->fields[6].stringV.value() == "text_" + to_string(rowNum)); REQUIRE(record->fields[7].longV.value() == static_cast(timestamp)); - REQUIRE(record->fields[8].dateV.value() == boost::gregorian::date(2025, 5, 15)); + REQUIRE(record->fields[8].dateV.value() == IoTdbDate(2025, 5, 15)); REQUIRE(record->fields[9].stringV.value() == "blob_" + to_string(rowNum)); REQUIRE(record->fields[10].stringV.value() == "string_" + to_string(rowNum)); } From 27fc23032fda84598b82004f2a39246adebb518d Mon Sep 17 00:00:00 2001 From: 761417898 <761417898@qq.com> Date: Tue, 26 May 2026 09:13:28 +0800 Subject: [PATCH 06/28] fix(client-cpp): include ctime for std::tm in Common.h Fixes Linux CI build where convertToTimestamp/int32ToDate declarations require std::tm from (C++11). --- iotdb-client/client-cpp/src/include/Common.h | 1 + 1 file changed, 1 insertion(+) diff --git a/iotdb-client/client-cpp/src/include/Common.h b/iotdb-client/client-cpp/src/include/Common.h index 958b9a716b51e..b2b904689b404 100644 --- a/iotdb-client/client-cpp/src/include/Common.h +++ b/iotdb-client/client-cpp/src/include/Common.h @@ -20,6 +20,7 @@ #define IOTDB_COMMON_H #include +#include #include #include #include From 25e5a489978928d8565df8d90a8912e0478aff69 Mon Sep 17 00:00:00 2001 From: 761417898 <761417898@qq.com> Date: Tue, 26 May 2026 09:30:46 +0800 Subject: [PATCH 07/28] fix(client-cpp): CMake 4 Thrift policy and Session.cpp cstring Pass CMAKE_POLICY_VERSION_MINIMUM=3.5 when configuring Thrift 0.21 on CMake 4.x (VS2026 CI). Include in Session.cpp for memcpy/strlen/strstr on strict Linux builds. --- iotdb-client/client-cpp/cmake/FetchThrift.cmake | 2 ++ iotdb-client/client-cpp/src/session/Session.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/iotdb-client/client-cpp/cmake/FetchThrift.cmake b/iotdb-client/client-cpp/cmake/FetchThrift.cmake index 98b205b3a93bc..390c031ff2203 100644 --- a/iotdb-client/client-cpp/cmake/FetchThrift.cmake +++ b/iotdb-client/client-cpp/cmake/FetchThrift.cmake @@ -95,6 +95,8 @@ endif() # 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" diff --git a/iotdb-client/client-cpp/src/session/Session.cpp b/iotdb-client/client-cpp/src/session/Session.cpp index 0964a5d859810..ca38ddd59c025 100644 --- a/iotdb-client/client-cpp/src/session/Session.cpp +++ b/iotdb-client/client-cpp/src/session/Session.cpp @@ -19,6 +19,7 @@ #include "Session.h" #include +#include #include #include #include From 5ce0b025bc4725652528da7499145ace56356b1a Mon Sep 17 00:00:00 2001 From: 761417898 <761417898@qq.com> Date: Tue, 26 May 2026 09:53:59 +0800 Subject: [PATCH 08/28] fix(client-cpp): Linux Thrift link and default Boost 1.84 Drop --whole-archive on Linux to avoid libgcc morestack duplicate symbols; build Thrift with -fno-split-stack. Bump default Boost to 1.84.0 for modern Clang on macOS CI. --- iotdb-client/client-cpp/CMakeLists.txt | 7 ++++--- iotdb-client/client-cpp/README.md | 12 ++++++------ iotdb-client/client-cpp/cmake/FetchThrift.cmake | 4 ++-- iotdb-client/client-cpp/third-party/README.md | 6 +++--- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/iotdb-client/client-cpp/CMakeLists.txt b/iotdb-client/client-cpp/CMakeLists.txt index 7645d55bc3e75..4b3ca53de5f35 100644 --- a/iotdb-client/client-cpp/CMakeLists.txt +++ b/iotdb-client/client-cpp/CMakeLists.txt @@ -47,7 +47,7 @@ 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/)") -set(BOOST_VERSION "1.60.0" +set(BOOST_VERSION "1.84.0" 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") @@ -107,8 +107,9 @@ target_include_directories(iotdb_session if(APPLE) target_link_libraries(iotdb_session PRIVATE "-Wl,-force_load,${THRIFT_STATIC_LIB_PATH}") elseif(UNIX AND NOT MSVC) - target_link_libraries(iotdb_session PRIVATE - -Wl,--whole-archive ${THRIFT_STATIC_LIB_PATH} -Wl,--no-as-needed) + # Link only required Thrift objects into the shared library. --whole-archive can + # pull duplicate libgcc morestack symbols on modern GCC (split-stack). + target_link_libraries(iotdb_session PRIVATE ${THRIFT_STATIC_LIB_PATH}) else() target_link_libraries(iotdb_session PRIVATE iotdb_thrift_static) endif() diff --git a/iotdb-client/client-cpp/README.md b/iotdb-client/client-cpp/README.md index c93b50a498ef4..8fb68a38e6c91 100644 --- a/iotdb-client/client-cpp/README.md +++ b/iotdb-client/client-cpp/README.md @@ -78,7 +78,7 @@ passed directly to `cmake`. | `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` | Boost version that CMake will look for / download. | +| `BOOST_VERSION` | `1.84.0` | 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`. | @@ -104,13 +104,13 @@ mvn -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests "-Dboost.include.dir | 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_60_0.tar.gz` (Apple already 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`) | + | `linux/` | `thrift-0.21.0.tar.gz`, `boost_1_84_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` (Apple already ships m4/flex/bison; `openssl-3.5.0.tar.gz` optional) | + | `windows/` | `thrift-0.21.0.tar.gz`, `boost_1_84_0.tar.gz` or `boost_1_84_0.zip` (headers only; no `b2` build required) | Reference URLs (the configure step uses the same): - Apache Thrift 0.21.0: - - Boost 1.60.0: + - Boost 1.84.0: - GNU m4 1.4.19: - GNU flex 2.6.4: - GNU bison 3.8: @@ -160,7 +160,7 @@ Prerequisites: 1. **Boost.** Download and extract - (any 1.60+ release will work). `iotdb_session` only needs Boost + (1.74+ recommended for modern Clang; 1.84.0 is the default download). `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). diff --git a/iotdb-client/client-cpp/cmake/FetchThrift.cmake b/iotdb-client/client-cpp/cmake/FetchThrift.cmake index 390c031ff2203..07727fae040d4 100644 --- a/iotdb-client/client-cpp/cmake/FetchThrift.cmake +++ b/iotdb-client/client-cpp/cmake/FetchThrift.cmake @@ -123,8 +123,8 @@ if(MSVC) "-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDLL") else() list(APPEND _thrift_cmake_args - "-DCMAKE_C_FLAGS=-fPIC" - "-DCMAKE_CXX_FLAGS=-fPIC") + "-DCMAKE_C_FLAGS=-fPIC -fno-split-stack" + "-DCMAKE_CXX_FLAGS=-fPIC -fno-split-stack") endif() if(WITH_SSL) diff --git a/iotdb-client/client-cpp/third-party/README.md b/iotdb-client/client-cpp/third-party/README.md index c92733d50c6a8..d02ce73b0a2d0 100644 --- a/iotdb-client/client-cpp/third-party/README.md +++ b/iotdb-client/client-cpp/third-party/README.md @@ -66,8 +66,8 @@ Alternatively copy files manually from the URLs listed in | Platform | Typical 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` (+ `openssl-3.5.0.tar.gz` when `WITH_SSL=ON`) | -| `mac/` | `thrift-0.21.0.tar.gz`, `boost_1_60_0.tar.gz` (Xcode CLT usually provides m4/flex/bison) | -| `windows/` | `thrift-0.21.0.tar.gz`, `boost_1_60_0.tar.gz`, `win_flex_bison-2.5.25.zip` (or any `win_flex_bison*.zip`; skip if flex/bison already on `PATH`) | +| `linux/` | `thrift-0.21.0.tar.gz`, `boost_1_84_0.tar.gz`, `m4-1.4.19.tar.gz`, `flex-2.6.4.tar.gz`, `bison-3.8.tar.gz` (+ `openssl-3.5.0.tar.gz` when `WITH_SSL=ON`) | +| `mac/` | `thrift-0.21.0.tar.gz`, `boost_1_84_0.tar.gz` (Xcode CLT usually provides m4/flex/bison) | +| `windows/` | `thrift-0.21.0.tar.gz`, `boost_1_84_0.tar.gz` or `boost_1_84_0.zip`, `win_flex_bison-2.5.25.zip` (or any `win_flex_bison*.zip`; skip if flex/bison already on `PATH`) | Download URLs: see the *Offline build* table in [`README.md`](../README.md). From 3864b9446a9cfc060dc2f57ea73def6cef47837e Mon Sep 17 00:00:00 2001 From: 761417898 <761417898@qq.com> Date: Tue, 26 May 2026 09:55:42 +0800 Subject: [PATCH 09/28] fix(client-cpp): Linux Thrift link and macOS Boost 1.84 Linux: keep --whole-archive for Thrift in libiotdb_session.so but add --allow-multiple-definition to avoid libgcc morestack duplicate symbols. macOS: default BOOST_VERSION to 1.84.0 for modern Clang enum checks (other platforms stay on 1.60.0). --- iotdb-client/client-cpp/CMakeLists.txt | 17 +++++++++++++---- iotdb-client/client-cpp/README.md | 12 ++++++------ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/iotdb-client/client-cpp/CMakeLists.txt b/iotdb-client/client-cpp/CMakeLists.txt index 4b3ca53de5f35..46983934b4661 100644 --- a/iotdb-client/client-cpp/CMakeLists.txt +++ b/iotdb-client/client-cpp/CMakeLists.txt @@ -47,7 +47,12 @@ 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/)") -set(BOOST_VERSION "1.84.0" +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") @@ -107,9 +112,13 @@ target_include_directories(iotdb_session if(APPLE) target_link_libraries(iotdb_session PRIVATE "-Wl,-force_load,${THRIFT_STATIC_LIB_PATH}") elseif(UNIX AND NOT MSVC) - # Link only required Thrift objects into the shared library. --whole-archive can - # pull duplicate libgcc morestack symbols on modern GCC (split-stack). - target_link_libraries(iotdb_session PRIVATE ${THRIFT_STATIC_LIB_PATH}) + # 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() diff --git a/iotdb-client/client-cpp/README.md b/iotdb-client/client-cpp/README.md index 8fb68a38e6c91..4ad9329fff5b4 100644 --- a/iotdb-client/client-cpp/README.md +++ b/iotdb-client/client-cpp/README.md @@ -78,7 +78,7 @@ passed directly to `cmake`. | `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.84.0` | Boost version that CMake will look for / download. | +| `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`. | @@ -104,13 +104,13 @@ mvn -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests "-Dboost.include.dir | Platform | Required files | |------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------| - | `linux/` | `thrift-0.21.0.tar.gz`, `boost_1_84_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` (Apple already ships m4/flex/bison; `openssl-3.5.0.tar.gz` optional) | - | `windows/` | `thrift-0.21.0.tar.gz`, `boost_1_84_0.tar.gz` or `boost_1_84_0.zip` (headers only; no `b2` build required) | + | `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.84.0: + - Boost 1.60.0: - GNU m4 1.4.19: - GNU flex 2.6.4: - GNU bison 3.8: @@ -160,7 +160,7 @@ Prerequisites: 1. **Boost.** Download and extract - (1.74+ recommended for modern Clang; 1.84.0 is the default download). `iotdb_session` only needs Boost + (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). From 75832c9394b01a3638aaa54ffa7e629d8525aefd Mon Sep 17 00:00:00 2001 From: 761417898 <761417898@qq.com> Date: Tue, 26 May 2026 10:46:14 +0800 Subject: [PATCH 10/28] ci(client-cpp): multi-toolchain package matrix for release zips Add per-classifier SDK packages (glibc 2.17 on CentOS 7, Windows VS2015-2026), workflow_dispatch variant filter, and documentation for choosing the right zip. --- .github/scripts/package-client-cpp-centos7.sh | 83 +++++++ .github/workflows/client-cpp-package.yml | 225 +++++++++++++----- example/client-cpp-example/README.md | 20 ++ example/client-cpp-example/README_zh.md | 19 ++ iotdb-client/client-cpp/README.md | 66 ++++- .../client-cpp/cmake/FetchThrift.cmake | 4 +- iotdb-client/client-cpp/pom.xml | 2 + .../client-cpp/src/assembly/client-cpp.xml | 2 +- iotdb-client/client-cpp/third-party/README.md | 6 +- 9 files changed, 357 insertions(+), 70 deletions(-) create mode 100644 .github/scripts/package-client-cpp-centos7.sh diff --git a/.github/scripts/package-client-cpp-centos7.sh b/.github/scripts/package-client-cpp-centos7.sh new file mode 100644 index 0000000000000..5572274cb1b91 --- /dev/null +++ b/.github/scripts/package-client-cpp-centos7.sh @@ -0,0 +1,83 @@ +#!/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 inside CentOS 7 + devtoolset-8 for glibc 2.17-compatible .so. +set -euxo pipefail + +# CentOS 7 EOL: use vault mirrors when default mirrors are unavailable. +if grep -q mirrorlist /etc/yum.repos.d/CentOS-*.repo 2>/dev/null; then + sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*.repo + sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*.repo +fi + +yum install -y centos-release-scl epel-release +yum install -y devtoolset-8-gcc devtoolset-8-gcc-c++ devtoolset-8-binutils \ + make wget tar which git patch unzip + +CMAKE_VERSION=3.28.4 +CMAKE_DIR=/opt/cmake-${CMAKE_VERSION} +if [[ ! -x "${CMAKE_DIR}/bin/cmake" ]]; then + wget -q "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-linux-x86_64.tar.gz" \ + -O /tmp/cmake.tar.gz + rm -rf "${CMAKE_DIR}" + mkdir -p /opt + tar xf /tmp/cmake.tar.gz -C /opt + mv "/opt/cmake-${CMAKE_VERSION}-linux-x86_64" "${CMAKE_DIR}" +fi + +JAVA_HOME=/opt/jdk-17 +if [[ ! -x "${JAVA_HOME}/bin/java" ]]; then + wget -q "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.13%2B11/OpenJDK17U-jdk_x64_linux_hotspot_17.0.13_11.tar.gz" \ + -O /tmp/jdk17.tar.gz + rm -rf "${JAVA_HOME}" + mkdir -p /opt + tar xf /tmp/jdk17.tar.gz -C /opt + mv /opt/jdk-17.0.13+11 "${JAVA_HOME}" +fi + +export PATH="${CMAKE_DIR}/bin:${JAVA_HOME}/bin:${PATH}" +export JAVA_HOME + +scl enable devtoolset-8 -- bash -c ' + set -euxo pipefail + 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=linux-x86_64-glibc217 +' + +SO="iotdb-client/client-cpp/target/install/lib/libiotdb_session.so" +test -f "${SO}" + +echo "=== Build host glibc ===" +ldd --version | head -1 + +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}" + +# Fail if any symbol requires glibc newer than 2.17 +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 76f5492015fdc..42215a01691db 100644 --- a/.github/workflows/client-cpp-package.yml +++ b/.github/workflows/client-cpp-package.yml @@ -1,9 +1,27 @@ # 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. +# +# Produces per-platform/per-toolchain SDK zips (classifier suffix in artifact name). 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-vs2015 + - windows-vs2017 + - windows-vs2019 + - windows-vs2022 + - windows-vs2026 release: types: [published] push: @@ -62,19 +80,107 @@ 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 + 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-vs2015|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" + + WINDOWS_MATRIX='[ + {"name":"windows-vs2026","runs-on":"windows-2025-vs2026","boost_choco":"boost-msvc-14.3","cmake_generator":"Visual Studio 18 2026","package_classifier":"windows-x86_64-vs2026","vs_choco":"","vs_choco_params":"","continue_on_error":false}, + {"name":"windows-vs2022","runs-on":"windows-2022","boost_choco":"boost-msvc-14.3","cmake_generator":"","package_classifier":"windows-x86_64-vs2022","vs_choco":"","vs_choco_params":"","continue_on_error":false}, + {"name":"windows-vs2019","runs-on":"windows-2022","boost_choco":"boost-msvc-14.2","cmake_generator":"Visual Studio 16 2019","package_classifier":"windows-x86_64-vs2019","vs_choco":"visualstudio2019buildtools","vs_choco_params":"--add Microsoft.VisualStudio.Workload.VCTools --includeRecommended","continue_on_error":false}, + {"name":"windows-vs2017","runs-on":"windows-2022","boost_choco":"boost-msvc-14.1","cmake_generator":"Visual Studio 15 2017","package_classifier":"windows-x86_64-vs2017","vs_choco":"visualstudio2017buildtools","vs_choco_params":"--add Microsoft.VisualStudio.Workload.VCTools --includeRecommended","continue_on_error":false}, + {"name":"windows-vs2015","runs-on":"windows-2022","boost_choco":"boost-msvc-14.0","cmake_generator":"Visual Studio 14 2015","package_classifier":"windows-x86_64-vs2015","vs_choco":"visualstudio2015buildtools","vs_choco_params":"","continue_on_error":true} + ]' + + 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 + echo "windows_matrix=${FILTERED}" >> "$GITHUB_OUTPUT" + else + echo "windows_matrix=[]" >> "$GITHUB_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' + runs-on: ubuntu-22.04 + container: + image: quay.io/centos/centos:7 + steps: + - uses: actions/checkout@v5 + - name: Cache Maven packages + uses: actions/cache@v5 + with: + 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 + chmod +x .github/scripts/package-client-cpp-centos7.sh + .github/scripts/package-client-cpp-centos7.sh + - name: Upload zip artifact + uses: actions/upload-artifact@v6 + with: + name: client-cpp-linux-x86_64-glibc217 + path: iotdb-client/client-cpp/target/client-cpp-*-cpp-linux-x86_64-glibc217.zip + if-no-files-found: error + + package-linux-aarch64: + name: Package (linux-aarch64) + needs: [should-package, resolve-matrix] + if: needs.should-package.outputs.run == 'true' && needs.resolve-matrix.outputs.run_linux == 'true' + runs-on: ubuntu-22.04-arm steps: - uses: actions/checkout@v5 - name: Set up JDK 17 @@ -82,48 +188,36 @@ jobs: with: distribution: temurin java-version: "17" - - name: Install C++ dependencies (Linux) + - name: Install C++ dependencies (Linux aarch64) 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 - 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 - name: Cache Maven packages uses: actions/cache@v5 with: path: ~/.m2 - key: ${{ runner.os }}-${{ runner.arch }}-m2-${{ hashFiles('**/pom.xml') }} + key: linux-aarch64-m2-${{ hashFiles('**/pom.xml') }} restore-keys: | - ${{ runner.os }}-${{ runner.arch }}-m2- + linux-aarch64-m2- - name: Package client-cpp shell: bash 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: 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: client-cpp-linux-aarch64 + path: iotdb-client/client-cpp/target/client-cpp-*-cpp-linux-aarch64.zip 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: @@ -154,16 +248,17 @@ jobs: 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: Upload zip artifact uses: actions/upload-artifact@v6 with: @@ -173,22 +268,13 @@ jobs: 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' + continue-on-error: ${{ matrix.continue_on_error }} 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 @@ -197,44 +283,59 @@ 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 + choco install winflexbison3 -y --no-progress + choco install ${{ matrix.boost_choco }} -y --no-progress $boost_path = (Get-ChildItem -Path 'C:\local\' -Filter 'boost_*').FullName echo $boost_path >> $env:GITHUB_PATH - choco install openssl -y + 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[@]}" + "${MVN_ARGS[@]}" 2>&1 | tee "mvn-package-${{ matrix.name }}.log" + - name: Upload build log (VS2015 fallback) + if: failure() && matrix.continue_on_error + uses: actions/upload-artifact@v6 + with: + name: client-cpp-${{ matrix.name }}-build-log + path: mvn-package-${{ matrix.name }}.log + retention-days: 14 - name: Upload zip artifact + if: success() uses: actions/upload-artifact@v6 with: name: client-cpp-${{ matrix.name }} - path: iotdb-client/client-cpp/target/client-cpp-*-cpp-*.zip + path: iotdb-client/client-cpp/target/client-cpp-*-cpp-${{ matrix.package_classifier }}.zip if-no-files-found: error diff --git a/example/client-cpp-example/README.md b/example/client-cpp-example/README.md index fbfe98c78a99f..aaaba608394b8 100644 --- a/example/client-cpp-example/README.md +++ b/example/client-cpp-example/README.md @@ -37,6 +37,26 @@ user `root` / `root`). | `TableModelSessionExample` | Table (relational) model | | `MultiSvrNodeClient` | Multi-node insert/query loop | +## 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--cpp-.zip`. + +| Deployment target | Classifier suffix | +|-------------------|-------------------| +| Linux x86_64, glibc ≥ 2.17 | `linux-x86_64-glibc217` | +| Linux aarch64, glibc ≥ 2.31 | `linux-aarch64` | +| 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 diff --git a/example/client-cpp-example/README_zh.md b/example/client-cpp-example/README_zh.md index fc7246da6f4d8..f9e86eb454118 100644 --- a/example/client-cpp-example/README_zh.md +++ b/example/client-cpp-example/README_zh.md @@ -36,6 +36,25 @@ | `TableModelSessionExample` | 表模型(关系型) | | `MultiSvrNodeClient` | 多节点写入/查询循环 | +## 选择哪个 SDK 压缩包 + +CI 发版([client-cpp-package.yml](../../.github/workflows/client-cpp-package.yml)) +会按平台/工具链打出多份 zip,文件名形如 +`client-cpp--cpp-.zip`。请按目标环境选择: + +| 目标环境 | classifier 后缀 | +|----------|-----------------| +| Linux x86_64,glibc ≥ 2.17 | `linux-x86_64-glibc217` | +| Linux aarch64,glibc ≥ 2.31 | `linux-aarch64` | +| macOS x86_64 | `mac-x86_64` | +| macOS arm64 | `mac-aarch64` | +| Windows + 与工程相同的 VS 版本 | `windows-x86_64-vs2015` … `vs2026`(VS2015 包由 CI 尽力构建,失败时请本地编译) | + +当前 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 压缩包只包含 **公开头文件** 和 **一个共享库**: diff --git a/iotdb-client/client-cpp/README.md b/iotdb-client/client-cpp/README.md index 4ad9329fff5b4..e58dcf5423dd4 100644 --- a/iotdb-client/client-cpp/README.md +++ b/iotdb-client/client-cpp/README.md @@ -65,7 +65,65 @@ During configure CMake will, in order: | 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--cpp-.zip`. +land at `iotdb-client/client-cpp/target/client-cpp--cpp-.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.31 | `linux-aarch64` | +| macOS x86_64 | `mac-x86_64` | +| macOS arm64 | `mac-aarch64` | +| Windows + Visual Studio 2015 | `windows-x86_64-vs2015` | +| 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-cpp-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 +``` + +Windows (match the Visual Studio version you use to build your application): + +```powershell +# Visual Studio 2022 (default on recent Windows) +mvn -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests package + +# 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 + +# Visual Studio 2017 +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 +``` ## CMake options @@ -154,7 +212,11 @@ CI environments can share a single cache by setting ### Windows -The recommended toolchain is Visual Studio 2019 or 2022. +Visual Studio **2017, 2019, 2022, or 2026** is supported for building the SDK. +CI also attempts a **VS2015** package (`windows-x86_64-vs2015`); if that job +fails, build locally with `-Dcmake.generator="Visual Studio 14 2015"` and the +matching classifier. Link your application against the zip built with the **same +VS generation** you use for your project. Prerequisites: diff --git a/iotdb-client/client-cpp/cmake/FetchThrift.cmake b/iotdb-client/client-cpp/cmake/FetchThrift.cmake index 07727fae040d4..390c031ff2203 100644 --- a/iotdb-client/client-cpp/cmake/FetchThrift.cmake +++ b/iotdb-client/client-cpp/cmake/FetchThrift.cmake @@ -123,8 +123,8 @@ if(MSVC) "-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDLL") else() list(APPEND _thrift_cmake_args - "-DCMAKE_C_FLAGS=-fPIC -fno-split-stack" - "-DCMAKE_CXX_FLAGS=-fPIC -fno-split-stack") + "-DCMAKE_C_FLAGS=-fPIC" + "-DCMAKE_CXX_FLAGS=-fPIC") endif() if(WITH_SSL) diff --git a/iotdb-client/client-cpp/pom.xml b/iotdb-client/client-cpp/pom.xml index cb97282671d3f..8aa3889a2a28f 100644 --- a/iotdb-client/client-cpp/pom.xml +++ b/iotdb-client/client-cpp/pom.xml @@ -55,6 +55,8 @@ + + ${os.classifier} diff --git a/iotdb-client/client-cpp/src/assembly/client-cpp.xml b/iotdb-client/client-cpp/src/assembly/client-cpp.xml index 60e5f3a29d7bd..a9ae8277f585c 100644 --- a/iotdb-client/client-cpp/src/assembly/client-cpp.xml +++ b/iotdb-client/client-cpp/src/assembly/client-cpp.xml @@ -23,7 +23,7 @@ the zip's include/ and lib/ directories. --> - cpp-${os.classifier} + cpp-${client.cpp.package.classifier} zip dir diff --git a/iotdb-client/client-cpp/third-party/README.md b/iotdb-client/client-cpp/third-party/README.md index d02ce73b0a2d0..c92733d50c6a8 100644 --- a/iotdb-client/client-cpp/third-party/README.md +++ b/iotdb-client/client-cpp/third-party/README.md @@ -66,8 +66,8 @@ Alternatively copy files manually from the URLs listed in | Platform | Typical files | |------------|---------------| -| `linux/` | `thrift-0.21.0.tar.gz`, `boost_1_84_0.tar.gz`, `m4-1.4.19.tar.gz`, `flex-2.6.4.tar.gz`, `bison-3.8.tar.gz` (+ `openssl-3.5.0.tar.gz` when `WITH_SSL=ON`) | -| `mac/` | `thrift-0.21.0.tar.gz`, `boost_1_84_0.tar.gz` (Xcode CLT usually provides m4/flex/bison) | -| `windows/` | `thrift-0.21.0.tar.gz`, `boost_1_84_0.tar.gz` or `boost_1_84_0.zip`, `win_flex_bison-2.5.25.zip` (or any `win_flex_bison*.zip`; skip if flex/bison already on `PATH`) | +| `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` (+ `openssl-3.5.0.tar.gz` when `WITH_SSL=ON`) | +| `mac/` | `thrift-0.21.0.tar.gz`, `boost_1_60_0.tar.gz` (Xcode CLT usually provides m4/flex/bison) | +| `windows/` | `thrift-0.21.0.tar.gz`, `boost_1_60_0.tar.gz`, `win_flex_bison-2.5.25.zip` (or any `win_flex_bison*.zip`; skip if flex/bison already on `PATH`) | Download URLs: see the *Offline build* table in [`README.md`](../README.md). From 26da4338e4de01d33531588e71baec98b552d8b2 Mon Sep 17 00:00:00 2001 From: 761417898 <761417898@qq.com> Date: Tue, 26 May 2026 10:52:52 +0800 Subject: [PATCH 11/28] fix(ci): write windows_matrix to GITHUB_OUTPUT without invalid format --- .github/workflows/client-cpp-package.yml | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/.github/workflows/client-cpp-package.yml b/.github/workflows/client-cpp-package.yml index 42215a01691db..b1b0b353674a5 100644 --- a/.github/workflows/client-cpp-package.yml +++ b/.github/workflows/client-cpp-package.yml @@ -122,13 +122,17 @@ jobs: echo "run_macos=${run_macos}" >> "$GITHUB_OUTPUT" echo "run_windows=${run_windows}" >> "$GITHUB_OUTPUT" - WINDOWS_MATRIX='[ - {"name":"windows-vs2026","runs-on":"windows-2025-vs2026","boost_choco":"boost-msvc-14.3","cmake_generator":"Visual Studio 18 2026","package_classifier":"windows-x86_64-vs2026","vs_choco":"","vs_choco_params":"","continue_on_error":false}, - {"name":"windows-vs2022","runs-on":"windows-2022","boost_choco":"boost-msvc-14.3","cmake_generator":"","package_classifier":"windows-x86_64-vs2022","vs_choco":"","vs_choco_params":"","continue_on_error":false}, - {"name":"windows-vs2019","runs-on":"windows-2022","boost_choco":"boost-msvc-14.2","cmake_generator":"Visual Studio 16 2019","package_classifier":"windows-x86_64-vs2019","vs_choco":"visualstudio2019buildtools","vs_choco_params":"--add Microsoft.VisualStudio.Workload.VCTools --includeRecommended","continue_on_error":false}, - {"name":"windows-vs2017","runs-on":"windows-2022","boost_choco":"boost-msvc-14.1","cmake_generator":"Visual Studio 15 2017","package_classifier":"windows-x86_64-vs2017","vs_choco":"visualstudio2017buildtools","vs_choco_params":"--add Microsoft.VisualStudio.Workload.VCTools --includeRecommended","continue_on_error":false}, - {"name":"windows-vs2015","runs-on":"windows-2022","boost_choco":"boost-msvc-14.0","cmake_generator":"Visual Studio 14 2015","package_classifier":"windows-x86_64-vs2015","vs_choco":"visualstudio2015buildtools","vs_choco_params":"","continue_on_error":true} - ]' + # 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","cmake_generator":"Visual Studio 18 2026","package_classifier":"windows-x86_64-vs2026","vs_choco":"","vs_choco_params":"","continue_on_error":false},{"name":"windows-vs2022","runs-on":"windows-2022","boost_choco":"boost-msvc-14.3","cmake_generator":"","package_classifier":"windows-x86_64-vs2022","vs_choco":"","vs_choco_params":"","continue_on_error":false},{"name":"windows-vs2019","runs-on":"windows-2022","boost_choco":"boost-msvc-14.2","cmake_generator":"Visual Studio 16 2019","package_classifier":"windows-x86_64-vs2019","vs_choco":"visualstudio2019buildtools","vs_choco_params":"--add Microsoft.VisualStudio.Workload.VCTools --includeRecommended","continue_on_error":false},{"name":"windows-vs2017","runs-on":"windows-2022","boost_choco":"boost-msvc-14.1","cmake_generator":"Visual Studio 15 2017","package_classifier":"windows-x86_64-vs2017","vs_choco":"visualstudio2017buildtools","vs_choco_params":"--add Microsoft.VisualStudio.Workload.VCTools --includeRecommended","continue_on_error":false},{"name":"windows-vs2015","runs-on":"windows-2022","boost_choco":"boost-msvc-14.0","cmake_generator":"Visual Studio 14 2015","package_classifier":"windows-x86_64-vs2015","vs_choco":"visualstudio2015buildtools","vs_choco_params":"","continue_on_error":true}]' + + 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 @@ -142,9 +146,10 @@ jobs: echo "No Windows matrix rows for variant=${VARIANT}" >&2 exit 1 fi - echo "windows_matrix=${FILTERED}" >> "$GITHUB_OUTPUT" + FILTERED=$(echo "$FILTERED" | jq -c '.') + write_windows_matrix_output "${FILTERED}" else - echo "windows_matrix=[]" >> "$GITHUB_OUTPUT" + write_windows_matrix_output '[]' fi package-linux-glibc217: From c58826b42edc635397aacd9d14f95e55fac91b62 Mon Sep 17 00:00:00 2001 From: 761417898 <761417898@qq.com> Date: Tue, 26 May 2026 11:18:40 +0800 Subject: [PATCH 12/28] fix(ci): scope C++ triggers, glibc231 arm64, CentOS7 and VS2015 boost - paths-ignore C++ workflows/scripts on Java IT jobs; narrow C++ path filters (no root pom.xml) - aarch64 package on Ubuntu 20.04 container (linux-aarch64-glibc231) - CentOS7 script: vault repos, Adoptium API JDK, devtoolset deps - VS2015/2017: pin boost-msvc-14.2/14.1 versions instead of missing boost-msvc-14.0 --- .github/scripts/package-client-cpp-centos7.sh | 26 ++++---- .../package-client-cpp-ubuntu20-arm.sh | 50 ++++++++++++++++ .github/workflows/client-cpp-package.yml | 60 ++++++++++--------- .github/workflows/client-cpp-source-build.yml | 8 ++- .github/workflows/cluster-it-1c1d.yml | 6 ++ .github/workflows/cluster-it-1c1d1a.yml | 6 ++ .github/workflows/cluster-it-1c3d.yml | 6 ++ .github/workflows/compile-check.yml | 6 ++ .github/workflows/dependency-check.yml | 6 ++ .github/workflows/multi-language-client.yml | 11 +++- .github/workflows/pipe-it.yml | 6 ++ .github/workflows/sonar-codecov.yml | 6 ++ .github/workflows/table-cluster-it-1c1d.yml | 6 ++ .github/workflows/table-cluster-it-1c3d.yml | 6 ++ .github/workflows/unit-test.yml | 6 ++ example/client-cpp-example/README.md | 2 +- example/client-cpp-example/README_zh.md | 2 +- iotdb-client/client-cpp/README.md | 18 +++--- 18 files changed, 183 insertions(+), 54 deletions(-) create mode 100644 .github/scripts/package-client-cpp-ubuntu20-arm.sh diff --git a/.github/scripts/package-client-cpp-centos7.sh b/.github/scripts/package-client-cpp-centos7.sh index 5572274cb1b91..9795168a3e333 100644 --- a/.github/scripts/package-client-cpp-centos7.sh +++ b/.github/scripts/package-client-cpp-centos7.sh @@ -18,14 +18,17 @@ set -euxo pipefail # CentOS 7 EOL: use vault mirrors when default mirrors are unavailable. -if grep -q mirrorlist /etc/yum.repos.d/CentOS-*.repo 2>/dev/null; then - sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*.repo - sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*.repo -fi +for repo in /etc/yum.repos.d/CentOS-*.repo; do + if [[ -f "${repo}" ]] && grep -q '^mirrorlist=' "${repo}"; then + sed -i 's/^mirrorlist=/#mirrorlist=/g' "${repo}" + sed -i 's|^#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' "${repo}" + fi +done -yum install -y centos-release-scl epel-release +yum install -y ca-certificates centos-release-scl epel-release yum install -y devtoolset-8-gcc devtoolset-8-gcc-c++ devtoolset-8-binutils \ - make wget tar which git patch unzip + devtoolset-8-libstdc++-devel scl-utils \ + make wget tar which git patch unzip bzip2 CMAKE_VERSION=3.28.4 CMAKE_DIR=/opt/cmake-${CMAKE_VERSION} @@ -40,12 +43,14 @@ fi JAVA_HOME=/opt/jdk-17 if [[ ! -x "${JAVA_HOME}/bin/java" ]]; then - wget -q "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.13%2B11/OpenJDK17U-jdk_x64_linux_hotspot_17.0.13_11.tar.gz" \ - -O /tmp/jdk17.tar.gz - rm -rf "${JAVA_HOME}" + wget -qL -O /tmp/jdk17.tar.gz \ + "https://api.adoptium.net/v3/binary/latest/17/ga/linux/x64/jdk/hotspot/normal/eclipse?project=jdk" + rm -rf /opt/jdk-17* mkdir -p /opt tar xf /tmp/jdk17.tar.gz -C /opt - mv /opt/jdk-17.0.13+11 "${JAVA_HOME}" + JAVA_HOME=$(find /opt -maxdepth 1 -type d -name 'jdk-17*' | head -1) + ln -sfn "${JAVA_HOME}" /opt/jdk-17 + JAVA_HOME=/opt/jdk-17 fi export PATH="${CMAKE_DIR}/bin:${JAVA_HOME}/bin:${PATH}" @@ -74,7 +79,6 @@ objdump -T "${SO}" | grep GLIBC_ | sed "s/.*GLIBC_/GLIBC_/" | sort -Vu | tail -1 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}" -# Fail if any symbol requires glibc newer than 2.17 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 diff --git a/.github/scripts/package-client-cpp-ubuntu20-arm.sh b/.github/scripts/package-client-cpp-ubuntu20-arm.sh new file mode 100644 index 0000000000000..af989dd362f34 --- /dev/null +++ b/.github/scripts/package-client-cpp-ubuntu20-arm.sh @@ -0,0 +1,50 @@ +#!/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 on Ubuntu 20.04 aarch64 (glibc 2.31 baseline). +set -euxo pipefail + +export DEBIAN_FRONTEND=noninteractive +apt-get update +apt-get install -y build-essential cmake wget git ca-certificates \ + openjdk-17-jdk binutils + +JAVA_BIN=$(readlink -f "$(command -v java)") +export JAVA_HOME=$(dirname "$(dirname "${JAVA_BIN}")") +export PATH="${JAVA_HOME}/bin:${PATH}" + +java -version +gcc --version +cmake --version +ldd --version | head -1 + +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=linux-aarch64-glibc231 + +SO="iotdb-client/client-cpp/target/install/lib/libiotdb_session.so" +test -f "${SO}" + +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.31) }"; then + echo "ERROR: libiotdb_session.so requires glibc > 2.31 (max=${max_glibc})" + exit 1 +fi + +echo "glibc compatibility check passed (max=${max_glibc} <= 2.31)" diff --git a/.github/workflows/client-cpp-package.yml b/.github/workflows/client-cpp-package.yml index b1b0b353674a5..cbd64afb9968e 100644 --- a/.github/workflows/client-cpp-package.yml +++ b/.github/workflows/client-cpp-package.yml @@ -52,10 +52,15 @@ 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' + - '.github/scripts/package-client-cpp-*.sh' - id: result shell: bash run: | @@ -123,7 +128,7 @@ jobs: 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","cmake_generator":"Visual Studio 18 2026","package_classifier":"windows-x86_64-vs2026","vs_choco":"","vs_choco_params":"","continue_on_error":false},{"name":"windows-vs2022","runs-on":"windows-2022","boost_choco":"boost-msvc-14.3","cmake_generator":"","package_classifier":"windows-x86_64-vs2022","vs_choco":"","vs_choco_params":"","continue_on_error":false},{"name":"windows-vs2019","runs-on":"windows-2022","boost_choco":"boost-msvc-14.2","cmake_generator":"Visual Studio 16 2019","package_classifier":"windows-x86_64-vs2019","vs_choco":"visualstudio2019buildtools","vs_choco_params":"--add Microsoft.VisualStudio.Workload.VCTools --includeRecommended","continue_on_error":false},{"name":"windows-vs2017","runs-on":"windows-2022","boost_choco":"boost-msvc-14.1","cmake_generator":"Visual Studio 15 2017","package_classifier":"windows-x86_64-vs2017","vs_choco":"visualstudio2017buildtools","vs_choco_params":"--add Microsoft.VisualStudio.Workload.VCTools --includeRecommended","continue_on_error":false},{"name":"windows-vs2015","runs-on":"windows-2022","boost_choco":"boost-msvc-14.0","cmake_generator":"Visual Studio 14 2015","package_classifier":"windows-x86_64-vs2015","vs_choco":"visualstudio2015buildtools","vs_choco_params":"","continue_on_error":true}]' + 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":"","continue_on_error":false},{"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":"","continue_on_error":false},{"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","continue_on_error":false},{"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","continue_on_error":false},{"name":"windows-vs2015","runs-on":"windows-2022","boost_choco":"boost-msvc-14.2","boost_choco_version":"1.67.0","cmake_generator":"Visual Studio 14 2015","package_classifier":"windows-x86_64-vs2015","vs_choco":"visualstudio2015buildtools","vs_choco_params":"","continue_on_error":true}]' write_windows_matrix_output() { local matrix_json="$1" @@ -181,42 +186,33 @@ jobs: path: iotdb-client/client-cpp/target/client-cpp-*-cpp-linux-x86_64-glibc217.zip if-no-files-found: error - package-linux-aarch64: - name: Package (linux-aarch64) + package-linux-aarch64-glibc231: + name: Package (linux-aarch64-glibc231) needs: [should-package, resolve-matrix] if: needs.should-package.outputs.run == 'true' && needs.resolve-matrix.outputs.run_linux == 'true' runs-on: ubuntu-22.04-arm + container: + image: ubuntu:20.04 steps: - uses: actions/checkout@v5 - - name: Set up JDK 17 - uses: actions/setup-java@v5 - with: - distribution: temurin - java-version: "17" - - name: Install C++ dependencies (Linux aarch64) - shell: bash - run: | - set -euxo pipefail - sudo apt-get update - sudo apt-get install -y libboost-all-dev openssl libssl-dev wget - name: Cache Maven packages uses: actions/cache@v5 with: path: ~/.m2 - key: linux-aarch64-m2-${{ hashFiles('**/pom.xml') }} + key: linux-aarch64-glibc231-m2-${{ hashFiles('**/pom.xml') }} restore-keys: | - linux-aarch64-m2- - - name: Package client-cpp + linux-aarch64-glibc231-m2- + - name: Package client-cpp (glibc 2.31 baseline) shell: bash run: | set -euxo pipefail - ./mvnw clean package -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests \ - -Dspotless.skip=true + chmod +x .github/scripts/package-client-cpp-ubuntu20-arm.sh + .github/scripts/package-client-cpp-ubuntu20-arm.sh - name: Upload zip artifact uses: actions/upload-artifact@v6 with: - name: client-cpp-linux-aarch64 - path: iotdb-client/client-cpp/target/client-cpp-*-cpp-linux-aarch64.zip + name: client-cpp-linux-aarch64-glibc231 + path: iotdb-client/client-cpp/target/client-cpp-*-cpp-linux-aarch64-glibc231.zip if-no-files-found: error package-macos: @@ -302,9 +298,19 @@ jobs: shell: pwsh run: | choco install winflexbison3 -y --no-progress - choco install ${{ matrix.boost_choco }} -y --no-progress - $boost_path = (Get-ChildItem -Path 'C:\local\' -Filter 'boost_*').FullName - echo $boost_path >> $env:GITHUB_PATH + $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 diff --git a/.github/workflows/client-cpp-source-build.yml b/.github/workflows/client-cpp-source-build.yml index c8f8e141c8830..a58ec91bd4234 100644 --- a/.github/workflows/client-cpp-source-build.yml +++ b/.github/workflows/client-cpp-source-build.yml @@ -10,24 +10,28 @@ on: - master - "rc/*" paths: - - "pom.xml" - "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: - - "pom.xml" - "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: diff --git a/.github/workflows/cluster-it-1c1d.yml b/.github/workflows/cluster-it-1c1d.yml index 48660a2b9cd28..5840b6f930c8d 100644 --- a/.github/workflows/cluster-it-1c1d.yml +++ b/.github/workflows/cluster-it-1c1d.yml @@ -11,6 +11,9 @@ on: - "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" pull_request: branches: - master @@ -21,6 +24,9 @@ on: - "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" # allow manually run the action: workflow_dispatch: diff --git a/.github/workflows/cluster-it-1c1d1a.yml b/.github/workflows/cluster-it-1c1d1a.yml index eab539933dbf0..687520ff22187 100644 --- a/.github/workflows/cluster-it-1c1d1a.yml +++ b/.github/workflows/cluster-it-1c1d1a.yml @@ -11,6 +11,9 @@ on: - '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' pull_request: branches: - master @@ -22,6 +25,9 @@ on: - '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' # allow manually run the action: workflow_dispatch: diff --git a/.github/workflows/cluster-it-1c3d.yml b/.github/workflows/cluster-it-1c3d.yml index 77888b0c64fc6..42e22e050ccf6 100644 --- a/.github/workflows/cluster-it-1c3d.yml +++ b/.github/workflows/cluster-it-1c3d.yml @@ -11,6 +11,9 @@ on: - "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" pull_request: branches: - master @@ -22,6 +25,9 @@ on: - "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" # allow manually run the action: workflow_dispatch: diff --git a/.github/workflows/compile-check.yml b/.github/workflows/compile-check.yml index 5db86d103875f..8e1f6cafc7678 100644 --- a/.github/workflows/compile-check.yml +++ b/.github/workflows/compile-check.yml @@ -13,6 +13,9 @@ on: - "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" pull_request: branches: - master @@ -24,6 +27,9 @@ on: - "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" # allow manually run the action: workflow_dispatch: diff --git a/.github/workflows/dependency-check.yml b/.github/workflows/dependency-check.yml index 884d0f293ae01..277e1133e5c5d 100644 --- a/.github/workflows/dependency-check.yml +++ b/.github/workflows/dependency-check.yml @@ -13,6 +13,9 @@ on: - "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" pull_request: branches: - master @@ -24,6 +27,9 @@ on: - "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" # allow manually run the action: workflow_dispatch: diff --git a/.github/workflows/multi-language-client.yml b/.github/workflows/multi-language-client.yml index 7b3e3089a6c6c..436bf4bfa4e38 100644 --- a/.github/workflows/multi-language-client.yml +++ b/.github/workflows/multi-language-client.yml @@ -5,7 +5,6 @@ on: - master - "rc/*" paths: - - 'pom.xml' - 'iotdb-client/pom.xml' - 'iotdb-client/client-py/**' - 'iotdb-client/client-cpp/**' @@ -13,13 +12,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 +28,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: @@ -54,7 +58,6 @@ jobs: with: filters: | cpp: - - 'pom.xml' - 'iotdb-client/pom.xml' - 'iotdb-client/client-cpp/**' - 'example/client-cpp-example/**' @@ -62,6 +65,8 @@ jobs: - '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' diff --git a/.github/workflows/pipe-it.yml b/.github/workflows/pipe-it.yml index 486a043f50a1c..eedacc7e8a636 100644 --- a/.github/workflows/pipe-it.yml +++ b/.github/workflows/pipe-it.yml @@ -11,6 +11,9 @@ on: - "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" - "iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/**" #queryengine pull_request: branches: @@ -23,6 +26,9 @@ on: - "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" - "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 a01cbce5242ed..486793c33dfd0 100644 --- a/.github/workflows/sonar-codecov.yml +++ b/.github/workflows/sonar-codecov.yml @@ -14,6 +14,9 @@ on: - "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" pull_request: branches: - master @@ -26,6 +29,9 @@ on: - "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" # 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 ef4590b447c96..a51bd20d56461 100644 --- a/.github/workflows/table-cluster-it-1c1d.yml +++ b/.github/workflows/table-cluster-it-1c1d.yml @@ -11,6 +11,9 @@ on: - "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" pull_request: branches: - master @@ -22,6 +25,9 @@ on: - "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" # 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 6ec2d4c23ac07..c74f467a156c3 100644 --- a/.github/workflows/table-cluster-it-1c3d.yml +++ b/.github/workflows/table-cluster-it-1c3d.yml @@ -11,6 +11,9 @@ on: - "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" pull_request: branches: - master @@ -22,6 +25,9 @@ on: - "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" # allow manually run the action: workflow_dispatch: diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 28d286c433066..f775b46acad1a 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -14,6 +14,9 @@ on: - "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" pull_request: branches: - master @@ -25,6 +28,9 @@ on: - "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" # allow manually run the action: workflow_dispatch: diff --git a/example/client-cpp-example/README.md b/example/client-cpp-example/README.md index aaaba608394b8..dd7afd671aafa 100644 --- a/example/client-cpp-example/README.md +++ b/example/client-cpp-example/README.md @@ -46,7 +46,7 @@ publishes one zip per platform/toolchain: | Deployment target | Classifier suffix | |-------------------|-------------------| | Linux x86_64, glibc ≥ 2.17 | `linux-x86_64-glibc217` | -| Linux aarch64, glibc ≥ 2.31 | `linux-aarch64` | +| Linux aarch64, glibc ≥ 2.31 | `linux-aarch64-glibc231` | | macOS x86_64 | `mac-x86_64` | | macOS arm64 | `mac-aarch64` | | Windows (match your Visual Studio version) | `windows-x86_64-vs2017` … `vs2026` | diff --git a/example/client-cpp-example/README_zh.md b/example/client-cpp-example/README_zh.md index f9e86eb454118..84f389130115d 100644 --- a/example/client-cpp-example/README_zh.md +++ b/example/client-cpp-example/README_zh.md @@ -45,7 +45,7 @@ CI 发版([client-cpp-package.yml](../../.github/workflows/client-cpp-package. | 目标环境 | classifier 后缀 | |----------|-----------------| | Linux x86_64,glibc ≥ 2.17 | `linux-x86_64-glibc217` | -| Linux aarch64,glibc ≥ 2.31 | `linux-aarch64` | +| Linux aarch64,glibc ≥ 2.31 | `linux-aarch64-glibc231` | | macOS x86_64 | `mac-x86_64` | | macOS arm64 | `mac-aarch64` | | Windows + 与工程相同的 VS 版本 | `windows-x86_64-vs2015` … `vs2026`(VS2015 包由 CI 尽力构建,失败时请本地编译) | diff --git a/iotdb-client/client-cpp/README.md b/iotdb-client/client-cpp/README.md index e58dcf5423dd4..5f21be7ae826a 100644 --- a/iotdb-client/client-cpp/README.md +++ b/iotdb-client/client-cpp/README.md @@ -79,7 +79,7 @@ deployment environment: | Target environment | Zip classifier (suffix) | |--------------------|-------------------------| | Linux x86_64, glibc ≥ 2.17 | `linux-x86_64-glibc217` | -| Linux aarch64, glibc ≥ 2.31 | `linux-aarch64` | +| Linux aarch64, glibc ≥ 2.31 | `linux-aarch64-glibc231` | | macOS x86_64 | `mac-x86_64` | | macOS arm64 | `mac-aarch64` | | Windows + Visual Studio 2015 | `windows-x86_64-vs2015` | @@ -311,22 +311,22 @@ as a separate install artifact. ```cpp #include "Session.h" -#include -#include + #include + #include -int main() { + int main() { auto session = std::make_shared("127.0.0.1", 6667, "root", "root"); - session->open(false); - session->setStorageGroup("root.test01"); - if (!session->checkTimeseriesExists("root.test01.d0.s0")) { + session->open(false); + session->setStorageGroup("root.test01"); + if (!session->checkTimeseriesExists("root.test01.d0.s0")) { session->createTimeseries( "root.test01.d0.s0", TSDataType::INT64, TSEncoding::RLE, CompressionType::SNAPPY); } - session->close(); -} + session->close(); + } ``` Compile against the produced SDK: From 213356a42e869f54b260e2cadfbd4dd7219da5e8 Mon Sep 17 00:00:00 2001 From: 761417898 <761417898@qq.com> Date: Tue, 26 May 2026 11:43:25 +0800 Subject: [PATCH 13/28] fix(ci): docker-based glibc builds, CMake 3.28 on arm64, drop VS2015 - glibc217/aarch64: checkout on host, build inside docker (fixes CentOS7 + Node 24) - aarch64: install Kitware CMake 3.28 (ARCHIVE_EXTRACT needs 3.18+) - Remove VS2015 package matrix and related docs --- .../package-client-cpp-ubuntu20-arm.sh | 16 +++++++- .github/workflows/client-cpp-package.yml | 38 +++++++++---------- example/client-cpp-example/README_zh.md | 2 +- iotdb-client/client-cpp/README.md | 7 +--- 4 files changed, 35 insertions(+), 28 deletions(-) diff --git a/.github/scripts/package-client-cpp-ubuntu20-arm.sh b/.github/scripts/package-client-cpp-ubuntu20-arm.sh index af989dd362f34..137b517622258 100644 --- a/.github/scripts/package-client-cpp-ubuntu20-arm.sh +++ b/.github/scripts/package-client-cpp-ubuntu20-arm.sh @@ -19,12 +19,24 @@ set -euxo pipefail export DEBIAN_FRONTEND=noninteractive apt-get update -apt-get install -y build-essential cmake wget git ca-certificates \ +apt-get install -y build-essential wget git ca-certificates \ openjdk-17-jdk binutils +# Ubuntu 20.04 ships CMake 3.16; FetchBoost.cmake needs ARCHIVE_EXTRACT (3.18+). +CMAKE_VERSION=3.28.4 +CMAKE_DIR=/opt/cmake-${CMAKE_VERSION} +if [[ ! -x "${CMAKE_DIR}/bin/cmake" ]]; then + wget -q "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-linux-aarch64.tar.gz" \ + -O /tmp/cmake.tar.gz + rm -rf "${CMAKE_DIR}" + mkdir -p /opt + tar xf /tmp/cmake.tar.gz -C /opt + mv "/opt/cmake-${CMAKE_VERSION}-linux-aarch64" "${CMAKE_DIR}" +fi + JAVA_BIN=$(readlink -f "$(command -v java)") export JAVA_HOME=$(dirname "$(dirname "${JAVA_BIN}")") -export PATH="${JAVA_HOME}/bin:${PATH}" +export PATH="${CMAKE_DIR}/bin:${JAVA_HOME}/bin:${PATH}" java -version gcc --version diff --git a/.github/workflows/client-cpp-package.yml b/.github/workflows/client-cpp-package.yml index cbd64afb9968e..b8de4a7c9e872 100644 --- a/.github/workflows/client-cpp-package.yml +++ b/.github/workflows/client-cpp-package.yml @@ -17,7 +17,6 @@ on: - linux - macos - windows - - windows-vs2015 - windows-vs2017 - windows-vs2019 - windows-vs2022 @@ -60,7 +59,6 @@ jobs: - '.github/workflows/client-cpp-package.yml' - '.github/workflows/client-cpp-source-build.yml' - '.github/scripts/package-client-cpp-*.sh' - - '.github/scripts/package-client-cpp-*.sh' - id: result shell: bash run: | @@ -114,7 +112,7 @@ jobs: linux) run_linux=true ;; macos) run_macos=true ;; windows) run_windows=true ;; - windows-vs2015|windows-vs2017|windows-vs2019|windows-vs2022|windows-vs2026) + windows-vs2017|windows-vs2019|windows-vs2022|windows-vs2026) run_windows=true ;; *) @@ -128,7 +126,7 @@ jobs: 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":"","continue_on_error":false},{"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":"","continue_on_error":false},{"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","continue_on_error":false},{"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","continue_on_error":false},{"name":"windows-vs2015","runs-on":"windows-2022","boost_choco":"boost-msvc-14.2","boost_choco_version":"1.67.0","cmake_generator":"Visual Studio 14 2015","package_classifier":"windows-x86_64-vs2015","vs_choco":"visualstudio2015buildtools","vs_choco_params":"","continue_on_error":true}]' + 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" @@ -161,9 +159,8 @@ jobs: 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' + # No job container: checkout uses Node 24 (needs glibc 2.27+); build runs in CentOS 7 via docker. runs-on: ubuntu-22.04 - container: - image: quay.io/centos/centos:7 steps: - uses: actions/checkout@v5 - name: Cache Maven packages @@ -178,7 +175,13 @@ jobs: run: | set -euxo pipefail chmod +x .github/scripts/package-client-cpp-centos7.sh - .github/scripts/package-client-cpp-centos7.sh + docker run --rm \ + -v "${{ github.workspace }}:/work" \ + -v "${HOME}/.m2:/root/.m2" \ + -w /work \ + -e GITHUB_WORKSPACE=/work \ + quay.io/centos/centos:7 \ + bash .github/scripts/package-client-cpp-centos7.sh - name: Upload zip artifact uses: actions/upload-artifact@v6 with: @@ -191,8 +194,6 @@ jobs: needs: [should-package, resolve-matrix] if: needs.should-package.outputs.run == 'true' && needs.resolve-matrix.outputs.run_linux == 'true' runs-on: ubuntu-22.04-arm - container: - image: ubuntu:20.04 steps: - uses: actions/checkout@v5 - name: Cache Maven packages @@ -207,7 +208,13 @@ jobs: run: | set -euxo pipefail chmod +x .github/scripts/package-client-cpp-ubuntu20-arm.sh - .github/scripts/package-client-cpp-ubuntu20-arm.sh + docker run --rm \ + -v "${{ github.workspace }}:/work" \ + -v "${HOME}/.m2:/root/.m2" \ + -w /work \ + -e GITHUB_WORKSPACE=/work \ + ubuntu:20.04 \ + bash .github/scripts/package-client-cpp-ubuntu20-arm.sh - name: Upload zip artifact uses: actions/upload-artifact@v6 with: @@ -271,7 +278,6 @@ jobs: name: Package (${{ matrix.name }}) needs: [should-package, resolve-matrix] if: needs.should-package.outputs.run == 'true' && needs.resolve-matrix.outputs.run_windows == 'true' - continue-on-error: ${{ matrix.continue_on_error }} strategy: fail-fast: false matrix: @@ -335,16 +341,8 @@ jobs: if [ -n "${CMAKE_GENERATOR:-}" ]; then MVN_ARGS+=("-Dcmake.generator=${CMAKE_GENERATOR}") fi - "${MVN_ARGS[@]}" 2>&1 | tee "mvn-package-${{ matrix.name }}.log" - - name: Upload build log (VS2015 fallback) - if: failure() && matrix.continue_on_error - uses: actions/upload-artifact@v6 - with: - name: client-cpp-${{ matrix.name }}-build-log - path: mvn-package-${{ matrix.name }}.log - retention-days: 14 + "${MVN_ARGS[@]}" - name: Upload zip artifact - if: success() uses: actions/upload-artifact@v6 with: name: client-cpp-${{ matrix.name }} diff --git a/example/client-cpp-example/README_zh.md b/example/client-cpp-example/README_zh.md index 84f389130115d..557a4f222f605 100644 --- a/example/client-cpp-example/README_zh.md +++ b/example/client-cpp-example/README_zh.md @@ -48,7 +48,7 @@ CI 发版([client-cpp-package.yml](../../.github/workflows/client-cpp-package. | Linux aarch64,glibc ≥ 2.31 | `linux-aarch64-glibc231` | | macOS x86_64 | `mac-x86_64` | | macOS arm64 | `mac-aarch64` | -| Windows + 与工程相同的 VS 版本 | `windows-x86_64-vs2015` … `vs2026`(VS2015 包由 CI 尽力构建,失败时请本地编译) | +| Windows + 与工程相同的 VS 版本 | `windows-x86_64-vs2017` … `vs2026` | 当前 CMake 构建在配置阶段从源码编译 Thrift 0.21,**不再**通过 `-Diotdb-tools-thrift.version=0.14.1.1-gcc4-SNAPSHOT` 等旧参数控制 glibc; diff --git a/iotdb-client/client-cpp/README.md b/iotdb-client/client-cpp/README.md index 5f21be7ae826a..c35bbe31e239f 100644 --- a/iotdb-client/client-cpp/README.md +++ b/iotdb-client/client-cpp/README.md @@ -82,7 +82,6 @@ deployment environment: | Linux aarch64, glibc ≥ 2.31 | `linux-aarch64-glibc231` | | macOS x86_64 | `mac-x86_64` | | macOS arm64 | `mac-aarch64` | -| Windows + Visual Studio 2015 | `windows-x86_64-vs2015` | | Windows + Visual Studio 2017 | `windows-x86_64-vs2017` | | Windows + Visual Studio 2019 | `windows-x86_64-vs2019` | | Windows + Visual Studio 2022 | `windows-x86_64-vs2022` | @@ -213,10 +212,8 @@ CI environments can share a single cache by setting ### Windows Visual Studio **2017, 2019, 2022, or 2026** is supported for building the SDK. -CI also attempts a **VS2015** package (`windows-x86_64-vs2015`); if that job -fails, build locally with `-Dcmake.generator="Visual Studio 14 2015"` and the -matching classifier. Link your application against the zip built with the **same -VS generation** you use for your project. +Link your application against the zip built with the **same VS generation** you +use for your project. Prerequisites: From 0238f2402ef82535c7ffe5e7c92c8e1e880f190b Mon Sep 17 00:00:00 2001 From: 761417898 <761417898@qq.com> Date: Tue, 26 May 2026 12:13:04 +0800 Subject: [PATCH 14/28] fix(client-cpp): flatten package zip name and layout - Zip: client-cpp--.zip (remove redundant -cpp- segment) - Root folder client-cpp--/ with include/ and lib/ inside - Update examples (strip one dir on unpack), distribution assembly, CI artifact paths - CentOS7 SCLo vault mirror fix; chown workspace after docker builds --- .github/scripts/package-client-cpp-centos7.sh | 22 ++++-- .github/workflows/client-cpp-package.yml | 74 +++++++++++++++++-- distribution/src/assembly/client-cpp.xml | 2 +- example/client-c-example/pom.xml | 8 +- example/client-cpp-example/README.md | 2 +- example/client-cpp-example/README_zh.md | 2 +- example/client-cpp-example/pom.xml | 8 +- example/client-cpp-example/src/CMakeLists.txt | 2 +- iotdb-client/client-cpp/README.md | 9 ++- iotdb-client/client-cpp/pom.xml | 2 +- .../client-cpp/src/assembly/client-cpp.xml | 9 ++- 11 files changed, 110 insertions(+), 30 deletions(-) diff --git a/.github/scripts/package-client-cpp-centos7.sh b/.github/scripts/package-client-cpp-centos7.sh index 9795168a3e333..46376b677f4d7 100644 --- a/.github/scripts/package-client-cpp-centos7.sh +++ b/.github/scripts/package-client-cpp-centos7.sh @@ -17,15 +17,23 @@ # Build client-cpp inside CentOS 7 + devtoolset-8 for glibc 2.17-compatible .so. set -euxo pipefail -# CentOS 7 EOL: use vault mirrors when default mirrors are unavailable. -for repo in /etc/yum.repos.d/CentOS-*.repo; do - if [[ -f "${repo}" ]] && grep -q '^mirrorlist=' "${repo}"; then - sed -i 's/^mirrorlist=/#mirrorlist=/g' "${repo}" - sed -i 's|^#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' "${repo}" - fi -done +# CentOS 7 EOL: point mirrorlist/baseurl entries at vault.centos.org. +fix_centos_vault_repos() { + find /etc/yum.repos.d/ -name 'CentOS*.repo' -print0 | while IFS= read -r -d '' repo_file; do + if grep -qE '^mirrorlist=' "${repo_file}"; then + sed -i 's/^mirrorlist=/#mirrorlist=/g' "${repo_file}" + sed -i 's|^#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' "${repo_file}" + fi + sed -i 's|http://mirror.centos.org|http://vault.centos.org|g' "${repo_file}" + done +} +# Base repos first; centos-release-scl adds CentOS-SCLo-*.repo (needed for devtoolset-8). +fix_centos_vault_repos yum install -y ca-certificates centos-release-scl epel-release +# SCLo repo files appear only after centos-release-scl is installed. +fix_centos_vault_repos + yum install -y devtoolset-8-gcc devtoolset-8-gcc-c++ devtoolset-8-binutils \ devtoolset-8-libstdc++-devel scl-utils \ make wget tar which git patch unzip bzip2 diff --git a/.github/workflows/client-cpp-package.yml b/.github/workflows/client-cpp-package.yml index b8de4a7c9e872..c9d91cd3088bb 100644 --- a/.github/workflows/client-cpp-package.yml +++ b/.github/workflows/client-cpp-package.yml @@ -182,11 +182,27 @@ jobs: -e GITHUB_WORKSPACE=/work \ quay.io/centos/centos:7 \ bash .github/scripts/package-client-cpp-centos7.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 + 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-linux-x86_64-glibc217 - path: iotdb-client/client-cpp/target/client-cpp-*-cpp-linux-x86_64-glibc217.zip + name: ${{ steps.pkg.outputs.name }} + path: ${{ steps.pkg.outputs.path }} if-no-files-found: error package-linux-aarch64-glibc231: @@ -215,11 +231,27 @@ jobs: -e GITHUB_WORKSPACE=/work \ ubuntu:20.04 \ bash .github/scripts/package-client-cpp-ubuntu20-arm.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-glibc231.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-linux-aarch64-glibc231 - path: iotdb-client/client-cpp/target/client-cpp-*-cpp-linux-aarch64-glibc231.zip + name: ${{ steps.pkg.outputs.name }} + path: ${{ steps.pkg.outputs.path }} if-no-files-found: error package-macos: @@ -267,11 +299,24 @@ jobs: set -euxo pipefail ./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: @@ -342,9 +387,22 @@ jobs: MVN_ARGS+=("-Dcmake.generator=${CMAKE_GENERATOR}") fi "${MVN_ARGS[@]}" + - 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-${{ matrix.package_classifier }}.zip + name: ${{ steps.pkg.outputs.name }} + path: ${{ steps.pkg.outputs.path }} if-no-files-found: error 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/pom.xml b/example/client-c-example/pom.xml index 3116c0fd0b4f2..49b048559ddc5 100644 --- a/example/client-c-example/pom.xml +++ b/example/client-c-example/pom.xml @@ -84,8 +84,14 @@ client-cpp ${project.version} zip - cpp-${os.classifier} + ${os.classifier} true + + + ^[^/]+/(.*)$ + $1 + + ${project.build.directory}/client diff --git a/example/client-cpp-example/README.md b/example/client-cpp-example/README.md index dd7afd671aafa..fa45dd4d2eed7 100644 --- a/example/client-cpp-example/README.md +++ b/example/client-cpp-example/README.md @@ -41,7 +41,7 @@ user `root` / `root`). Release CI ([client-cpp-package.yml](../../.github/workflows/client-cpp-package.yml)) publishes one zip per platform/toolchain: -`client-cpp--cpp-.zip`. +`client-cpp--.zip` (root folder `client-cpp--/` with `include/` and `lib/`). | Deployment target | Classifier suffix | |-------------------|-------------------| diff --git a/example/client-cpp-example/README_zh.md b/example/client-cpp-example/README_zh.md index 557a4f222f605..abdc8b72b5a8e 100644 --- a/example/client-cpp-example/README_zh.md +++ b/example/client-cpp-example/README_zh.md @@ -40,7 +40,7 @@ CI 发版([client-cpp-package.yml](../../.github/workflows/client-cpp-package.yml)) 会按平台/工具链打出多份 zip,文件名形如 -`client-cpp--cpp-.zip`。请按目标环境选择: +`client-cpp--.zip`(解压后为 `client-cpp--/`,内含 `include/` 与 `lib/`)。请按目标环境选择: | 目标环境 | classifier 后缀 | |----------|-----------------| diff --git a/example/client-cpp-example/pom.xml b/example/client-cpp-example/pom.xml index c19eb69214e18..50931fd9356dd 100644 --- a/example/client-cpp-example/pom.xml +++ b/example/client-cpp-example/pom.xml @@ -98,8 +98,14 @@ client-cpp ${project.version} zip - cpp-${os.classifier} + ${os.classifier} true + + + ^[^/]+/(.*)$ + $1 + + ${project.build.directory}/client diff --git a/example/client-cpp-example/src/CMakeLists.txt b/example/client-cpp-example/src/CMakeLists.txt index b9ea2dfacbd9e..4d03ce0c6bc57 100644 --- a/example/client-cpp-example/src/CMakeLists.txt +++ b/example/client-cpp-example/src/CMakeLists.txt @@ -65,7 +65,7 @@ endif() if(NOT EXISTS "${_iotdb_link_lib}") message(FATAL_ERROR "IoTDB SDK not found at ${IOTDB_SDK_ROOT}. " - "Unpack client-cpp--cpp-.zip so that ${_iotdb_link_lib} exists.") + "Unpack client-cpp--.zip so that ${_iotdb_link_lib} exists.") endif() ADD_EXECUTABLE(SessionExample SessionExample.cpp) diff --git a/iotdb-client/client-cpp/README.md b/iotdb-client/client-cpp/README.md index c35bbe31e239f..56dd5925bf1ff 100644 --- a/iotdb-client/client-cpp/README.md +++ b/iotdb-client/client-cpp/README.md @@ -65,7 +65,8 @@ During configure CMake will, in order: | 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--cpp-.zip`, +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. @@ -88,7 +89,7 @@ deployment environment: | Windows + Visual Studio 2026 | `windows-x86_64-vs2026` | Example file name: -`client-cpp-2.0.7-SNAPSHOT-cpp-linux-x86_64-glibc217.zip`. +`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 @@ -287,10 +288,10 @@ JDK 11+). ## Package layout A successful `mvn ... package` produces -`target/client-cpp--cpp-.zip` with the historical layout: +`target/client-cpp--.zip` with this layout: ``` -. +client-cpp--/ ├── include/ │ ├── Session.h │ ├── SessionC.h diff --git a/iotdb-client/client-cpp/pom.xml b/iotdb-client/client-cpp/pom.xml index 8aa3889a2a28f..3eb7fad711772 100644 --- a/iotdb-client/client-cpp/pom.xml +++ b/iotdb-client/client-cpp/pom.xml @@ -164,7 +164,7 @@ - + org.apache.maven.plugins maven-assembly-plugin diff --git a/iotdb-client/client-cpp/src/assembly/client-cpp.xml b/iotdb-client/client-cpp/src/assembly/client-cpp.xml index a9ae8277f585c..fc2bf5777d06b 100644 --- a/iotdb-client/client-cpp/src/assembly/client-cpp.xml +++ b/iotdb-client/client-cpp/src/assembly/client-cpp.xml @@ -19,16 +19,17 @@ --> - cpp-${client.cpp.package.classifier} + ${client.cpp.package.classifier} zip dir - false + true + ${project.artifactId}-${project.version}-${client.cpp.package.classifier} ${project.build.directory}/install/include From 776f65af01764b63c279a7f287d7f87df371922c Mon Sep 17 00:00:00 2001 From: 761417898 <761417898@qq.com> Date: Tue, 26 May 2026 12:22:04 +0800 Subject: [PATCH 15/28] fix(ci): pin CentOS7 SCLo repos to vault 7.9.2009 for glibc217 centos-sclo-sclo baseurl with releasever=7 404s on vault; rewrite SCLo repo files and refresh yum cache before devtoolset-8 install. --- .github/scripts/package-client-cpp-centos7.sh | 56 +++++++++++++++---- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/.github/scripts/package-client-cpp-centos7.sh b/.github/scripts/package-client-cpp-centos7.sh index 46376b677f4d7..1e240d75be603 100644 --- a/.github/scripts/package-client-cpp-centos7.sh +++ b/.github/scripts/package-client-cpp-centos7.sh @@ -17,22 +17,54 @@ # Build client-cpp inside CentOS 7 + devtoolset-8 for glibc 2.17-compatible .so. set -euxo pipefail -# CentOS 7 EOL: point mirrorlist/baseurl entries at vault.centos.org. -fix_centos_vault_repos() { - find /etc/yum.repos.d/ -name 'CentOS*.repo' -print0 | while IFS= read -r -d '' repo_file; do - if grep -qE '^mirrorlist=' "${repo_file}"; then - sed -i 's/^mirrorlist=/#mirrorlist=/g' "${repo_file}" - sed -i 's|^#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' "${repo_file}" - fi - sed -i 's|http://mirror.centos.org|http://vault.centos.org|g' "${repo_file}" +# CentOS 7 EOL: redirect yum repos to vault.centos.org (see CentOS wiki / SIG SCLo). +fix_yum_vault_repos() { + local repo + for repo in /etc/yum.repos.d/*.repo; do + [[ -f "${repo}" ]] || continue + sed -i \ + -e 's/mirror\.centos\.org/vault.centos.org/g' \ + -e 's/^mirrorlist=/#mirrorlist=/g' \ + -e 's/^#baseurl=/baseurl=/g' \ + -e 's/^# baseurl=/baseurl=/g' \ + "${repo}" done } -# Base repos first; centos-release-scl adds CentOS-SCLo-*.repo (needed for devtoolset-8). -fix_centos_vault_repos +# SCLo packages live under vault .../7.9.2009/sclo/... ; $releasever is "7" in the image. +write_sclo_vault_repos() { + cat > /etc/yum.repos.d/CentOS-SCLo-scl.repo <<'EOF' +[centos-sclo-sclo] +name=CentOS-7 - SCLo sclo +baseurl=http://vault.centos.org/centos/7.9.2009/sclo/$basearch/sclo/ +gpgcheck=1 +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-SCLo + +[centos-sclo-scl] +name=CentOS-7 - SCLo scl +baseurl=http://vault.centos.org/centos/7.9.2009/sclo/$basearch/scl/ +gpgcheck=1 +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-SCLo +EOF + + cat > /etc/yum.repos.d/CentOS-SCLo-scl-rh.repo <<'EOF' +[centos-sclo-rh] +name=CentOS-7 - SCLo rh +baseurl=http://vault.centos.org/centos/7.9.2009/sclo/$basearch/rh/ +gpgcheck=1 +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-SCLo +EOF +} + +fix_yum_vault_repos yum install -y ca-certificates centos-release-scl epel-release -# SCLo repo files appear only after centos-release-scl is installed. -fix_centos_vault_repos +write_sclo_vault_repos +fix_yum_vault_repos +yum clean all +yum makecache -y yum install -y devtoolset-8-gcc devtoolset-8-gcc-c++ devtoolset-8-binutils \ devtoolset-8-libstdc++-devel scl-utils \ From 6226915c0aa5348d43dea4f0bfc076501c0a07ac Mon Sep 17 00:00:00 2001 From: 761417898 <761417898@qq.com> Date: Tue, 26 May 2026 12:34:04 +0800 Subject: [PATCH 16/28] fix(ci): build glibc217 in manylinux2014 job container Replace docker run on ubuntu-22.04 with job-level container quay.io/pypa/manylinux2014_x86_64 and checkout@v4, matching PyPA manylinux CI style. --- .github/scripts/package-client-cpp-centos7.sh | 2 +- .github/workflows/client-cpp-package.yml | 22 ++++++------------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/.github/scripts/package-client-cpp-centos7.sh b/.github/scripts/package-client-cpp-centos7.sh index 1e240d75be603..55f894d54a700 100644 --- a/.github/scripts/package-client-cpp-centos7.sh +++ b/.github/scripts/package-client-cpp-centos7.sh @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # -# Build client-cpp inside CentOS 7 + devtoolset-8 for glibc 2.17-compatible .so. +# Build client-cpp on manylinux2014 (CentOS 7, glibc 2.17 baseline) with devtoolset-8. set -euxo pipefail # CentOS 7 EOL: redirect yum repos to vault.centos.org (see CentOS wiki / SIG SCLo). diff --git a/.github/workflows/client-cpp-package.yml b/.github/workflows/client-cpp-package.yml index c9d91cd3088bb..d14fe24d8fb2f 100644 --- a/.github/workflows/client-cpp-package.yml +++ b/.github/workflows/client-cpp-package.yml @@ -159,12 +159,13 @@ jobs: 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' - # No job container: checkout uses Node 24 (needs glibc 2.27+); build runs in CentOS 7 via docker. - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest + container: + image: quay.io/pypa/manylinux2014_x86_64 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v4 - name: Cache Maven packages - uses: actions/cache@v5 + uses: actions/cache@v4 with: path: ~/.m2 key: linux-glibc217-m2-${{ hashFiles('**/pom.xml') }} @@ -175,16 +176,7 @@ jobs: run: | set -euxo pipefail chmod +x .github/scripts/package-client-cpp-centos7.sh - docker run --rm \ - -v "${{ github.workspace }}:/work" \ - -v "${HOME}/.m2:/root/.m2" \ - -w /work \ - -e GITHUB_WORKSPACE=/work \ - quay.io/centos/centos:7 \ - bash .github/scripts/package-client-cpp-centos7.sh - - name: Restore workspace ownership after container build - if: always() - run: sudo chown -R "$(id -u):$(id -g)" "${{ github.workspace }}" + bash .github/scripts/package-client-cpp-centos7.sh - name: Resolve package zip id: pkg shell: bash @@ -199,7 +191,7 @@ jobs: echo "path=${zips[0]}" >> "$GITHUB_OUTPUT" echo "name=$(basename "${zips[0]}" .zip)" >> "$GITHUB_OUTPUT" - name: Upload zip artifact - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v4 with: name: ${{ steps.pkg.outputs.name }} path: ${{ steps.pkg.outputs.path }} From f633f3b9b97d7c4aa1663cd65b912794a2a9cc7c Mon Sep 17 00:00:00 2001 From: 761417898 <761417898@qq.com> Date: Tue, 26 May 2026 12:38:31 +0800 Subject: [PATCH 17/28] fix(ci): host checkout + docker manylinux2014 for glibc217 Job container cannot run Node-based actions on glibc 2.17. Run checkout/cache on ubuntu-latest and build inside manylinux2014 via docker run; use preinstalled devtoolset-10 in the image. --- .github/scripts/package-client-cpp-centos7.sh | 62 +++++++++++++------ .github/workflows/client-cpp-package.yml | 20 ++++-- 2 files changed, 56 insertions(+), 26 deletions(-) diff --git a/.github/scripts/package-client-cpp-centos7.sh b/.github/scripts/package-client-cpp-centos7.sh index 55f894d54a700..04ed0c879cc49 100644 --- a/.github/scripts/package-client-cpp-centos7.sh +++ b/.github/scripts/package-client-cpp-centos7.sh @@ -14,9 +14,19 @@ # See the License for the specific language governing permissions and # limitations under the License. # -# Build client-cpp on manylinux2014 (CentOS 7, glibc 2.17 baseline) with devtoolset-8. +# Build client-cpp for glibc 2.17 baseline (manylinux2014 or CentOS 7 + devtoolset-8). set -euxo pipefail +run_maven_build() { + 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=linux-x86_64-glibc217 +} + # CentOS 7 EOL: redirect yum repos to vault.centos.org (see CentOS wiki / SIG SCLo). fix_yum_vault_repos() { local repo @@ -59,16 +69,24 @@ gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-SCLo EOF } -fix_yum_vault_repos -yum install -y ca-certificates centos-release-scl epel-release -write_sclo_vault_repos -fix_yum_vault_repos -yum clean all -yum makecache -y +install_centos7_devtoolset8() { + fix_yum_vault_repos + yum install -y ca-certificates centos-release-scl epel-release + write_sclo_vault_repos + fix_yum_vault_repos + yum clean all + yum makecache -y + yum install -y devtoolset-8-gcc devtoolset-8-gcc-c++ devtoolset-8-binutils \ + devtoolset-8-libstdc++-devel scl-utils \ + make wget tar which git patch unzip bzip2 +} -yum install -y devtoolset-8-gcc devtoolset-8-gcc-c++ devtoolset-8-binutils \ - devtoolset-8-libstdc++-devel scl-utils \ - make wget tar which git patch unzip bzip2 +if [[ -x /opt/rh/devtoolset-10/root/usr/bin/gcc ]]; then + # manylinux2014_x86_64 ships devtoolset-10 on PATH for glibc 2.17-compatible builds. + yum install -y wget tar which git patch unzip bzip2 || true +else + install_centos7_devtoolset8 +fi CMAKE_VERSION=3.28.4 CMAKE_DIR=/opt/cmake-${CMAKE_VERSION} @@ -96,16 +114,20 @@ fi export PATH="${CMAKE_DIR}/bin:${JAVA_HOME}/bin:${PATH}" export JAVA_HOME -scl enable devtoolset-8 -- bash -c ' - set -euxo pipefail - 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=linux-x86_64-glibc217 -' +if [[ -x /opt/rh/devtoolset-10/root/usr/bin/gcc ]]; then + run_maven_build +else + scl enable devtoolset-8 -- bash -c ' + set -euxo pipefail + 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=linux-x86_64-glibc217 + ' +fi SO="iotdb-client/client-cpp/target/install/lib/libiotdb_session.so" test -f "${SO}" diff --git a/.github/workflows/client-cpp-package.yml b/.github/workflows/client-cpp-package.yml index d14fe24d8fb2f..1c03973a29170 100644 --- a/.github/workflows/client-cpp-package.yml +++ b/.github/workflows/client-cpp-package.yml @@ -159,13 +159,12 @@ jobs: 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 - container: - image: quay.io/pypa/manylinux2014_x86_64 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Cache Maven packages - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ~/.m2 key: linux-glibc217-m2-${{ hashFiles('**/pom.xml') }} @@ -176,7 +175,16 @@ jobs: run: | set -euxo pipefail chmod +x .github/scripts/package-client-cpp-centos7.sh - bash .github/scripts/package-client-cpp-centos7.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-centos7.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 @@ -191,7 +199,7 @@ jobs: echo "path=${zips[0]}" >> "$GITHUB_OUTPUT" echo "name=$(basename "${zips[0]}" .zip)" >> "$GITHUB_OUTPUT" - name: Upload zip artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: ${{ steps.pkg.outputs.name }} path: ${{ steps.pkg.outputs.path }} From 8cacdb1f43dfbe5854cc00895fc4463f3c05c62e Mon Sep 17 00:00:00 2001 From: 761417898 <761417898@qq.com> Date: Tue, 26 May 2026 14:49:12 +0800 Subject: [PATCH 18/28] fix(ci): avoid SIGPIPE 141 from head/tail under pipefail Replace ldd | head -1 with sed -n 1p and find | head -1 with find -quit so glibc checks do not fail after a successful build. --- .github/scripts/package-client-cpp-centos7.sh | 4 ++-- .github/scripts/package-client-cpp-ubuntu20-arm.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/scripts/package-client-cpp-centos7.sh b/.github/scripts/package-client-cpp-centos7.sh index 04ed0c879cc49..2327d07e0b1a9 100644 --- a/.github/scripts/package-client-cpp-centos7.sh +++ b/.github/scripts/package-client-cpp-centos7.sh @@ -106,7 +106,7 @@ if [[ ! -x "${JAVA_HOME}/bin/java" ]]; then 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*' | head -1) + 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 @@ -133,7 +133,7 @@ SO="iotdb-client/client-cpp/target/install/lib/libiotdb_session.so" test -f "${SO}" echo "=== Build host glibc ===" -ldd --version | head -1 +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 diff --git a/.github/scripts/package-client-cpp-ubuntu20-arm.sh b/.github/scripts/package-client-cpp-ubuntu20-arm.sh index 137b517622258..8ad9fe053a673 100644 --- a/.github/scripts/package-client-cpp-ubuntu20-arm.sh +++ b/.github/scripts/package-client-cpp-ubuntu20-arm.sh @@ -41,7 +41,7 @@ export PATH="${CMAKE_DIR}/bin:${JAVA_HOME}/bin:${PATH}" java -version gcc --version cmake --version -ldd --version | head -1 +ldd --version 2>&1 | sed -n '1p' cd "${GITHUB_WORKSPACE:?GITHUB_WORKSPACE is not set}" ./mvnw clean package -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests \ From 5b50e61314c621004f9e51db8b413c9bd73d31ec Mon Sep 17 00:00:00 2001 From: 761417898 <761417898@qq.com> Date: Tue, 26 May 2026 15:33:47 +0800 Subject: [PATCH 19/28] fix(client-cpp): force x64 for Visual Studio Windows packages VS2017 generator defaults to Win32; pass -DCMAKE_GENERATOR_PLATFORM=x64 on Windows via Maven profile. Add CI PE check that iotdb_session.dll is x64. --- .github/workflows/client-cpp-package.yml | 14 ++++++++++++ iotdb-client/client-cpp/README.md | 6 +++++- iotdb-client/client-cpp/pom.xml | 27 ++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/.github/workflows/client-cpp-package.yml b/.github/workflows/client-cpp-package.yml index 1c03973a29170..a412a475c9a92 100644 --- a/.github/workflows/client-cpp-package.yml +++ b/.github/workflows/client-cpp-package.yml @@ -387,6 +387,20 @@ jobs: MVN_ARGS+=("-Dcmake.generator=${CMAKE_GENERATOR}") fi "${MVN_ARGS[@]}" + - name: Verify Windows SDK is x64 + 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 diff --git a/iotdb-client/client-cpp/README.md b/iotdb-client/client-cpp/README.md index 56dd5925bf1ff..c15326b7c081e 100644 --- a/iotdb-client/client-cpp/README.md +++ b/iotdb-client/client-cpp/README.md @@ -119,12 +119,16 @@ 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 -# Visual Studio 2017 +# 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 All of these can be set on the Maven command line (`-DWITH_SSL=ON`, etc.) or diff --git a/iotdb-client/client-cpp/pom.xml b/iotdb-client/client-cpp/pom.xml index 3eb7fad711772..d08619bbb40e0 100644 --- a/iotdb-client/client-cpp/pom.xml +++ b/iotdb-client/client-cpp/pom.xml @@ -258,6 +258,33 @@ win + + + client-cpp-vs-x64 + + + windows + + + + + + io.github.cmake-maven-plugin + cmake-maven-plugin + + + cmake-generate + + + + + + + + + + + .skipTests From 1e3cb7b5c65d0ea5d2a1f4421a7c896222431516 Mon Sep 17 00:00:00 2001 From: 761417898 <761417898@qq.com> Date: Tue, 26 May 2026 15:47:55 +0800 Subject: [PATCH 20/28] fix(ci): build linux-aarch64 glibc217 with manylinux2014 Use manylinux2014_aarch64 and the shared packaging script instead of Ubuntu 20.04 glibc231. Extend the script for aarch64 CMake/JDK arch and classifier auto-detection. Update docs and remove the obsolete ubuntu20-arm script. --- .github/scripts/package-client-cpp-centos7.sh | 45 +++++++++++--- .../package-client-cpp-ubuntu20-arm.sh | 62 ------------------- .github/workflows/client-cpp-package.yml | 25 ++++---- example/client-cpp-example/README.md | 2 +- example/client-cpp-example/README_zh.md | 2 +- iotdb-client/client-cpp/README.md | 2 +- iotdb-client/client-cpp/pom.xml | 2 +- 7 files changed, 52 insertions(+), 88 deletions(-) delete mode 100644 .github/scripts/package-client-cpp-ubuntu20-arm.sh diff --git a/.github/scripts/package-client-cpp-centos7.sh b/.github/scripts/package-client-cpp-centos7.sh index 2327d07e0b1a9..80b9536f9504f 100644 --- a/.github/scripts/package-client-cpp-centos7.sh +++ b/.github/scripts/package-client-cpp-centos7.sh @@ -14,9 +14,34 @@ # See the License for the specific language governing permissions and # limitations under the License. # -# Build client-cpp for glibc 2.17 baseline (manylinux2014 or CentOS 7 + devtoolset-8). +# Build client-cpp for glibc 2.17 baseline (manylinux2014 x86_64/aarch64, or CentOS 7 fallback). +# Set PACKAGE_CLASSIFIER (e.g. linux-x86_64-glibc217 / linux-aarch64-glibc217). set -euxo pipefail +MACHINE=$(uname -m) +case "${MACHINE}" in + x86_64) + CMAKE_PKG_ARCH=linux-x86_64 + JDK_API_ARCH=linux/x64 + ;; + aarch64) + CMAKE_PKG_ARCH=linux-aarch64 + JDK_API_ARCH=linux/aarch64 + ;; + *) + echo "Unsupported architecture: ${MACHINE}" >&2 + exit 1 + ;; +esac + +if [[ -z "${PACKAGE_CLASSIFIER:-}" ]]; then + if [[ "${MACHINE}" == "x86_64" ]]; then + PACKAGE_CLASSIFIER=linux-x86_64-glibc217 + else + PACKAGE_CLASSIFIER=linux-aarch64-glibc217 + fi +fi + run_maven_build() { gcc --version cmake --version @@ -24,7 +49,7 @@ run_maven_build() { 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=linux-x86_64-glibc217 + -Dclient.cpp.package.classifier="${PACKAGE_CLASSIFIER}" } # CentOS 7 EOL: redirect yum repos to vault.centos.org (see CentOS wiki / SIG SCLo). @@ -82,7 +107,7 @@ install_centos7_devtoolset8() { } if [[ -x /opt/rh/devtoolset-10/root/usr/bin/gcc ]]; then - # manylinux2014_x86_64 ships devtoolset-10 on PATH for glibc 2.17-compatible builds. + # manylinux2014 images ship devtoolset-10 on PATH for glibc 2.17-compatible builds. yum install -y wget tar which git patch unzip bzip2 || true else install_centos7_devtoolset8 @@ -91,18 +116,18 @@ fi CMAKE_VERSION=3.28.4 CMAKE_DIR=/opt/cmake-${CMAKE_VERSION} if [[ ! -x "${CMAKE_DIR}/bin/cmake" ]]; then - wget -q "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-linux-x86_64.tar.gz" \ + wget -q "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-${CMAKE_PKG_ARCH}.tar.gz" \ -O /tmp/cmake.tar.gz rm -rf "${CMAKE_DIR}" mkdir -p /opt tar xf /tmp/cmake.tar.gz -C /opt - mv "/opt/cmake-${CMAKE_VERSION}-linux-x86_64" "${CMAKE_DIR}" + mv "/opt/cmake-${CMAKE_VERSION}-${CMAKE_PKG_ARCH}" "${CMAKE_DIR}" fi JAVA_HOME=/opt/jdk-17 if [[ ! -x "${JAVA_HOME}/bin/java" ]]; then wget -qL -O /tmp/jdk17.tar.gz \ - "https://api.adoptium.net/v3/binary/latest/17/ga/linux/x64/jdk/hotspot/normal/eclipse?project=jdk" + "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 @@ -117,16 +142,16 @@ export JAVA_HOME if [[ -x /opt/rh/devtoolset-10/root/usr/bin/gcc ]]; then run_maven_build else - scl enable devtoolset-8 -- bash -c ' + scl enable devtoolset-8 -- bash -c " set -euxo pipefail gcc --version cmake --version java -version - cd "${GITHUB_WORKSPACE:?GITHUB_WORKSPACE is not set}" + 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=linux-x86_64-glibc217 - ' + -Dclient.cpp.package.classifier=${PACKAGE_CLASSIFIER} + " fi SO="iotdb-client/client-cpp/target/install/lib/libiotdb_session.so" diff --git a/.github/scripts/package-client-cpp-ubuntu20-arm.sh b/.github/scripts/package-client-cpp-ubuntu20-arm.sh deleted file mode 100644 index 8ad9fe053a673..0000000000000 --- a/.github/scripts/package-client-cpp-ubuntu20-arm.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/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 on Ubuntu 20.04 aarch64 (glibc 2.31 baseline). -set -euxo pipefail - -export DEBIAN_FRONTEND=noninteractive -apt-get update -apt-get install -y build-essential wget git ca-certificates \ - openjdk-17-jdk binutils - -# Ubuntu 20.04 ships CMake 3.16; FetchBoost.cmake needs ARCHIVE_EXTRACT (3.18+). -CMAKE_VERSION=3.28.4 -CMAKE_DIR=/opt/cmake-${CMAKE_VERSION} -if [[ ! -x "${CMAKE_DIR}/bin/cmake" ]]; then - wget -q "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-linux-aarch64.tar.gz" \ - -O /tmp/cmake.tar.gz - rm -rf "${CMAKE_DIR}" - mkdir -p /opt - tar xf /tmp/cmake.tar.gz -C /opt - mv "/opt/cmake-${CMAKE_VERSION}-linux-aarch64" "${CMAKE_DIR}" -fi - -JAVA_BIN=$(readlink -f "$(command -v java)") -export JAVA_HOME=$(dirname "$(dirname "${JAVA_BIN}")") -export PATH="${CMAKE_DIR}/bin:${JAVA_HOME}/bin:${PATH}" - -java -version -gcc --version -cmake --version -ldd --version 2>&1 | sed -n '1p' - -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=linux-aarch64-glibc231 - -SO="iotdb-client/client-cpp/target/install/lib/libiotdb_session.so" -test -f "${SO}" - -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.31) }"; then - echo "ERROR: libiotdb_session.so requires glibc > 2.31 (max=${max_glibc})" - exit 1 -fi - -echo "glibc compatibility check passed (max=${max_glibc} <= 2.31)" diff --git a/.github/workflows/client-cpp-package.yml b/.github/workflows/client-cpp-package.yml index a412a475c9a92..bc38f1dc893df 100644 --- a/.github/workflows/client-cpp-package.yml +++ b/.github/workflows/client-cpp-package.yml @@ -205,10 +205,11 @@ jobs: path: ${{ steps.pkg.outputs.path }} if-no-files-found: error - package-linux-aarch64-glibc231: - name: Package (linux-aarch64-glibc231) + 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 @@ -216,21 +217,21 @@ jobs: uses: actions/cache@v5 with: path: ~/.m2 - key: linux-aarch64-glibc231-m2-${{ hashFiles('**/pom.xml') }} + key: linux-aarch64-glibc217-m2-${{ hashFiles('**/pom.xml') }} restore-keys: | - linux-aarch64-glibc231-m2- - - name: Package client-cpp (glibc 2.31 baseline) + linux-aarch64-glibc217-m2- + - name: Package client-cpp (glibc 2.17 baseline) shell: bash run: | set -euxo pipefail - chmod +x .github/scripts/package-client-cpp-ubuntu20-arm.sh + chmod +x .github/scripts/package-client-cpp-centos7.sh docker run --rm \ - -v "${{ github.workspace }}:/work" \ + -v "${{ github.workspace }}:/workspace" \ -v "${HOME}/.m2:/root/.m2" \ - -w /work \ - -e GITHUB_WORKSPACE=/work \ - ubuntu:20.04 \ - bash .github/scripts/package-client-cpp-ubuntu20-arm.sh + -w /workspace \ + -e GITHUB_WORKSPACE=/workspace \ + quay.io/pypa/manylinux2014_aarch64 \ + bash .github/scripts/package-client-cpp-centos7.sh - name: Restore workspace ownership after container build if: always() run: sudo chown -R "$(id -u):$(id -g)" "${{ github.workspace }}" @@ -240,7 +241,7 @@ jobs: run: | set -euo pipefail shopt -s nullglob - zips=(iotdb-client/client-cpp/target/client-cpp-*-linux-aarch64-glibc231.zip) + 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 diff --git a/example/client-cpp-example/README.md b/example/client-cpp-example/README.md index fa45dd4d2eed7..6efabeedb69f3 100644 --- a/example/client-cpp-example/README.md +++ b/example/client-cpp-example/README.md @@ -46,7 +46,7 @@ publishes one zip per platform/toolchain: | Deployment target | Classifier suffix | |-------------------|-------------------| | Linux x86_64, glibc ≥ 2.17 | `linux-x86_64-glibc217` | -| Linux aarch64, glibc ≥ 2.31 | `linux-aarch64-glibc231` | +| 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` | diff --git a/example/client-cpp-example/README_zh.md b/example/client-cpp-example/README_zh.md index abdc8b72b5a8e..871c536e5ad9e 100644 --- a/example/client-cpp-example/README_zh.md +++ b/example/client-cpp-example/README_zh.md @@ -45,7 +45,7 @@ CI 发版([client-cpp-package.yml](../../.github/workflows/client-cpp-package. | 目标环境 | classifier 后缀 | |----------|-----------------| | Linux x86_64,glibc ≥ 2.17 | `linux-x86_64-glibc217` | -| Linux aarch64,glibc ≥ 2.31 | `linux-aarch64-glibc231` | +| 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` | diff --git a/iotdb-client/client-cpp/README.md b/iotdb-client/client-cpp/README.md index c15326b7c081e..5297bb3b37c5c 100644 --- a/iotdb-client/client-cpp/README.md +++ b/iotdb-client/client-cpp/README.md @@ -80,7 +80,7 @@ deployment environment: | Target environment | Zip classifier (suffix) | |--------------------|-------------------------| | Linux x86_64, glibc ≥ 2.17 | `linux-x86_64-glibc217` | -| Linux aarch64, glibc ≥ 2.31 | `linux-aarch64-glibc231` | +| 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` | diff --git a/iotdb-client/client-cpp/pom.xml b/iotdb-client/client-cpp/pom.xml index d08619bbb40e0..5bf68c3ee3d8f 100644 --- a/iotdb-client/client-cpp/pom.xml +++ b/iotdb-client/client-cpp/pom.xml @@ -258,7 +258,7 @@ win - + client-cpp-vs-x64 From 0b97892deb9924479c52eb34af9d931065f9a803 Mon Sep 17 00:00:00 2001 From: 761417898 <761417898@qq.com> Date: Tue, 26 May 2026 17:00:14 +0800 Subject: [PATCH 21/28] fix(client-cpp): PR review follow-ups for SDK branch Guard checkTemplateExists against a null dataset, document DataIterator lifetime, correct README Maven vs CMake option names, drop unused IotdbResolveTarball.cmake, and skip server CI when only multi-language-client workflow changes. --- .github/workflows/cluster-it-1c1d.yml | 2 + .github/workflows/cluster-it-1c1d1a.yml | 2 + .github/workflows/cluster-it-1c3d.yml | 2 + .github/workflows/compile-check.yml | 2 + .github/workflows/dependency-check.yml | 2 + .github/workflows/pipe-it.yml | 2 + .github/workflows/sonar-codecov.yml | 2 + .github/workflows/table-cluster-it-1c1d.yml | 2 + .github/workflows/table-cluster-it-1c3d.yml | 2 + .github/workflows/unit-test.yml | 2 + iotdb-client/client-cpp/README.md | 23 ++++-- .../cmake/IotdbResolveTarball.cmake | 73 ------------------- .../client-cpp/src/include/SessionDataSet.h | 1 + .../client-cpp/src/session/Session.cpp | 3 + 14 files changed, 41 insertions(+), 79 deletions(-) delete mode 100644 iotdb-client/client-cpp/cmake/IotdbResolveTarball.cmake diff --git a/.github/workflows/cluster-it-1c1d.yml b/.github/workflows/cluster-it-1c1d.yml index 5840b6f930c8d..275e5002d4324 100644 --- a/.github/workflows/cluster-it-1c1d.yml +++ b/.github/workflows/cluster-it-1c1d.yml @@ -14,6 +14,7 @@ on: - ".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 @@ -27,6 +28,7 @@ on: - ".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 687520ff22187..5e132ea3145b2 100644 --- a/.github/workflows/cluster-it-1c1d1a.yml +++ b/.github/workflows/cluster-it-1c1d1a.yml @@ -14,6 +14,7 @@ on: - '.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 @@ -28,6 +29,7 @@ on: - '.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 42e22e050ccf6..2758b097fcca8 100644 --- a/.github/workflows/cluster-it-1c3d.yml +++ b/.github/workflows/cluster-it-1c3d.yml @@ -14,6 +14,7 @@ on: - ".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 @@ -28,6 +29,7 @@ on: - ".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 8e1f6cafc7678..eaac65a47c469 100644 --- a/.github/workflows/compile-check.yml +++ b/.github/workflows/compile-check.yml @@ -16,6 +16,7 @@ on: - ".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 @@ -30,6 +31,7 @@ on: - ".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 277e1133e5c5d..67b2054ec9605 100644 --- a/.github/workflows/dependency-check.yml +++ b/.github/workflows/dependency-check.yml @@ -16,6 +16,7 @@ on: - ".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 @@ -30,6 +31,7 @@ on: - ".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/pipe-it.yml b/.github/workflows/pipe-it.yml index eedacc7e8a636..a25072a618950 100644 --- a/.github/workflows/pipe-it.yml +++ b/.github/workflows/pipe-it.yml @@ -14,6 +14,7 @@ on: - ".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: @@ -29,6 +30,7 @@ on: - ".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 486793c33dfd0..810cf91b2e561 100644 --- a/.github/workflows/sonar-codecov.yml +++ b/.github/workflows/sonar-codecov.yml @@ -17,6 +17,7 @@ on: - ".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 @@ -32,6 +33,7 @@ on: - ".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 a51bd20d56461..f47d84967c5e5 100644 --- a/.github/workflows/table-cluster-it-1c1d.yml +++ b/.github/workflows/table-cluster-it-1c1d.yml @@ -14,6 +14,7 @@ on: - ".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 @@ -28,6 +29,7 @@ on: - ".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 c74f467a156c3..a8498732d6f7d 100644 --- a/.github/workflows/table-cluster-it-1c3d.yml +++ b/.github/workflows/table-cluster-it-1c3d.yml @@ -14,6 +14,7 @@ on: - ".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 @@ -28,6 +29,7 @@ on: - ".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 f775b46acad1a..ca4130d901580 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -17,6 +17,7 @@ on: - ".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 @@ -31,6 +32,7 @@ on: - ".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/iotdb-client/client-cpp/README.md b/iotdb-client/client-cpp/README.md index 5297bb3b37c5c..12c70ce05d3f1 100644 --- a/iotdb-client/client-cpp/README.md +++ b/iotdb-client/client-cpp/README.md @@ -127,12 +127,22 @@ mvn -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests ` On Windows, the build passes `-DCMAKE_GENERATOR_PLATFORM=x64` so Visual Studio generators target **x64** (VS2017 otherwise defaults to Win32). -``` ## CMake options -All of these can be set on the Maven command line (`-DWITH_SSL=ON`, etc.) or -passed directly to `cmake`. +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 | |-----------------------|----------------------------------|----------------------------------------------------------------------------------------------------------| @@ -178,11 +188,11 @@ mvn -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests "-Dboost.include.dir - GNU bison 3.8: - OpenSSL 3.5.0: -2. Run the build with `-DIOTDB_OFFLINE=ON`: +2. Run the build with offline mode enabled: ```bash mvn -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests \ - -DIOTDB_OFFLINE=ON package + -Diotdb.offline=ON package ``` or, going straight through CMake: @@ -247,7 +257,8 @@ the GNU autotools tarballs assume a POSIX shell environment. ## SSL Both Thrift and `iotdb_session` build without OpenSSL by default. Enable -SSL support with `-DWITH_SSL=ON`. CMake first calls `find_package(OpenSSL)`; +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 diff --git a/iotdb-client/client-cpp/cmake/IotdbResolveTarball.cmake b/iotdb-client/client-cpp/cmake/IotdbResolveTarball.cmake deleted file mode 100644 index 69c06bea3f5b7..0000000000000 --- a/iotdb-client/client-cpp/cmake/IotdbResolveTarball.cmake +++ /dev/null @@ -1,73 +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. -# -# ============================================================================= -# IotdbResolveTarball.cmake -# -# Shared helper used by FetchBuildTools, FetchThrift, etc. -# -# Resolution order: -# 1. Exact filename under ${IOTDB_OS_DEPS_DIR}/ -# 2. Optional GLOB_PATTERN match under ${IOTDB_OS_DEPS_DIR}/ -# 3. file(DOWNLOAD) into ${IOTDB_OS_DEPS_DIR}/ when IOTDB_OFFLINE is OFF -# 4. FATAL_ERROR otherwise -# ============================================================================= - -function(_iotdb_resolve_tarball OUT_VAR FILENAME URL) - cmake_parse_arguments(ARG "" "GLOB_PATTERN;LOG_PREFIX" "" ${ARGN}) - if(NOT ARG_LOG_PREFIX) - set(ARG_LOG_PREFIX "Deps") - endif() - - set(_local "${IOTDB_OS_DEPS_DIR}/${FILENAME}") - if(EXISTS "${_local}") - message(STATUS "[${ARG_LOG_PREFIX}] using ${_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 "[${ARG_LOG_PREFIX}] 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 - "[${ARG_LOG_PREFIX}] IOTDB_OFFLINE=ON but ${_hint} is missing in " - "${IOTDB_OS_DEPS_DIR}.") - endif() - - message(STATUS "[${ARG_LOG_PREFIX}] 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 "[${ARG_LOG_PREFIX}] download failed for ${FILENAME}: ${_msg}") - endif() - message(STATUS "[${ARG_LOG_PREFIX}] cached ${_local}") - set(${OUT_VAR} "${_local}" PARENT_SCOPE) -endfunction() diff --git a/iotdb-client/client-cpp/src/include/SessionDataSet.h b/iotdb-client/client-cpp/src/include/SessionDataSet.h index dc0f7dc421de8..9afe01e82b24c 100644 --- a/iotdb-client/client-cpp/src/include/SessionDataSet.h +++ b/iotdb-client/client-cpp/src/include/SessionDataSet.h @@ -117,6 +117,7 @@ class SessionDataSet { const std::vector& getColumnTypeList() const; }; + // The returned iterator must not outlive this SessionDataSet. DataIterator getIterator(); }; diff --git a/iotdb-client/client-cpp/src/session/Session.cpp b/iotdb-client/client-cpp/src/session/Session.cpp index ca38ddd59c025..8636be085f5c1 100644 --- a/iotdb-client/client-cpp/src/session/Session.cpp +++ b/iotdb-client/client-cpp/src/session/Session.cpp @@ -2330,6 +2330,9 @@ bool Session::checkTemplateExists(const string& template_name) { try { std::unique_ptr dataset = executeQueryStatement("SHOW NODES IN DEVICE TEMPLATE " + template_name); + if (dataset == nullptr) { + throw IoTDBException("executeQueryStatement failed"); + } bool isExisted = dataset->hasNext(); dataset->closeOperationHandle(); return isExisted; From 2877b2d1a97a6474acf8d5970442bfbae651f9e7 Mon Sep 17 00:00:00 2001 From: 761417898 <761417898@qq.com> Date: Wed, 27 May 2026 16:35:17 +0800 Subject: [PATCH 22/28] chore(ci): slim manylinux glibc217 package path Rename the Linux packaging helper to a manylinux-specific script, drop unused CentOS7 fallback branches, and keep only build plus GLIBC<=2.17 verification steps. Also add concise C++ workflow comments and unify client-cpp CMake minimum version to 3.15. --- .github/scripts/package-client-cpp-centos7.sh | 174 ------------------ .../package-client-cpp-manylinux-glibc217.sh | 90 +++++++++ .github/workflows/client-cpp-package.yml | 19 +- .github/workflows/client-cpp-source-build.yml | 8 +- .github/workflows/multi-language-client.yml | 2 + example/client-cpp-example/src/CMakeLists.txt | 2 +- iotdb-client/client-cpp/CMakeLists.txt | 2 +- 7 files changed, 109 insertions(+), 188 deletions(-) delete mode 100644 .github/scripts/package-client-cpp-centos7.sh create mode 100644 .github/scripts/package-client-cpp-manylinux-glibc217.sh diff --git a/.github/scripts/package-client-cpp-centos7.sh b/.github/scripts/package-client-cpp-centos7.sh deleted file mode 100644 index 80b9536f9504f..0000000000000 --- a/.github/scripts/package-client-cpp-centos7.sh +++ /dev/null @@ -1,174 +0,0 @@ -#!/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 for glibc 2.17 baseline (manylinux2014 x86_64/aarch64, or CentOS 7 fallback). -# Set PACKAGE_CLASSIFIER (e.g. linux-x86_64-glibc217 / linux-aarch64-glibc217). -set -euxo pipefail - -MACHINE=$(uname -m) -case "${MACHINE}" in - x86_64) - CMAKE_PKG_ARCH=linux-x86_64 - JDK_API_ARCH=linux/x64 - ;; - aarch64) - CMAKE_PKG_ARCH=linux-aarch64 - JDK_API_ARCH=linux/aarch64 - ;; - *) - echo "Unsupported architecture: ${MACHINE}" >&2 - exit 1 - ;; -esac - -if [[ -z "${PACKAGE_CLASSIFIER:-}" ]]; then - if [[ "${MACHINE}" == "x86_64" ]]; then - PACKAGE_CLASSIFIER=linux-x86_64-glibc217 - else - PACKAGE_CLASSIFIER=linux-aarch64-glibc217 - fi -fi - -run_maven_build() { - 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}" -} - -# CentOS 7 EOL: redirect yum repos to vault.centos.org (see CentOS wiki / SIG SCLo). -fix_yum_vault_repos() { - local repo - for repo in /etc/yum.repos.d/*.repo; do - [[ -f "${repo}" ]] || continue - sed -i \ - -e 's/mirror\.centos\.org/vault.centos.org/g' \ - -e 's/^mirrorlist=/#mirrorlist=/g' \ - -e 's/^#baseurl=/baseurl=/g' \ - -e 's/^# baseurl=/baseurl=/g' \ - "${repo}" - done -} - -# SCLo packages live under vault .../7.9.2009/sclo/... ; $releasever is "7" in the image. -write_sclo_vault_repos() { - cat > /etc/yum.repos.d/CentOS-SCLo-scl.repo <<'EOF' -[centos-sclo-sclo] -name=CentOS-7 - SCLo sclo -baseurl=http://vault.centos.org/centos/7.9.2009/sclo/$basearch/sclo/ -gpgcheck=1 -enabled=1 -gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-SCLo - -[centos-sclo-scl] -name=CentOS-7 - SCLo scl -baseurl=http://vault.centos.org/centos/7.9.2009/sclo/$basearch/scl/ -gpgcheck=1 -enabled=1 -gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-SCLo -EOF - - cat > /etc/yum.repos.d/CentOS-SCLo-scl-rh.repo <<'EOF' -[centos-sclo-rh] -name=CentOS-7 - SCLo rh -baseurl=http://vault.centos.org/centos/7.9.2009/sclo/$basearch/rh/ -gpgcheck=1 -enabled=1 -gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-SCLo -EOF -} - -install_centos7_devtoolset8() { - fix_yum_vault_repos - yum install -y ca-certificates centos-release-scl epel-release - write_sclo_vault_repos - fix_yum_vault_repos - yum clean all - yum makecache -y - yum install -y devtoolset-8-gcc devtoolset-8-gcc-c++ devtoolset-8-binutils \ - devtoolset-8-libstdc++-devel scl-utils \ - make wget tar which git patch unzip bzip2 -} - -if [[ -x /opt/rh/devtoolset-10/root/usr/bin/gcc ]]; then - # manylinux2014 images ship devtoolset-10 on PATH for glibc 2.17-compatible builds. - yum install -y wget tar which git patch unzip bzip2 || true -else - install_centos7_devtoolset8 -fi - -CMAKE_VERSION=3.28.4 -CMAKE_DIR=/opt/cmake-${CMAKE_VERSION} -if [[ ! -x "${CMAKE_DIR}/bin/cmake" ]]; then - wget -q "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-${CMAKE_PKG_ARCH}.tar.gz" \ - -O /tmp/cmake.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 - wget -qL -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 - -if [[ -x /opt/rh/devtoolset-10/root/usr/bin/gcc ]]; then - run_maven_build -else - scl enable devtoolset-8 -- bash -c " - set -euxo pipefail - 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} - " -fi - -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/scripts/package-client-cpp-manylinux-glibc217.sh b/.github/scripts/package-client-cpp-manylinux-glibc217.sh new file mode 100644 index 0000000000000..e99b221ea7c6b --- /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 + wget -q "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-${CMAKE_PKG_ARCH}.tar.gz" -O /tmp/cmake.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 + wget -qL -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 bc38f1dc893df..b8fabcefbe1a0 100644 --- a/.github/workflows/client-cpp-package.yml +++ b/.github/workflows/client-cpp-package.yml @@ -1,7 +1,7 @@ -# 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. -# -# Produces per-platform/per-toolchain SDK zips (classifier suffix in artifact name). +# 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: @@ -39,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 }} @@ -95,6 +96,7 @@ jobs: 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 @@ -174,14 +176,14 @@ jobs: shell: bash run: | set -euxo pipefail - chmod +x .github/scripts/package-client-cpp-centos7.sh + 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-centos7.sh + 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 }}" @@ -224,14 +226,14 @@ jobs: shell: bash run: | set -euxo pipefail - chmod +x .github/scripts/package-client-cpp-centos7.sh + 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-centos7.sh + 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 }}" @@ -389,6 +391,7 @@ jobs: 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" diff --git a/.github/workflows/client-cpp-source-build.yml b/.github/workflows/client-cpp-source-build.yml index a58ec91bd4234..6c0ecc28e82a3 100644 --- a/.github/workflows/client-cpp-source-build.yml +++ b/.github/workflows/client-cpp-source-build.yml @@ -1,7 +1,6 @@ -# Verify client-cpp builds from a minimal toolchain: CMake downloads third-party -# sources into third-party// and compiles Thrift + iotdb_session without -# pre-installed Boost / flex / bison packages (except where the OS image lacks -# a working compiler or CMake). +# 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: @@ -105,6 +104,7 @@ jobs: ${{ 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 }} diff --git a/.github/workflows/multi-language-client.yml b/.github/workflows/multi-language-client.yml index 436bf4bfa4e38..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: @@ -88,6 +89,7 @@ jobs: 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 diff --git a/example/client-cpp-example/src/CMakeLists.txt b/example/client-cpp-example/src/CMakeLists.txt index 4d03ce0c6bc57..04a3c7dc983c5 100644 --- a/example/client-cpp-example/src/CMakeLists.txt +++ b/example/client-cpp-example/src/CMakeLists.txt @@ -16,7 +16,7 @@ # under the License. # -CMAKE_MINIMUM_REQUIRED(VERSION 3.16) +CMAKE_MINIMUM_REQUIRED(VERSION 3.15) CMAKE_POLICY(SET CMP0091 NEW) PROJECT(iotdb_cpp_client_examples) diff --git a/iotdb-client/client-cpp/CMakeLists.txt b/iotdb-client/client-cpp/CMakeLists.txt index 46983934b4661..31fbfc8f96836 100644 --- a/iotdb-client/client-cpp/CMakeLists.txt +++ b/iotdb-client/client-cpp/CMakeLists.txt @@ -19,7 +19,7 @@ # Apache IoTDB - C++ Session Client (top-level CMake build) # ============================================================================= -cmake_minimum_required(VERSION 3.16) +cmake_minimum_required(VERSION 3.15) project(iotdb_session CXX C) set(CMAKE_CXX_STANDARD 11) From 31438de7b726dbb233e26a676b4c27c9eef52425 Mon Sep 17 00:00:00 2001 From: 761417898 <761417898@qq.com> Date: Wed, 27 May 2026 16:37:11 +0800 Subject: [PATCH 23/28] refactor(client-cpp): rename IoTDBDate and move tests Rename public Date type from IoTdbDate to IoTDBDate across headers, RPC/session code, and ITs. Move tests from src/test to a top-level test directory and update CMake, Maven, and README paths accordingly. --- iotdb-client/client-cpp/CMakeLists.txt | 2 +- iotdb-client/client-cpp/README.md | 4 ++-- iotdb-client/client-cpp/pom.xml | 4 ++-- iotdb-client/client-cpp/src/include/Common.h | 6 +++--- iotdb-client/client-cpp/src/include/Date.h | 18 +++++++++--------- iotdb-client/client-cpp/src/include/Session.h | 4 ++-- .../client-cpp/src/include/SessionDataSet.h | 4 ++-- .../client-cpp/src/rpc/IoTDBRpcDataSet.cpp | 8 ++++---- .../client-cpp/src/rpc/IoTDBRpcDataSet.h | 6 +++--- iotdb-client/client-cpp/src/session/Common.cpp | 4 ++-- iotdb-client/client-cpp/src/session/Date.cpp | 10 +++++----- .../client-cpp/src/session/Session.cpp | 18 +++++++++--------- .../client-cpp/src/session/SessionDataSet.cpp | 4 ++-- .../client-cpp/{src => }/test/CMakeLists.txt | 2 +- .../client-cpp/{src => }/test/catch2/catch.hpp | 0 .../{src => }/test/cpp/sessionCIT.cpp | 0 .../test/cpp/sessionCRelationalIT.cpp | 0 .../{src => }/test/cpp/sessionIT.cpp | 4 ++-- .../{src => }/test/cpp/sessionRelationalIT.cpp | 6 +++--- .../client-cpp/{src => }/test/main.cpp | 0 .../{src => }/test/main_Relational.cpp | 0 .../client-cpp/{src => }/test/main_c.cpp | 0 .../{src => }/test/main_c_Relational.cpp | 0 23 files changed, 52 insertions(+), 52 deletions(-) rename iotdb-client/client-cpp/{src => }/test/CMakeLists.txt (98%) rename iotdb-client/client-cpp/{src => }/test/catch2/catch.hpp (100%) rename iotdb-client/client-cpp/{src => }/test/cpp/sessionCIT.cpp (100%) rename iotdb-client/client-cpp/{src => }/test/cpp/sessionCRelationalIT.cpp (100%) rename iotdb-client/client-cpp/{src => }/test/cpp/sessionIT.cpp (99%) rename iotdb-client/client-cpp/{src => }/test/cpp/sessionRelationalIT.cpp (98%) rename iotdb-client/client-cpp/{src => }/test/main.cpp (100%) rename iotdb-client/client-cpp/{src => }/test/main_Relational.cpp (100%) rename iotdb-client/client-cpp/{src => }/test/main_c.cpp (100%) rename iotdb-client/client-cpp/{src => }/test/main_c_Relational.cpp (100%) diff --git a/iotdb-client/client-cpp/CMakeLists.txt b/iotdb-client/client-cpp/CMakeLists.txt index 31fbfc8f96836..ac946faa23ed8 100644 --- a/iotdb-client/client-cpp/CMakeLists.txt +++ b/iotdb-client/client-cpp/CMakeLists.txt @@ -168,7 +168,7 @@ endforeach() if(BUILD_TESTING) enable_testing() - add_subdirectory(src/test) + add_subdirectory(test) endif() message(STATUS "iotdb_session configuration summary:") diff --git a/iotdb-client/client-cpp/README.md b/iotdb-client/client-cpp/README.md index 12c70ce05d3f1..22543c743f272 100644 --- a/iotdb-client/client-cpp/README.md +++ b/iotdb-client/client-cpp/README.md @@ -36,7 +36,7 @@ iotdb-client/client-cpp/ ├── src/include/ # public API headers (installed to include/) ├── src/session/ # Session / Table / C API implementation (.cpp) ├── src/rpc/ # Thrift RPC layer (private, not installed) -├── src/test/ # Catch2-based integration tests +├── test/ # Catch2-based integration tests └── pom.xml # Maven wrapper (cmake-maven-plugin) ``` @@ -282,7 +282,7 @@ mvn -P with-cpp -pl iotdb-client/client-cpp -am verify Running ctest directly (after a `mvn ... package` build) is also supported: ```bash -cd iotdb-client/client-cpp/target/build/src/test +cd iotdb-client/client-cpp/target/build/test ctest --output-on-failure ``` diff --git a/iotdb-client/client-cpp/pom.xml b/iotdb-client/client-cpp/pom.xml index 5bf68c3ee3d8f..b465fb09b1bfb 100644 --- a/iotdb-client/client-cpp/pom.xml +++ b/iotdb-client/client-cpp/pom.xml @@ -117,7 +117,7 @@ integration-test ${cmake.build.type} - ${cmake.project.dir}/src/test + ${cmake.project.dir}/test ${maven.test.skip} @@ -322,7 +322,7 @@ src/**/*.cpp - src/test/catch2/** + test/catch2/** ${clang.format.version} diff --git a/iotdb-client/client-cpp/src/include/Common.h b/iotdb-client/client-cpp/src/include/Common.h index b2b904689b404..49dca0bca4b14 100644 --- a/iotdb-client/client-cpp/src/include/Common.h +++ b/iotdb-client/client-cpp/src/include/Common.h @@ -155,7 +155,7 @@ class Field { TSDataType::TSDataType dataType = TSDataType::UNKNOWN; Optional boolV; Optional intV; - Optional dateV; + Optional dateV; Optional longV; Optional floatV; Optional doubleV; @@ -203,7 +203,7 @@ class MyStringBuffer { void clear(); bool hasRemaining(); int getInt(); - IoTdbDate getDate(); + IoTDBDate getDate(); int64_t getInt64(); float getFloat(); double getDouble(); @@ -212,7 +212,7 @@ class MyStringBuffer { std::string getString(); void putInt(int ins); - void putDate(IoTdbDate date); + void putDate(IoTDBDate date); void putInt64(int64_t ins); void putFloat(float ins); void putDouble(double ins); diff --git a/iotdb-client/client-cpp/src/include/Date.h b/iotdb-client/client-cpp/src/include/Date.h index e97bef6ad3c3e..e2fa114b8904c 100644 --- a/iotdb-client/client-cpp/src/include/Date.h +++ b/iotdb-client/client-cpp/src/include/Date.h @@ -24,14 +24,14 @@ constexpr int32_t EMPTY_DATE_INT = 10000101; -class IoTdbDate { +class IoTDBDate { public: - IoTdbDate() : valid_(false), year_(0), month_(0), day_(0) {} + IoTDBDate() : valid_(false), year_(0), month_(0), day_(0) {} - IoTdbDate(int year, int month, int day) : valid_(true), year_(year), month_(month), day_(day) {} + IoTDBDate(int year, int month, int day) : valid_(true), year_(year), month_(month), day_(day) {} - static IoTdbDate notADate() { - return IoTdbDate(); + static IoTDBDate notADate() { + return IoTDBDate(); } bool is_not_a_date() const { @@ -52,12 +52,12 @@ class IoTdbDate { std::string toIsoExtendedString() const; - friend bool operator==(const IoTdbDate& lhs, const IoTdbDate& rhs) { + friend bool operator==(const IoTDBDate& lhs, const IoTDBDate& rhs) { return lhs.valid_ == rhs.valid_ && lhs.year_ == rhs.year_ && lhs.month_ == rhs.month_ && lhs.day_ == rhs.day_; } - friend bool operator!=(const IoTdbDate& lhs, const IoTdbDate& rhs) { + friend bool operator!=(const IoTDBDate& lhs, const IoTDBDate& rhs) { return !(lhs == rhs); } @@ -68,7 +68,7 @@ class IoTdbDate { int day_; }; -int32_t parseDateExpressionToInt(const IoTdbDate& date); -IoTdbDate parseIntToDate(int32_t dateInt); +int32_t parseDateExpressionToInt(const IoTDBDate& date); +IoTDBDate parseIntToDate(int32_t dateInt); #endif diff --git a/iotdb-client/client-cpp/src/include/Session.h b/iotdb-client/client-cpp/src/include/Session.h index 818e49bee994e..2b5bb147849ad 100644 --- a/iotdb-client/client-cpp/src/include/Session.h +++ b/iotdb-client/client-cpp/src/include/Session.h @@ -265,7 +265,7 @@ class Tablet { break; } case TSDataType::DATE: { - safe_cast(value, ((IoTdbDate*)values[schemaId])[rowIndex]); + safe_cast(value, ((IoTDBDate*)values[schemaId])[rowIndex]); break; } case TSDataType::TIMESTAMP: @@ -373,7 +373,7 @@ class Tablet { case TSDataType::INT32: return &(reinterpret_cast(values[schemaId])[rowIndex]); case TSDataType::DATE: - return &(reinterpret_cast(values[schemaId])[rowIndex]); + return &(reinterpret_cast(values[schemaId])[rowIndex]); case TSDataType::TIMESTAMP: case TSDataType::INT64: return &(reinterpret_cast(values[schemaId])[rowIndex]); diff --git a/iotdb-client/client-cpp/src/include/SessionDataSet.h b/iotdb-client/client-cpp/src/include/SessionDataSet.h index 9afe01e82b24c..9eea926d343d9 100644 --- a/iotdb-client/client-cpp/src/include/SessionDataSet.h +++ b/iotdb-client/client-cpp/src/include/SessionDataSet.h @@ -109,8 +109,8 @@ class SessionDataSet { Optional getTimestampByIndex(int32_t columnIndex); Optional getTimestamp(const std::string& columnName); - Optional getDateByIndex(int32_t columnIndex); - Optional getDate(const std::string& columnName); + Optional getDateByIndex(int32_t columnIndex); + Optional getDate(const std::string& columnName); int32_t findColumn(const std::string& columnName); const std::vector& getColumnNames() const; diff --git a/iotdb-client/client-cpp/src/rpc/IoTDBRpcDataSet.cpp b/iotdb-client/client-cpp/src/rpc/IoTDBRpcDataSet.cpp index b6ca0b52962ea..cf8454af1a14c 100644 --- a/iotdb-client/client-cpp/src/rpc/IoTDBRpcDataSet.cpp +++ b/iotdb-client/client-cpp/src/rpc/IoTDBRpcDataSet.cpp @@ -473,20 +473,20 @@ Optional IoTDBRpcDataSet::getTimestampByTsBlockColumnIndex(int32_t tsBl return getLongByTsBlockColumnIndex(tsBlockColumnIndex); } -Optional IoTDBRpcDataSet::getDateByIndex(int32_t columnIndex) { +Optional IoTDBRpcDataSet::getDateByIndex(int32_t columnIndex) { int32_t index = getTsBlockColumnIndexForColumnIndex(columnIndex); return getDateByTsBlockColumnIndex(index); } -Optional IoTDBRpcDataSet::getDate(const std::string& columnName) { +Optional IoTDBRpcDataSet::getDate(const std::string& columnName) { int32_t index = getTsBlockColumnIndexForColumnName(columnName); return getDateByTsBlockColumnIndex(index); } -Optional IoTDBRpcDataSet::getDateByTsBlockColumnIndex(int32_t tsBlockColumnIndex) { +Optional IoTDBRpcDataSet::getDateByTsBlockColumnIndex(int32_t tsBlockColumnIndex) { auto value = getIntByTsBlockColumnIndex(tsBlockColumnIndex); if (!value.is_initialized()) { - return Optional::none(); + return Optional::none(); } return parseIntToDate(value.value()); } diff --git a/iotdb-client/client-cpp/src/rpc/IoTDBRpcDataSet.h b/iotdb-client/client-cpp/src/rpc/IoTDBRpcDataSet.h index d339edbc91031..054dd84a2e320 100644 --- a/iotdb-client/client-cpp/src/rpc/IoTDBRpcDataSet.h +++ b/iotdb-client/client-cpp/src/rpc/IoTDBRpcDataSet.h @@ -77,8 +77,8 @@ class IoTDBRpcDataSet { Optional getString(const std::string& columnName); Optional getTimestampByIndex(int32_t columnIndex); Optional getTimestamp(const std::string& columnName); - Optional getDateByIndex(int32_t columnIndex); - Optional getDate(const std::string& columnName); + Optional getDateByIndex(int32_t columnIndex); + Optional getDate(const std::string& columnName); TSDataType::TSDataType getDataTypeByIndex(int32_t columnIndex); TSDataType::TSDataType getDataType(const std::string& columnName); @@ -114,7 +114,7 @@ class IoTDBRpcDataSet { Optional getLongByTsBlockColumnIndex(int32_t tsBlockColumnIndex); std::shared_ptr getBinaryByTsBlockColumnIndex(int32_t tsBlockColumnIndex); Optional getStringByTsBlockColumnIndex(int32_t tsBlockColumnIndex); - Optional getDateByTsBlockColumnIndex(int32_t tsBlockColumnIndex); + Optional getDateByTsBlockColumnIndex(int32_t tsBlockColumnIndex); Optional getTimestampByTsBlockColumnIndex(int32_t tsBlockColumnIndex); std::string sql_; diff --git a/iotdb-client/client-cpp/src/session/Common.cpp b/iotdb-client/client-cpp/src/session/Common.cpp index 06be4790123f6..9b66734c10893 100644 --- a/iotdb-client/client-cpp/src/session/Common.cpp +++ b/iotdb-client/client-cpp/src/session/Common.cpp @@ -129,7 +129,7 @@ int MyStringBuffer::getInt() { return *(int*)getOrderedByte(4); } -IoTdbDate MyStringBuffer::getDate() { +IoTDBDate MyStringBuffer::getDate() { return parseIntToDate(getInt()); } @@ -199,7 +199,7 @@ void MyStringBuffer::putInt(int ins) { putOrderedByte((char*)&ins, 4); } -void MyStringBuffer::putDate(IoTdbDate date) { +void MyStringBuffer::putDate(IoTDBDate date) { putInt(parseDateExpressionToInt(date)); } diff --git a/iotdb-client/client-cpp/src/session/Date.cpp b/iotdb-client/client-cpp/src/session/Date.cpp index afb8288d8ab1d..91095c250dad4 100644 --- a/iotdb-client/client-cpp/src/session/Date.cpp +++ b/iotdb-client/client-cpp/src/session/Date.cpp @@ -25,7 +25,7 @@ #include "Common.h" -std::string IoTdbDate::toIsoExtendedString() const { +std::string IoTDBDate::toIsoExtendedString() const { if (!valid_) { return ""; } @@ -34,7 +34,7 @@ std::string IoTdbDate::toIsoExtendedString() const { return std::string(buf); } -int32_t parseDateExpressionToInt(const IoTdbDate& date) { +int32_t parseDateExpressionToInt(const IoTDBDate& date) { if (date.is_not_a_date()) { throw IoTDBException("Date expression is null or empty."); } @@ -52,12 +52,12 @@ int32_t parseDateExpressionToInt(const IoTdbDate& date) { return static_cast(result); } -IoTdbDate parseIntToDate(int32_t dateInt) { +IoTDBDate parseIntToDate(int32_t dateInt) { if (dateInt == EMPTY_DATE_INT) { - return IoTdbDate::notADate(); + return IoTDBDate::notADate(); } const int year = dateInt / 10000; const int month = (dateInt % 10000) / 100; const int day = dateInt % 100; - return IoTdbDate(year, month, day); + return IoTDBDate(year, month, day); } diff --git a/iotdb-client/client-cpp/src/session/Session.cpp b/iotdb-client/client-cpp/src/session/Session.cpp index 8636be085f5c1..8d54e15c6c277 100644 --- a/iotdb-client/client-cpp/src/session/Session.cpp +++ b/iotdb-client/client-cpp/src/session/Session.cpp @@ -77,7 +77,7 @@ void Tablet::createColumns() { values[i] = new bool[maxRowNumber]; break; case TSDataType::DATE: - values[i] = new IoTdbDate[maxRowNumber]; + values[i] = new IoTDBDate[maxRowNumber]; break; case TSDataType::INT32: values[i] = new int[maxRowNumber]; @@ -122,7 +122,7 @@ void Tablet::deleteColumns() { break; } case TSDataType::DATE: { - IoTdbDate* valueBuf = (IoTdbDate*)(values[i]); + IoTDBDate* valueBuf = (IoTDBDate*)(values[i]); delete[] valueBuf; break; } @@ -184,9 +184,9 @@ void Tablet::deepCopyTabletColValue(void* const* srcPtr, void** destPtr, memcpy(*destPtr, src, maxRowNumber * sizeof(double)); break; case TSDataType::DATE: { - *destPtr = new IoTdbDate[maxRowNumber]; - IoTdbDate* srcDate = static_cast(src); - IoTdbDate* destDate = static_cast(*destPtr); + *destPtr = new IoTDBDate[maxRowNumber]; + IoTDBDate* srcDate = static_cast(src); + IoTDBDate* destDate = static_cast(*destPtr); for (size_t j = 0; j < maxRowNumber; ++j) { destDate[j] = srcDate[j]; } @@ -323,7 +323,7 @@ string SessionUtils::getValue(const Tablet& tablet) { break; } case TSDataType::DATE: { - IoTdbDate* valueBuf = (IoTdbDate*)(tablet.values[i]); + IoTDBDate* valueBuf = (IoTDBDate*)(tablet.values[i]); for (size_t index = 0; index < tablet.rowSize; index++) { if (!bitMap.isMarked(index)) { valueBuffer.putDate(valueBuf[index]); @@ -666,7 +666,7 @@ void Session::Impl::sortTablet(Tablet& tablet) { break; } case TSDataType::DATE: { - sortValuesList((IoTdbDate*)(tablet.values[i]), index, tablet.rowSize); + sortValuesList((IoTDBDate*)(tablet.values[i]), index, tablet.rowSize); break; } case TSDataType::TIMESTAMP: @@ -742,7 +742,7 @@ void Session::Impl::putValuesIntoBuffer(const vector& ty appendValues(buf, values[i], sizeof(int32_t)); break; case TSDataType::DATE: - date = parseDateExpressionToInt(*(IoTdbDate*)values[i]); + date = parseDateExpressionToInt(*(IoTDBDate*)values[i]); appendValues(buf, (char*)&date, sizeof(int32_t)); break; case TSDataType::TIMESTAMP: @@ -1514,7 +1514,7 @@ void Session::insertRelationalTablet(Tablet& tablet, bool sorted) { case TSDataType::DATE: { currentTablet.addValue( tablet.schemas[col].first, rowIndex, - *(IoTdbDate*)tablet.getValue(col, row, tablet.schemas[col].second)); + *(IoTDBDate*)tablet.getValue(col, row, tablet.schemas[col].second)); break; } case TSDataType::STRING: diff --git a/iotdb-client/client-cpp/src/session/SessionDataSet.cpp b/iotdb-client/client-cpp/src/session/SessionDataSet.cpp index 50ce431b1528a..0cb5d3e1b73e2 100644 --- a/iotdb-client/client-cpp/src/session/SessionDataSet.cpp +++ b/iotdb-client/client-cpp/src/session/SessionDataSet.cpp @@ -251,11 +251,11 @@ Optional SessionDataSet::DataIterator::getTimestamp(const std::string& return impl_->iotdbRpcDataSet_->getTimestamp(columnName); } -Optional SessionDataSet::DataIterator::getDateByIndex(int32_t columnIndex) { +Optional SessionDataSet::DataIterator::getDateByIndex(int32_t columnIndex) { return impl_->iotdbRpcDataSet_->getDateByIndex(columnIndex); } -Optional SessionDataSet::DataIterator::getDate(const std::string& columnName) { +Optional SessionDataSet::DataIterator::getDate(const std::string& columnName) { return impl_->iotdbRpcDataSet_->getDate(columnName); } diff --git a/iotdb-client/client-cpp/src/test/CMakeLists.txt b/iotdb-client/client-cpp/test/CMakeLists.txt similarity index 98% rename from iotdb-client/client-cpp/src/test/CMakeLists.txt rename to iotdb-client/client-cpp/test/CMakeLists.txt index d26512cba0ae0..a3524319b4104 100644 --- a/iotdb-client/client-cpp/src/test/CMakeLists.txt +++ b/iotdb-client/client-cpp/test/CMakeLists.txt @@ -38,7 +38,7 @@ add_executable(session_c_relational_tests main_c_Relational.cpp cpp/sessionCRela foreach(_t IN LISTS _test_targets) target_include_directories(${_t} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/catch2" - "${CMAKE_CURRENT_SOURCE_DIR}/../rpc" + "${CMAKE_CURRENT_SOURCE_DIR}/../src/rpc" "${THRIFT_GEN_CPP_DIR}" "${THRIFT_INCLUDE_DIR}") if(BOOST_INCLUDE_DIR) diff --git a/iotdb-client/client-cpp/src/test/catch2/catch.hpp b/iotdb-client/client-cpp/test/catch2/catch.hpp similarity index 100% rename from iotdb-client/client-cpp/src/test/catch2/catch.hpp rename to iotdb-client/client-cpp/test/catch2/catch.hpp diff --git a/iotdb-client/client-cpp/src/test/cpp/sessionCIT.cpp b/iotdb-client/client-cpp/test/cpp/sessionCIT.cpp similarity index 100% rename from iotdb-client/client-cpp/src/test/cpp/sessionCIT.cpp rename to iotdb-client/client-cpp/test/cpp/sessionCIT.cpp diff --git a/iotdb-client/client-cpp/src/test/cpp/sessionCRelationalIT.cpp b/iotdb-client/client-cpp/test/cpp/sessionCRelationalIT.cpp similarity index 100% rename from iotdb-client/client-cpp/src/test/cpp/sessionCRelationalIT.cpp rename to iotdb-client/client-cpp/test/cpp/sessionCRelationalIT.cpp diff --git a/iotdb-client/client-cpp/src/test/cpp/sessionIT.cpp b/iotdb-client/client-cpp/test/cpp/sessionIT.cpp similarity index 99% rename from iotdb-client/client-cpp/src/test/cpp/sessionIT.cpp rename to iotdb-client/client-cpp/test/cpp/sessionIT.cpp index 8db819eee61c6..0a58e8289feb1 100644 --- a/iotdb-client/client-cpp/src/test/cpp/sessionIT.cpp +++ b/iotdb-client/client-cpp/test/cpp/sessionIT.cpp @@ -249,7 +249,7 @@ TEST_CASE("Test insertRecord with new datatypes ", "[testTypedInsertRecordNewDat string deviceId = "root.test.d1"; vector measurements = {"s1", "s2", "s3", "s4"}; int64_t value1 = 20250507; - IoTdbDate value2 = IoTdbDate(2025, 5, 7); + IoTDBDate value2 = IoTDBDate(2025, 5, 7); string value3 = "20250507"; string value4 = "20250507"; @@ -480,7 +480,7 @@ TEST_CASE("Test insertTablet multi datatype", "[testInsertTabletMultiDatatype]") } int64_t s1Value = 20250507; - IoTdbDate s2Value(2025, 5, 7); + IoTDBDate s2Value(2025, 5, 7); std::string s3Value("20250507"); std::string s4Value("20250507"); diff --git a/iotdb-client/client-cpp/src/test/cpp/sessionRelationalIT.cpp b/iotdb-client/client-cpp/test/cpp/sessionRelationalIT.cpp similarity index 98% rename from iotdb-client/client-cpp/src/test/cpp/sessionRelationalIT.cpp rename to iotdb-client/client-cpp/test/cpp/sessionRelationalIT.cpp index aa241a8654f50..461a3ec863055 100644 --- a/iotdb-client/client-cpp/src/test/cpp/sessionRelationalIT.cpp +++ b/iotdb-client/client-cpp/test/cpp/sessionRelationalIT.cpp @@ -207,7 +207,7 @@ TEST_CASE("Test RelationalTabletTsblockRead", "[testRelationalTabletTsblockRead] tablet.addValue(4, rowIndex, static_cast(row * 1.1f)); tablet.addValue(5, rowIndex, "text_" + to_string(row)); tablet.addValue(6, rowIndex, static_cast(timestamp)); - tablet.addValue(7, rowIndex, IoTdbDate(2025, 5, 15)); + tablet.addValue(7, rowIndex, IoTDBDate(2025, 5, 15)); tablet.addValue(8, rowIndex, "blob_" + to_string(row)); tablet.addValue(9, rowIndex, "string_" + to_string(row)); @@ -255,7 +255,7 @@ TEST_CASE("Test RelationalTabletTsblockRead", "[testRelationalTabletTsblockRead] REQUIRE(fabs(dataIter.getDoubleByIndex(6).value() - rowNum * 1.1f) < 0.1); REQUIRE(dataIter.getStringByIndex(7).value() == "text_" + to_string(rowNum)); REQUIRE(dataIter.getTimestampByIndex(8).value() == static_cast(timestamp)); - REQUIRE(dataIter.getDateByIndex(9).value() == IoTdbDate(2025, 5, 15)); + REQUIRE(dataIter.getDateByIndex(9).value() == IoTDBDate(2025, 5, 15)); REQUIRE(dataIter.getStringByIndex(10).value() == "blob_" + to_string(rowNum)); REQUIRE(dataIter.getStringByIndex(11).value() == "string_" + to_string(rowNum)); } @@ -287,7 +287,7 @@ TEST_CASE("Test RelationalTabletTsblockRead", "[testRelationalTabletTsblockRead] REQUIRE(fabs(record->fields[5].doubleV.value() - rowNum * 1.1f) < 0.1); REQUIRE(record->fields[6].stringV.value() == "text_" + to_string(rowNum)); REQUIRE(record->fields[7].longV.value() == static_cast(timestamp)); - REQUIRE(record->fields[8].dateV.value() == IoTdbDate(2025, 5, 15)); + REQUIRE(record->fields[8].dateV.value() == IoTDBDate(2025, 5, 15)); REQUIRE(record->fields[9].stringV.value() == "blob_" + to_string(rowNum)); REQUIRE(record->fields[10].stringV.value() == "string_" + to_string(rowNum)); } diff --git a/iotdb-client/client-cpp/src/test/main.cpp b/iotdb-client/client-cpp/test/main.cpp similarity index 100% rename from iotdb-client/client-cpp/src/test/main.cpp rename to iotdb-client/client-cpp/test/main.cpp diff --git a/iotdb-client/client-cpp/src/test/main_Relational.cpp b/iotdb-client/client-cpp/test/main_Relational.cpp similarity index 100% rename from iotdb-client/client-cpp/src/test/main_Relational.cpp rename to iotdb-client/client-cpp/test/main_Relational.cpp diff --git a/iotdb-client/client-cpp/src/test/main_c.cpp b/iotdb-client/client-cpp/test/main_c.cpp similarity index 100% rename from iotdb-client/client-cpp/src/test/main_c.cpp rename to iotdb-client/client-cpp/test/main_c.cpp diff --git a/iotdb-client/client-cpp/src/test/main_c_Relational.cpp b/iotdb-client/client-cpp/test/main_c_Relational.cpp similarity index 100% rename from iotdb-client/client-cpp/src/test/main_c_Relational.cpp rename to iotdb-client/client-cpp/test/main_c_Relational.cpp From 252894ade08812257a6267b0b961f2afea5b5ced Mon Sep 17 00:00:00 2001 From: 761417898 <761417898@qq.com> Date: Wed, 27 May 2026 16:39:09 +0800 Subject: [PATCH 24/28] example: merge C Session demos into client-cpp-example Move tree_example.c and table_example.c into client-cpp-example, build them from the shared CMake entry, and update EN/ZH docs. Remove the standalone client-c-example module and drop it from the with-cpp profile. --- example/client-c-example/README.md | 68 -------- example/client-c-example/pom.xml | 156 ------------------ example/client-cpp-example/README.md | 8 +- example/client-cpp-example/README_zh.md | 8 +- example/client-cpp-example/pom.xml | 8 + example/client-cpp-example/src/CMakeLists.txt | 6 +- .../src/table_example.c | 1 - .../src/tree_example.c | 2 +- example/pom.xml | 1 - 9 files changed, 26 insertions(+), 232 deletions(-) delete mode 100644 example/client-c-example/README.md delete mode 100644 example/client-c-example/pom.xml rename example/{client-c-example => client-cpp-example}/src/table_example.c (97%) rename example/{client-c-example => client-cpp-example}/src/tree_example.c (100%) 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 49b048559ddc5..0000000000000 --- a/example/client-c-example/pom.xml +++ /dev/null @@ -1,156 +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 - ${os.classifier} - true - - - ^[^/]+/(.*)$ - $1 - - - - - ${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-cpp-example/README.md b/example/client-cpp-example/README.md index 6efabeedb69f3..77db316f32020 100644 --- a/example/client-cpp-example/README.md +++ b/example/client-cpp-example/README.md @@ -36,6 +36,8 @@ user `root` / `root`). | `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 @@ -92,7 +94,7 @@ the generator; on Windows with Visual Studio: `target/Release/`). 1. Build or download the SDK and unpack it so `client/include` and `client/lib` exist (see layout above). -2. Copy `src/*.cpp` and `src/CMakeLists.txt` into one directory (or use +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: @@ -248,7 +250,9 @@ client-cpp-example/ ├── SessionExample.cpp ├── AlignedTimeseriesSessionExample.cpp ├── TableModelSessionExample.cpp - └── MultiSvrNodeClient.cpp + ├── MultiSvrNodeClient.cpp + ├── tree_example.c + └── table_example.c ``` After `mvn package`, the runnable tree is under `target/` (sources, `client/`, diff --git a/example/client-cpp-example/README_zh.md b/example/client-cpp-example/README_zh.md index 871c536e5ad9e..acdc11df23277 100644 --- a/example/client-cpp-example/README_zh.md +++ b/example/client-cpp-example/README_zh.md @@ -35,6 +35,8 @@ | `AlignedTimeseriesSessionExample` | 对齐时间序列与模板 | | `TableModelSessionExample` | 表模型(关系型) | | `MultiSvrNodeClient` | 多节点写入/查询循环 | +| `tree_example` | C Session API(树模型) | +| `table_example` | C Session API(表模型) | ## 选择哪个 SDK 压缩包 @@ -89,7 +91,7 @@ Windows + Visual Studio 一般为 `target/Release/`)。 1. 自行编译或下载 SDK,解压后保证存在 `client/include` 与 `client/lib`(见 上文目录结构)。 -2. 将 `src/*.cpp` 与 `src/CMakeLists.txt` 放在同一目录(或保留 `src/` +2. 将 `src/*.{cpp,c}` 与 `src/CMakeLists.txt` 放在同一目录(或保留 `src/` 结构,并在同级放置 `client/`)。 3. 配置并编译: @@ -241,7 +243,9 @@ client-cpp-example/ ├── SessionExample.cpp ├── AlignedTimeseriesSessionExample.cpp ├── TableModelSessionExample.cpp - └── MultiSvrNodeClient.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 50931fd9356dd..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 diff --git a/example/client-cpp-example/src/CMakeLists.txt b/example/client-cpp-example/src/CMakeLists.txt index 04a3c7dc983c5..b1ea7d0f79cba 100644 --- a/example/client-cpp-example/src/CMakeLists.txt +++ b/example/client-cpp-example/src/CMakeLists.txt @@ -72,12 +72,16 @@ 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) set(_example_targets SessionExample AlignedTimeseriesSessionExample TableModelSessionExample - MultiSvrNodeClient) + MultiSvrNodeClient + tree_example + table_example) foreach(_t IN LISTS _example_targets) IF(WITH_SSL) diff --git a/example/client-c-example/src/table_example.c b/example/client-cpp-example/src/table_example.c similarity index 97% rename from example/client-c-example/src/table_example.c rename to example/client-cpp-example/src/table_example.c index 9ad844ec4c2af..e118264a6ff71 100644 --- a/example/client-c-example/src/table_example.c +++ b/example/client-cpp-example/src/table_example.c @@ -46,7 +46,6 @@ static void fail(const char* ctx, CTableSession* s) { } 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()); diff --git a/example/client-c-example/src/tree_example.c b/example/client-cpp-example/src/tree_example.c similarity index 100% rename from example/client-c-example/src/tree_example.c rename to example/client-cpp-example/src/tree_example.c index a98df2831b69e..7b99a2c78c8b5 100644 --- a/example/client-c-example/src/tree_example.c +++ b/example/client-cpp-example/src/tree_example.c @@ -22,9 +22,9 @@ * Edit HOST / PORT / credentials below to match your IoTDB. */ +#include #include #include -#include #include #include "SessionC.h" 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 From a52c9a3400395c275d8590d861149bb62dd3c9c5 Mon Sep 17 00:00:00 2001 From: 761417898 <761417898@qq.com> Date: Wed, 27 May 2026 16:53:57 +0800 Subject: [PATCH 25/28] style(client-cpp): apply spotless to C examples --- .../client-cpp-example/src/table_example.c | 202 +++++++++--------- example/client-cpp-example/src/tree_example.c | 122 +++++------ 2 files changed, 163 insertions(+), 161 deletions(-) diff --git a/example/client-cpp-example/src/table_example.c b/example/client-cpp-example/src/table_example.c index e118264a6ff71..bc9df9aa82345 100644 --- a/example/client-cpp-example/src/table_example.c +++ b/example/client-cpp-example/src/table_example.c @@ -37,115 +37,117 @@ #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); + 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); + 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); } - - 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); + 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); } - - snprintf(sql, sizeof(sql), "USE \"%s\"", DB_NAME); - if (ts_table_session_execute_non_query(session, sql) != TS_OK) { - fail("USE DATABASE", 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); } - - 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); + 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); + } - 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); - + 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 0; + 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 index 7b99a2c78c8b5..b1eb53fafb836 100644 --- a/example/client-cpp-example/src/tree_example.c +++ b/example/client-cpp-example/src/tree_example.c @@ -38,77 +38,77 @@ #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); + 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); - } + 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); + 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); - } + 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); + 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++; + int rows = 0; + while (ts_dataset_has_next(dataSet)) { + CRowRecord* record = ts_dataset_next(dataSet); + if (!record) { + break; } - ts_dataset_destroy(dataSet); + 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); + 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); - } + 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; + ts_session_close(session); + ts_session_destroy(session); + return 0; } From f744a14402a0bf7821cd5aa43491461e66f7f9e2 Mon Sep 17 00:00:00 2001 From: 761417898 <761417898@qq.com> Date: Wed, 27 May 2026 17:02:35 +0800 Subject: [PATCH 26/28] fix(ci): use curl for downloads in manylinux glibc217 script --- .../package-client-cpp-manylinux-glibc217.sh | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/.github/scripts/package-client-cpp-manylinux-glibc217.sh b/.github/scripts/package-client-cpp-manylinux-glibc217.sh index e99b221ea7c6b..0b6c9a4ed9890 100644 --- a/.github/scripts/package-client-cpp-manylinux-glibc217.sh +++ b/.github/scripts/package-client-cpp-manylinux-glibc217.sh @@ -37,10 +37,24 @@ esac PACKAGE_CLASSIFIER="${PACKAGE_CLASSIFIER:-${DEFAULT_CLASSIFIER}}" +# manylinux2014 images ship curl but not wget (old CentOS7 path installed wget via yum). +download() { + local url="$1" + local out="$2" + if command -v curl >/dev/null 2>&1; then + curl -fsSL -o "${out}" "${url}" + elif command -v wget >/dev/null 2>&1; then + wget -qL -O "${out}" "${url}" + else + echo "Need curl or wget to download: ${url}" >&2 + exit 1 + fi +} + CMAKE_VERSION=3.28.4 CMAKE_DIR="/opt/cmake-${CMAKE_VERSION}" if [[ ! -x "${CMAKE_DIR}/bin/cmake" ]]; then - wget -q "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-${CMAKE_PKG_ARCH}.tar.gz" -O /tmp/cmake.tar.gz + download "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-${CMAKE_PKG_ARCH}.tar.gz" /tmp/cmake.tar.gz rm -rf "${CMAKE_DIR}" mkdir -p /opt tar xf /tmp/cmake.tar.gz -C /opt @@ -49,7 +63,7 @@ fi JAVA_HOME=/opt/jdk-17 if [[ ! -x "${JAVA_HOME}/bin/java" ]]; then - wget -qL -O /tmp/jdk17.tar.gz "https://api.adoptium.net/v3/binary/latest/17/ga/${JDK_API_ARCH}/jdk/hotspot/normal/eclipse?project=jdk" + download "https://api.adoptium.net/v3/binary/latest/17/ga/${JDK_API_ARCH}/jdk/hotspot/normal/eclipse?project=jdk" /tmp/jdk17.tar.gz rm -rf /opt/jdk-17* mkdir -p /opt tar xf /tmp/jdk17.tar.gz -C /opt From 30c55e7abe51033f0e03e611395290e50e4b9650 Mon Sep 17 00:00:00 2001 From: 761417898 <761417898@qq.com> Date: Wed, 27 May 2026 17:04:46 +0800 Subject: [PATCH 27/28] fix(ci): use curl directly in manylinux glibc217 script --- .../package-client-cpp-manylinux-glibc217.sh | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/.github/scripts/package-client-cpp-manylinux-glibc217.sh b/.github/scripts/package-client-cpp-manylinux-glibc217.sh index 0b6c9a4ed9890..c359ce8b40aae 100644 --- a/.github/scripts/package-client-cpp-manylinux-glibc217.sh +++ b/.github/scripts/package-client-cpp-manylinux-glibc217.sh @@ -37,24 +37,10 @@ esac PACKAGE_CLASSIFIER="${PACKAGE_CLASSIFIER:-${DEFAULT_CLASSIFIER}}" -# manylinux2014 images ship curl but not wget (old CentOS7 path installed wget via yum). -download() { - local url="$1" - local out="$2" - if command -v curl >/dev/null 2>&1; then - curl -fsSL -o "${out}" "${url}" - elif command -v wget >/dev/null 2>&1; then - wget -qL -O "${out}" "${url}" - else - echo "Need curl or wget to download: ${url}" >&2 - exit 1 - fi -} - CMAKE_VERSION=3.28.4 CMAKE_DIR="/opt/cmake-${CMAKE_VERSION}" if [[ ! -x "${CMAKE_DIR}/bin/cmake" ]]; then - download "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-${CMAKE_PKG_ARCH}.tar.gz" /tmp/cmake.tar.gz + 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 @@ -63,7 +49,7 @@ fi JAVA_HOME=/opt/jdk-17 if [[ ! -x "${JAVA_HOME}/bin/java" ]]; then - download "https://api.adoptium.net/v3/binary/latest/17/ga/${JDK_API_ARCH}/jdk/hotspot/normal/eclipse?project=jdk" /tmp/jdk17.tar.gz + 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 From 3501aaca063916dd94f050796d9499933315e481 Mon Sep 17 00:00:00 2001 From: 761417898 <761417898@qq.com> Date: Wed, 27 May 2026 17:54:15 +0800 Subject: [PATCH 28/28] fix(client-cpp): centralize SessionConfig defaults and align fetchSize with Java --- iotdb-client/client-cpp/CMakeLists.txt | 1 + .../src/include/AbstractSessionBuilder.h | 10 +++--- iotdb-client/client-cpp/src/include/Session.h | 5 +-- .../client-cpp/src/include/SessionConfig.h | 34 +++++++++++++++++++ .../client-cpp/src/rpc/NodesSupplier.cpp | 1 - .../client-cpp/src/rpc/NodesSupplier.h | 1 - .../client-cpp/src/rpc/SessionConnection.h | 9 +++-- iotdb-client/client-cpp/src/rpc/SessionImpl.h | 5 ++- .../client-cpp/src/rpc/ThriftConnection.cpp | 1 - .../client-cpp/src/rpc/ThriftConnection.h | 4 +-- .../client-cpp/src/session/Session.cpp | 2 +- iotdb-client/client-cpp/third-party/README.md | 4 ++- 12 files changed, 58 insertions(+), 19 deletions(-) create mode 100644 iotdb-client/client-cpp/src/include/SessionConfig.h diff --git a/iotdb-client/client-cpp/CMakeLists.txt b/iotdb-client/client-cpp/CMakeLists.txt index ac946faa23ed8..a0d77a1dfc450 100644 --- a/iotdb-client/client-cpp/CMakeLists.txt +++ b/iotdb-client/client-cpp/CMakeLists.txt @@ -138,6 +138,7 @@ include(GNUInstallDirs) set(IOTDB_PUBLIC_HEADERS Export.h + SessionConfig.h Session.h Common.h Optional.h diff --git a/iotdb-client/client-cpp/src/include/AbstractSessionBuilder.h b/iotdb-client/client-cpp/src/include/AbstractSessionBuilder.h index 9f59504d3887b..3735dfa227d0c 100644 --- a/iotdb-client/client-cpp/src/include/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/include/Session.h b/iotdb-client/client-cpp/src/include/Session.h index 2b5bb147849ad..1d207a8eebd9f 100644 --- a/iotdb-client/client-cpp/src/include/Session.h +++ b/iotdb-client/client-cpp/src/include/Session.h @@ -572,10 +572,11 @@ class Session { Session(const std::string& host, int rpcPort, const std::string& username, const std::string& password); Session(const std::string& host, int rpcPort, const std::string& username, - const std::string& password, const std::string& zoneId, int fetchSize = 10000); + const std::string& password, const std::string& zoneId, + int fetchSize = AbstractSessionBuilder::DEFAULT_FETCH_SIZE); Session(const std::string& host, const std::string& rpcPort, const std::string& username = "user", const std::string& password = "password", const std::string& zoneId = "", - int fetchSize = 10000); + int fetchSize = AbstractSessionBuilder::DEFAULT_FETCH_SIZE); Session(AbstractSessionBuilder* builder); ~Session(); diff --git a/iotdb-client/client-cpp/src/include/SessionConfig.h b/iotdb-client/client-cpp/src/include/SessionConfig.h new file mode 100644 index 0000000000000..2106a1b6c7b5a --- /dev/null +++ b/iotdb-client/client-cpp/src/include/SessionConfig.h @@ -0,0 +1,34 @@ +/** + * 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. + */ +#ifndef IOTDB_SESSION_CONFIG_H +#define IOTDB_SESSION_CONFIG_H + +namespace iotdb { +namespace session { + +// Defaults aligned with org.apache.iotdb.isession.SessionConfig (Java client). +constexpr int DEFAULT_FETCH_SIZE = 5000; +constexpr int DEFAULT_CONNECT_TIMEOUT_MS = 3 * 1000; +constexpr int DEFAULT_MAX_RETRIES = 3; +constexpr int DEFAULT_RETRY_DELAY_MS = 500; + +} // namespace session +} // namespace iotdb + +#endif // IOTDB_SESSION_CONFIG_H diff --git a/iotdb-client/client-cpp/src/rpc/NodesSupplier.cpp b/iotdb-client/client-cpp/src/rpc/NodesSupplier.cpp index 848274619f8da..604099a82d1bf 100644 --- a/iotdb-client/client-cpp/src/rpc/NodesSupplier.cpp +++ b/iotdb-client/client-cpp/src/rpc/NodesSupplier.cpp @@ -31,7 +31,6 @@ const std::string NodesSupplier::PORT_COLUMN_NAME = "RpcPort"; const std::string NodesSupplier::REMOVING_STATUS = "Removing"; const int64_t NodesSupplier::TIMEOUT_IN_MS = 60000; -const int NodesSupplier::FETCH_SIZE = 10000; const int NodesSupplier::THRIFT_DEFAULT_BUFFER_SIZE = 4096; const int NodesSupplier::THRIFT_MAX_FRAME_SIZE = 1048576; const int NodesSupplier::CONNECTION_TIMEOUT_IN_MS = 1000; diff --git a/iotdb-client/client-cpp/src/rpc/NodesSupplier.h b/iotdb-client/client-cpp/src/rpc/NodesSupplier.h index af9e4dfec624e..c067bbb6d722a 100644 --- a/iotdb-client/client-cpp/src/rpc/NodesSupplier.h +++ b/iotdb-client/client-cpp/src/rpc/NodesSupplier.h @@ -72,7 +72,6 @@ class NodesSupplier : public INodesSupplier { static const std::string REMOVING_STATUS; static const int64_t TIMEOUT_IN_MS; - static const int FETCH_SIZE; static const int THRIFT_DEFAULT_BUFFER_SIZE; static const int THRIFT_MAX_FRAME_SIZE; static const int CONNECTION_TIMEOUT_IN_MS; diff --git a/iotdb-client/client-cpp/src/rpc/SessionConnection.h b/iotdb-client/client-cpp/src/rpc/SessionConnection.h index 7579d7fb1fc2f..472e29fd66545 100644 --- a/iotdb-client/client-cpp/src/rpc/SessionConnection.h +++ b/iotdb-client/client-cpp/src/rpc/SessionConnection.h @@ -33,6 +33,7 @@ #include "Common.h" #include "RpcCommon.h" #include "Session.h" +#include "SessionConfig.h" class SessionDataSet; @@ -40,9 +41,11 @@ class SessionConnection : public std::enable_shared_from_this public: SessionConnection(Session::Impl* session_ptr, const TEndPoint& endpoint, const std::string& zoneId, std::shared_ptr nodeSupplier, - int fetchSize = 10000, int maxRetries = 3, int64_t retryInterval = 500, - int64_t connectionTimeoutMs = 3 * 1000, std::string dialect = "tree", - std::string db = ""); + int fetchSize = iotdb::session::DEFAULT_FETCH_SIZE, + int maxRetries = iotdb::session::DEFAULT_MAX_RETRIES, + int64_t retryInterval = iotdb::session::DEFAULT_RETRY_DELAY_MS, + int64_t connectionTimeoutMs = iotdb::session::DEFAULT_CONNECT_TIMEOUT_MS, + std::string dialect = "tree", std::string db = ""); ~SessionConnection(); diff --git a/iotdb-client/client-cpp/src/rpc/SessionImpl.h b/iotdb-client/client-cpp/src/rpc/SessionImpl.h index b849fb976e91d..4d14c99f38146 100644 --- a/iotdb-client/client-cpp/src/rpc/SessionImpl.h +++ b/iotdb-client/client-cpp/src/rpc/SessionImpl.h @@ -49,10 +49,9 @@ class Session::Impl { const TSProtocolVersion::type protocolVersion_ = TSProtocolVersion::IOTDB_SERVICE_PROTOCOL_V3; bool isClosed_ = true; std::string zoneId_; - int fetchSize_ = 10000; - static const int DEFAULT_FETCH_SIZE = 10000; + int fetchSize_ = iotdb::session::DEFAULT_FETCH_SIZE; static const int DEFAULT_TIMEOUT_MS = 0; - int connectTimeoutMs_ = 3000; + int connectTimeoutMs_ = iotdb::session::DEFAULT_CONNECT_TIMEOUT_MS; Version::Version version = Version::V_1_0; std::string sqlDialect_ = "tree"; std::string database_; diff --git a/iotdb-client/client-cpp/src/rpc/ThriftConnection.cpp b/iotdb-client/client-cpp/src/rpc/ThriftConnection.cpp index fadfc18dffb1a..1cc6c5417b2dc 100644 --- a/iotdb-client/client-cpp/src/rpc/ThriftConnection.cpp +++ b/iotdb-client/client-cpp/src/rpc/ThriftConnection.cpp @@ -36,7 +36,6 @@ using namespace apache::thrift::transport; const int ThriftConnection::THRIFT_DEFAULT_BUFFER_SIZE = 4096; const int ThriftConnection::THRIFT_MAX_FRAME_SIZE = 1048576; const int ThriftConnection::CONNECTION_TIMEOUT_IN_MS = 1000; -const int ThriftConnection::DEFAULT_FETCH_SIZE = 10000; ThriftConnection::ThriftConnection(const TEndPoint& endPoint, int thriftDefaultBufferSize, int thriftMaxFrameSize, int connectionTimeoutInMs, int fetchSize) diff --git a/iotdb-client/client-cpp/src/rpc/ThriftConnection.h b/iotdb-client/client-cpp/src/rpc/ThriftConnection.h index ab094c6608c52..286911740316e 100644 --- a/iotdb-client/client-cpp/src/rpc/ThriftConnection.h +++ b/iotdb-client/client-cpp/src/rpc/ThriftConnection.h @@ -24,6 +24,7 @@ #include #endif #include "IClientRPCService.h" +#include "SessionConfig.h" class SessionDataSet; @@ -32,13 +33,12 @@ class ThriftConnection { static const int THRIFT_DEFAULT_BUFFER_SIZE; static const int THRIFT_MAX_FRAME_SIZE; static const int CONNECTION_TIMEOUT_IN_MS; - static const int DEFAULT_FETCH_SIZE; explicit ThriftConnection(const TEndPoint& endPoint, int thriftDefaultBufferSize = THRIFT_DEFAULT_BUFFER_SIZE, int thriftMaxFrameSize = THRIFT_MAX_FRAME_SIZE, int connectionTimeoutInMs = CONNECTION_TIMEOUT_IN_MS, - int fetchSize = DEFAULT_FETCH_SIZE); + int fetchSize = iotdb::session::DEFAULT_FETCH_SIZE); ~ThriftConnection(); diff --git a/iotdb-client/client-cpp/src/session/Session.cpp b/iotdb-client/client-cpp/src/session/Session.cpp index 8d54e15c6c277..6635aeeef2551 100644 --- a/iotdb-client/client-cpp/src/session/Session.cpp +++ b/iotdb-client/client-cpp/src/session/Session.cpp @@ -493,7 +493,7 @@ Session::Session(const std::string& host, int rpcPort, const std::string& userna impl_->rpcPort_ = rpcPort; impl_->username_ = username; impl_->password_ = password; - impl_->fetchSize_ = Impl::DEFAULT_FETCH_SIZE; + impl_->fetchSize_ = iotdb::session::DEFAULT_FETCH_SIZE; impl_->version = Version::V_1_0; impl_->initZoneId(); impl_->initNodesSupplier(); diff --git a/iotdb-client/client-cpp/third-party/README.md b/iotdb-client/client-cpp/third-party/README.md index c92733d50c6a8..313a6fb79a1d6 100644 --- a/iotdb-client/client-cpp/third-party/README.md +++ b/iotdb-client/client-cpp/third-party/README.md @@ -25,7 +25,9 @@ build `client-cpp` with `-DIOTDB_OFFLINE=ON`**. Tarballs themselves are **not** committed to Git (see per-platform `.gitignore` files). Only this README and the empty platform folders are -tracked. +tracked. Each `linux/`, `mac/`, and `windows/` sub-folder ships a minimal +`.gitignore` (`*` with `!.gitignore`) so Git keeps the directory in the +tree while ignoring downloaded archives. ## Layout