This is an automated email from the ASF dual-hosted git repository.

jt2594838 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/master by this push:
     new 3767282ad12 feat(client-cpp): add SessionC DATE/BLOB support and 
RowRecord getters (#17956)
3767282ad12 is described below

commit 3767282ad1210a11becf7c32499a899bb5acc845
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/include/SessionC.h   | 12 +++++++
 iotdb-client/client-cpp/src/session/SessionC.cpp | 33 +++++++++++++++++++
 iotdb-client/client-cpp/test/cpp/sessionCIT.cpp  | 42 +++++++++++++++++++-----
 3 files changed, 79 insertions(+), 8 deletions(-)

diff --git a/iotdb-client/client-cpp/src/include/SessionC.h 
b/iotdb-client/client-cpp/src/include/SessionC.h
index 5c850c09c12..fdce5801a9d 100644
--- a/iotdb-client/client-cpp/src/include/SessionC.h
+++ b/iotdb-client/client-cpp/src/include/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/session/SessionC.cpp 
b/iotdb-client/client-cpp/src/session/SessionC.cpp
index e7c43cdb9f1..7d86bd348f8 100644
--- a/iotdb-client/client-cpp/src/session/SessionC.cpp
+++ b/iotdb-client/client-cpp/src/session/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/test/cpp/sessionCIT.cpp 
b/iotdb-client/client-cpp/test/cpp/sessionCIT.cpp
index f56e10bb5ae..9db5361635d 100644
--- a/iotdb-client/client-cpp/test/cpp/sessionCIT.cpp
+++ b/iotdb-client/client-cpp/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);
 }

Reply via email to