blob: d24ec140f970665acee993aa51c8d60af583be50 [file] [view]
# C Native API
## **1. Overview**
The C Native API (SessionC) is a C language wrapper for the C++ Session SDK. It is used in the same way as the C++ driver. You only need to include the additional header file `SessionC.h`. Compilation, linking, and runtime deployment share the same `iotdb_session` shared library as the C++ driver.
Thrift and Boost are already packaged into `iotdb_session`. **Applications do not need to install** Thrift or Boost headers/libraries separately.
> Note: This feature is supported since V2.0.10.
>
## **2. Installation**
### **2.1 Option 1: Use the precompiled SDK package (recommended)**
CI publishes zip packages by platform/toolchain. The file name is in the form `iotdb-session-cpp-<version>-<classifier>.zip`. After extraction, the directory structure is as follows:
```Plain Text
iotdb-session-cpp-<version>-<classifier>/
├── include/
│ ├── SessionC.h # C Native API header file
│ ├── Session.h # C++ API header file
│ └── ...
├── lib/
│ ├── libiotdb_session.so # Linux
│ ├── libiotdb_session.dylib # macOS
│ └── iotdb_session.dll + .lib # Windows
├── cmake/iotdb-session-config.cmake
├── pkgconfig/iotdb-session.pc
└── examples/ # Includes tree_example.c
```
Select the classifier according to the target environment:
|Target environment|classifier suffix|
|---|---|
|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`|
**Note: Do not use a higher-version client to connect to a lower-version server.**
#### **2.1.1 C program compilation example**
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:
Compile in the **x64 Native Tools Command Prompt** (or run `vcvars64.bat` first to initialize the environment):
```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" .
```
At runtime, place `libiotdb_session.so` / `.dylib` / `.dll` in the same directory as the executable, or configure the corresponding dynamic library search path for your platform.
#### **2.1.2 Compile examples in the SDK package**
Run the following commands in the **root directory of the extracted SDK package**. The `examples/` directory must be at the same level as `include/` and `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
```
If the library is installed in another path, such as the source CMake installation directory `iotdb-client/client-cpp/target/install`, explicitly specify `IOTDB_SDK_ROOT`. This directory must contain `include/` and `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 example:
```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 Option 2: Build from source**
#### **2.2.1 Install build dependencies (required only for source builds)**
- **macOS**
```Shell
brew install bison boost openssl
```
- **Ubuntu 16.04+ or other Debian distributions**
```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 or other Red Hat distributions**
```Shell
sudo yum update
sudo yum install gcc gcc-c++ boost-devel bison flex openssl-devel cmake
```
- **Windows**
1. Install MS Visual Studio (2019+ recommended), and select the C/C++ IDE and compiler components with CMake support.
2. Install [CMake](https://cmake.org/download/).
3. Install [Win_Flex_Bison](https://sourceforge.net/projects/winflexbison/), rename the executables to `flex.exe` and `bison.exe`, and add them to PATH.
4. Install Boost (optional, CMake can also fetch it automatically) and [OpenSSL](http://slproweb.com/products/Win32OpenSSL.html).
The CMake build compiles Thrift 0.23 from source. SSL is enabled by default. If system OpenSSL cannot be found, the build falls back to building OpenSSL from source.
#### **2.2.2 Build**
Clone the source code from git:
```Shell
git clone https://github.com/apache/iotdb.git
cd iotdb
```
To use a specific release version, switch to the corresponding branch, such as 2.0.6:
```Shell
git checkout rc/2.0.6
```
Run the Maven build in the IoTDB root directory (recommended):
```Shell
# Linux / macOS: build and package the SDK
./mvnw -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests package
# Windows (Visual Studio 2022 example)
.\mvnw.cmd -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests package
```
If Boost is not added to PATH on Windows, append a parameter such as:
```Plain Text
-Dboost.include.dir="C:\boost_1_88_0"
```
You can also use CMake directly:
```Shell
cmake -S iotdb-client/client-cpp -B build
cmake --build build --target install
```
Linux release packages are built in the `manylinux_2_28` container. **The target machine requires glibc 2.28 or later**. The current build **no longer** uses old parameters such as `-Diotdb-tools-thrift.version=0.14.1.1-gcc4-SNAPSHOT`.
Full verification with integration tests:
```Shell
./mvnw clean verify -P with-cpp -pl iotdb-client/client-cpp -am
```
### **2.3 Build artifacts**
After a successful build, C API related files are located as follows:
- C API header file (source): `iotdb-client/client-cpp/src/include/SessionC.h`
- C API header file (installation/SDK package): `include/SessionC.h`
- Library files:
- Source build: `iotdb-client/client-cpp/target/install/lib/`
- Maven package: `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`
- Example source code:
- Tree model: `iotdb-client/client-cpp/examples/tree_example.c`
- Table model: `iotdb-client/client-cpp/examples/table_example.c`
- Integration tests:
- Tree model: `iotdb-client/client-cpp/test/cpp/sessionCIT.cpp`
- Table model: `iotdb-client/client-cpp/test/cpp/sessionCRelationalIT.cpp`
## **3. Basic API description**
**Description: The C driver is used in the same way as the C++ driver. You only need to include the additional header file `SessionC.h`. Compilation, runtime behavior, and system dependencies are shared with the C++ driver.**
### **3.1 Common conventions**
#### **3.1.1 Status codes and error messages**
- `TsStatus`: `TS_OK (0)` indicates success. Any non-zero value indicates failure.
- Predefined error codes:
- `TS_ERR_CONNECTION (-1)`
- `TS_ERR_EXECUTION (-2)`
- `TS_ERR_INVALID_PARAM (-3)`
- `TS_ERR_NULL_PTR (-4)`
- `TS_ERR_UNKNOWN (-99)`
- The implementation may also return other negative values, which must be interpreted together with `ts_get_last_error()`.
- The Session C++ API reports many errors through exceptions and does not return a unified status code. The C API uniformly returns the integer type `TsStatus`, and fine-grained error information can be obtained through `ts_get_last_error()`.
```C
const char* ts_get_last_error(void);
```
Returns the error message of the last **failed** C API call in the current thread. The returned pointer is valid until the next C API call in the same thread.
#### **3.1.2 Memory and handle rules**
- All `char* buf + int bufLen` output parameters must be allocated by the caller.
- `CSession*`, `CTablet*`, `CSessionDataSet*`, and `CRowRecord*` are opaque pointers. After successful creation, the caller must release them according to the conventions of each API.
### **3.2 Enumerations and constants**
- **TSDataType_C (data type)**
|Enumeration value|Meaning|
|---|---|
|`TS_TYPE_BOOLEAN`|Boolean|
|`TS_TYPE_INT32`|32-bit integer|
|`TS_TYPE_INT64`|64-bit integer|
|`TS_TYPE_FLOAT`|Single-precision floating point|
|`TS_TYPE_DOUBLE`|Double-precision floating point|
|`TS_TYPE_TEXT`|Text|
|`TS_TYPE_TIMESTAMP`|Timestamp|
|`TS_TYPE_DATE`|Date|
|`TS_TYPE_BLOB`|Binary large object|
|`TS_TYPE_STRING`|String|
|`TS_TYPE_INVALID`|Invalid parameter/error path (not a server-side type)|
- **TSEncoding_C (encoding)**
`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 (compression)**
`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 Handles, status codes, and constants**
|Name|C definition|Meaning|Lifecycle responsibility|
|---|---|---|---|
|`CSession*`|`typedef struct CSession_ CSession;`|Tree model session|After `ts_session_new` / `ts_session_new_with_zone` / `ts_session_new_multi_node` succeeds, the caller calls `ts_session_close` if it has been opened, and then `ts_session_destroy`|
|`CTablet*`|`typedef struct CTablet_ CTablet;` (opaque)|Tablet batch writing, shared by tree and table models|After `ts_tablet_new` / `ts_tablet_new_with_category` succeeds, the caller calls `ts_tablet_destroy`|
|`CSessionDataSet*`|`typedef struct CSessionDataSet_ CSessionDataSet;` (opaque)|Query result set, shared by tree and table models|After a query API successfully returns `*dataSet`, the caller calls `ts_dataset_destroy`|
|`CRowRecord*`|`typedef struct CRowRecord_ CRowRecord;` (opaque)|Current row|When `ts_dataset_next` returns a non-null value, the caller calls `ts_row_record_destroy`|
|`TsStatus`<br>|`typedef int64_t TsStatus;`|API execution result code|`TS_OK` is 0. Any non-zero value indicates failure|
|`ts_get_last_error`|`const char* ts_get_last_error(void);`|Error message of the last **failed** C API call in the current thread|The returned pointer is valid until the next C API call in the same thread|
### **3.4 Common Tablet APIs**
#### **3.4.1 Creation and destruction**
|API signature|Function|Input parameters|Return value|Success condition|Failure condition|Resource responsibility|
|---|---|---|---|---|---|---|
|`CTablet* ts_tablet_new(const char* deviceId, int columnCount, const char* const* columnNames, const TSDataType_C* dataTypes, int maxRowNumber);`|Create a Tablet handle|deviceId: device or table name; columnNames / dataTypes: arrays of column names and types; maxRowNumber: maximum number of rows|`CTablet*`|Returns a non-null handle|Returns a null handle|Caller calls `ts_tablet_destroy`|
|`void ts_tablet_destroy(CTablet* tablet);`|Destroy a Tablet handle|tablet: handle to release|None|The handle must not be used after the call|-|Releases tablet|
#### **3.4.2 Data filling and state control**
|API signature|Function|Return value|Success condition|Remarks|
|---|---|---|---|---|
|`int ts_tablet_get_row_count(CTablet* tablet);`|Query the current valid row count of the Tablet|int|Row count >= 0|Read-only query|
|`TsStatus ts_tablet_set_row_count(CTablet* tablet, int rowCount);`|Set the valid row count of the Tablet|TsStatus|`TS_OK`|The valid row count must be set before writing|
|`TsStatus ts_tablet_add_timestamp(CTablet* tablet, int rowIndex, int64_t timestamp);`|Write a timestamp for the specified row|TsStatus|`TS_OK`||
|`TsStatus ts_tablet_add_value_bool(CTablet* tablet, int colIndex, int rowIndex, bool value);`|Write a Boolean value|TsStatus|`TS_OK`||
|`TsStatus ts_tablet_add_value_int32(CTablet* tablet, int colIndex, int rowIndex, int32_t value);`|Write an int32 value|TsStatus|`TS_OK`||
|`TsStatus ts_tablet_add_value_int64(CTablet* tablet, int colIndex, int rowIndex, int64_t value);`|Write an int64 value|TsStatus|`TS_OK`||
|`TsStatus ts_tablet_add_value_float(CTablet* tablet, int colIndex, int rowIndex, float value);`|Write a float value|TsStatus|`TS_OK`||
|`TsStatus ts_tablet_add_value_double(CTablet* tablet, int colIndex, int rowIndex, double value);`|Write a double value|TsStatus|`TS_OK`||
|`TsStatus ts_tablet_add_value_string(CTablet* tablet, int colIndex, int rowIndex, const char* value);`|Write a string|TsStatus|`TS_OK`|String memory is managed by the caller|
|`void ts_tablet_reset(CTablet* tablet);`|Reset the internal state of the Tablet for reuse|void|-|Does not release the object. Only clears the state|
> **Description**: The current SessionC implementation **does not provide** `ts_tablet_add_value_object`. Use the C++ Session API to write OBJECT values.
>
>
### **3.5 Common DataSet APIs**
#### **3.5.1 Iteration control and metadata**
|API signature|Function|Return value|Remarks|
|---|---|---|---|
|`void ts_dataset_set_fetch_size(CSessionDataSet* dataSet, int fetchSize);`|Set the fetch batch size of the result set|None||
|`bool ts_dataset_has_next(CSessionDataSet* dataSet);`|Determine whether there may be another row|bool|On failure, check `ts_get_last_error()`|
|`CRowRecord* ts_dataset_next(CSessionDataSet* dataSet);`|Get the next row record handle|Row handle pointer|Non-NULL indicates a valid row. NULL indicates end or failure|
|`int ts_dataset_get_column_count(CSessionDataSet* dataSet);`|Get the number of columns in the result set|int||
|`const char* ts_dataset_get_column_name(CSessionDataSet* dataSet, int index);`|Get a column name by index|String pointer|No buf/bufLen output|
|`const char* ts_dataset_get_column_type(CSessionDataSet* dataSet, int index);`|Get a column type name by index|Type name string pointer|No buf/bufLen output|
|`void ts_dataset_destroy(CSessionDataSet* dataSet);`|Release a query result set handle|None|After each non-null `CRowRecord*` returned by `ts_dataset_next`, call `ts_row_record_destroy` in time|
#### **3.5.2 Value access**
|API signature|Function|Return value|Remarks|
|---|---|---|---|
|`void ts_row_record_destroy(CRowRecord* record);`|Release a row record handle|None||
|`int64_t ts_row_record_get_timestamp(CRowRecord* record);`|Read the timestamp of the current row|int64_t|The timestamp is not read from DataSet|
|`int ts_row_record_get_field_count(CRowRecord* record);`|Read the number of fields in the current row|int||
|`bool ts_row_record_is_null(CRowRecord* record, int index);`|Determine whether the specified column is null|bool||
|`bool ts_row_record_get_bool(CRowRecord* record, int index);`|Read a Boolean value by column index|bool||
|`int32_t ts_row_record_get_int32(CRowRecord* record, int index);`|Read an int32 value by column index|int32_t||
|`int64_t ts_row_record_get_int64(CRowRecord* record, int index);`|Read an int64 value by column index|int64_t||
|`float ts_row_record_get_float(CRowRecord* record, int index);`|Read a float value by column index|float||
|`double ts_row_record_get_double(CRowRecord* record, int index);`|Read a double value by column index|double||
|`const char* ts_row_record_get_string(CRowRecord* record, int index);`|Read the byte view of a text/binary column|const char.|May contain `.`. Not a buf . bufLen pattern|
|`int32_t ts_row_record_get_date_int32(CRowRecord* record, int index);`|Read a DATE column and return an integer in YYYYMMDD format|int32_t|Returns 0 if the field is null, out of bounds, or not DATE|
|`size_t ts_row_record_get_string_byte_length(CRowRecord* record, int index);`|Read the byte length of a string/binary field|size_t|TEXT/BLOB/STRING, etc. Do not use strlen|
|`TSDataType_C ts_row_record_get_data_type(CRowRecord* record, int index);`|Read the data type enumeration by column index|Enumeration|Returns `TS_TYPE_INVALID` for invalid parameters or out-of-bounds indexes|
### **3.6 Tree model CSession API matrix**
#### **3.6.1 Lifecycle and session properties**
|API signature|Function|Return value|Success condition|Resource responsibility|
|---|---|---|---|---|
|`CSession* ts_session_new(const char* host, int rpcPort, const char* username, const char* password);`|Create a tree model session (single host)|`CSession*`|Returns a non-null handle|If opened, call `ts_session_close` first, and then `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);`|Create a session and specify the time zone and fetch size|`CSession*`|Returns a non-null handle|Same as above|
|`CSession* ts_session_new_multi_node(const char* const* nodeUrls, int urlCount, const char* username, const char* password);`|Create a tree model session (multi-node URL)|`CSession*`|Returns a non-null handle|Same as above|
|`void ts_session_destroy(CSession* session);`|Destroy a tree model session handle|None|-|Releases session|
|`TsStatus ts_session_open(CSession* session);`|Open a tree model RPC connection|TsStatus|`TS_OK`|On failure, read `ts_get_last_error()`|
|`TsStatus ts_session_open_with_compression(CSession* session, bool enableRPCCompression);`|Open a connection and set whether to enable RPC compression|TsStatus|`TS_OK`|Same as above|
|`TsStatus ts_session_close(CSession* session);`|Close a tree model connection|TsStatus|`TS_OK`|`ts_session_destroy` is still required|
|`TsStatus ts_session_set_timezone(CSession* session, const char* zoneId);`|Set the session time zone|TsStatus|`TS_OK`||
|`TsStatus ts_session_get_timezone(CSession* session, char* buf, int bufLen);`|Get the current session time zone string into a buffer|TsStatus|`TS_OK` and buf is valid|The caller allocates the buffer|
#### **3.6.2 Schema management**
|API signature|Function|Return value|Remarks|
|---|---|---|---|
|`TsStatus ts_session_create_database(CSession* session, const char* database);`|Create a database|TsStatus||
|`TsStatus ts_session_delete_database(CSession* session, const char* database);`|Delete a database|TsStatus||
|`TsStatus ts_session_delete_databases(CSession* session, const char* const* databases, int count);`|Delete databases in batches|TsStatus||
|`TsStatus ts_session_create_timeseries(CSession* session, const char* path, TSDataType_C dataType, TSEncoding_C encoding, TSCompressionType_C compressor);`|Create a single timeseries|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);`|Create a timeseries with extensions such as properties, tags, attributes, and alias|TsStatus|`propsCount`/`tagsCount`/`attrsCount` must match their corresponding key/value arrays. `measurementAlias` can be 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);`|Create timeseries in batches|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);`|Create aligned timeseries under the specified device|TsStatus||
|`TsStatus ts_session_check_timeseries_exists(CSession* session, const char* path, bool* exists);`|Check whether the timeseries for the path exists|TsStatus|Existence is output through `bool*`|
|`TsStatus ts_session_delete_timeseries(CSession* session, const char* path);`|Delete a single timeseries|TsStatus||
|`TsStatus ts_session_delete_timeseries_batch(CSession* session, const char* const* paths, int count);`|Delete timeseries in batches|TsStatus||
#### **3.6.3 Writing**
|API signature|Function|Return value|Remarks|
|---|---|---|---|
|`TsStatus ts_session_insert_record_str(CSession* session, const char* deviceId, int64_t time, int count, const char* const* measurements, const char* const* values);`|Insert one record for one device (string values)|TsStatus|No new handle|
|`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);`|Insert one record for one device (strongly typed values)|TsStatus|`values[i]` points to the value of the type corresponding to `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);`|Insert one record for an aligned device (string 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);`|Insert one record for an aligned device (strongly typed 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);`|Batch insert for multiple devices (string values)|TsStatus|The lengths of `measurementsList[i]` / `valuesList[i]` are determined by `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);`|Batch insert for multiple aligned devices (string values)|TsStatus|Same as above|
|`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);`|Batch insert for multiple devices (strongly typed values)|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);`|Batch insert for multiple aligned devices (strongly typed values)|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);`|Batch insert multiple rows for one device|TsStatus|`sorted` indicates whether timestamps are already 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);`|Batch insert multiple aligned rows for one device|TsStatus|Same as above|
|`TsStatus ts_session_insert_tablet(CSession* session, CTablet* tablet, bool sorted);`|Batch write by Tablet in the tree model|TsStatus|Ownership of tablet is not transferred|
|`TsStatus ts_session_insert_aligned_tablet(CSession* session, CTablet* tablet, bool sorted);`|Batch write by Tablet in the aligned model|TsStatus|Ownership of tablet is not transferred|
|`TsStatus ts_session_insert_tablets(CSession* session, int tabletCount, const char* const* deviceIds, CTablet** tablets, bool sorted);`|Batch write multiple Tablets|TsStatus|Ownership of tablets is not transferred|
|`TsStatus ts_session_insert_aligned_tablets(CSession* session, int tabletCount, const char* const* deviceIds, CTablet** tablets, bool sorted);`|Batch write multiple aligned Tablets|TsStatus|Same as above|
#### **3.6.4 Querying**
|API signature|Function|Return value|Resource responsibility|
|---|---|---|---|
|`TsStatus ts_session_execute_query(CSession* session, const char* sql, CSessionDataSet** dataSet);`|Execute query SQL and return a result set|TsStatus|Caller calls `ts_dataset_destroy` for `*dataSet`|
|`TsStatus ts_session_execute_query_with_timeout(CSession* session, const char* sql, int64_t timeoutInMs, CSessionDataSet** dataSet);`|Execute a query with timeout|TsStatus|Same as above|
|`TsStatus ts_session_execute_non_query(CSession* session, const char* sql);`|Execute non-query SQL|TsStatus|No new handle|
|`TsStatus ts_session_execute_raw_data_query(CSession* session, int pathCount, const char* const* paths, int64_t startTime, int64_t endTime, CSessionDataSet** dataSet);`|Query raw data by paths and time range|TsStatus|Caller destroys `*dataSet`|
|`TsStatus ts_session_execute_last_data_query(CSession* session, int pathCount, const char* const* paths, CSessionDataSet** dataSet);`|Query last point data for specified paths|TsStatus|Caller destroys `*dataSet`|
|`TsStatus ts_session_execute_last_data_query_with_time(CSession* session, int pathCount, const char* const* paths, int64_t lastTime, CSessionDataSet** dataSet);`|Query last point data with lastTime|TsStatus|Caller destroys `*dataSet`|
#### **3.6.5 Data deletion**
|API signature|Function|Return value|
|---|---|---|
|`TsStatus ts_session_delete_data(CSession* session, const char* path, int64_t endTime);`|Delete data by path|TsStatus|
|`TsStatus ts_session_delete_data_batch(CSession* session, int pathCount, const char* const* paths, int64_t endTime);`|Delete data by multiple paths in batches|TsStatus|
|`TsStatus ts_session_delete_data_range(CSession* session, int pathCount, const char* const* paths, int64_t startTime, int64_t endTime);`|Delete data by time range|TsStatus|
## **4. Sample code**
```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.", 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.", 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.");
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.", rows, (long long)v);
ts_row_record_destroy(record);
rows++;
}
ts_dataset_destroy(dataSet);
printf("[tree_example] done, read %d row(s)..", 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;
}
```