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 c1843f2ff7e Fix C++ client tablet bounds and session close semantics 
(#18005)
c1843f2ff7e is described below

commit c1843f2ff7effdf89578f1457358dc4d403e6bce
Author: Hongzhi Gao <[email protected]>
AuthorDate: Tue Jun 23 12:10:36 2026 +0800

    Fix C++ client tablet bounds and session close semantics (#18005)
    
    Add boundary checks for Tablet addTimestamp/addValue and validate 
ts_tablet_set_row_count to prevent rowSize from exceeding maxRowNumber. Align 
Session::close with Java by closing connections and routing all operations 
through getDefaultSessionConnection(). Map C API out_of_range to 
TS_ERR_INVALID_PARAM and add regression tests.
---
 iotdb-client/client-cpp/src/include/Session.h      |  20 +++-
 iotdb-client/client-cpp/src/rpc/SessionImpl.h      |  11 +-
 iotdb-client/client-cpp/src/session/Session.cpp    | 124 +++++++++++++--------
 iotdb-client/client-cpp/src/session/SessionC.cpp   |  16 ++-
 iotdb-client/client-cpp/test/cpp/sessionCIT.cpp    |  21 ++++
 .../client-cpp/test/cpp/sessionCRelationalIT.cpp   |  13 +++
 iotdb-client/client-cpp/test/cpp/sessionIT.cpp     |  25 +++++
 .../client-cpp/test/cpp/sessionRelationalIT.cpp    |  13 +++
 8 files changed, 189 insertions(+), 54 deletions(-)

diff --git a/iotdb-client/client-cpp/src/include/Session.h 
b/iotdb-client/client-cpp/src/include/Session.h
index bd9d77f3bba..a0910584e57 100644
--- a/iotdb-client/client-cpp/src/include/Session.h
+++ b/iotdb-client/client-cpp/src/include/Session.h
@@ -232,6 +232,14 @@ public:
   }
 
   void addTimestamp(size_t rowIndex, int64_t timestamp) {
+    if (rowIndex >= static_cast<size_t>(maxRowNumber)) {
+      char tmpStr[100];
+      snprintf(tmpStr, sizeof(tmpStr),
+               "Tablet::addTimestamp(), rowIndex >= maxRowNumber. 
rowIndex=%ld, "
+               "maxRowNumber=%ld.",
+               (long)rowIndex, (long)maxRowNumber);
+      throw std::out_of_range(tmpStr);
+    }
     timestamps[rowIndex] = timestamp;
     rowSize = max(rowSize, rowIndex + 1);
   }
@@ -248,10 +256,18 @@ public:
       throw std::out_of_range(tmpStr);
     }
 
-    if (rowIndex >= rowSize) {
+    if (rowIndex >= static_cast<size_t>(maxRowNumber)) {
+      char tmpStr[100];
+      snprintf(tmpStr, sizeof(tmpStr),
+               "Tablet::addValue(), rowIndex >= maxRowNumber. rowIndex=%ld, 
maxRowNumber=%ld.",
+               (long)rowIndex, (long)maxRowNumber);
+      throw std::out_of_range(tmpStr);
+    }
+
+    if (rowIndex >= static_cast<size_t>(rowSize)) {
       char tmpStr[100];
       snprintf(tmpStr, sizeof(tmpStr),
-               "Tablet::addValue(), rowIndex >= rowSize. rowIndex=%ld, 
rowSize.size()=%ld.",
+               "Tablet::addValue(), rowIndex >= rowSize. rowIndex=%ld, 
rowSize=%ld.",
                (long)rowIndex, (long)rowSize);
       throw std::out_of_range(tmpStr);
     }
diff --git a/iotdb-client/client-cpp/src/rpc/SessionImpl.h 
b/iotdb-client/client-cpp/src/rpc/SessionImpl.h
index 4d14c99f381..9fc3d917293 100644
--- a/iotdb-client/client-cpp/src/rpc/SessionImpl.h
+++ b/iotdb-client/client-cpp/src/rpc/SessionImpl.h
@@ -60,6 +60,13 @@ public:
   std::shared_ptr<INodesSupplier> nodesSupplier_;
   std::shared_ptr<SessionConnection> defaultSessionConnection_;
 
+  std::shared_ptr<SessionConnection> getDefaultSessionConnection() {
+    if (isClosed_ || !defaultSessionConnection_) {
+      throw IoTDBConnectionException("Session is not open, please invoke 
Session.open() first");
+    }
+    return defaultSessionConnection_;
+  }
+
   TEndPoint defaultEndPoint_;
 
   struct TEndPointHash {
@@ -168,7 +175,7 @@ void Session::Impl::insertByGroup(
         if (endPointToSessionConnection.size() > 1) {
           removeBrokenSessionConnection(connection);
           try {
-            insertConsumer(defaultSessionConnection_, req);
+            insertConsumer(getDefaultSessionConnection(), req);
           } catch (const RedirectException&) {
           }
         } else {
@@ -216,7 +223,7 @@ void Session::Impl::insertOnce(
     if (endPointToSessionConnection.size() > 1) {
       removeBrokenSessionConnection(connection);
       try {
-        insertConsumer(defaultSessionConnection_, req);
+        insertConsumer(getDefaultSessionConnection(), req);
       } catch (const RedirectException&) {
       }
     } else {
diff --git a/iotdb-client/client-cpp/src/session/Session.cpp 
b/iotdb-client/client-cpp/src/session/Session.cpp
index 3af4de3bcce..7dd0a7813ed 100644
--- a/iotdb-client/client-cpp/src/session/Session.cpp
+++ b/iotdb-client/client-cpp/src/session/Session.cpp
@@ -1067,6 +1067,31 @@ void Session::close() {
   if (impl_->isClosed_) {
     return;
   }
+  try {
+    if (impl_->enableRedirection_) {
+      for (auto& entry : impl_->endPointToSessionConnection) {
+        if (entry.second) {
+          try {
+            entry.second->close();
+          } catch (const exception& e) {
+            log_debug(e.what());
+          }
+        }
+      }
+      impl_->endPointToSessionConnection.clear();
+    }
+    if (impl_->defaultSessionConnection_) {
+      try {
+        impl_->defaultSessionConnection_->close();
+      } catch (const exception& e) {
+        log_debug(e.what());
+      }
+      impl_->defaultSessionConnection_.reset();
+    }
+  } catch (...) {
+    impl_->isClosed_ = true;
+    throw;
+  }
   impl_->isClosed_ = true;
 }
 
@@ -1087,7 +1112,7 @@ void Session::insertRecord(const string& deviceId, 
int64_t time, const vector<st
         impl_->deviceIdToEndpoint.find(deviceId) != 
impl_->deviceIdToEndpoint.end()) {
       impl_->deviceIdToEndpoint.erase(deviceId);
       try {
-        impl_->defaultSessionConnection_->insertStringRecord(req);
+        impl_->getDefaultSessionConnection()->insertStringRecord(req);
       } catch (RedirectException& e) {
       }
     } else {
@@ -1116,7 +1141,7 @@ void Session::insertRecord(const string& deviceId, 
int64_t time, const vector<st
         impl_->deviceIdToEndpoint.find(deviceId) != 
impl_->deviceIdToEndpoint.end()) {
       impl_->deviceIdToEndpoint.erase(deviceId);
       try {
-        impl_->defaultSessionConnection_->insertRecord(req);
+        impl_->getDefaultSessionConnection()->insertRecord(req);
       } catch (RedirectException& e) {
       }
     } else {
@@ -1143,7 +1168,7 @@ void Session::insertAlignedRecord(const string& deviceId, 
int64_t time,
         impl_->deviceIdToEndpoint.find(deviceId) != 
impl_->deviceIdToEndpoint.end()) {
       impl_->deviceIdToEndpoint.erase(deviceId);
       try {
-        impl_->defaultSessionConnection_->insertStringRecord(req);
+        impl_->getDefaultSessionConnection()->insertStringRecord(req);
       } catch (RedirectException& e) {
       }
     } else {
@@ -1173,7 +1198,7 @@ void Session::insertAlignedRecord(const string& deviceId, 
int64_t time,
         impl_->deviceIdToEndpoint.find(deviceId) != 
impl_->deviceIdToEndpoint.end()) {
       impl_->deviceIdToEndpoint.erase(deviceId);
       try {
-        impl_->defaultSessionConnection_->insertRecord(req);
+        impl_->getDefaultSessionConnection()->insertRecord(req);
       } catch (RedirectException& e) {
       }
     } else {
@@ -1202,7 +1227,7 @@ void Session::insertRecords(const vector<string>& 
deviceIds, const vector<int64_
     request.__set_valuesList(valuesList);
     request.__set_isAligned(false);
     try {
-      impl_->defaultSessionConnection_->insertStringRecords(request);
+      impl_->getDefaultSessionConnection()->insertStringRecords(request);
     } catch (RedirectException& e) {
     }
   }
@@ -1235,7 +1260,7 @@ void Session::insertRecords(const vector<string>& 
deviceIds, const vector<int64_
     request.__set_valuesList(bufferList);
     request.__set_isAligned(false);
     try {
-      impl_->defaultSessionConnection_->insertRecords(request);
+      impl_->getDefaultSessionConnection()->insertRecords(request);
     } catch (RedirectException& e) {
     }
   }
@@ -1260,7 +1285,7 @@ void Session::insertAlignedRecords(const vector<string>& 
deviceIds, const vector
     request.__set_valuesList(valuesList);
     request.__set_isAligned(true);
     try {
-      impl_->defaultSessionConnection_->insertStringRecords(request);
+      impl_->getDefaultSessionConnection()->insertStringRecords(request);
     } catch (RedirectException& e) {
     }
   }
@@ -1293,7 +1318,7 @@ void Session::insertAlignedRecords(const vector<string>& 
deviceIds, const vector
     request.__set_valuesList(bufferList);
     request.__set_isAligned(false);
     try {
-      impl_->defaultSessionConnection_->insertRecords(request);
+      impl_->getDefaultSessionConnection()->insertRecords(request);
     } catch (RedirectException& e) {
     }
   }
@@ -1345,7 +1370,7 @@ void Session::insertRecordsOfOneDevice(const string& 
deviceId, vector<int64_t>&
         impl_->deviceIdToEndpoint.find(deviceId) != 
impl_->deviceIdToEndpoint.end()) {
       impl_->deviceIdToEndpoint.erase(deviceId);
       try {
-        impl_->defaultSessionConnection_->insertRecordsOfOneDevice(request);
+        
impl_->getDefaultSessionConnection()->insertRecordsOfOneDevice(request);
       } catch (RedirectException& e) {
       }
     } else {
@@ -1400,7 +1425,7 @@ void Session::insertAlignedRecordsOfOneDevice(const 
string& deviceId, vector<int
         impl_->deviceIdToEndpoint.find(deviceId) != 
impl_->deviceIdToEndpoint.end()) {
       impl_->deviceIdToEndpoint.erase(deviceId);
       try {
-        impl_->defaultSessionConnection_->insertRecordsOfOneDevice(request);
+        
impl_->getDefaultSessionConnection()->insertRecordsOfOneDevice(request);
       } catch (RedirectException& e) {
       }
     } else {
@@ -1452,7 +1477,7 @@ void Session::Impl::insertTablet(TSInsertTabletReq 
request) {
     if (enableRedirection_ && deviceIdToEndpoint.find(deviceId) != 
deviceIdToEndpoint.end()) {
       deviceIdToEndpoint.erase(deviceId);
       try {
-        defaultSessionConnection_->insertTablet(request);
+        getDefaultSessionConnection()->insertTablet(request);
       } catch (RedirectException& e) {
       }
     } else {
@@ -1470,7 +1495,7 @@ void Session::insertTablet(Tablet& tablet, bool sorted) {
 void Session::insertRelationalTablet(Tablet& tablet, bool sorted) {
   std::unordered_map<std::shared_ptr<SessionConnection>, Tablet> 
relationalTabletGroup;
   if (impl_->tableModelDeviceIdToEndpoint.empty()) {
-    relationalTabletGroup.insert(make_pair(impl_->defaultSessionConnection_, 
tablet));
+    
relationalTabletGroup.insert(make_pair(impl_->getDefaultSessionConnection(), 
tablet));
   } else if (SessionUtils::isTabletContainsSingleDevice(tablet)) {
     relationalTabletGroup.insert(
         make_pair(impl_->getSessionConnection(tablet.getDeviceID(0)), tablet));
@@ -1571,7 +1596,7 @@ void Session::Impl::insertRelationalTabletOnce(
       removeBrokenSessionConnection(connection);
       try {
         TSStatus respStatus;
-        
defaultSessionConnection_->getSessionClient()->insertTablet(respStatus, 
request);
+        
getDefaultSessionConnection()->getSessionClient()->insertTablet(respStatus, 
request);
         RpcUtils::verifySuccess(respStatus);
       } catch (RedirectException& e) {
       }
@@ -1693,7 +1718,7 @@ void Session::insertTablets(unordered_map<string, 
Tablet*>& tablets, bool sorted
     request.__set_isAligned(isAligned);
     try {
       TSStatus respStatus;
-      impl_->defaultSessionConnection_->insertTablets(request);
+      impl_->getDefaultSessionConnection()->insertTablets(request);
       RpcUtils::verifySuccess(respStatus);
     } catch (RedirectException& e) {
     }
@@ -1722,7 +1747,7 @@ void Session::testInsertRecord(const string& deviceId, 
int64_t time,
   req.__set_values(values);
   TSStatus tsStatus;
   try {
-    impl_->defaultSessionConnection_->testInsertStringRecord(req);
+    impl_->getDefaultSessionConnection()->testInsertStringRecord(req);
     RpcUtils::verifySuccess(tsStatus);
   } catch (const TTransportException& e) {
     log_debug(e.what());
@@ -1748,7 +1773,7 @@ void Session::testInsertTablet(const Tablet& tablet) {
   request.__set_size(tablet.rowSize);
   try {
     TSStatus tsStatus;
-    impl_->defaultSessionConnection_->testInsertTablet(request);
+    impl_->getDefaultSessionConnection()->testInsertTablet(request);
     RpcUtils::verifySuccess(tsStatus);
   } catch (const TTransportException& e) {
     log_debug(e.what());
@@ -1778,7 +1803,8 @@ void Session::testInsertRecords(const vector<string>& 
deviceIds, const vector<in
 
   try {
     TSStatus tsStatus;
-    
impl_->defaultSessionConnection_->getSessionClient()->insertStringRecords(tsStatus,
 request);
+    
impl_->getDefaultSessionConnection()->getSessionClient()->insertStringRecords(tsStatus,
+                                                                               
   request);
     RpcUtils::verifySuccess(tsStatus);
   } catch (const TTransportException& e) {
     log_debug(e.what());
@@ -1799,7 +1825,7 @@ void Session::deleteTimeseries(const string& path) {
 }
 
 void Session::deleteTimeseries(const vector<string>& paths) {
-  impl_->defaultSessionConnection_->deleteTimeseries(paths);
+  impl_->getDefaultSessionConnection()->deleteTimeseries(paths);
 }
 
 void Session::deleteData(const string& path, int64_t endTime) {
@@ -1817,11 +1843,11 @@ void Session::deleteData(const vector<string>& paths, 
int64_t startTime, int64_t
   req.__set_paths(paths);
   req.__set_startTime(startTime);
   req.__set_endTime(endTime);
-  impl_->defaultSessionConnection_->deleteData(req);
+  impl_->getDefaultSessionConnection()->deleteData(req);
 }
 
 void Session::setStorageGroup(const string& storageGroupId) {
-  impl_->defaultSessionConnection_->setStorageGroup(storageGroupId);
+  impl_->getDefaultSessionConnection()->setStorageGroup(storageGroupId);
 }
 
 void Session::deleteStorageGroup(const string& storageGroup) {
@@ -1831,7 +1857,7 @@ void Session::deleteStorageGroup(const string& 
storageGroup) {
 }
 
 void Session::deleteStorageGroups(const vector<string>& storageGroups) {
-  impl_->defaultSessionConnection_->deleteStorageGroups(storageGroups);
+  impl_->getDefaultSessionConnection()->deleteStorageGroups(storageGroups);
 }
 
 void Session::createDatabase(const string& database) {
@@ -1880,7 +1906,7 @@ void Session::createTimeseries(const string& path, 
TSDataType::TSDataType dataTy
   if (!measurementAlias.empty()) {
     req.__set_measurementAlias(measurementAlias);
   }
-  impl_->defaultSessionConnection_->createTimeseries(req);
+  impl_->getDefaultSessionConnection()->createTimeseries(req);
 }
 
 void Session::createMultiTimeseries(const vector<string>& paths,
@@ -1929,7 +1955,7 @@ void Session::createMultiTimeseries(const vector<string>& 
paths,
     request.__set_measurementAliasList(*measurementAliasList);
   }
 
-  impl_->defaultSessionConnection_->createMultiTimeseries(request);
+  impl_->getDefaultSessionConnection()->createMultiTimeseries(request);
 }
 
 void Session::createAlignedTimeseries(
@@ -1962,7 +1988,7 @@ void Session::createAlignedTimeseries(
   }
   request.__set_compressors(compressorsOrdinal);
 
-  impl_->defaultSessionConnection_->createAlignedTimeseries(request);
+  impl_->getDefaultSessionConnection()->createAlignedTimeseries(request);
 }
 
 bool Session::checkTimeseriesExists(const string& path) {
@@ -1983,7 +2009,7 @@ bool Session::checkTimeseriesExists(const string& path) {
 shared_ptr<SessionConnection> Session::Impl::getQuerySessionConnection() {
   auto endPoint = nodesSupplier_->getQueryEndPoint();
   if (!endPoint.is_initialized() || endPointToSessionConnection.empty()) {
-    return defaultSessionConnection_;
+    return getDefaultSessionConnection();
   }
 
   auto it = endPointToSessionConnection.find(endPoint.value());
@@ -1991,6 +2017,7 @@ shared_ptr<SessionConnection> 
Session::Impl::getQuerySessionConnection() {
     return it->second;
   }
 
+  getDefaultSessionConnection();
   shared_ptr<SessionConnection> newConnection;
   try {
     newConnection =
@@ -2000,7 +2027,7 @@ shared_ptr<SessionConnection> 
Session::Impl::getQuerySessionConnection() {
     return newConnection;
   } catch (exception& e) {
     log_debug("Session::Impl::getQuerySessionConnection() exception: " + 
e.what());
-    return newConnection;
+    return getDefaultSessionConnection();
   }
 }
 
@@ -2008,7 +2035,7 @@ shared_ptr<SessionConnection> 
Session::Impl::getSessionConnection(std::string de
   if (!enableRedirection_ || deviceIdToEndpoint.find(deviceId) == 
deviceIdToEndpoint.end() ||
       endPointToSessionConnection.find(deviceIdToEndpoint[deviceId]) ==
           endPointToSessionConnection.end()) {
-    return defaultSessionConnection_;
+    return getDefaultSessionConnection();
   }
   return 
endPointToSessionConnection.find(deviceIdToEndpoint[deviceId])->second;
 }
@@ -2019,21 +2046,21 @@ 
Session::Impl::getSessionConnection(std::shared_ptr<storage::IDeviceID> deviceId
       tableModelDeviceIdToEndpoint.find(deviceId) == 
tableModelDeviceIdToEndpoint.end() ||
       endPointToSessionConnection.find(tableModelDeviceIdToEndpoint[deviceId]) 
==
           endPointToSessionConnection.end()) {
-    return defaultSessionConnection_;
+    return getDefaultSessionConnection();
   }
   return 
endPointToSessionConnection.find(tableModelDeviceIdToEndpoint[deviceId])->second;
 }
 
 string Session::getTimeZone() {
-  auto ret = impl_->defaultSessionConnection_->getTimeZone();
+  auto ret = impl_->getDefaultSessionConnection()->getTimeZone();
   return ret.timeZone;
 }
 
 void Session::setTimeZone(const string& zoneId) {
   TSSetTimeZoneReq req;
-  req.__set_sessionId(impl_->defaultSessionConnection_->sessionId);
+  req.__set_sessionId(impl_->getDefaultSessionConnection()->sessionId);
   req.__set_timeZone(zoneId);
-  impl_->defaultSessionConnection_->setTimeZone(req);
+  impl_->getDefaultSessionConnection()->setTimeZone(req);
 }
 
 unique_ptr<SessionDataSet> Session::executeQueryStatement(const string& sql) {
@@ -2047,6 +2074,7 @@ unique_ptr<SessionDataSet> 
Session::executeQueryStatement(const string& sql, int
 void Session::Impl::handleQueryRedirection(TEndPoint endPoint) {
   if (!enableRedirection_)
     return;
+  getDefaultSessionConnection();
   shared_ptr<SessionConnection> newConnection;
   auto it = endPointToSessionConnection.find(endPoint);
   if (it != endPointToSessionConnection.end()) {
@@ -2070,6 +2098,7 @@ void Session::Impl::handleRedirection(const std::string& 
deviceId, TEndPoint end
     return;
   if (endPoint.ip == "0.0.0.0")
     return;
+  getDefaultSessionConnection();
   deviceIdToEndpoint[deviceId] = endPoint;
 
   shared_ptr<SessionConnection> newConnection;
@@ -2095,6 +2124,7 @@ void Session::Impl::handleRedirection(const 
std::shared_ptr<storage::IDeviceID>&
     return;
   if (endPoint.ip == "0.0.0.0")
     return;
+  getDefaultSessionConnection();
   tableModelDeviceIdToEndpoint[deviceId] = endPoint;
 
   shared_ptr<SessionConnection> newConnection;
@@ -2127,7 +2157,7 @@ std::unique_ptr<SessionDataSet> 
Session::executeQueryStatementMayRedirect(const
     log_warn("Session connection redirect exception: " + e.what());
     impl_->handleQueryRedirection(endpointToThrift(e.endPoint));
     try {
-      return impl_->defaultSessionConnection_->executeQueryStatement(sql, 
timeoutInMs);
+      return impl_->getDefaultSessionConnection()->executeQueryStatement(sql, 
timeoutInMs);
     } catch (exception& e) {
       log_error("Exception while executing redirected query statement: %s", 
e.what());
       throw ExecutionException(e.what());
@@ -2140,7 +2170,9 @@ std::unique_ptr<SessionDataSet> 
Session::executeQueryStatementMayRedirect(const
 
 void Session::executeNonQueryStatement(const string& sql) {
   try {
-    impl_->defaultSessionConnection_->executeNonQueryStatement(sql);
+    impl_->getDefaultSessionConnection()->executeNonQueryStatement(sql);
+  } catch (const IoTDBConnectionException&) {
+    throw;
   } catch (const exception& e) {
     throw IoTDBException(e.what());
   }
@@ -2148,7 +2180,7 @@ void Session::executeNonQueryStatement(const string& sql) 
{
 
 unique_ptr<SessionDataSet> Session::executeRawDataQuery(const vector<string>& 
paths,
                                                         int64_t startTime, 
int64_t endTime) {
-  return impl_->defaultSessionConnection_->executeRawDataQuery(paths, 
startTime, endTime);
+  return impl_->getDefaultSessionConnection()->executeRawDataQuery(paths, 
startTime, endTime);
 }
 
 unique_ptr<SessionDataSet> Session::executeLastDataQuery(const vector<string>& 
paths) {
@@ -2157,28 +2189,28 @@ unique_ptr<SessionDataSet> 
Session::executeLastDataQuery(const vector<string>& p
 
 unique_ptr<SessionDataSet> Session::executeLastDataQuery(const vector<string>& 
paths,
                                                          int64_t lastTime) {
-  return impl_->defaultSessionConnection_->executeLastDataQuery(paths, 
lastTime);
+  return impl_->getDefaultSessionConnection()->executeLastDataQuery(paths, 
lastTime);
 }
 
 void Session::createSchemaTemplate(const Template& templ) {
   TSCreateSchemaTemplateReq req;
   req.__set_name(templ.getName());
   req.__set_serializedTemplate(templ.serialize());
-  impl_->defaultSessionConnection_->createSchemaTemplate(req);
+  impl_->getDefaultSessionConnection()->createSchemaTemplate(req);
 }
 
 void Session::setSchemaTemplate(const string& template_name, const string& 
prefix_path) {
   TSSetSchemaTemplateReq req;
   req.__set_templateName(template_name);
   req.__set_prefixPath(prefix_path);
-  impl_->defaultSessionConnection_->setSchemaTemplate(req);
+  impl_->getDefaultSessionConnection()->setSchemaTemplate(req);
 }
 
 void Session::unsetSchemaTemplate(const string& prefix_path, const string& 
template_name) {
   TSUnsetSchemaTemplateReq req;
   req.__set_templateName(template_name);
   req.__set_prefixPath(prefix_path);
-  impl_->defaultSessionConnection_->unsetSchemaTemplate(req);
+  impl_->getDefaultSessionConnection()->unsetSchemaTemplate(req);
 }
 
 void Session::addAlignedMeasurementsInTemplate(
@@ -2212,7 +2244,7 @@ void Session::addAlignedMeasurementsInTemplate(
   }
   req.__set_compressors(compressorsOrdinal);
 
-  impl_->defaultSessionConnection_->appendSchemaTemplate(req);
+  impl_->getDefaultSessionConnection()->appendSchemaTemplate(req);
 }
 
 void Session::addAlignedMeasurementsInTemplate(const string& template_name,
@@ -2258,7 +2290,7 @@ void Session::addUnalignedMeasurementsInTemplate(
   }
   req.__set_compressors(compressorsOrdinal);
 
-  impl_->defaultSessionConnection_->appendSchemaTemplate(req);
+  impl_->getDefaultSessionConnection()->appendSchemaTemplate(req);
 }
 
 void Session::addUnalignedMeasurementsInTemplate(const string& template_name,
@@ -2278,14 +2310,14 @@ void Session::deleteNodeInTemplate(const string& 
template_name, const string& pa
   TSPruneSchemaTemplateReq req;
   req.__set_name(template_name);
   req.__set_path(path);
-  impl_->defaultSessionConnection_->pruneSchemaTemplate(req);
+  impl_->getDefaultSessionConnection()->pruneSchemaTemplate(req);
 }
 
 int Session::countMeasurementsInTemplate(const string& template_name) {
   TSQueryTemplateReq req;
   req.__set_name(template_name);
   req.__set_queryType(TemplateQueryType::COUNT_MEASUREMENTS);
-  TSQueryTemplateResp resp = 
impl_->defaultSessionConnection_->querySchemaTemplate(req);
+  TSQueryTemplateResp resp = 
impl_->getDefaultSessionConnection()->querySchemaTemplate(req);
   return resp.count;
 }
 
@@ -2294,7 +2326,7 @@ bool Session::isMeasurementInTemplate(const string& 
template_name, const string&
   req.__set_name(template_name);
   req.__set_measurement(path);
   req.__set_queryType(TemplateQueryType::IS_MEASUREMENT);
-  TSQueryTemplateResp resp = 
impl_->defaultSessionConnection_->querySchemaTemplate(req);
+  TSQueryTemplateResp resp = 
impl_->getDefaultSessionConnection()->querySchemaTemplate(req);
   return resp.result;
 }
 
@@ -2303,7 +2335,7 @@ bool Session::isPathExistInTemplate(const string& 
template_name, const string& p
   req.__set_name(template_name);
   req.__set_measurement(path);
   req.__set_queryType(TemplateQueryType::PATH_EXIST);
-  TSQueryTemplateResp resp = 
impl_->defaultSessionConnection_->querySchemaTemplate(req);
+  TSQueryTemplateResp resp = 
impl_->getDefaultSessionConnection()->querySchemaTemplate(req);
   return resp.result;
 }
 
@@ -2312,7 +2344,7 @@ std::vector<std::string> 
Session::showMeasurementsInTemplate(const string& templ
   req.__set_name(template_name);
   req.__set_measurement("");
   req.__set_queryType(TemplateQueryType::SHOW_MEASUREMENTS);
-  TSQueryTemplateResp resp = 
impl_->defaultSessionConnection_->querySchemaTemplate(req);
+  TSQueryTemplateResp resp = 
impl_->getDefaultSessionConnection()->querySchemaTemplate(req);
   return resp.measurements;
 }
 
@@ -2322,7 +2354,7 @@ std::vector<std::string> 
Session::showMeasurementsInTemplate(const string& templ
   req.__set_name(template_name);
   req.__set_measurement(pattern);
   req.__set_queryType(TemplateQueryType::SHOW_MEASUREMENTS);
-  TSQueryTemplateResp resp = 
impl_->defaultSessionConnection_->querySchemaTemplate(req);
+  TSQueryTemplateResp resp = 
impl_->getDefaultSessionConnection()->querySchemaTemplate(req);
   return resp.measurements;
 }
 
diff --git a/iotdb-client/client-cpp/src/session/SessionC.cpp 
b/iotdb-client/client-cpp/src/session/SessionC.cpp
index 7d86bd348f8..79287cf0252 100644
--- a/iotdb-client/client-cpp/src/session/SessionC.cpp
+++ b/iotdb-client/client-cpp/src/session/SessionC.cpp
@@ -26,11 +26,12 @@
 #include "SessionDataSet.h"
 
 #include <cstring>
-#include <string>
-#include <vector>
 #include <map>
-#include <unordered_map>
 #include <memory>
+#include <stdexcept>
+#include <string>
+#include <unordered_map>
+#include <vector>
 
 /* ============================================================
  *  Internal wrapper structs — the opaque handles point to these
@@ -87,6 +88,10 @@ static TsStatus handleException(const std::exception& e) {
       dynamic_cast<const BatchExecutionException*>(&e)) {
     return setError(TS_ERR_EXECUTION, e);
   }
+  if (dynamic_cast<const std::out_of_range*>(&e) ||
+      dynamic_cast<const std::invalid_argument*>(&e)) {
+    return setError(TS_ERR_INVALID_PARAM, e);
+  }
 #endif
   return setError(TS_ERR_UNKNOWN, e);
 }
@@ -678,7 +683,10 @@ TsStatus ts_tablet_set_row_count(CTablet* tablet, int 
rowCount) {
   clearError();
   if (!tablet)
     return setError(TS_ERR_NULL_PTR, "tablet is null");
-  tablet->cpp.rowSize = rowCount;
+  if (rowCount < 0 || static_cast<size_t>(rowCount) > 
tablet->cpp.maxRowNumber) {
+    return setError(TS_ERR_INVALID_PARAM, "rowCount out of range [0, 
maxRowNumber]");
+  }
+  tablet->cpp.rowSize = static_cast<size_t>(rowCount);
   return TS_OK;
 }
 
diff --git a/iotdb-client/client-cpp/test/cpp/sessionCIT.cpp 
b/iotdb-client/client-cpp/test/cpp/sessionCIT.cpp
index 9db5361635d..0e0791c5d29 100644
--- a/iotdb-client/client-cpp/test/cpp/sessionCIT.cpp
+++ b/iotdb-client/client-cpp/test/cpp/sessionCIT.cpp
@@ -497,6 +497,27 @@ TEST_CASE("C API - Tablet row count and reset", 
"[c_tabletReset]") {
   ts_tablet_destroy(tablet);
 }
 
+TEST_CASE("C API - Tablet index bounds", "[c_tabletBounds]") {
+  CaseReporter cr("c_tabletBounds");
+  const char* colNames[] = {"s1"};
+  TSDataType_C dts[] = {TS_TYPE_INT64};
+  CTablet* tablet = ts_tablet_new("root.ctest.d1", 1, colNames, dts, 10);
+  REQUIRE(tablet != nullptr);
+
+  REQUIRE(ts_tablet_add_timestamp(tablet, 0, 1) == TS_OK);
+  REQUIRE(ts_tablet_add_value_int64(tablet, 0, 0, 100) == TS_OK);
+  REQUIRE(ts_tablet_add_timestamp(tablet, 100, 2) != TS_OK);
+  REQUIRE(ts_tablet_add_value_int64(tablet, 1, 0, 100) != TS_OK);
+  REQUIRE(ts_tablet_add_value_int64(tablet, 0, 100, 100) != TS_OK);
+  REQUIRE(ts_tablet_set_row_count(tablet, -1) != TS_OK);
+  REQUIRE(ts_tablet_set_row_count(tablet, 11) != TS_OK);
+  REQUIRE(ts_tablet_set_row_count(tablet, 1000000) != TS_OK);
+  REQUIRE(ts_tablet_set_row_count(tablet, 5) == TS_OK);
+  REQUIRE(ts_tablet_get_row_count(tablet) == 5);
+
+  ts_tablet_destroy(tablet);
+}
+
 TEST_CASE("C API - Aligned timeseries and aligned writes", "[c_aligned]") {
   CaseReporter cr("c_aligned");
 
diff --git a/iotdb-client/client-cpp/test/cpp/sessionCRelationalIT.cpp 
b/iotdb-client/client-cpp/test/cpp/sessionCRelationalIT.cpp
index 9a78f2512ed..4a298dd1c1a 100644
--- a/iotdb-client/client-cpp/test/cpp/sessionCRelationalIT.cpp
+++ b/iotdb-client/client-cpp/test/cpp/sessionCRelationalIT.cpp
@@ -254,6 +254,19 @@ TEST_CASE("C API Table - Multi-node table session", 
"[c_table_multiNode][c_table
   ts_table_session_destroy(localSession);
 }
 
+TEST_CASE("C API Table - Reject SQL after close", 
"[c_table_close][c_table_lifecycle]") {
+  CaseReporter cr("c_table_close");
+
+  CTableSession* localSession = ts_table_session_new("127.0.0.1", 6667, 
"root", "root", "");
+  REQUIRE(localSession != nullptr);
+  REQUIRE(ts_table_session_open(localSession) == TS_OK);
+
+  ts_table_session_close(localSession);
+
+  REQUIRE(ts_table_session_execute_non_query(localSession, "SHOW DATABASES") 
!= TS_OK);
+  ts_table_session_destroy(localSession);
+}
+
 /* ============================================================
  *  Dataset column info (table model)
  * ============================================================ */
diff --git a/iotdb-client/client-cpp/test/cpp/sessionIT.cpp 
b/iotdb-client/client-cpp/test/cpp/sessionIT.cpp
index c0428f6e84a..3b19f2e2b25 100644
--- a/iotdb-client/client-cpp/test/cpp/sessionIT.cpp
+++ b/iotdb-client/client-cpp/test/cpp/sessionIT.cpp
@@ -28,6 +28,7 @@
 #include "common_types.h"
 
 #include <atomic>
+#include <stdexcept>
 #include <thread>
 
 using namespace std;
@@ -369,6 +370,30 @@ TEST_CASE("Test insertRecordsOfOneDevice", 
"[testInsertRecordsOfOneDevice]") {
   REQUIRE(count == 100);
 }
 
+TEST_CASE("Tablet index bounds", "[tabletBounds]") {
+  CaseReporter cr("tabletBounds");
+  vector<pair<string, TSDataType::TSDataType>> schemaList;
+  schemaList.emplace_back("s1", TSDataType::INT64);
+  Tablet tablet("root.test.d1", schemaList, 10);
+  tablet.addTimestamp(0, 1);
+  tablet.addValue(0, 0, static_cast<int64_t>(100));
+
+  REQUIRE_THROWS_AS(tablet.addTimestamp(10, 11), out_of_range);
+  REQUIRE_THROWS_AS(tablet.addValue(1, 0, static_cast<int64_t>(1)), 
out_of_range);
+  REQUIRE_THROWS_AS(tablet.addValue(0, 100, static_cast<int64_t>(1)), 
out_of_range);
+}
+
+TEST_CASE("Session rejects SQL after close", "[sessionClose]") {
+  CaseReporter cr("sessionClose");
+  SessionBuilder builder;
+  auto localSession =
+      
builder.host("127.0.0.1")->rpcPort(6667)->username("root")->password("root")->build();
+  localSession->open();
+  localSession->close();
+  REQUIRE_THROWS_AS(localSession->executeNonQueryStatement("show databases"),
+                    IoTDBConnectionException);
+}
+
 TEST_CASE("Test insertTablet ", "[testInsertTablet]") {
   CaseReporter cr("testInsertTablet");
   prepareTimeseries();
diff --git a/iotdb-client/client-cpp/test/cpp/sessionRelationalIT.cpp 
b/iotdb-client/client-cpp/test/cpp/sessionRelationalIT.cpp
index 461a3ec8630..9ed3d334b1c 100644
--- a/iotdb-client/client-cpp/test/cpp/sessionRelationalIT.cpp
+++ b/iotdb-client/client-cpp/test/cpp/sessionRelationalIT.cpp
@@ -86,6 +86,19 @@ TEST_CASE("Test TableSession builder with nodeUrls", 
"[SessionBuilderInit]") {
   session->close();
 }
 
+TEST_CASE("TableSession rejects SQL after close", "[tableSessionClose]") {
+  CaseReporter cr("tableSessionClose");
+
+  TableSessionBuilder builder;
+  auto localSession =
+      
builder.host("127.0.0.1")->rpcPort(6667)->username("root")->password("root")->build();
+  localSession->open();
+  localSession->close();
+
+  REQUIRE_THROWS_AS(localSession->executeNonQueryStatement("SHOW DATABASES"),
+                    IoTDBConnectionException);
+}
+
 TEST_CASE("Test insertRelationalTablet", "[testInsertRelationalTablet]") {
   CaseReporter cr("testInsertRelationalTablet");
   session->executeNonQueryStatement("CREATE DATABASE IF NOT EXISTS db1");

Reply via email to