blob: 576e1b852ad9ccbb3ba29efe9b928fd71242f3ae [file] [view]
# C 原生接口
## **1. 概述**
C 原生接口(SessionC)是对 C++ Session SDK 的 C 语言封装。使用方式与 C++ 驱动一致,仅需额外包含头文件 `SessionC.h`;编译、链接、运行时部署与 C++ 驱动共用同一套 `iotdb_session` 共享库。
Thrift 与 Boost 已封装进 `iotdb_session`,**应用侧接入时无需单独安装** Thrift 或 Boost 头文件/库。
> 注意:该功能自 V2.0.10 版本起支持
>
## **2. 安装**
### **2.1 方式一:使用预编译 SDK 包(推荐)**
CI 会按平台/工具链发布 zip,文件名形如 `iotdb-session-cpp-<version>-<classifier>.zip`。解压后目录结构如下:
```Plain Text
iotdb-session-cpp-<version>-<classifier>/
├── include/
│ ├── SessionC.h # C 原生接口头文件
│ ├── Session.h # C++ 接口头文件
│ └── ...
├── lib/
│ ├── libiotdb_session.so # Linux
│ ├── libiotdb_session.dylib # macOS
│ └── iotdb_session.dll + .lib # Windows
├── cmake/iotdb-session-config.cmake
├── pkgconfig/iotdb-session.pc
└── examples/ # 含 tree_example.c
```
按目标环境选择 classifier:
|目标环境|classifier 后缀|
|---|---|
|Linux x86_64,glibc >= 2.28|`linux-x86_64-glibc2.28`|
|Linux aarch64,glibc >= 2.28|`linux-aarch64-glibc2.28`|
|macOS x86_64|`macos-x86_64`|
|macOS arm64|`macos-aarch64`|
|Windows + Visual Studio 2017|`windows-x86_64-msvc14.1`|
|Windows + Visual Studio 2019|`windows-x86_64-msvc14.2`|
|Windows + Visual Studio 2022|`windows-x86_64-msvc14.3`|
|Windows + Visual Studio 2026|`windows-x86_64-msvc14.4`|
**注意:请勿使用高版本客户端连接低版本服务。**
#### **2.1.1 C 程序编译示例**
Linux / macOS:
```Bash
gcc -std=c11 tree_example.c \
-I"$IOTDB_SESSION_HOME/include" \
-L"$IOTDB_SESSION_HOME/lib" \
-liotdb_session -pthread \
-Wl,-rpath,"$IOTDB_SESSION_HOME/lib" \
-o tree_example
```
Windows + MSVC:
在 **x64 本机工具命令提示**(或先执行 `vcvars64.bat` 初始化环境)中编译:
```Plain Text
set IOTDB_SESSION_HOME=C:\path\to\iotdb-session-cpp-<version>-<classifier>
cd /d %IOTDB_SESSION_HOME%\examples
cl /TC /std:c11 tree_example.c /I "%IOTDB_SESSION_HOME%\include" ^
/link /LIBPATH:"%IOTDB_SESSION_HOME%\lib" iotdb_session.lib
copy /Y "%IOTDB_SESSION_HOME%\lib\iotdb_session.dll" .
```
运行时请将 `libiotdb_session.so` / `.dylib` / `.dll` 与可执行文件放在同一目录,或配置平台对应的动态库搜索路径。
#### **2.1.2 编译 SDK 包内 examples**
在**解压后的 SDK 包根目录**执行(要求 `examples/` 与 `include/`、`lib/` 同级):
```Bash
cd iotdb-session-cpp-<version>-<classifier>
cmake -S examples -B examples-build -DCMAKE_BUILD_TYPE=Release
cmake --build examples-build
```
Windows + Visual Studio:
```Plain Text
cd iotdb-session-cpp-<version>-<classifier>
cmake -S examples -B examples-build -G "Visual Studio 17 2022" -A x64
cmake --build examples-build --config Release
```
若库安装在其他路径(例如源码 CMake 安装目录 `iotdb-client/client-cpp/target/install`),请显式指定 `IOTDB_SDK_ROOT`(该目录下须包含 `include/` 与 `lib/`):
```Bash
cmake -S iotdb-client/client-cpp/examples -B examples-build -DCMAKE_BUILD_TYPE=Release \
-DIOTDB_SDK_ROOT=iotdb-client/client-cpp/target/install
cmake --build examples-build
```
Windows 示例:
```Plain Text
cmake -S iotdb-client\client-cpp\examples -B examples-build -G "Visual Studio 17 2022" -A x64 ^
-DIOTDB_SDK_ROOT=D:\iotdb\iotdb-client\client-cpp\target\install
cmake --build examples-build --config Release --target tree_example
```
### **2.2 方式二:从源码构建**
#### **2.2.1 安装构建依赖(仅源码构建需要)**
- **macOS**
```Shell
brew install bison boost openssl
```
- **Ubuntu 16.04+ 或其他 Debian 系列**
```Shell
sudo apt-get update
sudo apt-get install gcc g++ bison flex libboost-all-dev libssl-dev cmake
```
- **CentOS 7.7+/Fedora/Rocky Linux 或其他 Red-hat 系列**
```Shell
sudo yum update
sudo yum install gcc gcc-c++ boost-devel bison flex openssl-devel cmake
```
- **Windows**
1. 安装 MS Visual Studio(推荐 2019+),勾选 C/C++ IDE 与编译器(支持 CMake)。
2. 安装 [CMake](https://cmake.org/download/)。
3. 安装 [Win_Flex_Bison](https://sourceforge.net/projects/winflexbison/),将可执行文件重命名为 `flex.exe` 和 `bison.exe` 并加入 PATH。
4. 安装 Boost(可选,CMake 也可自动获取)与 [OpenSSL](http://slproweb.com/products/Win32OpenSSL.html)。
CMake 构建会从源码编译 Thrift 0.23;SSL 默认开启,找不到系统 OpenSSL 时会回退到从源码构建。
#### **2.2.2 执行编译**
从 git 克隆源代码:
```Shell
git clone https://github.com/apache/iotdb.git
cd iotdb
```
如需使用某个发布版本,请切换分支(如 2.0.6):
```Shell
git checkout rc/2.0.6
```
在 IoTDB 根目录执行 Maven 编译(推荐):
```Shell
# Linux / macOS:构建 SDK 并打包
./mvnw -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests package
# Windows(Visual Studio 2022 示例)
.\mvnw.cmd -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests package
```
若 Windows 上 Boost 未加入 PATH,可追加参数,例如:
```Plain Text
-Dboost.include.dir="C:\boost_1_88_0"
```
也可直接使用 CMake:
```Shell
cmake -S iotdb-client/client-cpp -B build
cmake --build build --target install
```
Linux 发版包在 `manylinux_2_28` 容器中构建,**目标机器需要 glibc 2.28 或更新版本**。当前构建**不再**使用 `-Diotdb-tools-thrift.version=0.14.1.1-gcc4-SNAPSHOT` 等旧参数。
带集成测试的完整验证:
```Shell
./mvnw clean verify -P with-cpp -pl iotdb-client/client-cpp -am
```
### **2.3 编译产物**
编译成功后,C 接口相关文件位置:
- C 接口头文件(源码):`iotdb-client/client-cpp/src/include/SessionC.h`
- C 接口头文件(安装/SDK 包):`include/SessionC.h`
- 库文件:
- 源码构建:`iotdb-client/client-cpp/target/install/lib/`
- Maven 打包:`iotdb-client/client-cpp/target/iotdb-session-cpp-<version>-<classifier>.zip`
- Linux:`lib/libiotdb_session.so`
- Windows:`lib/iotdb_session.dll` / `lib/iotdb_session.lib`
- 示例源码:
- 树模型:`iotdb-client/client-cpp/examples/tree_example.c`
- 表模型:`iotdb-client/client-cpp/examples/table_example.c`
- 集成测试:
- 树模型:`iotdb-client/client-cpp/test/cpp/sessionCIT.cpp`
- 表模型:`iotdb-client/client-cpp/test/cpp/sessionCRelationalIT.cpp`
## **3. 基本接口说明**
**说明:C 驱动使用方式与 C++ 驱动完全一致,仅需额外包含头文件 `SessionC.h`,编译、运行、系统依赖与 C++ 驱动通用。**
### **3.1 统一约定**
#### **3.1.1 状态码与错误信息**
- `TsStatus`:`TS_OK(0)` 表示成功;失败为非 0。
- 预定义错误码:
- `TS_ERR_CONNECTION(-1)`
- `TS_ERR_EXECUTION(-2)`
- `TS_ERR_INVALID_PARAM(-3)`
- `TS_ERR_NULL_PTR(-4)`
- `TS_ERR_UNKNOWN(-99)`
- 实现也可能返回其他负值,须结合 `ts_get_last_error()` 判断。
- Session C++ 大量用异常报错,不返回统一状态码;C API 统一返回整型 `TsStatus`,细粒度错误信息通过 `ts_get_last_error()` 获取。
```C
const char* ts_get_last_error(void);
```
返回当前线程上一次**失败**的 C API 调用的错误信息;返回指针在同线程下一次任意 C API 调用之前有效。
#### **3.1.2 内存与句柄规则**
- 所有 `char* buf + int bufLen` 输出参数,均由调用方分配内存。
- `CSession*`、`CTablet*`、`CSessionDataSet*`、`CRowRecord*` 均为不透明指针,创建成功后由调用方按各接口约定释放。
### **3.2 枚举与常量**
- **TSDataType_C(数据类型)**
|枚举值|含义|
|---|---|
|`TS_TYPE_BOOLEAN`|布尔|
|`TS_TYPE_INT32`|32 位整数|
|`TS_TYPE_INT64`|64 位整数|
|`TS_TYPE_FLOAT`|单精度浮点|
|`TS_TYPE_DOUBLE`|双精度浮点|
|`TS_TYPE_TEXT`|文本|
|`TS_TYPE_TIMESTAMP`|时间戳|
|`TS_TYPE_DATE`|日期|
|`TS_TYPE_BLOB`|二进制大对象|
|`TS_TYPE_STRING`|字符串|
|`TS_TYPE_INVALID`|非法参数/错误路径(非服务端类型)|
- **TSEncoding_C(编码)**
`TS_ENCODING_PLAIN`、`TS_ENCODING_DICTIONARY`、`TS_ENCODING_RLE`、`TS_ENCODING_DIFF`、`TS_ENCODING_TS_2DIFF`、`TS_ENCODING_BITMAP`、`TS_ENCODING_GORILLA_V1`、`TS_ENCODING_REGULAR`、`TS_ENCODING_GORILLA`、`TS_ENCODING_ZIGZAG`、`TS_ENCODING_FREQ`
- **TSCompressionType_C(压缩)**
`TS_COMPRESSION_UNCOMPRESSED`、`TS_COMPRESSION_SNAPPY`、`TS_COMPRESSION_GZIP`、`TS_COMPRESSION_LZO`、`TS_COMPRESSION_SDT`、`TS_COMPRESSION_PAA`、`TS_COMPRESSION_PLA`、`TS_COMPRESSION_LZ4`、`TS_COMPRESSION_ZSTD`、`TS_COMPRESSION_LZMA2`
### **3.3 句柄、状态码与常量**
|名称|C 定义|含义|生命周期责任|
|---|---|---|---|
|`CSession*`|`typedef struct CSession_ CSession;`|树模型会话|`ts_session_new` / `ts_session_new_with_zone` / `ts_session_new_multi_node` 成功后由调用方 `ts_session_close`(若已 open)再 `ts_session_destroy`|
|`CTablet*`|`typedef struct CTablet_ CTablet;`(不透明)|Tablet 批量写入(树/表共用)|`ts_tablet_new` / `ts_tablet_new_with_category` 成功后由调用方 `ts_tablet_destroy`|
|`CSessionDataSet*`|`typedef struct CSessionDataSet_ CSessionDataSet;`(不透明)|查询结果集(树/表共用)|查询接口成功得到 `*dataSet` 后由调用方 `ts_dataset_destroy`|
|`CRowRecord*`|`typedef struct CRowRecord_ CRowRecord;`(不透明)|当前行|`ts_dataset_next` 返回非空时由调用方 `ts_row_record_destroy`|
|`TsStatus`<br>|`typedef int64_t TsStatus;`|接口执行结果码|`TS_OK` 为 0;失败为非 0|
|`ts_get_last_error`|`const char* ts_get_last_error(void);`|当前线程最后一次**失败**的 C API 的错误信息|返回指针有效至同线程下一次 C API 调用前|
### **3.4 公共 Tablet 接口**
#### **3.4.1 创建与销毁**
|接口签名|函数功能|入参定义|返回定义|成功判定|失败判定|资源责任|
|---|---|---|---|---|---|---|
|`CTablet* ts_tablet_new(const char* deviceId, int columnCount, const char* const* columnNames, const TSDataType_C* dataTypes, int maxRowNumber);`|创建 Tablet 句柄|deviceId:设备或表名;columnNames / dataTypes:列名与类型数组;maxRowNumber:最大行数|`CTablet*`|返回非空句柄|返回空句柄|调用方 `ts_tablet_destroy`|
|`void ts_tablet_destroy(CTablet* tablet);`|销毁 Tablet 句柄|tablet:待释放句柄|无|调用后句柄不可再用|—|释放 tablet|
#### **3.4.2 数据填充与状态控制**
|接口签名|函数功能|返回|成功判定|备注|
|---|---|---|---|---|
|`int ts_tablet_get_row_count(CTablet* tablet);`|查询 Tablet 当前有效行数|int|行数 ≥ 0|只读查询|
|`TsStatus ts_tablet_set_row_count(CTablet* tablet, int rowCount);`|设置 Tablet 有效行数|TsStatus|`TS_OK`|写入前需设置有效行数|
|`TsStatus ts_tablet_add_timestamp(CTablet* tablet, int rowIndex, int64_t timestamp);`|为指定行写入时间戳|TsStatus|`TS_OK`||
|`TsStatus ts_tablet_add_value_bool(CTablet* tablet, int colIndex, int rowIndex, bool value);`|写入布尔值|TsStatus|`TS_OK`||
|`TsStatus ts_tablet_add_value_int32(CTablet* tablet, int colIndex, int rowIndex, int32_t value);`|写入 int32|TsStatus|`TS_OK`||
|`TsStatus ts_tablet_add_value_int64(CTablet* tablet, int colIndex, int rowIndex, int64_t value);`|写入 int64|TsStatus|`TS_OK`||
|`TsStatus ts_tablet_add_value_float(CTablet* tablet, int colIndex, int rowIndex, float value);`|写入 float|TsStatus|`TS_OK`||
|`TsStatus ts_tablet_add_value_double(CTablet* tablet, int colIndex, int rowIndex, double value);`|写入 double|TsStatus|`TS_OK`||
|`TsStatus ts_tablet_add_value_string(CTablet* tablet, int colIndex, int rowIndex, const char* value);`|写入字符串|TsStatus|`TS_OK`|字符串内存归调用方管理|
|`void ts_tablet_reset(CTablet* tablet);`|重置 Tablet 内部状态以便复用|void|—|不释放对象,仅清状态|
> **说明**:当前 SessionC 实现**不提供** `ts_tablet_add_value_object`;OBJECT 类型写入请使用 C++ Session API。
>
>
### **3.5 公共 DataSet 接口**
#### **3.5.1 迭代控制与元信息**
|接口签名|函数功能|返回|备注|
|---|---|---|---|
|`void ts_dataset_set_fetch_size(CSessionDataSet* dataSet, int fetchSize);`|设置结果集拉取批大小|无||
|`bool ts_dataset_has_next(CSessionDataSet* dataSet);`|判断是否可能还有下一行|bool|失败可查 `ts_get_last_error()`|
|`CRowRecord* ts_dataset_next(CSessionDataSet* dataSet);`|获取下一行行记录句柄|行句柄指针|非 NULL 为有效行;NULL 表示结束或失败|
|`int ts_dataset_get_column_count(CSessionDataSet* dataSet);`|获取结果集列数|int||
|`const char* ts_dataset_get_column_name(CSessionDataSet* dataSet, int index);`|按索引获取列名|字符串指针|无 buf/bufLen 输出|
|`const char* ts_dataset_get_column_type(CSessionDataSet* dataSet, int index);`|按索引获取列类型名|类型名字符串指针|无 buf/bufLen 输出|
|`void ts_dataset_destroy(CSessionDataSet* dataSet);`|释放查询结果集句柄|无|每次 `ts_dataset_next` 返回非空 `CRowRecord*` 后须及时 `ts_row_record_destroy`|
#### **3.5.2 取值**
|接口签名|函数功能|返回|备注|
|---|---|---|---|
|`void ts_row_record_destroy(CRowRecord* record);`|释放行记录句柄|无||
|`int64_t ts_row_record_get_timestamp(CRowRecord* record);`|读取当前行时间戳|int64_t|时间戳不在 DataSet 上取|
|`int ts_row_record_get_field_count(CRowRecord* record);`|读取当前行字段数|int||
|`bool ts_row_record_is_null(CRowRecord* record, int index);`|判断指定列是否空值|bool||
|`bool ts_row_record_get_bool(CRowRecord* record, int index);`|按列索引读取布尔值|bool||
|`int32_t ts_row_record_get_int32(CRowRecord* record, int index);`|按列索引读取 int32|int32_t||
|`int64_t ts_row_record_get_int64(CRowRecord* record, int index);`|按列索引读取 int64|int64_t||
|`float ts_row_record_get_float(CRowRecord* record, int index);`|按列索引读取 float|float||
|`double ts_row_record_get_double(CRowRecord* record, int index);`|按列索引读取 double|double||
|`const char* ts_row_record_get_string(CRowRecord* record, int index);`|读取文本/二进制列字节视图|const char\*|可能含 `\0`;非 buf + bufLen 模式|
|`int32_t ts_row_record_get_date_int32(CRowRecord* record, int index);`|读取 DATE 列,返回 YYYYMMDD 整数|int32_t|字段为 null、越界或非 DATE 时返回 0|
|`size_t ts_row_record_get_string_byte_length(CRowRecord* record, int index);`|读取字符串/二进制字段字节长度|size_t|TEXT/BLOB/STRING 等;勿用 strlen|
|`TSDataType_C ts_row_record_get_data_type(CRowRecord* record, int index);`|按列索引读取数据类型枚举|枚举|非法参数/越界返回 `TS_TYPE_INVALID`|
### **3.6 树模型 CSession 接口矩阵**
#### **3.6.1 生命周期与会话属性**
|接口签名|函数功能|返回|成功判定|资源责任|
|---|---|---|---|---|
|`CSession* ts_session_new(const char* host, int rpcPort, const char* username, const char* password);`|创建树模型会话(单主机)|`CSession*`|返回非空句柄|若已 open,先 `ts_session_close`,再 `ts_session_destroy`|
|`CSession* ts_session_new_with_zone(const char* host, int rpcPort, const char* username, const char* password, const char* zoneId, int fetchSize);`|创建会话并指定时区与 fetch 大小|`CSession*`|返回非空句柄|同上|
|`CSession* ts_session_new_multi_node(const char* const* nodeUrls, int urlCount, const char* username, const char* password);`|创建树模型会话(多节点 URL)|`CSession*`|返回非空句柄|同上|
|`void ts_session_destroy(CSession* session);`|销毁树模型会话句柄|无|—|释放 session|
|`TsStatus ts_session_open(CSession* session);`|打开树模型 RPC 连接|TsStatus|`TS_OK`|失败可读 `ts_get_last_error()`|
|`TsStatus ts_session_open_with_compression(CSession* session, bool enableRPCCompression);`|打开连接并设置是否启用 RPC 压缩|TsStatus|`TS_OK`|同上|
|`TsStatus ts_session_close(CSession* session);`|关闭树模型连接|TsStatus|`TS_OK`|仍需 `ts_session_destroy`|
|`TsStatus ts_session_set_timezone(CSession* session, const char* zoneId);`|设置会话时区|TsStatus|`TS_OK`||
|`TsStatus ts_session_get_timezone(CSession* session, char* buf, int bufLen);`|获取当前会话时区字符串到缓冲区|TsStatus|`TS_OK` 且 buf 有效|缓冲区调用方分配|
#### **3.6.2 Schema 管理**
|接口签名|函数功能|返回|备注|
|---|---|---|---|
|`TsStatus ts_session_create_database(CSession* session, const char* database);`|创建数据库|TsStatus||
|`TsStatus ts_session_delete_database(CSession* session, const char* database);`|删除数据库|TsStatus||
|`TsStatus ts_session_delete_databases(CSession* session, const char* const* databases, int count);`|批量删除数据库|TsStatus||
|`TsStatus ts_session_create_timeseries(CSession* session, const char* path, TSDataType_C dataType, TSEncoding_C encoding, TSCompressionType_C compressor);`|创建单条时间序列|TsStatus||
|`TsStatus ts_session_create_timeseries_ex(CSession* session, const char* path, TSDataType_C dataType, TSEncoding_C encoding, TSCompressionType_C compressor, int propsCount, const char* const* propKeys, const char* const* propValues, int tagsCount, const char* const* tagKeys, const char* const* tagValues, int attrsCount, const char* const* attrKeys, const char* const* attrValues, const char* measurementAlias);`|创建时间序列(含属性、标签、别名等扩展)|TsStatus|`propsCount`/`tagsCount`/`attrsCount` 与对应 key/value 数组成对;`measurementAlias` 可为 NULL|
|`TsStatus ts_session_create_multi_timeseries(CSession* session, int count, const char* const* paths, const TSDataType_C* dataTypes, const TSEncoding_C* encodings, const TSCompressionType_C* compressors);`|批量创建时间序列|TsStatus||
|`TsStatus ts_session_create_aligned_timeseries(CSession* session, const char* deviceId, int count, const char* const* measurements, const TSDataType_C* dataTypes, const TSEncoding_C* encodings, const TSCompressionType_C* compressors);`|在指定设备下创建对齐时间序列|TsStatus||
|`TsStatus ts_session_check_timeseries_exists(CSession* session, const char* path, bool* exists);`|检查路径对应时间序列是否存在|TsStatus|存在性通过 `bool*` 输出|
|`TsStatus ts_session_delete_timeseries(CSession* session, const char* path);`|删除单条时间序列|TsStatus||
|`TsStatus ts_session_delete_timeseries_batch(CSession* session, const char* const* paths, int count);`|批量删除时间序列|TsStatus||
#### **3.6.3 写入**
|接口签名|函数功能|返回|备注|
|---|---|---|---|
|`TsStatus ts_session_insert_record_str(CSession* session, const char* deviceId, int64_t time, int count, const char* const* measurements, const char* const* values);`|单设备单条插入(字符串值)|TsStatus|无新增句柄|
|`TsStatus ts_session_insert_record(CSession* session, const char* deviceId, int64_t time, int count, const char* const* measurements, const TSDataType_C* types, const void* const* values);`|单设备单条插入(强类型值)|TsStatus|`values[i]` 指向与 `types[i]` 对应类型的值|
|`TsStatus ts_session_insert_aligned_record_str(CSession* session, const char* deviceId, int64_t time, int count, const char* const* measurements, const char* const* values);`|对齐设备单条插入(字符串值)|TsStatus||
|`TsStatus ts_session_insert_aligned_record(CSession* session, const char* deviceId, int64_t time, int count, const char* const* measurements, const TSDataType_C* types, const void* const* values);`|对齐设备单条插入(强类型值)|TsStatus||
|`TsStatus ts_session_insert_records_str(CSession* session, int deviceCount, const char* const* deviceIds, const int64_t* times, const int* measurementCounts, const char* const* const* measurementsList, const char* const* const* valuesList);`|多设备批量插入(字符串值)|TsStatus|`measurementsList[i]` / `valuesList[i]` 长度由 `measurementCounts[i]` 决定|
|`TsStatus ts_session_insert_aligned_records_str(CSession* session, int deviceCount, const char* const* deviceIds, const int64_t* times, const int* measurementCounts, const char* const* const* measurementsList, const char* const* const* valuesList);`|多设备对齐批量插入(字符串值)|TsStatus|同上|
|`TsStatus ts_session_insert_records(CSession* session, int deviceCount, const char* const* deviceIds, const int64_t* times, const int* measurementCounts, const char* const* const* measurementsList, const TSDataType_C* const* typesList, const void* const* const* valuesList);`|多设备批量插入(强类型值)|TsStatus||
|`TsStatus ts_session_insert_aligned_records(CSession* session, int deviceCount, const char* const* deviceIds, const int64_t* times, const int* measurementCounts, const char* const* const* measurementsList, const TSDataType_C* const* typesList, const void* const* const* valuesList);`|多设备对齐批量插入(强类型值)|TsStatus||
|`TsStatus ts_session_insert_records_of_one_device(CSession* session, const char* deviceId, int rowCount, const int64_t* times, const int* measurementCounts, const char* const* const* measurementsList, const TSDataType_C* const* typesList, const void* const* const* valuesList, bool sorted);`|单设备多行批量插入|TsStatus|`sorted` 表示时间戳是否已排序|
|`TsStatus ts_session_insert_aligned_records_of_one_device(CSession* session, const char* deviceId, int rowCount, const int64_t* times, const int* measurementCounts, const char* const* const* measurementsList, const TSDataType_C* const* typesList, const void* const* const* valuesList, bool sorted);`|单设备对齐多行批量插入|TsStatus|同上|
|`TsStatus ts_session_insert_tablet(CSession* session, CTablet* tablet, bool sorted);`|树模型下按 Tablet 批量写入|TsStatus|tablet 不转移所有权|
|`TsStatus ts_session_insert_aligned_tablet(CSession* session, CTablet* tablet, bool sorted);`|对齐模型下按 Tablet 批量写入|TsStatus|tablet 不转移所有权|
|`TsStatus ts_session_insert_tablets(CSession* session, int tabletCount, const char* const* deviceIds, CTablet** tablets, bool sorted);`|多 Tablet 批量写入|TsStatus|tablets 不转移所有权|
|`TsStatus ts_session_insert_aligned_tablets(CSession* session, int tabletCount, const char* const* deviceIds, CTablet** tablets, bool sorted);`|多对齐 Tablet 批量写入|TsStatus|同上|
#### **3.6.4 查询**
|接口签名|函数功能|返回|资源责任|
|---|---|---|---|
|`TsStatus ts_session_execute_query(CSession* session, const char* sql, CSessionDataSet** dataSet);`|执行查询 SQL 并返回结果集|TsStatus|`*dataSet` 调用方 `ts_dataset_destroy`|
|`TsStatus ts_session_execute_query_with_timeout(CSession* session, const char* sql, int64_t timeoutInMs, CSessionDataSet** dataSet);`|带超时执行查询|TsStatus|同上|
|`TsStatus ts_session_execute_non_query(CSession* session, const char* sql);`|执行非查询类 SQL|TsStatus|无新增句柄|
|`TsStatus ts_session_execute_raw_data_query(CSession* session, int pathCount, const char* const* paths, int64_t startTime, int64_t endTime, CSessionDataSet** dataSet);`|按路径与时间范围查询原始数据|TsStatus|`*dataSet` 调用方销毁|
|`TsStatus ts_session_execute_last_data_query(CSession* session, int pathCount, const char* const* paths, CSessionDataSet** dataSet);`|查询指定路径的 last 点数据|TsStatus|`*dataSet` 调用方销毁|
|`TsStatus ts_session_execute_last_data_query_with_time(CSession* session, int pathCount, const char* const* paths, int64_t lastTime, CSessionDataSet** dataSet);`|带 lastTime 的 last 点数据查询|TsStatus|`*dataSet` 调用方销毁|
#### **3.6.5 数据删除**
|接口签名|函数功能|返回|
|---|---|---|
|`TsStatus ts_session_delete_data(CSession* session, const char* path, int64_t endTime);`|按路径删除数据|TsStatus|
|`TsStatus ts_session_delete_data_batch(CSession* session, int pathCount, const char* const* paths, int64_t endTime);`|多路径批量删除数据|TsStatus|
|`TsStatus ts_session_delete_data_range(CSession* session, int pathCount, const char* const* paths, int64_t startTime, int64_t endTime);`|按时间范围删除数据|TsStatus|
## **4. 示例代码**
```C
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SessionC.h"
#define HOST "127.0.0.1"
#define PORT 6667
#define USER "root"
#define PASS "root"
#define TS_PATH "root.cdemo.d0.s0"
#define DEVICE "root.cdemo.d0"
static void fail(const char* ctx, CSession* s) {
fprintf(stderr, "[tree_example] %s failed: %s\n", ctx, ts_get_last_error());
if (s) {
ts_session_close(s);
ts_session_destroy(s);
}
exit(1);
}
int main(void) {
const char* path = TS_PATH;
CSession* session = ts_session_new(HOST, PORT, USER, PASS);
if (!session) {
fprintf(stderr, "[tree_example] ts_session_new returned NULL: %s\n", ts_get_last_error());
return 1;
}
if (ts_session_open(session) != TS_OK) {
fail("ts_session_open", session);
}
bool exists = false;
if (ts_session_check_timeseries_exists(session, path, &exists) != TS_OK) {
fail("ts_session_check_timeseries_exists", session);
}
if (exists) {
if (ts_session_delete_timeseries(session, path) != TS_OK) {
fail("ts_session_delete_timeseries (cleanup old)", session);
}
}
if (ts_session_create_timeseries(session, path, TS_TYPE_INT64, TS_ENCODING_RLE,
TS_COMPRESSION_SNAPPY) != TS_OK) {
fail("ts_session_create_timeseries", session);
}
const char* measurements[] = {"s0"};
const char* values[] = {"100"};
if (ts_session_insert_record_str(session, DEVICE, 1LL, 1, measurements, values) != TS_OK) {
fail("ts_session_insert_record_str", session);
}
CSessionDataSet* dataSet = NULL;
if (ts_session_execute_query(session, "select s0 from root.cdemo.d0", &dataSet) != TS_OK) {
fail("ts_session_execute_query", session);
}
if (!dataSet) {
fprintf(stderr, "[tree_example] dataSet is NULL\n");
ts_session_close(session);
ts_session_destroy(session);
return 1;
}
ts_dataset_set_fetch_size(dataSet, 1024);
int rows = 0;
while (ts_dataset_has_next(dataSet)) {
CRowRecord* record = ts_dataset_next(dataSet);
if (!record) {
break;
}
int64_t v = ts_row_record_get_int64(record, 0);
printf("[tree_example] row %d: s0 = %lld\n", rows, (long long)v);
ts_row_record_destroy(record);
rows++;
}
ts_dataset_destroy(dataSet);
printf("[tree_example] done, read %d row(s).\n", rows);
if (ts_session_delete_timeseries(session, path) != TS_OK) {
fail("ts_session_delete_timeseries", session);
}
ts_session_close(session);
ts_session_destroy(session);
return 0;
}
```