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 8439807f722 Fix C++ client DATE 1000-01-01 query crash (#18096)
8439807f722 is described below
commit 8439807f72297c147bfe5e50211ed86cdd2eedf0
Author: Hongzhi Gao <[email protected]>
AuthorDate: Fri Jul 3 09:14:47 2026 +0800
Fix C++ client DATE 1000-01-01 query crash (#18096)
Stop treating EMPTY_DATE_INT as a null sentinel when decoding query
results, since it encodes the valid date 1000-01-01 and caused C API reads to
throw in parseDateExpressionToInt.
---
iotdb-client/client-cpp/src/include/Common.h | 2 +-
iotdb-client/client-cpp/src/session/Date.cpp | 3 ---
iotdb-client/client-cpp/src/session/SessionC.cpp | 4 +++-
iotdb-client/client-cpp/test/cpp/sessionCIT.cpp | 30 ++++++++++++++++++++++++
iotdb-client/client-cpp/test/cpp/sessionIT.cpp | 28 ++++++++++++++++++++++
5 files changed, 62 insertions(+), 5 deletions(-)
diff --git a/iotdb-client/client-cpp/src/include/Common.h
b/iotdb-client/client-cpp/src/include/Common.h
index 49dca0bca4b..f36b38206b8 100644
--- a/iotdb-client/client-cpp/src/include/Common.h
+++ b/iotdb-client/client-cpp/src/include/Common.h
@@ -185,7 +185,7 @@ public:
case TSDataType::BLOB:
return !stringV.is_initialized();
case TSDataType::DATE:
- return !dateV.is_initialized();
+ return !dateV.is_initialized() || dateV.value().is_not_a_date();
default:
return true;
}
diff --git a/iotdb-client/client-cpp/src/session/Date.cpp
b/iotdb-client/client-cpp/src/session/Date.cpp
index 91095c250da..1e6f62edd1d 100644
--- a/iotdb-client/client-cpp/src/session/Date.cpp
+++ b/iotdb-client/client-cpp/src/session/Date.cpp
@@ -53,9 +53,6 @@ int32_t parseDateExpressionToInt(const IoTDBDate& date) {
}
IoTDBDate parseIntToDate(int32_t dateInt) {
- if (dateInt == EMPTY_DATE_INT) {
- return IoTDBDate::notADate();
- }
const int year = dateInt / 10000;
const int month = (dateInt % 10000) / 100;
const int day = dateInt % 100;
diff --git a/iotdb-client/client-cpp/src/session/SessionC.cpp
b/iotdb-client/client-cpp/src/session/SessionC.cpp
index 79287cf0252..7365d6ff645 100644
--- a/iotdb-client/client-cpp/src/session/SessionC.cpp
+++ b/iotdb-client/client-cpp/src/session/SessionC.cpp
@@ -1495,8 +1495,10 @@ int32_t ts_row_record_get_date_int32(CRowRecord* record,
int index) {
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())
+ if (f.dataType != TSDataType::DATE || !f.dateV.is_initialized() ||
+ f.dateV.value().is_not_a_date()) {
return 0;
+ }
return parseDateExpressionToInt(f.dateV.value());
}
diff --git a/iotdb-client/client-cpp/test/cpp/sessionCIT.cpp
b/iotdb-client/client-cpp/test/cpp/sessionCIT.cpp
index 0e0791c5d29..08aace0ca93 100644
--- a/iotdb-client/client-cpp/test/cpp/sessionCIT.cpp
+++ b/iotdb-client/client-cpp/test/cpp/sessionCIT.cpp
@@ -792,3 +792,33 @@ TEST_CASE("C API - RowRecord and delete data APIs",
"[c_rowDelete]") {
REQUIRE(ts_session_delete_timeseries(g_session, pblob) == TS_OK);
REQUIRE(ts_session_delete_database(g_session, sg) == TS_OK);
}
+
+TEST_CASE("C API - Query DATE 1000-01-01", "[c_dateMinYear]") {
+ CaseReporter cr("c_dateMinYear");
+
+ const char* path = "root.ctest.d1.s_date_min";
+ ensureTimeseries(g_session, path, TS_TYPE_DATE, TS_ENCODING_PLAIN,
TS_COMPRESSION_SNAPPY);
+
+ const char* deviceId = "root.ctest.d1";
+ const char* measurements[] = {"s_date_min"};
+ TSDataType_C types[] = {TS_TYPE_DATE};
+ TSDate_C dateVal = {1000, 1, 1};
+ const void* vals[] = {&dateVal};
+ REQUIRE(ts_session_insert_record(g_session, deviceId, 1000LL, 1,
measurements, types, vals) ==
+ TS_OK);
+
+ CSessionDataSet* dataSet = nullptr;
+ REQUIRE(ts_session_execute_query(g_session,
+ "select s_date_min from root.ctest.d1 where
time=1000",
+ &dataSet) == TS_OK);
+ REQUIRE(dataSet != nullptr);
+ REQUIRE(ts_dataset_has_next(dataSet));
+ CRowRecord* record = ts_dataset_next(dataSet);
+ REQUIRE(record != nullptr);
+ REQUIRE_FALSE(ts_row_record_is_null(record, 0));
+ REQUIRE(ts_row_record_get_date_int32(record, 0) == 10000101);
+ ts_row_record_destroy(record);
+ ts_dataset_destroy(dataSet);
+
+ REQUIRE(ts_session_delete_timeseries(g_session, path) == TS_OK);
+}
diff --git a/iotdb-client/client-cpp/test/cpp/sessionIT.cpp
b/iotdb-client/client-cpp/test/cpp/sessionIT.cpp
index 3b19f2e2b25..97c078d9d59 100644
--- a/iotdb-client/client-cpp/test/cpp/sessionIT.cpp
+++ b/iotdb-client/client-cpp/test/cpp/sessionIT.cpp
@@ -1062,3 +1062,31 @@ TEST_CASE("SessionPool getSession times out when
exhausted", "[sessionPool]") {
reused.release();
pool->close();
}
+
+TEST_CASE("Query DATE 1000-01-01", "[dateMinYear]") {
+ CaseReporter cr("dateMinYear");
+ const string timeseries = "root.test.d1.s_date_min";
+ if (session->checkTimeseriesExists(timeseries)) {
+ session->deleteTimeseries(timeseries);
+ }
+ session->createTimeseries(timeseries, TSDataType::DATE, TSEncoding::PLAIN,
+ CompressionType::SNAPPY);
+
+ const string deviceId = "root.test.d1";
+ const vector<string> measurements = {"s_date_min"};
+ const vector<TSDataType::TSDataType> types = {TSDataType::DATE};
+ const IoTDBDate dateValue(1000, 1, 1);
+ vector<char*> values = {const_cast<char*>(reinterpret_cast<const
char*>(&dateValue))};
+ session->insertRecord(deviceId, 1000LL, measurements, types, values);
+
+ unique_ptr<SessionDataSet> sessionDataSet =
+ session->executeQueryStatement("select s_date_min from root.test.d1
where time=1000");
+ REQUIRE(sessionDataSet->hasNext());
+ auto record = sessionDataSet->next();
+ REQUIRE(record->fields.size() == 1);
+ REQUIRE_FALSE(record->fields[0].isNull());
+ REQUIRE(record->fields[0].dateV.value() == dateValue);
+ REQUIRE(record->fields[0].dateV.value().toIsoExtendedString() ==
"1000-01-01");
+
+ session->deleteTimeseries(timeseries);
+}