blob: 80b2279364a62570e419b73c5f45303904061a16 [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 table_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 table_example.c \
-I"$IOTDB_SESSION_HOME/include" \
-L"$IOTDB_SESSION_HOME/lib" \
-liotdb_session -pthread \
-Wl,-rpath,"$IOTDB_SESSION_HOME/lib" \
-o table_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 table_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 table_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/table_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.
- `CTableSession*`, `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`
- **TSColumnCategory_C (table model column category)**
|Enumeration value|Meaning|
|---|---|
|`TS_COL_TAG`|TAG column|
|`TS_COL_FIELD`|FIELD column|
|`TS_COL_ATTRIBUTE`|ATTRIBUTE column|
### **3.3 Handles, status codes, and constants**
|Name|C definition|Meaning|Lifecycle responsibility|
|---|---|---|---|
|`CTableSession*`|`typedef struct CTableSession_ CTableSession;`|Table model session|After `ts_table_session_new` / `ts_table_session_new_multi_node` succeeds, the caller calls `ts_table_session_close` if it has been opened, and then `ts_table_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`|`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<br>|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`|
|`CTablet* ts_tablet_new_with_category(const char* deviceId, int columnCount, const char* const* columnNames, const TSDataType_C* dataTypes, const TSColumnCategory_C* columnCategories, int maxRowNumber);`|Create a Tablet with column categories (TAG/FIELD/ATTRIBUTE)|columnCategories: `TS_COL_TAG` / `TS_COL_FIELD` / `TS_COL_ATTRIBUTE`|`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 Table model CTableSession API matrix**
#### **3.6.1 Lifecycle**
|API signature|Function|Return value|Resource responsibility|
|---|---|---|---|
|`CTableSession* ts_table_session_new(const char* host, int rpcPort, const char* username, const char* password, const char* database);`|Create a table model session|`CTableSession*`|If opened, call `ts_table_session_close` first, and then `ts_table_session_destroy`|
|`CTableSession* ts_table_session_new_multi_node(const char* const* nodeUrls, int urlCount, const char* username, const char* password, const char* database);`|Create a table model session (multi-node URL)|`CTableSession*`|Same as above|
|`TsStatus ts_table_session_open(CTableSession* session);`|Open a table model RPC connection|TsStatus|On failure, check `ts_get_last_error()`|
|`TsStatus ts_table_session_close(CTableSession* session);`|Close a table model connection|TsStatus|`ts_table_session_destroy` is still required|
|`void ts_table_session_destroy(CTableSession* session);`|Destroy a table model session handle|None|Releases session|
> **Description**: The `database` parameter is the default database name. Pass the empty string `""` to leave it unset, and switch later through the `USE` SQL statement.
>
>
#### **3.6.2 Writing and querying**
|API signature|Function|Return value|Resource responsibility|
|---|---|---|---|
|`TsStatus ts_table_session_insert(CTableSession* session, CTablet* tablet);`|Write data by Tablet in the table model|TsStatus|Ownership of tablet is not transferred|
|`TsStatus ts_table_session_execute_query(CTableSession* session, const char* sql, CSessionDataSet** dataSet);`|Execute query SQL in the table model|TsStatus|Caller calls `ts_dataset_destroy` for `*dataSet`|
|`TsStatus ts_table_session_execute_query_with_timeout(CTableSession* session, const char* sql, int64_t timeoutInMs, CSessionDataSet** dataSet);`|Execute a query with timeout in the table model|TsStatus|Same as above|
|`TsStatus ts_table_session_execute_non_query(CTableSession* session, const char* sql);`|Execute non-query SQL in the table model|TsStatus|No new handle|
## **4. Sample code**
```C
#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 DB_NAME "cdemo_db"
#define TABLE_NAME "cdemo_t0"
static void fail(const char* ctx, CTableSession* s) {
fprintf(stderr, "[table_example] %s failed: %s.", ctx, ts_get_last_error());
if (s) {
ts_table_session_close(s);
ts_table_session_destroy(s);
}
exit(1);
}
int main(void) {
/* The last parameter is the default database name. Pass "" to leave it unset and switch later through USE SQL. */
CTableSession* session = ts_table_session_new(HOST, PORT, USER, PASS, "");
if (!session) {
fprintf(stderr, "[table_example] ts_table_session_new returned NULL: %s.",
ts_get_last_error());
return 1;
}
if (ts_table_session_open(session) != TS_OK) {
fail("ts_table_session_open", session);
}
char sql[512];
snprintf(sql, sizeof(sql), "DROP DATABASE IF EXISTS %s", DB_NAME);
(void)ts_table_session_execute_non_query(session, sql);
snprintf(sql, sizeof(sql), "CREATE DATABASE %s", DB_NAME);
if (ts_table_session_execute_non_query(session, sql) != TS_OK) {
fail("CREATE DATABASE", session);
}
snprintf(sql, sizeof(sql), "USE .%s.", DB_NAME);
if (ts_table_session_execute_non_query(session, sql) != TS_OK) {
fail("USE DATABASE", session);
}
const char* ddl = "CREATE TABLE " TABLE_NAME " ("
"tag1 string tag,"
"attr1 string attribute,"
"m1 double field)";
if (ts_table_session_execute_non_query(session, ddl) != TS_OK) {
fail("CREATE TABLE", session);
}
const char* columnNames[] = {"tag1", "attr1", "m1"};
TSDataType_C dataTypes[] = {TS_TYPE_STRING, TS_TYPE_STRING, TS_TYPE_DOUBLE};
TSColumnCategory_C colCategories[] = {TS_COL_TAG, TS_COL_ATTRIBUTE, TS_COL_FIELD};
CTablet* tablet =
ts_tablet_new_with_category(TABLE_NAME, 3, columnNames, dataTypes, colCategories, 100);
if (!tablet) {
fail("ts_tablet_new_with_category", session);
}
int i;
for (i = 0; i < 5; i++) {
if (ts_tablet_add_timestamp(tablet, i, (int64_t)i) != TS_OK) {
ts_tablet_destroy(tablet);
fail("ts_tablet_add_timestamp", session);
}
if (ts_tablet_add_value_string(tablet, 0, i, "device_A") != TS_OK) {
ts_tablet_destroy(tablet);
fail("ts_tablet_add_value_string tag", session);
}
if (ts_tablet_add_value_string(tablet, 1, i, "attr_val") != TS_OK) {
ts_tablet_destroy(tablet);
fail("ts_tablet_add_value_string attr", session);
}
if (ts_tablet_add_value_double(tablet, 2, i, (double)i * 1.5) != TS_OK) {
ts_tablet_destroy(tablet);
fail("ts_tablet_add_value_double", session);
}
}
if (ts_tablet_set_row_count(tablet, 5) != TS_OK) {
ts_tablet_destroy(tablet);
fail("ts_tablet_set_row_count", session);
}
if (ts_table_session_insert(session, tablet) != TS_OK) {
ts_tablet_destroy(tablet);
fail("ts_table_session_insert", session);
}
ts_tablet_destroy(tablet);
CSessionDataSet* dataSet = NULL;
if (ts_table_session_execute_query(session, "SELECT * FROM " TABLE_NAME, &dataSet) != TS_OK) {
fail("ts_table_session_execute_query", session);
}
if (!dataSet) {
fprintf(stderr, "[table_example] dataSet is NULL.");
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.", 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)..", 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;
}
```