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 aa365aa53f1 [Client] Add Fast Last Query API to C++ session (#18860)
aa365aa53f1 is described below

commit aa365aa53f1c429750fd15ce69ad9e1bebafb56b
Author: Hongzhi Gao <[email protected]>
AuthorDate: Fri Oct 16 10:22:31 2026 +0800

    [Client] Add Fast Last Query API to C++ session (#18860)
---
 iotdb-client/client-cpp/src/include/Session.h      |  5 +++
 .../client-cpp/src/rpc/SessionConnection.cpp       | 38 +++++++++++++++++
 .../client-cpp/src/rpc/SessionConnection.h         |  3 ++
 iotdb-client/client-cpp/src/session/Session.cpp    |  5 +++
 iotdb-client/client-cpp/test/cpp/sessionIT.cpp     | 47 ++++++++++++++++++++++
 5 files changed, 98 insertions(+)

diff --git a/iotdb-client/client-cpp/src/include/Session.h 
b/iotdb-client/client-cpp/src/include/Session.h
index 054c8f6f773..0e8e1541ba0 100644
--- a/iotdb-client/client-cpp/src/include/Session.h
+++ b/iotdb-client/client-cpp/src/include/Session.h
@@ -780,6 +780,11 @@ public:
   std::unique_ptr<SessionDataSet> executeLastDataQuery(const 
std::vector<std::string>& paths,
                                                        int64_t lastTime);
 
+  // Query the latest value of each series below a tree-model prefix in a 1C1D 
deployment.
+  // Pass path nodes without wildcards; result rows are not ordered.
+  std::unique_ptr<SessionDataSet>
+  executeFastLastDataQueryForOnePrefixPath(const std::vector<std::string>& 
prefixes);
+
   void createSchemaTemplate(const Template& templ);
 
   void setSchemaTemplate(const std::string& template_name, const std::string& 
prefix_path);
diff --git a/iotdb-client/client-cpp/src/rpc/SessionConnection.cpp 
b/iotdb-client/client-cpp/src/rpc/SessionConnection.cpp
index 3eea30cb989..615dcc5deb4 100644
--- a/iotdb-client/client-cpp/src/rpc/SessionConnection.cpp
+++ b/iotdb-client/client-cpp/src/rpc/SessionConnection.cpp
@@ -27,6 +27,7 @@
 #include <thrift/transport/TSocket.h>
 #include <thrift/transport/TTransportException.h>
 
+#include <stdexcept>
 #include <utility>
 
 #include "SessionDataSet.h"
@@ -257,6 +258,43 @@ SessionConnection::executeLastDataQuery(const 
std::vector<std::string>& paths, i
                               zoneId, timeFactor, 
resp.columnIndex2TsBlockColumnIndexList);
 }
 
+std::unique_ptr<SessionDataSet> 
SessionConnection::executeFastLastDataQueryForOnePrefixPath(
+    const std::vector<std::string>& prefixes) {
+  for (const auto& prefix : prefixes) {
+    if (prefix.find('*') != std::string::npos) {
+      throw std::invalid_argument("Fast Last Query prefix must not contain 
wildcards");
+    }
+  }
+
+  TSFastLastDataQueryForOnePrefixPathReq req;
+  req.__set_prefixes(prefixes);
+  req.__set_fetchSize(fetchSize);
+  req.__set_enableRedirectQuery(session->enableRedirection_);
+
+  auto result = callWithRetryAndReconnect<TSExecuteStatementResp>(
+      [this, &req]() {
+        req.__set_sessionId(sessionId);
+        req.__set_statementId(statementId);
+        TSExecuteStatementResp resp;
+        client->executeFastLastDataQueryForOnePrefixPath(resp, req);
+        return resp;
+      },
+      [](const TSExecuteStatementResp& resp) { return resp.status; });
+  if (result.getException()) {
+    throw 
IoTDBConnectionException(extractExceptionMessage(result.getException()));
+  }
+  TSExecuteStatementResp resp = result.getResult();
+  if (result.getRetryAttempts() == 0) {
+    RpcUtils::verifySuccessWithRedirection(resp.status);
+  } else {
+    RpcUtils::verifySuccess(resp.status);
+  }
+  return createSessionDataSet("", resp.columns, resp.dataTypeList, 
resp.columnNameIndexMap,
+                              resp.queryId, statementId, client, sessionId, 
resp.queryResult,
+                              resp.ignoreTimeStamp, connectionTimeoutInMs, 
resp.moreData, fetchSize,
+                              zoneId, timeFactor, 
resp.columnIndex2TsBlockColumnIndexList);
+}
+
 void SessionConnection::executeNonQueryStatement(const string& sql) {
   TSExecuteStatementReq req;
   req.__set_sessionId(sessionId);
diff --git a/iotdb-client/client-cpp/src/rpc/SessionConnection.h 
b/iotdb-client/client-cpp/src/rpc/SessionConnection.h
index c3c6f1a5735..b9d838b135b 100644
--- a/iotdb-client/client-cpp/src/rpc/SessionConnection.h
+++ b/iotdb-client/client-cpp/src/rpc/SessionConnection.h
@@ -113,6 +113,9 @@ public:
   std::unique_ptr<SessionDataSet> executeLastDataQuery(const 
std::vector<std::string>& paths,
                                                        int64_t lastTime);
 
+  std::unique_ptr<SessionDataSet>
+  executeFastLastDataQueryForOnePrefixPath(const std::vector<std::string>& 
prefixes);
+
   void executeNonQueryStatement(const std::string& sql);
 
   std::unique_ptr<SessionDataSet> executeQueryStatement(const std::string& sql,
diff --git a/iotdb-client/client-cpp/src/session/Session.cpp 
b/iotdb-client/client-cpp/src/session/Session.cpp
index e8cbc55d23c..b3a90cc49ed 100644
--- a/iotdb-client/client-cpp/src/session/Session.cpp
+++ b/iotdb-client/client-cpp/src/session/Session.cpp
@@ -2312,6 +2312,11 @@ unique_ptr<SessionDataSet> 
Session::executeLastDataQuery(const vector<string>& p
   return impl_->getDefaultSessionConnection()->executeLastDataQuery(paths, 
lastTime);
 }
 
+unique_ptr<SessionDataSet>
+Session::executeFastLastDataQueryForOnePrefixPath(const vector<string>& 
prefixes) {
+  return 
impl_->getDefaultSessionConnection()->executeFastLastDataQueryForOnePrefixPath(prefixes);
+}
+
 void Session::createSchemaTemplate(const Template& templ) {
   TSCreateSchemaTemplateReq req;
   req.__set_name(templ.getName());
diff --git a/iotdb-client/client-cpp/test/cpp/sessionIT.cpp 
b/iotdb-client/client-cpp/test/cpp/sessionIT.cpp
index 0c04d6bab68..2a0ec6cb7f8 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 <map>
 #include <stdexcept>
 #include <thread>
 
@@ -844,6 +845,52 @@ TEST_CASE("Test executeLastDataQuery ", 
"[testExecuteLastDataQuery]") {
   REQUIRE(sessionDataSet->hasNext() == false);
 }
 
+TEST_CASE("Fast Last Query returns all series under a tree prefix", 
"[fastLastQuery]") {
+  const vector<string> paths = {"root.test.fast_last_cpp.d1.s1", 
"root.test.fast_last_cpp.d1.s2",
+                                "root.test.fast_last_cpp.d2.s1"};
+  for (const auto& path : paths) {
+    if (session->checkTimeseriesExists(path)) {
+      session->deleteTimeseries(path);
+    }
+    session->createTimeseries(path, TSDataType::INT64, TSEncoding::RLE,
+                              CompressionType::SNAPPY);
+  }
+  session->insertRecord("root.test.fast_last_cpp.d1", 20, {"s1", "s2"}, {"1", 
"2"});
+  session->insertRecord("root.test.fast_last_cpp.d1", 30, {"s1"}, {"3"});
+  session->insertRecord("root.test.fast_last_cpp.d2", 40, {"s1"}, {"4"});
+
+  const map<string, string> expected = {{paths[0], "30,3,INT64"},
+                                        {paths[1], "20,2,INT64"},
+                                        {paths[2], "40,4,INT64"}};
+  const vector<string> prefix = {"root", "test", "fast_last_cpp"};
+  for (int query = 0; query < 2; ++query) {
+    auto dataSet = session->executeFastLastDataQueryForOnePrefixPath(prefix);
+    map<string, string> actual;
+    while (dataSet->hasNext()) {
+      auto row = dataSet->next();
+      REQUIRE(row->fields.size() == 3);
+      const auto& fields = row->fields;
+      auto inserted = actual.emplace(fields[0].stringV.value(),
+                                     to_string(row->timestamp) + "," +
+                                         fields[1].stringV.value() + "," + 
fields[2].stringV.value());
+      REQUIRE(inserted.second);
+    }
+    dataSet->closeOperationHandle();
+    REQUIRE(actual == expected);
+  }
+
+  auto empty = session->executeFastLastDataQueryForOnePrefixPath(
+      {"root", "test", "fast_last_cpp", "missing"});
+  REQUIRE_FALSE(empty->hasNext());
+  empty->closeOperationHandle();
+  REQUIRE_THROWS_AS(session->executeFastLastDataQueryForOnePrefixPath({"root", 
"test", "*"}),
+                    std::invalid_argument);
+
+  for (const auto& path : paths) {
+    session->deleteTimeseries(path);
+  }
+}
+
 // Helper function for comparing TEndPoint with detailed error message
 void assertTEndPointEqual(const TEndPoint& actual, const std::string& 
expectedIp, int expectedPort,
                           const char* file, int line) {

Reply via email to