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

jiangtian 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 3e6aaa3a4cc fix cpp client processing null value (#15700)
3e6aaa3a4cc is described below

commit 3e6aaa3a4cc3a69b3f09c97fe18a294235cce6aa
Author: Hongzhi Gao <[email protected]>
AuthorDate: Mon Jun 16 12:24:12 2025 +0800

    fix cpp client processing null value (#15700)
---
 iotdb-client/client-cpp/src/main/Common.h          | 15 ++--
 .../client-cpp/src/main/IoTDBRpcDataSet.cpp        | 68 +++++++++---------
 iotdb-client/client-cpp/src/main/IoTDBRpcDataSet.h | 42 +++++------
 iotdb-client/client-cpp/src/main/NodesSupplier.cpp | 16 +++--
 .../client-cpp/src/main/SessionDataSet.cpp         | 78 ++++++++++++++-------
 iotdb-client/client-cpp/src/main/SessionDataSet.h  | 32 ++++-----
 iotdb-client/client-cpp/src/test/cpp/sessionIT.cpp | 66 +++++++++---------
 .../src/test/cpp/sessionRelationalIT.cpp           | 81 ++++++++++++++++++----
 8 files changed, 244 insertions(+), 154 deletions(-)

diff --git a/iotdb-client/client-cpp/src/main/Common.h 
b/iotdb-client/client-cpp/src/main/Common.h
index a9f4552ecc5..aa583cb6ba8 100644
--- a/iotdb-client/client-cpp/src/main/Common.h
+++ b/iotdb-client/client-cpp/src/main/Common.h
@@ -30,6 +30,7 @@
 #include <thrift/transport/TBufferTransports.h>
 #include <boost/date_time/gregorian/gregorian.hpp>
 #include <cstdint>
+#include <boost/optional/optional.hpp>
 
 #include "client_types.h"
 #include "common_types.h"
@@ -178,13 +179,13 @@ enum TSStatusCode {
 class Field {
 public:
     TSDataType::TSDataType dataType = TSDataType::UNKNOWN;
-    bool boolV{};
-    int intV{};
-    boost::gregorian::date dateV;
-    int64_t longV{};
-    float floatV{};
-    double doubleV{};
-    std::string stringV;
+    boost::optional<bool> boolV;
+    boost::optional<int> intV;
+    boost::optional<boost::gregorian::date> dateV;
+    boost::optional<int64_t> longV;
+    boost::optional<float> floatV;
+    boost::optional<double> doubleV;
+    boost::optional<std::string> stringV;
 
     explicit Field(TSDataType::TSDataType a) {
         dataType = a;
diff --git a/iotdb-client/client-cpp/src/main/IoTDBRpcDataSet.cpp 
b/iotdb-client/client-cpp/src/main/IoTDBRpcDataSet.cpp
index 1d55b7e0b9a..8fa020851fe 100644
--- a/iotdb-client/client-cpp/src/main/IoTDBRpcDataSet.cpp
+++ b/iotdb-client/client-cpp/src/main/IoTDBRpcDataSet.cpp
@@ -22,6 +22,9 @@
 #include <stdexcept>
 
 #include "IoTDBRpcDataSet.h"
+
+#include <boost/optional/optional.hpp>
+
 #include "Column.h"
 
 const int32_t IoTDBRpcDataSet::startIndex = 2;
@@ -257,17 +260,17 @@ bool IoTDBRpcDataSet::isNull(int32_t index, int32_t 
rowNum) {
     return index >= 0 && curTsBlock_->getColumn(index)->isNull(rowNum);
 }
 
-bool IoTDBRpcDataSet::getBooleanByIndex(int32_t columnIndex) {
+boost::optional<bool> IoTDBRpcDataSet::getBooleanByIndex(int32_t columnIndex) {
     int32_t index = getTsBlockColumnIndexForColumnIndex(columnIndex);
     return getBooleanByTsBlockColumnIndex(index);
 }
 
-bool IoTDBRpcDataSet::getBoolean(const std::string& columnName) {
+boost::optional<bool> IoTDBRpcDataSet::getBoolean(const std::string& 
columnName) {
     int32_t index = getTsBlockColumnIndexForColumnName(columnName);
     return getBooleanByTsBlockColumnIndex(index);
 }
 
-bool IoTDBRpcDataSet::getBooleanByTsBlockColumnIndex(int32_t 
tsBlockColumnIndex) {
+boost::optional<bool> IoTDBRpcDataSet::getBooleanByTsBlockColumnIndex(int32_t 
tsBlockColumnIndex) {
     checkRecord();
     if (!isNull(tsBlockColumnIndex, tsBlockIndex_)) {
         lastReadWasNull_ = false;
@@ -275,21 +278,21 @@ bool 
IoTDBRpcDataSet::getBooleanByTsBlockColumnIndex(int32_t tsBlockColumnIndex)
     }
     else {
         lastReadWasNull_ = true;
-        return false;
+        return boost::none;
     }
 }
 
-double IoTDBRpcDataSet::getDoubleByIndex(int32_t columnIndex) {
+boost::optional<double> IoTDBRpcDataSet::getDoubleByIndex(int32_t columnIndex) 
{
     int32_t index = getTsBlockColumnIndexForColumnIndex(columnIndex);
     return getDoubleByTsBlockColumnIndex(index);
 }
 
-double IoTDBRpcDataSet::getDouble(const std::string& columnName) {
+boost::optional<double> IoTDBRpcDataSet::getDouble(const std::string& 
columnName) {
     int32_t index = getTsBlockColumnIndexForColumnName(columnName);
     return getDoubleByTsBlockColumnIndex(index);
 }
 
-double IoTDBRpcDataSet::getDoubleByTsBlockColumnIndex(int32_t 
tsBlockColumnIndex) {
+boost::optional<double> IoTDBRpcDataSet::getDoubleByTsBlockColumnIndex(int32_t 
tsBlockColumnIndex) {
     checkRecord();
     if (!isNull(tsBlockColumnIndex, tsBlockIndex_)) {
         lastReadWasNull_ = false;
@@ -297,21 +300,21 @@ double 
IoTDBRpcDataSet::getDoubleByTsBlockColumnIndex(int32_t tsBlockColumnIndex
     }
     else {
         lastReadWasNull_ = true;
-        return 0.0;
+        return boost::none;
     }
 }
 
-float IoTDBRpcDataSet::getFloatByIndex(int32_t columnIndex) {
+boost::optional<float> IoTDBRpcDataSet::getFloatByIndex(int32_t columnIndex) {
     int32_t index = getTsBlockColumnIndexForColumnIndex(columnIndex);
     return getFloatByTsBlockColumnIndex(index);
 }
 
-float IoTDBRpcDataSet::getFloat(const std::string& columnName) {
+boost::optional<float> IoTDBRpcDataSet::getFloat(const std::string& 
columnName) {
     int32_t index = getTsBlockColumnIndexForColumnName(columnName);
     return getFloatByTsBlockColumnIndex(index);
 }
 
-float IoTDBRpcDataSet::getFloatByTsBlockColumnIndex(int32_t 
tsBlockColumnIndex) {
+boost::optional<float> IoTDBRpcDataSet::getFloatByTsBlockColumnIndex(int32_t 
tsBlockColumnIndex) {
     checkRecord();
     if (!isNull(tsBlockColumnIndex, tsBlockIndex_)) {
         lastReadWasNull_ = false;
@@ -319,21 +322,21 @@ float 
IoTDBRpcDataSet::getFloatByTsBlockColumnIndex(int32_t tsBlockColumnIndex)
     }
     else {
         lastReadWasNull_ = true;
-        return 0.0f;
+        return boost::none;
     }
 }
 
-int32_t IoTDBRpcDataSet::getIntByIndex(int32_t columnIndex) {
+boost::optional<int32_t> IoTDBRpcDataSet::getIntByIndex(int32_t columnIndex) {
     int32_t index = getTsBlockColumnIndexForColumnIndex(columnIndex);
     return getIntByTsBlockColumnIndex(index);
 }
 
-int32_t IoTDBRpcDataSet::getInt(const std::string& columnName) {
+boost::optional<int32_t> IoTDBRpcDataSet::getInt(const std::string& 
columnName) {
     int32_t index = getTsBlockColumnIndexForColumnName(columnName);
     return getIntByTsBlockColumnIndex(index);
 }
 
-int32_t IoTDBRpcDataSet::getIntByTsBlockColumnIndex(int32_t 
tsBlockColumnIndex) {
+boost::optional<int32_t> IoTDBRpcDataSet::getIntByTsBlockColumnIndex(int32_t 
tsBlockColumnIndex) {
     checkRecord();
     if (!isNull(tsBlockColumnIndex, tsBlockIndex_)) {
         lastReadWasNull_ = false;
@@ -345,21 +348,21 @@ int32_t 
IoTDBRpcDataSet::getIntByTsBlockColumnIndex(int32_t tsBlockColumnIndex)
     }
     else {
         lastReadWasNull_ = true;
-        return 0;
+        return boost::none;
     }
 }
 
-int64_t IoTDBRpcDataSet::getLongByIndex(int32_t columnIndex) {
+boost::optional<int64_t> IoTDBRpcDataSet::getLongByIndex(int32_t columnIndex) {
     int32_t index = getTsBlockColumnIndexForColumnIndex(columnIndex);
     return getLongByTsBlockColumnIndex(index);
 }
 
-int64_t IoTDBRpcDataSet::getLong(const std::string& columnName) {
+boost::optional<int64_t> IoTDBRpcDataSet::getLong(const std::string& 
columnName) {
     int32_t index = getTsBlockColumnIndexForColumnName(columnName);
     return getLongByTsBlockColumnIndex(index);
 }
 
-int64_t IoTDBRpcDataSet::getLongByTsBlockColumnIndex(int32_t 
tsBlockColumnIndex) {
+boost::optional<int64_t> IoTDBRpcDataSet::getLongByTsBlockColumnIndex(int32_t 
tsBlockColumnIndex) {
     checkRecord();
     if (tsBlockColumnIndex < 0) {
         lastReadWasNull_ = false;
@@ -375,7 +378,7 @@ int64_t 
IoTDBRpcDataSet::getLongByTsBlockColumnIndex(int32_t tsBlockColumnIndex)
     }
     else {
         lastReadWasNull_ = true;
-        return 0;
+        return boost::none;
     }
 }
 
@@ -401,25 +404,25 @@ std::shared_ptr<Binary> 
IoTDBRpcDataSet::getBinaryByTsBlockColumnIndex(int32_t t
     }
 }
 
-std::string IoTDBRpcDataSet::getStringByIndex(int32_t columnIndex) {
+boost::optional<std::string> IoTDBRpcDataSet::getStringByIndex(int32_t 
columnIndex) {
     int32_t index = getTsBlockColumnIndexForColumnIndex(columnIndex);
     return getStringByTsBlockColumnIndex(index);
 }
 
-std::string IoTDBRpcDataSet::getString(const std::string& columnName) {
+boost::optional<std::string> IoTDBRpcDataSet::getString(const std::string& 
columnName) {
     int32_t index = getTsBlockColumnIndexForColumnName(columnName);
     return getStringByTsBlockColumnIndex(index);
 }
 
-std::string IoTDBRpcDataSet::getStringByTsBlockColumnIndex(int32_t 
tsBlockColumnIndex) {
+boost::optional<std::string> 
IoTDBRpcDataSet::getStringByTsBlockColumnIndex(int32_t tsBlockColumnIndex) {
     checkRecord();
-    if (tsBlockColumnIndex == -1) {
+    if (tsBlockColumnIndex < 0) {
         int64_t timestamp = curTsBlock_->getTimeByIndex(tsBlockIndex_);
         return std::to_string(timestamp);
     }
     if (isNull(tsBlockColumnIndex, tsBlockIndex_)) {
         lastReadWasNull_ = true;
-        return "";
+        return boost::none;
     }
     lastReadWasNull_ = false;
     return getStringByTsBlockColumnIndexAndDataType(tsBlockColumnIndex,
@@ -470,22 +473,25 @@ int64_t IoTDBRpcDataSet::getTimestamp(const std::string& 
columnName) {
 }
 
 int64_t IoTDBRpcDataSet::getTimestampByTsBlockColumnIndex(int32_t 
tsBlockColumnIndex) {
-    return getLongByTsBlockColumnIndex(tsBlockColumnIndex);
+    return getLongByTsBlockColumnIndex(tsBlockColumnIndex).value();
 }
 
-boost::gregorian::date IoTDBRpcDataSet::getDateByIndex(int32_t columnIndex) {
+boost::optional<boost::gregorian::date> 
IoTDBRpcDataSet::getDateByIndex(int32_t columnIndex) {
     int32_t index = getTsBlockColumnIndexForColumnIndex(columnIndex);
     return getDateByTsBlockColumnIndex(index);
 }
 
-boost::gregorian::date IoTDBRpcDataSet::getDate(const std::string& columnName) 
{
+boost::optional<boost::gregorian::date> IoTDBRpcDataSet::getDate(const 
std::string& columnName) {
     int32_t index = getTsBlockColumnIndexForColumnName(columnName);
     return getDateByTsBlockColumnIndex(index);
 }
 
-boost::gregorian::date IoTDBRpcDataSet::getDateByTsBlockColumnIndex(int32_t 
tsBlockColumnIndex) {
-    int32_t value = getIntByTsBlockColumnIndex(tsBlockColumnIndex);
-    return parseIntToDate(value);
+boost::optional<boost::gregorian::date> 
IoTDBRpcDataSet::getDateByTsBlockColumnIndex(int32_t tsBlockColumnIndex) {
+    auto value = getIntByTsBlockColumnIndex(tsBlockColumnIndex);
+    if (!value.is_initialized()) {
+        return boost::none;
+    }
+    return parseIntToDate(value.value());
 }
 
 TSDataType::TSDataType IoTDBRpcDataSet::getDataTypeByIndex(int32_t 
columnIndex) {
diff --git a/iotdb-client/client-cpp/src/main/IoTDBRpcDataSet.h 
b/iotdb-client/client-cpp/src/main/IoTDBRpcDataSet.h
index 96e5fd4b7ab..e3b591bb90d 100644
--- a/iotdb-client/client-cpp/src/main/IoTDBRpcDataSet.h
+++ b/iotdb-client/client-cpp/src/main/IoTDBRpcDataSet.h
@@ -69,24 +69,24 @@ public:
     bool isNull(int32_t index, int32_t rowNum);
     bool isNullByIndex(int32_t columnIndex);
     bool isNullByColumnName(const std::string& columnName);
-    bool getBooleanByIndex(int32_t columnIndex);
-    bool getBoolean(const std::string& columnName);
-    double getDoubleByIndex(int32_t columnIndex);
-    double getDouble(const std::string& columnName);
-    float getFloatByIndex(int32_t columnIndex);
-    float getFloat(const std::string& columnName);
-    int32_t getIntByIndex(int32_t columnIndex);
-    int32_t getInt(const std::string& columnName);
-    int64_t getLongByIndex(int32_t columnIndex);
-    int64_t getLong(const std::string& columnName);
+    boost::optional<bool> getBooleanByIndex(int32_t columnIndex);
+    boost::optional<bool> getBoolean(const std::string& columnName);
+    boost::optional<double> getDoubleByIndex(int32_t columnIndex);
+    boost::optional<double> getDouble(const std::string& columnName);
+    boost::optional<float> getFloatByIndex(int32_t columnIndex);
+    boost::optional<float> getFloat(const std::string& columnName);
+    boost::optional<int32_t> getIntByIndex(int32_t columnIndex);
+    boost::optional<int32_t> getInt(const std::string& columnName);
+    boost::optional<int64_t> getLongByIndex(int32_t columnIndex);
+    boost::optional<int64_t> getLong(const std::string& columnName);
     std::shared_ptr<Binary> getBinaryByIndex(int32_t columnIndex);
     std::shared_ptr<Binary> getBinary(const std::string& columnName);
-    std::string getStringByIndex(int32_t columnIndex);
-    std::string getString(const std::string& columnName);
+    boost::optional<std::string> getStringByIndex(int32_t columnIndex);
+    boost::optional<std::string> getString(const std::string& columnName);
     int64_t getTimestampByIndex(int32_t columnIndex);
     int64_t getTimestamp(const std::string& columnName);
-    boost::gregorian::date getDateByIndex(int32_t columnIndex);
-    boost::gregorian::date getDate(const std::string& columnName);
+    boost::optional<boost::gregorian::date> getDateByIndex(int32_t 
columnIndex);
+    boost::optional<boost::gregorian::date> getDate(const std::string& 
columnName);
 
     TSDataType::TSDataType getDataTypeByIndex(int32_t columnIndex);
     TSDataType::TSDataType getDataType(const std::string& columnName);
@@ -113,15 +113,15 @@ private:
     int32_t getTsBlockColumnIndexForColumnIndex(int32_t columnIndex);
     void checkRecord();
     TSDataType::TSDataType getDataTypeByTsBlockColumnIndex(int32_t 
tsBlockColumnIndex);
-    bool getBooleanByTsBlockColumnIndex(int32_t tsBlockColumnIndex);
+    boost::optional<bool> getBooleanByTsBlockColumnIndex(int32_t 
tsBlockColumnIndex);
     std::string getStringByTsBlockColumnIndexAndDataType(int32_t index, 
TSDataType::TSDataType tsDataType);
-    double getDoubleByTsBlockColumnIndex(int32_t tsBlockColumnIndex);
-    float getFloatByTsBlockColumnIndex(int32_t tsBlockColumnIndex);
-    int32_t getIntByTsBlockColumnIndex(int32_t tsBlockColumnIndex);
-    int64_t getLongByTsBlockColumnIndex(int32_t tsBlockColumnIndex);
+    boost::optional<double> getDoubleByTsBlockColumnIndex(int32_t 
tsBlockColumnIndex);
+    boost::optional<float> getFloatByTsBlockColumnIndex(int32_t 
tsBlockColumnIndex);
+    boost::optional<int32_t> getIntByTsBlockColumnIndex(int32_t 
tsBlockColumnIndex);
+    boost::optional<int64_t> getLongByTsBlockColumnIndex(int32_t 
tsBlockColumnIndex);
     std::shared_ptr<Binary> getBinaryByTsBlockColumnIndex(int32_t 
tsBlockColumnIndex);
-    std::string getStringByTsBlockColumnIndex(int32_t tsBlockColumnIndex);
-    boost::gregorian::date getDateByTsBlockColumnIndex(int32_t 
tsBlockColumnIndex);
+    boost::optional<std::string> getStringByTsBlockColumnIndex(int32_t 
tsBlockColumnIndex);
+    boost::optional<boost::gregorian::date> 
getDateByTsBlockColumnIndex(int32_t tsBlockColumnIndex);
     int64_t getTimestampByTsBlockColumnIndex(int32_t tsBlockColumnIndex);
 
     std::string sql_;
diff --git a/iotdb-client/client-cpp/src/main/NodesSupplier.cpp 
b/iotdb-client/client-cpp/src/main/NodesSupplier.cpp
index 5f268f075a1..f9ee90f169a 100644
--- a/iotdb-client/client-cpp/src/main/NodesSupplier.cpp
+++ b/iotdb-client/client-cpp/src/main/NodesSupplier.cpp
@@ -176,10 +176,18 @@ std::vector<TEndPoint> 
NodesSupplier::fetchLatestEndpoints() {
         std::vector<TEndPoint> ret;
         while (sessionDataSet->hasNext()) {
             auto record = sessionDataSet->next();
-            std::string ip = record->fields.at(columnAddrIdx).stringV;
-            int32_t port = record->fields.at(columnPortIdx).intV;
-            std::string status = record->fields.at(columnStatusIdx).stringV;
-
+            std::string ip;
+            int32_t port;
+            std::string status;
+            if (record->fields.at(columnAddrIdx).stringV.is_initialized()) {
+                ip = record->fields.at(columnAddrIdx).stringV.value();
+            }
+            if (record->fields.at(columnPortIdx).intV.is_initialized()) {
+                port = record->fields.at(columnPortIdx).intV.value();
+            }
+            if (record->fields.at(columnStatusIdx).stringV.is_initialized()) {
+                status = record->fields.at(columnStatusIdx).stringV.value();
+            }
             if (ip == "0.0.0.0" || status == REMOVING_STATUS) {
                 log_warn("Skipping invalid node: " + ip + ":" + 
to_string(port));
                 continue;
diff --git a/iotdb-client/client-cpp/src/main/SessionDataSet.cpp 
b/iotdb-client/client-cpp/src/main/SessionDataSet.cpp
index 30e11fa1efb..048d5340916 100644
--- a/iotdb-client/client-cpp/src/main/SessionDataSet.cpp
+++ b/iotdb-client/client-cpp/src/main/SessionDataSet.cpp
@@ -54,28 +54,56 @@ std::string RowRecord::toString() {
         TSDataType::TSDataType dataType = fields[i].dataType;
         switch (dataType) {
         case TSDataType::BOOLEAN:
-            ret.append(fields[i].boolV ? "true" : "false");
+            if (!fields[i].boolV.is_initialized()) {
+                ret.append("null");
+            } else {
+                ret.append(fields[i].boolV.value() ? "true" : "false");
+            }
             break;
         case TSDataType::INT32:
-            ret.append(std::to_string(fields[i].intV));
+            if (!fields[i].intV.is_initialized()) {
+                ret.append("null");
+            } else {
+                ret.append(std::to_string(fields[i].intV.value()));
+            }
             break;
         case TSDataType::DATE:
-            
ret.append(boost::gregorian::to_iso_extended_string(fields[i].dateV));
+            if (!fields[i].dateV.is_initialized()) {
+                ret.append("null");
+            } else {
+                
ret.append(boost::gregorian::to_iso_extended_string(fields[i].dateV.value()));
+            }
             break;
         case TSDataType::TIMESTAMP:
         case TSDataType::INT64:
-            ret.append(std::to_string(fields[i].longV));
+            if (!fields[i].longV.is_initialized()) {
+                ret.append("null");
+            } else {
+                ret.append(std::to_string(fields[i].longV.value()));
+            }
             break;
         case TSDataType::FLOAT:
-            ret.append(std::to_string(fields[i].floatV));
+            if (!fields[i].floatV.is_initialized()) {
+                ret.append("null");
+            } else {
+                ret.append(std::to_string(fields[i].floatV.value()));
+            }
             break;
         case TSDataType::DOUBLE:
-            ret.append(std::to_string(fields[i].doubleV));
+            if (!fields[i].doubleV.is_initialized()) {
+                ret.append("null");
+            } else {
+                ret.append(std::to_string(fields[i].doubleV.value()));
+            }
             break;
         case TSDataType::BLOB:
         case TSDataType::STRING:
         case TSDataType::TEXT:
-            ret.append(fields[i].stringV);
+            if (!fields[i].stringV.is_initialized()) {
+                ret.append("null");
+            } else {
+                ret.append(fields[i].stringV.value());
+            }
             break;
         default:
             break;
@@ -133,67 +161,67 @@ bool SessionDataSet::DataIterator::isNullByIndex(int32_t 
columnIndex) {
     return iotdbRpcDataSet_->isNullByIndex(columnIndex);
 }
 
-bool SessionDataSet::DataIterator::getBooleanByIndex(int32_t columnIndex) {
+boost::optional<bool> SessionDataSet::DataIterator::getBooleanByIndex(int32_t 
columnIndex) {
     return iotdbRpcDataSet_->getBooleanByIndex(columnIndex);
 }
 
-bool SessionDataSet::DataIterator::getBoolean(const std::string& columnName) {
+boost::optional<bool> SessionDataSet::DataIterator::getBoolean(const 
std::string& columnName) {
     return iotdbRpcDataSet_->getBoolean(columnName);
 }
 
-double SessionDataSet::DataIterator::getDoubleByIndex(int32_t columnIndex) {
+boost::optional<double> SessionDataSet::DataIterator::getDoubleByIndex(int32_t 
columnIndex) {
     return iotdbRpcDataSet_->getDoubleByIndex(columnIndex);
 }
 
-double SessionDataSet::DataIterator::getDouble(const std::string& columnName) {
+boost::optional<double> SessionDataSet::DataIterator::getDouble(const 
std::string& columnName) {
     return iotdbRpcDataSet_->getDouble(columnName);
 }
 
-float SessionDataSet::DataIterator::getFloatByIndex(int32_t columnIndex) {
+boost::optional<float> SessionDataSet::DataIterator::getFloatByIndex(int32_t 
columnIndex) {
     return iotdbRpcDataSet_->getFloatByIndex(columnIndex);
 }
 
-float SessionDataSet::DataIterator::getFloat(const std::string& columnName) {
+boost::optional<float> SessionDataSet::DataIterator::getFloat(const 
std::string& columnName) {
     return iotdbRpcDataSet_->getFloat(columnName);
 }
 
-int32_t SessionDataSet::DataIterator::getIntByIndex(int32_t columnIndex) {
+boost::optional<int32_t> SessionDataSet::DataIterator::getIntByIndex(int32_t 
columnIndex) {
     return iotdbRpcDataSet_->getIntByIndex(columnIndex);
 }
 
-int32_t SessionDataSet::DataIterator::getInt(const std::string& columnName) {
+boost::optional<int32_t> SessionDataSet::DataIterator::getInt(const 
std::string& columnName) {
     return iotdbRpcDataSet_->getInt(columnName);
 }
 
-int64_t SessionDataSet::DataIterator::getLongByIndex(int32_t columnIndex) {
+boost::optional<int64_t> SessionDataSet::DataIterator::getLongByIndex(int32_t 
columnIndex) {
     return iotdbRpcDataSet_->getLongByIndex(columnIndex);
 }
 
-int64_t SessionDataSet::DataIterator::getLong(const std::string& columnName) {
+boost::optional<int64_t> SessionDataSet::DataIterator::getLong(const 
std::string& columnName) {
     return iotdbRpcDataSet_->getLong(columnName);
 }
 
-std::string SessionDataSet::DataIterator::getStringByIndex(int32_t 
columnIndex) {
+boost::optional<std::string> 
SessionDataSet::DataIterator::getStringByIndex(int32_t columnIndex) {
     return iotdbRpcDataSet_->getStringByIndex(columnIndex);
 }
 
-std::string SessionDataSet::DataIterator::getString(const std::string& 
columnName) {
+boost::optional<std::string> SessionDataSet::DataIterator::getString(const 
std::string& columnName) {
     return iotdbRpcDataSet_->getString(columnName);
 }
 
-int64_t SessionDataSet::DataIterator::getTimestampByIndex(int32_t columnIndex) 
{
+boost::optional<int64_t> 
SessionDataSet::DataIterator::getTimestampByIndex(int32_t columnIndex) {
     return iotdbRpcDataSet_->getTimestampByIndex(columnIndex);
 }
 
-int64_t SessionDataSet::DataIterator::getTimestamp(const std::string& 
columnName) {
+boost::optional<int64_t> SessionDataSet::DataIterator::getTimestamp(const 
std::string& columnName) {
     return iotdbRpcDataSet_->getTimestamp(columnName);
 }
 
-boost::gregorian::date SessionDataSet::DataIterator::getDateByIndex(int32_t 
columnIndex) {
+boost::optional<boost::gregorian::date> 
SessionDataSet::DataIterator::getDateByIndex(int32_t columnIndex) {
     return iotdbRpcDataSet_->getDateByIndex(columnIndex);
 }
 
-boost::gregorian::date SessionDataSet::DataIterator::getDate(const 
std::string& columnName) {
+boost::optional<boost::gregorian::date> 
SessionDataSet::DataIterator::getDate(const std::string& columnName) {
     return iotdbRpcDataSet_->getDate(columnName);
 }
 
@@ -225,7 +253,7 @@ shared_ptr<RowRecord> 
SessionDataSet::constructRowRecordFromValueArray() {
                 field.intV = iotdbRpcDataSet_->getInt(columnName);
                 break;
             case TSDataType::DATE:
-                field.dateV = 
parseIntToDate(iotdbRpcDataSet_->getInt(columnName));
+                field.dateV = iotdbRpcDataSet_->getDate(columnName);
                 break;
             case TSDataType::INT64:
             case TSDataType::TIMESTAMP:
@@ -243,7 +271,7 @@ shared_ptr<RowRecord> 
SessionDataSet::constructRowRecordFromValueArray() {
                 field.stringV = 
iotdbRpcDataSet_->getBinary(columnName)->getStringValue();
                 break;
             default:
-                throw new UnSupportedDataTypeException("Data type %s is not 
supported." + dataType);
+                throw UnSupportedDataTypeException("Data type %s is not 
supported." + dataType);
             }
         }
         outFields.emplace_back(field);
diff --git a/iotdb-client/client-cpp/src/main/SessionDataSet.h 
b/iotdb-client/client-cpp/src/main/SessionDataSet.h
index 0b8e4566604..c796c5758e7 100644
--- a/iotdb-client/client-cpp/src/main/SessionDataSet.h
+++ b/iotdb-client/client-cpp/src/main/SessionDataSet.h
@@ -104,29 +104,29 @@ public:
         bool isNull(const std::string& columnName);
         bool isNullByIndex(int32_t columnIndex);
 
-        bool getBooleanByIndex(int32_t columnIndex);
-        bool getBoolean(const std::string& columnName);
+        boost::optional<bool> getBooleanByIndex(int32_t columnIndex);
+        boost::optional<bool> getBoolean(const std::string& columnName);
 
-        double getDoubleByIndex(int32_t columnIndex);
-        double getDouble(const std::string& columnName);
+        boost::optional<double> getDoubleByIndex(int32_t columnIndex);
+        boost::optional<double> getDouble(const std::string& columnName);
 
-        float getFloatByIndex(int32_t columnIndex);
-        float getFloat(const std::string& columnName);
+        boost::optional<float> getFloatByIndex(int32_t columnIndex);
+        boost::optional<float> getFloat(const std::string& columnName);
 
-        int32_t getIntByIndex(int32_t columnIndex);
-        int32_t getInt(const std::string& columnName);
+        boost::optional<int32_t> getIntByIndex(int32_t columnIndex);
+        boost::optional<int32_t> getInt(const std::string& columnName);
 
-        int64_t getLongByIndex(int32_t columnIndex);
-        int64_t getLong(const std::string& columnName);
+        boost::optional<int64_t> getLongByIndex(int32_t columnIndex);
+        boost::optional<int64_t> getLong(const std::string& columnName);
 
-        std::string getStringByIndex(int32_t columnIndex);
-        std::string getString(const std::string& columnName);
+        boost::optional<std::string> getStringByIndex(int32_t columnIndex);
+        boost::optional<std::string> getString(const std::string& columnName);
 
-        int64_t getTimestampByIndex(int32_t columnIndex);
-        int64_t getTimestamp(const std::string& columnName);
+        boost::optional<int64_t> getTimestampByIndex(int32_t columnIndex);
+        boost::optional<int64_t> getTimestamp(const std::string& columnName);
 
-        boost::gregorian::date getDateByIndex(int32_t columnIndex);
-        boost::gregorian::date getDate(const std::string& columnName);
+        boost::optional<boost::gregorian::date> getDateByIndex(int32_t 
columnIndex);
+        boost::optional<boost::gregorian::date> getDate(const std::string& 
columnName);
 
         int32_t findColumn(const std::string& columnName);
         const std::vector<std::string>& getColumnNames() const;
diff --git a/iotdb-client/client-cpp/src/test/cpp/sessionIT.cpp 
b/iotdb-client/client-cpp/src/test/cpp/sessionIT.cpp
index 803e7f583e2..bf2c7521769 100644
--- a/iotdb-client/client-cpp/src/test/cpp/sessionIT.cpp
+++ b/iotdb-client/client-cpp/src/test/cpp/sessionIT.cpp
@@ -92,7 +92,7 @@ TEST_CASE("Test insertRecord by string", 
"[testInsertRecord]") {
         long index = 1;
         count++;
         for (const Field &f: sessionDataSet->next()->fields) {
-            REQUIRE(f.longV == index);
+            REQUIRE(f.longV.value() == index);
             index++;
         }
     }
@@ -137,7 +137,7 @@ TEST_CASE("Test insertRecords ", "[testInsertRecords]") {
         long index = 1;
         count++;
         for (const Field &f: sessionDataSet->next()->fields) {
-            REQUIRE(f.longV == index);
+            REQUIRE(f.longV.value() == index);
             index++;
         }
     }
@@ -211,10 +211,10 @@ TEST_CASE("Test insertRecord with new datatypes ", 
"[testTypedInsertRecordNewDat
         for (int i = 0; i < 4; i++) {
             REQUIRE(types[i] == record->fields[i].dataType);
         }
-        REQUIRE(record->fields[0].longV == value1);
-        REQUIRE(record->fields[1].dateV == value2);
-        REQUIRE(record->fields[2].stringV == value3);
-        REQUIRE(record->fields[3].stringV == value4);
+        REQUIRE(record->fields[0].longV.value() == value1);
+        REQUIRE(record->fields[1].dateV.value() == value2);
+        REQUIRE(record->fields[2].stringV.value() == value3);
+        REQUIRE(record->fields[3].stringV.value() == value4);
         count++;
     }
     REQUIRE(count == 100);
@@ -337,7 +337,7 @@ TEST_CASE("Test insertTablet ", "[testInsertTablet]") {
         long index = 0;
         count++;
         for (const Field& f: sessionDataSet->next()->fields) {
-            REQUIRE(f.longV == index);
+            REQUIRE(f.longV.value() == index);
             index++;
         }
     }
@@ -387,14 +387,14 @@ TEST_CASE("Test insertTablets ", "[testInsertTablets]") {
         long index = 0;
         count++;
         for (const Field& f: sessionDataSet->next()->fields) {
-            REQUIRE(f.longV == index);
+            REQUIRE(f.longV.value() == index);
             index++;
         }
     }
     REQUIRE(count == 100);
 }
 
-TEST_CASE("Test insertTablet new datatype", "[testInsertTabletNewDatatype]") {
+TEST_CASE("Test insertTablet multi datatype", 
"[testInsertTabletMultiDatatype]") {
     CaseReporter cr("testInsertTabletNewDatatype");
     string deviceId = "root.test.d2";
     vector<pair<string, TSDataType::TSDataType>> schemaList;
@@ -437,18 +437,14 @@ TEST_CASE("Test insertTablet new datatype", 
"[testInsertTabletNewDatatype]") {
         tablet.reset();
     }
     unique_ptr<SessionDataSet> sessionDataSet = 
session->executeQueryStatement("select s1,s2,s3,s4 from root.test.d2");
+    auto dataIter = sessionDataSet->getIterator();
     sessionDataSet->setFetchSize(1024);
     int count = 0;
-    while (sessionDataSet->hasNext()) {
-        auto record = sessionDataSet->next();
-        REQUIRE(record->fields.size() == 4);
-        for (int i = 0; i < 4; i++) {
-            REQUIRE(dataTypes[i] == record->fields[i].dataType);
-        }
-        REQUIRE(record->fields[0].longV == s1Value);
-        REQUIRE(record->fields[1].dateV == s2Value);
-        REQUIRE(record->fields[2].stringV == s3Value);
-        REQUIRE(record->fields[3].stringV == s4Value);
+    while (dataIter.next()) {
+        REQUIRE(dataIter.getLongByIndex(2).value() == s1Value);
+        REQUIRE(dataIter.getDateByIndex(3).value() == s2Value);
+        REQUIRE(dataIter.getStringByIndex(4).value() == s3Value);
+        REQUIRE(dataIter.getStringByIndex(5).value() == s4Value);
         count++;
     }
     REQUIRE(count == 100);
@@ -472,8 +468,8 @@ TEST_CASE("Test Last query ", "[testLastQuery]") {
     long index = 0;
     while (sessionDataSet->hasNext()) {
         vector<Field> fields = sessionDataSet->next()->fields;
-        REQUIRE("1" <= fields[1].stringV);
-        REQUIRE(fields[1].stringV <= "3");
+        REQUIRE("1" <= fields[1].stringV.value());
+        REQUIRE(fields[1].stringV.value() <= "3");
         index++;
     }
 }
@@ -509,9 +505,9 @@ TEST_CASE("Test Huge query ", "[testHugeQuery]") {
     while (sessionDataSet->hasNext()) {
         auto rowRecord = sessionDataSet->next();
         REQUIRE(rowRecord->timestamp == count);
-        REQUIRE(rowRecord->fields[0].longV== 1);
-        REQUIRE(rowRecord->fields[1].longV == 2);
-        REQUIRE(rowRecord->fields[2].longV == 3);
+        REQUIRE(rowRecord->fields[0].longV.value() == 1);
+        REQUIRE(rowRecord->fields[1].longV.value() == 2);
+        REQUIRE(rowRecord->fields[2].longV.value() == 3);
         count++;
         if (count % 1000 == 0) {
             std::cout << count << "\t" << std::flush;
@@ -585,11 +581,11 @@ TEST_CASE("Test executeRawDataQuery ", 
"[executeRawDataQuery]") {
         vector<Field> fields = rowRecordPtr->fields;
         REQUIRE(rowRecordPtr->timestamp == ts);
         REQUIRE(fields[0].dataType == TSDataType::INT64);
-        REQUIRE(fields[0].longV == ts);
+        REQUIRE(fields[0].longV.value() == ts);
         REQUIRE(fields[1].dataType == TSDataType::INT64);
-        REQUIRE(fields[1].longV == ts * 2);
+        REQUIRE(fields[1].longV.value() == ts * 2);
         REQUIRE(fields[2].dataType == TSDataType::INT64);
-        REQUIRE(fields[2].longV == ts *3);
+        REQUIRE(fields[2].longV.value() == ts *3);
         ts++;
     }
 
@@ -617,10 +613,10 @@ TEST_CASE("Test executeRawDataQuery ", 
"[executeRawDataQuery]") {
         vector<Field> fields = rowRecordPtr->fields;
         REQUIRE(rowRecordPtr->timestamp == ts);
         REQUIRE(fields[0].dataType == TSDataType::INT64);
-        REQUIRE(fields[0].longV == 9);
+        REQUIRE(fields[0].longV.value() == 9);
         REQUIRE(fields[1].dataType == TSDataType::UNKNOWN);
         REQUIRE(fields[2].dataType == TSDataType::INT64);
-        REQUIRE(fields[2].longV == 999);
+        REQUIRE(fields[2].longV.value() == 999);
     }
 
     //== Test executeRawDataQuery() with empty data
@@ -686,9 +682,9 @@ TEST_CASE("Test executeLastDataQuery ", 
"[testExecuteLastDataQuery]") {
 
         vector<Field> fields = rowRecordPtr->fields;
         REQUIRE(rowRecordPtr->timestamp == tsCheck[index]);
-        REQUIRE(fields[0].stringV == paths[index]);
-        REQUIRE(fields[1].stringV == valueCheck[index]);
-        REQUIRE(fields[2].stringV == "INT64");
+        REQUIRE(fields[0].stringV.value() == paths[index]);
+        REQUIRE(fields[1].stringV.value() == valueCheck[index]);
+        REQUIRE(fields[2].stringV.value() == "INT64");
         index++;
     }
 
@@ -708,9 +704,9 @@ TEST_CASE("Test executeLastDataQuery ", 
"[testExecuteLastDataQuery]") {
 
         vector<Field> fields = rowRecordPtr->fields;
         REQUIRE(rowRecordPtr->timestamp == tsCheck[index]);
-        REQUIRE(fields[0].stringV == paths[index]);
-        REQUIRE(fields[1].stringV == valueCheck[index]);
-        REQUIRE(fields[2].stringV == "INT64");
+        REQUIRE(fields[0].stringV.value() == paths[index]);
+        REQUIRE(fields[1].stringV.value() == valueCheck[index]);
+        REQUIRE(fields[2].stringV.value() == "INT64");
         index++;
     }
 
diff --git a/iotdb-client/client-cpp/src/test/cpp/sessionRelationalIT.cpp 
b/iotdb-client/client-cpp/src/test/cpp/sessionRelationalIT.cpp
index 420c2c441bc..3534abd46f8 100644
--- a/iotdb-client/client-cpp/src/test/cpp/sessionRelationalIT.cpp
+++ b/iotdb-client/client-cpp/src/test/cpp/sessionRelationalIT.cpp
@@ -59,7 +59,7 @@ TEST_CASE("Create table success", "[createTable]") {
     sessionDataSet->setFetchSize(1024);
     bool tableExist = false;
     while (sessionDataSet->hasNext()) {
-        if (sessionDataSet->next()->fields[0].stringV == "table0") {
+        if (sessionDataSet->next()->fields[0].stringV.value() == "table0") {
             tableExist = true;
             break;
         }
@@ -112,9 +112,9 @@ TEST_CASE("Test insertRelationalTablet", 
"[testInsertRelationalTablet]") {
     unique_ptr<SessionDataSet> sessionDataSet = 
session->executeQueryStatement("SELECT * FROM table1 order by time");
     while (sessionDataSet->hasNext()) {
         auto rowRecord = sessionDataSet->next();
-        REQUIRE(rowRecord->fields[1].stringV == string("tag:") + 
to_string(cnt));
-        REQUIRE(rowRecord->fields[2].stringV == string("attr:") + 
to_string(cnt));
-        REQUIRE(fabs(rowRecord->fields[3].doubleV - cnt * 1.1) < 0.0001);
+        REQUIRE(rowRecord->fields[1].stringV.value() == string("tag:") + 
to_string(cnt));
+        REQUIRE(rowRecord->fields[2].stringV.value() == string("attr:") + 
to_string(cnt));
+        REQUIRE(fabs(rowRecord->fields[3].doubleV.value() - cnt * 1.1) < 
0.0001);
         cnt++;
     }
     REQUIRE(cnt == 15);
@@ -169,6 +169,12 @@ TEST_CASE("Test RelationalTabletTsblockRead", 
"[testRelationalTabletTsblockRead]
         tablet.addValue(8, rowIndex, "blob_" + to_string(row));
         tablet.addValue(9, rowIndex, "string_" + to_string(row));
 
+        if (row % 2 == 0) {
+            for (int col = 0; col <= 9; col++) {
+                tablet.bitMaps[col].mark(row);
+            }
+        }
+
         if (tablet.rowSize == tablet.maxRowNumber) {
             session->insert(tablet, true);
             tablet.reset();
@@ -186,17 +192,62 @@ TEST_CASE("Test RelationalTabletTsblockRead", 
"[testRelationalTabletTsblockRead]
     int rowNum = 0;
     timestamp = 0;
     while (dataIter.next()) {
-        REQUIRE(dataIter.getLongByIndex(1) == timestamp + rowNum);
-        REQUIRE(dataIter.getBooleanByIndex(2) == (rowNum % 2 == 0));
-        REQUIRE(dataIter.getIntByIndex(3) == static_cast<int32_t>(rowNum));
-        REQUIRE(dataIter.getLongByIndex(4) == static_cast<int64_t>(timestamp));
-        REQUIRE(fabs(dataIter.getFloatByIndex(5) - rowNum * 1.1f) < 0.1f);
-        REQUIRE(fabs(dataIter.getDoubleByIndex(6) - rowNum * 1.1f) < 0.1);
-        REQUIRE(dataIter.getStringByIndex(7) == "text_" + to_string(rowNum));
-        REQUIRE(dataIter.getLongByIndex(8) == static_cast<int64_t>(timestamp));
-        REQUIRE(dataIter.getDateByIndex(9) == boost::gregorian::date(2025, 5, 
15));
-        REQUIRE(dataIter.getStringByIndex(10) == "blob_" + to_string(rowNum));
-        REQUIRE(dataIter.getStringByIndex(11) == "string_" + 
to_string(rowNum));
+        if (rowNum % 2 == 0) {
+            REQUIRE_FALSE(dataIter.getBooleanByIndex(2).is_initialized());
+            REQUIRE_FALSE(dataIter.getIntByIndex(3).is_initialized());
+            REQUIRE_FALSE(dataIter.getLongByIndex(4).is_initialized());
+            REQUIRE_FALSE(dataIter.getFloatByIndex(5).is_initialized());
+            REQUIRE_FALSE(dataIter.getDoubleByIndex(6).is_initialized());
+            REQUIRE_FALSE(dataIter.getStringByIndex(7).is_initialized());
+            REQUIRE_FALSE(dataIter.getLongByIndex(8).is_initialized());
+            REQUIRE_FALSE(dataIter.getDateByIndex(9).is_initialized());
+            REQUIRE_FALSE(dataIter.getStringByIndex(10).is_initialized());
+            REQUIRE_FALSE(dataIter.getStringByIndex(11).is_initialized());
+        } else {
+            REQUIRE(dataIter.getLongByIndex(1).value() == timestamp + rowNum);
+            REQUIRE(dataIter.getBooleanByIndex(2).value() == (rowNum % 2 == 
0));
+            REQUIRE(dataIter.getIntByIndex(3).value() == 
static_cast<int32_t>(rowNum));
+            REQUIRE(dataIter.getLongByIndex(4).value() == 
static_cast<int64_t>(timestamp));
+            REQUIRE(fabs(dataIter.getFloatByIndex(5).value() - rowNum * 1.1f) 
< 0.1f);
+            REQUIRE(fabs(dataIter.getDoubleByIndex(6).value() - rowNum * 1.1f) 
< 0.1);
+            REQUIRE(dataIter.getStringByIndex(7).value() == "text_" + 
to_string(rowNum));
+            REQUIRE(dataIter.getLongByIndex(8).value() == 
static_cast<int64_t>(timestamp));
+            REQUIRE(dataIter.getDateByIndex(9).value() == 
boost::gregorian::date(2025, 5, 15));
+            REQUIRE(dataIter.getStringByIndex(10).value() == "blob_" + 
to_string(rowNum));
+            REQUIRE(dataIter.getStringByIndex(11).value() == "string_" + 
to_string(rowNum));
+        }
+        rowNum++;
+    }
+    REQUIRE(rowNum == maxRowNumber);
+
+    sessionDataSet = session->executeQueryStatement("SELECT * FROM table1 
order by time");
+    rowNum = 0;
+    timestamp = 0;
+    while (sessionDataSet->hasNext()) {
+        auto record = sessionDataSet->next();
+        if (rowNum % 2 == 0) {
+            REQUIRE_FALSE(record->fields[1].boolV.is_initialized());
+            REQUIRE_FALSE(record->fields[2].intV.is_initialized());
+            REQUIRE_FALSE(record->fields[3].longV.is_initialized());
+            REQUIRE_FALSE(record->fields[4].floatV.is_initialized());
+            REQUIRE_FALSE(record->fields[5].doubleV.is_initialized());
+            REQUIRE_FALSE(record->fields[6].stringV.is_initialized());
+            REQUIRE_FALSE(record->fields[7].longV.is_initialized());
+            REQUIRE_FALSE(record->fields[8].dateV.is_initialized());
+            REQUIRE_FALSE(record->fields[9].stringV.is_initialized());
+            REQUIRE_FALSE(record->fields[10].stringV.is_initialized());
+        } else {
+            REQUIRE(record->fields[1].boolV.value() == (rowNum % 2 == 0));
+            REQUIRE(record->fields[2].intV.value() == 
static_cast<int32_t>(rowNum));
+            REQUIRE(record->fields[3].longV.value() == 
static_cast<int64_t>(timestamp));
+            REQUIRE(fabs(record->fields[4].floatV.value() - rowNum * 1.1f) < 
0.1f);
+            REQUIRE(fabs(record->fields[5].doubleV.value() - rowNum * 1.1f) < 
0.1);
+            REQUIRE(record->fields[6].stringV.value() == "text_" + 
to_string(rowNum));
+            REQUIRE(record->fields[7].longV.value() == 
static_cast<int64_t>(timestamp));
+            REQUIRE(record->fields[8].dateV.value() == 
boost::gregorian::date(2025, 5, 15));
+            REQUIRE(record->fields[9].stringV.value() == "blob_" + 
to_string(rowNum));
+            REQUIRE(record->fields[10].stringV.value() == "string_" + 
to_string(rowNum));
+        }
         rowNum++;
     }
     REQUIRE(rowNum == maxRowNumber);


Reply via email to