This is an automated email from the ASF dual-hosted git repository. JackieTien97 pushed a commit to branch rc/2.0.10 in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit ef5f7bea7ded2a27e49bb43002986017f6ac59f7 Author: Hongzhi Gao <[email protected]> AuthorDate: Tue Jun 16 16:59:09 2026 +0800 feat(client-cpp): add SessionC DATE/BLOB support and RowRecord getters (#17956) * feat(client-cpp): add SessionC DATE/BLOB support and RowRecord getters Introduce TSDate_C for typed DATE inserts, ts_row_record_get_date_int32 and ts_row_record_get_string_byte_length, and expand c_rowDelete IT to cover DATE/BLOB readback and deletion paths. * test(client-cpp): cover TEXT and STRING in c_rowDelete IT Add TS_TYPE_STRING readback assertions alongside explicit TEXT checks in the RowRecord integration test. * chore(client-cpp): remove redundant TSDate_C comment --- iotdb-client/client-cpp/src/main/SessionC.cpp | 33 +++++++++++++++++ iotdb-client/client-cpp/src/main/SessionC.h | 12 +++++++ .../client-cpp/src/test/cpp/sessionCIT.cpp | 42 +++++++++++++++++----- 3 files changed, 79 insertions(+), 8 deletions(-) diff --git a/iotdb-client/client-cpp/src/main/SessionC.cpp b/iotdb-client/client-cpp/src/main/SessionC.cpp index e7c43cdb9f1..7d86bd348f8 100644 --- a/iotdb-client/client-cpp/src/main/SessionC.cpp +++ b/iotdb-client/client-cpp/src/main/SessionC.cpp @@ -18,6 +18,7 @@ */ #include "SessionC.h" +#include "Date.h" #include "Session.h" #include "TableSession.h" #include "TableSessionBuilder.h" @@ -184,6 +185,12 @@ static std::vector<char*> toCharPtrVec(const TSDataType_C* types, const void* co result[i] = reinterpret_cast<char*>(p); break; } + case TS_TYPE_DATE: { + const TSDate_C* src = static_cast<const TSDate_C*>(values[i]); + IoTDBDate* p = new IoTDBDate(src->year, src->month, src->day); + result[i] = reinterpret_cast<char*>(p); + break; + } case TS_TYPE_TEXT: case TS_TYPE_STRING: case TS_TYPE_BLOB: @@ -219,6 +226,9 @@ static void freeCharPtrVec(std::vector<char*>& vec, const TSDataType_C* types, i case TS_TYPE_DOUBLE: delete reinterpret_cast<double*>(vec[i]); break; + case TS_TYPE_DATE: + delete reinterpret_cast<IoTDBDate*>(vec[i]); + break; default: delete[] vec[i]; break; @@ -1471,6 +1481,29 @@ const char* ts_row_record_get_string(CRowRecord* record, int index) { return ""; } +int32_t ts_row_record_get_date_int32(CRowRecord* record, int index) { + if (!record || !record->cpp) + return 0; + if (index < 0 || index >= (int)record->cpp->fields.size()) + return 0; + const Field& f = record->cpp->fields[index]; + if (f.dataType != TSDataType::DATE || !f.dateV.is_initialized()) + return 0; + return parseDateExpressionToInt(f.dateV.value()); +} + +size_t ts_row_record_get_string_byte_length(CRowRecord* record, int index) { + if (!record || !record->cpp) + return 0; + if (index < 0 || index >= (int)record->cpp->fields.size()) + return 0; + const Field& f = record->cpp->fields[index]; + if (f.stringV.is_initialized()) { + return f.stringV.value().size(); + } + return 0; +} + TSDataType_C ts_row_record_get_data_type(CRowRecord* record, int index) { if (!record || !record->cpp) return TS_TYPE_INVALID; diff --git a/iotdb-client/client-cpp/src/main/SessionC.h b/iotdb-client/client-cpp/src/main/SessionC.h index 5c850c09c12..fdce5801a9d 100644 --- a/iotdb-client/client-cpp/src/main/SessionC.h +++ b/iotdb-client/client-cpp/src/main/SessionC.h @@ -105,6 +105,12 @@ typedef enum { typedef enum { TS_COL_TAG = 0, TS_COL_FIELD = 1, TS_COL_ATTRIBUTE = 2 } TSColumnCategory_C; +typedef struct { + int year; + int month; + int day; +} TSDate_C; + /* ============================================================ * Session Lifecycle — Tree Model * ============================================================ */ @@ -382,6 +388,12 @@ double ts_row_record_get_double(CRowRecord* record, int index); const char* ts_row_record_get_string(CRowRecord* record, int index); +/** Returns YYYYMMDD for DATE fields; 0 if record is null, index is out of range, field is null, or not DATE. */ +int32_t ts_row_record_get_date_int32(CRowRecord* record, int index); + +/** Byte length of the string/binary field (TEXT, BLOB, STRING, OBJECT, ...); 0 if null or out of range. */ +size_t ts_row_record_get_string_byte_length(CRowRecord* record, int index); + /** Returns TS_TYPE_INVALID if record is null or index is out of range. */ TSDataType_C ts_row_record_get_data_type(CRowRecord* record, int index); diff --git a/iotdb-client/client-cpp/src/test/cpp/sessionCIT.cpp b/iotdb-client/client-cpp/src/test/cpp/sessionCIT.cpp index f56e10bb5ae..9db5361635d 100644 --- a/iotdb-client/client-cpp/src/test/cpp/sessionCIT.cpp +++ b/iotdb-client/client-cpp/src/test/cpp/sessionCIT.cpp @@ -687,7 +687,10 @@ TEST_CASE("C API - RowRecord and delete data APIs", "[c_rowDelete]") { const char* pf = "root.cov_types.d1.sf"; const char* pd = "root.cov_types.d1.sd"; const char* pt = "root.cov_types.d1.st"; - const char* tpaths[] = {pb, pi, pf, pd, pt}; + const char* pstr = "root.cov_types.d1.sstr"; + const char* pdate = "root.cov_types.d1.sdate"; + const char* pblob = "root.cov_types.d1.sblob"; + const char* tpaths[] = {pb, pi, pf, pd, pt, pstr, pdate, pblob}; for (const char* tp : tpaths) { dropTimeseriesIfExists(g_session, tp); } @@ -701,36 +704,56 @@ TEST_CASE("C API - RowRecord and delete data APIs", "[c_rowDelete]") { TS_COMPRESSION_SNAPPY) == TS_OK); REQUIRE(ts_session_create_timeseries(g_session, pt, TS_TYPE_TEXT, TS_ENCODING_PLAIN, TS_COMPRESSION_SNAPPY) == TS_OK); + REQUIRE(ts_session_create_timeseries(g_session, pstr, TS_TYPE_STRING, TS_ENCODING_PLAIN, + TS_COMPRESSION_SNAPPY) == TS_OK); + REQUIRE(ts_session_create_timeseries(g_session, pdate, TS_TYPE_DATE, TS_ENCODING_PLAIN, + TS_COMPRESSION_SNAPPY) == TS_OK); + REQUIRE(ts_session_create_timeseries(g_session, pblob, TS_TYPE_BLOB, TS_ENCODING_PLAIN, + TS_COMPRESSION_SNAPPY) == TS_OK); const char* dev = "root.cov_types.d1"; - const char* names[] = {"sb", "si", "sf", "sd", "st"}; + const char* names[] = {"sb", "si", "sf", "sd", "st", "sstr", "sdate", "sblob"}; TSDataType_C types[] = {TS_TYPE_BOOLEAN, TS_TYPE_INT32, TS_TYPE_FLOAT, TS_TYPE_DOUBLE, - TS_TYPE_TEXT}; + TS_TYPE_TEXT, TS_TYPE_STRING, TS_TYPE_DATE, TS_TYPE_BLOB}; bool bv = true; int32_t iv = 42; float fv = 2.5f; double dv = 3.25; const char* tv = "hi"; - const void* vals[] = {&bv, &iv, &fv, &dv, tv}; - REQUIRE(ts_session_insert_record(g_session, dev, 500LL, 5, names, types, vals) == TS_OK); + const char* strVal = "hello"; + TSDate_C dateVal = {2025, 5, 7}; + const char* blobVal = "blobXY"; + const void* vals[] = {&bv, &iv, &fv, &dv, tv, strVal, &dateVal, blobVal}; + REQUIRE(ts_session_insert_record(g_session, dev, 500LL, 8, names, types, vals) == TS_OK); CSessionDataSet* dataSet = nullptr; REQUIRE(ts_session_execute_query(g_session, - "select sb,si,sf,sd,st from root.cov_types.d1 where time=500", + "select sb,si,sf,sd,st,sstr,sdate,sblob from root.cov_types.d1 " + "where time=500", &dataSet) == TS_OK); REQUIRE(dataSet != nullptr); REQUIRE(ts_dataset_has_next(dataSet)); CRowRecord* record = ts_dataset_next(dataSet); REQUIRE(record != nullptr); REQUIRE(ts_row_record_get_timestamp(record) == 500LL); - REQUIRE(ts_row_record_get_field_count(record) == 5); + REQUIRE(ts_row_record_get_field_count(record) == 8); REQUIRE_FALSE(ts_row_record_is_null(record, 0)); REQUIRE(ts_row_record_get_bool(record, 0) == true); REQUIRE(ts_row_record_get_int32(record, 1) == 42); REQUIRE(std::fabs(ts_row_record_get_float(record, 2) - 2.5f) < 1e-4f); REQUIRE(std::fabs(ts_row_record_get_double(record, 3) - 3.25) < 1e-9); + REQUIRE(ts_row_record_get_data_type(record, 4) == TS_TYPE_TEXT); REQUIRE(std::string(ts_row_record_get_string(record, 4)) == "hi"); - REQUIRE(ts_row_record_get_data_type(record, 0) == TS_TYPE_BOOLEAN); + REQUIRE(ts_row_record_get_string_byte_length(record, 4) == 2); + REQUIRE(ts_row_record_get_data_type(record, 5) == TS_TYPE_STRING); + REQUIRE(std::string(ts_row_record_get_string(record, 5)) == "hello"); + REQUIRE(ts_row_record_get_string_byte_length(record, 5) == 5); + REQUIRE(ts_row_record_get_date_int32(record, 6) == 20250507); + REQUIRE(std::string(ts_row_record_get_string(record, 7)) == "blobXY"); + REQUIRE(ts_row_record_get_string_byte_length(record, 7) == 6); + for (int i = 0; i < 8; i++) { + REQUIRE(ts_row_record_get_data_type(record, i) == types[i]); + } ts_row_record_destroy(record); ts_dataset_destroy(dataSet); @@ -743,5 +766,8 @@ TEST_CASE("C API - RowRecord and delete data APIs", "[c_rowDelete]") { REQUIRE(ts_session_delete_timeseries(g_session, pf) == TS_OK); REQUIRE(ts_session_delete_timeseries(g_session, pd) == TS_OK); REQUIRE(ts_session_delete_timeseries(g_session, pt) == TS_OK); + REQUIRE(ts_session_delete_timeseries(g_session, pstr) == TS_OK); + REQUIRE(ts_session_delete_timeseries(g_session, pdate) == TS_OK); + REQUIRE(ts_session_delete_timeseries(g_session, pblob) == TS_OK); REQUIRE(ts_session_delete_database(g_session, sg) == TS_OK); }
