diff --git a/example/client-c-example/README.md b/example/client-c-example/README.md
new file mode 100644
index 0000000000000..8920883ddbcd6
--- /dev/null
+++ b/example/client-c-example/README.md
@@ -0,0 +1,68 @@
+
+
+# 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
new file mode 100644
index 0000000000000..3116c0fd0b4f2
--- /dev/null
+++ b/example/client-c-example/pom.xml
@@ -0,0 +1,150 @@
+
+
+
+ 4.0.0
+
+ org.apache.iotdb
+ iotdb-examples
+ 2.0.7-SNAPSHOT
+
+ client-c-example
+ IoTDB: Example: C Client (SessionC)
+
+
+ org.apache.iotdb
+ client-cpp
+ ${project.version}
+ pom
+ provided
+
+
+
+
+
+ com.coderplus.maven.plugins
+ copy-rename-maven-plugin
+
+
+ copy-c-sources-and-cmake
+
+ copy
+
+
+
+
+ ${project.basedir}/src/tree_example.c
+ ${project.build.directory}/tree_example.c
+
+
+ ${project.basedir}/src/table_example.c
+ ${project.build.directory}/table_example.c
+
+
+ ${project.basedir}/src/CMakeLists.txt
+ ${project.build.directory}/CMakeLists.txt
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+
+ unpack-client
+
+ unpack
+
+ generate-sources
+
+
+
+ org.apache.iotdb
+ client-cpp
+ ${project.version}
+ zip
+ cpp-${os.classifier}
+ true
+
+
+ ${project.build.directory}/client
+
+
+
+ unpack-thrift
+
+ unpack
+
+ generate-sources
+
+
+
+ org.apache.iotdb.tools
+ iotdb-tools-thrift
+ ${iotdb-tools-thrift.version}
+ ${os.classifier}
+ zip
+ true
+ ${project.build.directory}/thrift
+
+
+
+
+
+
+
+ io.github.cmake-maven-plugin
+ cmake-maven-plugin
+
+
+ cmake-generate
+
+ generate
+
+ compile
+
+ ${cmake.generator}
+ ${project.build.directory}
+ ${project.build.directory}
+
+
+
+
+
+
+ cmake-compile
+
+ compile
+
+ compile
+
+ ${cmake.build.type}
+ ${project.build.directory}
+
+
+
+
+
+
+
diff --git a/example/client-c-example/src/table_example.c b/example/client-c-example/src/table_example.c
new file mode 100644
index 0000000000000..9ad844ec4c2af
--- /dev/null
+++ b/example/client-c-example/src/table_example.c
@@ -0,0 +1,152 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * Table model: CREATE DATABASE/TABLE, insert rows via Tablet, SELECT, DROP DATABASE.
+ * Requires IoTDB table-SQL support. Edit HOST / PORT / credentials below.
+ */
+
+#include
+#include
+#include
+
+#include "SessionC.h"
+
+#define HOST "127.0.0.1"
+#define PORT 6667
+#define USER "root"
+#define PASS "root"
+
+#define DB_NAME "cdemo_db"
+#define TABLE_NAME "cdemo_t0"
+
+static void fail(const char* ctx, CTableSession* s) {
+ fprintf(stderr, "[table_example] %s failed: %s\n", ctx, ts_get_last_error());
+ if (s) {
+ ts_table_session_close(s);
+ ts_table_session_destroy(s);
+ }
+ exit(1);
+}
+
+int main(void) {
+ /* Last arg: default database name; empty string leaves it unset (we USE "cdemo_db" via SQL below). */
+ CTableSession* session = ts_table_session_new(HOST, PORT, USER, PASS, "");
+ if (!session) {
+ fprintf(stderr, "[table_example] ts_table_session_new returned NULL: %s\n", ts_get_last_error());
+ return 1;
+ }
+ if (ts_table_session_open(session) != TS_OK) {
+ fail("ts_table_session_open", session);
+ }
+
+ char sql[512];
+ snprintf(sql, sizeof(sql), "DROP DATABASE IF EXISTS %s", DB_NAME);
+ (void)ts_table_session_execute_non_query(session, sql);
+
+ snprintf(sql, sizeof(sql), "CREATE DATABASE %s", DB_NAME);
+ if (ts_table_session_execute_non_query(session, sql) != TS_OK) {
+ fail("CREATE DATABASE", session);
+ }
+
+ snprintf(sql, sizeof(sql), "USE \"%s\"", DB_NAME);
+ if (ts_table_session_execute_non_query(session, sql) != TS_OK) {
+ fail("USE DATABASE", session);
+ }
+
+ const char* ddl =
+ "CREATE TABLE " TABLE_NAME " ("
+ "tag1 string tag,"
+ "attr1 string attribute,"
+ "m1 double field)";
+ if (ts_table_session_execute_non_query(session, ddl) != TS_OK) {
+ fail("CREATE TABLE", session);
+ }
+
+ const char* columnNames[] = {"tag1", "attr1", "m1"};
+ TSDataType_C dataTypes[] = {TS_TYPE_STRING, TS_TYPE_STRING, TS_TYPE_DOUBLE};
+ TSColumnCategory_C colCategories[] = {TS_COL_TAG, TS_COL_ATTRIBUTE, TS_COL_FIELD};
+
+ CTablet* tablet = ts_tablet_new_with_category(TABLE_NAME, 3, columnNames, dataTypes, colCategories, 100);
+ if (!tablet) {
+ fail("ts_tablet_new_with_category", session);
+ }
+
+ int i;
+ for (i = 0; i < 5; i++) {
+ if (ts_tablet_add_timestamp(tablet, i, (int64_t)i) != TS_OK) {
+ ts_tablet_destroy(tablet);
+ fail("ts_tablet_add_timestamp", session);
+ }
+ if (ts_tablet_add_value_string(tablet, 0, i, "device_A") != TS_OK) {
+ ts_tablet_destroy(tablet);
+ fail("ts_tablet_add_value_string tag", session);
+ }
+ if (ts_tablet_add_value_string(tablet, 1, i, "attr_val") != TS_OK) {
+ ts_tablet_destroy(tablet);
+ fail("ts_tablet_add_value_string attr", session);
+ }
+ if (ts_tablet_add_value_double(tablet, 2, i, (double)i * 1.5) != TS_OK) {
+ ts_tablet_destroy(tablet);
+ fail("ts_tablet_add_value_double", session);
+ }
+ }
+ if (ts_tablet_set_row_count(tablet, 5) != TS_OK) {
+ ts_tablet_destroy(tablet);
+ fail("ts_tablet_set_row_count", session);
+ }
+
+ if (ts_table_session_insert(session, tablet) != TS_OK) {
+ ts_tablet_destroy(tablet);
+ fail("ts_table_session_insert", session);
+ }
+ ts_tablet_destroy(tablet);
+
+ CSessionDataSet* dataSet = NULL;
+ if (ts_table_session_execute_query(session, "SELECT * FROM " TABLE_NAME, &dataSet) != TS_OK) {
+ fail("ts_table_session_execute_query", session);
+ }
+ if (!dataSet) {
+ fprintf(stderr, "[table_example] dataSet is NULL\n");
+ ts_table_session_close(session);
+ ts_table_session_destroy(session);
+ return 1;
+ }
+ ts_dataset_set_fetch_size(dataSet, 1024);
+
+ int count = 0;
+ while (ts_dataset_has_next(dataSet)) {
+ CRowRecord* record = ts_dataset_next(dataSet);
+ if (!record) {
+ break;
+ }
+ printf("[table_example] row %d: time=%lld\n", count, (long long)ts_row_record_get_timestamp(record));
+ ts_row_record_destroy(record);
+ count++;
+ }
+ ts_dataset_destroy(dataSet);
+ printf("[table_example] SELECT returned %d row(s).\n", count);
+
+ snprintf(sql, sizeof(sql), "DROP DATABASE IF EXISTS %s", DB_NAME);
+ (void)ts_table_session_execute_non_query(session, sql);
+
+ ts_table_session_close(session);
+ ts_table_session_destroy(session);
+ return 0;
+}
diff --git a/example/client-c-example/src/tree_example.c b/example/client-c-example/src/tree_example.c
new file mode 100644
index 0000000000000..a98df2831b69e
--- /dev/null
+++ b/example/client-c-example/src/tree_example.c
@@ -0,0 +1,114 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * Tree model: create one timeseries, insert one row via string values, SELECT, cleanup.
+ * Edit HOST / PORT / credentials below to match your IoTDB.
+ */
+
+#include
+#include
+#include
+#include
+
+#include "SessionC.h"
+
+#define HOST "127.0.0.1"
+#define PORT 6667
+#define USER "root"
+#define PASS "root"
+
+#define TS_PATH "root.cdemo.d0.s0"
+#define DEVICE "root.cdemo.d0"
+
+static void fail(const char* ctx, CSession* s) {
+ fprintf(stderr, "[tree_example] %s failed: %s\n", ctx, ts_get_last_error());
+ if (s) {
+ ts_session_close(s);
+ ts_session_destroy(s);
+ }
+ exit(1);
+}
+
+int main(void) {
+ const char* path = TS_PATH;
+ CSession* session = ts_session_new(HOST, PORT, USER, PASS);
+ if (!session) {
+ fprintf(stderr, "[tree_example] ts_session_new returned NULL: %s\n", ts_get_last_error());
+ return 1;
+ }
+ if (ts_session_open(session) != TS_OK) {
+ fail("ts_session_open", session);
+ }
+
+ bool exists = false;
+ if (ts_session_check_timeseries_exists(session, path, &exists) != TS_OK) {
+ fail("ts_session_check_timeseries_exists", session);
+ }
+ if (exists) {
+ if (ts_session_delete_timeseries(session, path) != TS_OK) {
+ fail("ts_session_delete_timeseries (cleanup old)", session);
+ }
+ }
+ if (ts_session_create_timeseries(session, path, TS_TYPE_INT64, TS_ENCODING_RLE, TS_COMPRESSION_SNAPPY) !=
+ TS_OK) {
+ fail("ts_session_create_timeseries", session);
+ }
+
+ const char* measurements[] = {"s0"};
+ const char* values[] = {"100"};
+ if (ts_session_insert_record_str(session, DEVICE, 1LL, 1, measurements, values) != TS_OK) {
+ fail("ts_session_insert_record_str", session);
+ }
+
+ CSessionDataSet* dataSet = NULL;
+ if (ts_session_execute_query(session, "select s0 from root.cdemo.d0", &dataSet) != TS_OK) {
+ fail("ts_session_execute_query", session);
+ }
+ if (!dataSet) {
+ fprintf(stderr, "[tree_example] dataSet is NULL\n");
+ ts_session_close(session);
+ ts_session_destroy(session);
+ return 1;
+ }
+ ts_dataset_set_fetch_size(dataSet, 1024);
+
+ int rows = 0;
+ while (ts_dataset_has_next(dataSet)) {
+ CRowRecord* record = ts_dataset_next(dataSet);
+ if (!record) {
+ break;
+ }
+ int64_t v = ts_row_record_get_int64(record, 0);
+ printf("[tree_example] row %d: s0 = %lld\n", rows, (long long)v);
+ ts_row_record_destroy(record);
+ rows++;
+ }
+ ts_dataset_destroy(dataSet);
+
+ printf("[tree_example] done, read %d row(s).\n", rows);
+
+ if (ts_session_delete_timeseries(session, path) != TS_OK) {
+ fail("ts_session_delete_timeseries", session);
+ }
+
+ ts_session_close(session);
+ ts_session_destroy(session);
+ return 0;
+}
diff --git a/example/pom.xml b/example/pom.xml
index 8abb5e30d54e1..a8415b04d0741 100644
--- a/example/pom.xml
+++ b/example/pom.xml
@@ -85,6 +85,7 @@
with-cpp
client-cpp-example
+ client-c-example
diff --git a/iotdb-client/client-cpp/pom.xml b/iotdb-client/client-cpp/pom.xml
index 7f43fd77440e0..88b70cebdf108 100644
--- a/iotdb-client/client-cpp/pom.xml
+++ b/iotdb-client/client-cpp/pom.xml
@@ -273,6 +273,7 @@
integration-test
+ ${cmake.build.type}
${project.build.directory}/build/test
${maven.test.skip}
@@ -314,8 +315,8 @@
${ctest.skip.tests}
iotdb-server
false
-
- 15
+
+ 45
${project.build.directory}/build/test/test.log
diff --git a/iotdb-client/client-cpp/src/main/CMakeLists.txt b/iotdb-client/client-cpp/src/main/CMakeLists.txt
index 2a6173514d7fe..8cfed4e7db912 100644
--- a/iotdb-client/client-cpp/src/main/CMakeLists.txt
+++ b/iotdb-client/client-cpp/src/main/CMakeLists.txt
@@ -21,7 +21,10 @@ PROJECT(iotdb_session CXX)
SET(CMAKE_CXX_STANDARD 11)
SET(CMAKE_CXX_STANDARD_REQUIRED ON)
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
-SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -g -O2 ")
+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)
diff --git a/iotdb-client/client-cpp/src/main/Common.h b/iotdb-client/client-cpp/src/main/Common.h
index aee4449860572..afdfac130da66 100644
--- a/iotdb-client/client-cpp/src/main/Common.h
+++ b/iotdb-client/client-cpp/src/main/Common.h
@@ -193,6 +193,31 @@ 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:
+ return !boolV.is_initialized();
+ case TSDataType::INT32:
+ return !intV.is_initialized();
+ case TSDataType::INT64:
+ case TSDataType::TIMESTAMP:
+ return !longV.is_initialized();
+ case TSDataType::FLOAT:
+ return !floatV.is_initialized();
+ case TSDataType::DOUBLE:
+ return !doubleV.is_initialized();
+ case TSDataType::TEXT:
+ case TSDataType::STRING:
+ case TSDataType::BLOB:
+ return !stringV.is_initialized();
+ case TSDataType::DATE:
+ return !dateV.is_initialized();
+ default:
+ return true;
+ }
+ }
};
enum class ColumnCategory {
diff --git a/iotdb-client/client-cpp/src/main/SessionC.cpp b/iotdb-client/client-cpp/src/main/SessionC.cpp
new file mode 100644
index 0000000000000..15d0deaec56de
--- /dev/null
+++ b/iotdb-client/client-cpp/src/main/SessionC.cpp
@@ -0,0 +1,1457 @@
+/**
+ * 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 "SessionC.h"
+#include "Session.h"
+#include "TableSession.h"
+#include "TableSessionBuilder.h"
+#include "SessionBuilder.h"
+#include "SessionDataSet.h"
+
+#include
+#include
+#include
+#include