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

hongzhigao pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/tsfile.git


The following commit(s) were added to refs/heads/develop by this push:
     new 12bd435e fix query-by-row unexist path
12bd435e is described below

commit 12bd435ecc361369a67ec6c52d5c4f7bccf928a5
Author: 761417898 <[email protected]>
AuthorDate: Tue Apr 14 15:31:58 2026 +0800

    fix query-by-row unexist path
---
 cpp/src/reader/qds_without_timegenerator.cc        |   8 +-
 .../tree_view/tsfile_tree_query_by_row_test.cc     | 144 +++++++++++++++++++++
 2 files changed, 151 insertions(+), 1 deletion(-)

diff --git a/cpp/src/reader/qds_without_timegenerator.cc 
b/cpp/src/reader/qds_without_timegenerator.cc
index b895f2e3..474e13b7 100644
--- a/cpp/src/reader/qds_without_timegenerator.cc
+++ b/cpp/src/reader/qds_without_timegenerator.cc
@@ -67,10 +67,15 @@ int QDSWithoutTimeGenerator::init_internal(TsFileIOReader* 
io_reader,
         TsFileSeriesScanIterator* ssi = nullptr;
         ret = io_reader_->alloc_ssi(paths[i].device_id_, paths[i].measurement_,
                                     ssi, pa_, global_time_filter);
-        if (ret == E_MEASUREMENT_NOT_EXIST || ret == E_DEVICE_NOT_EXIST) {
+        if (ret == E_MEASUREMENT_NOT_EXIST || ret == E_DEVICE_NOT_EXIST ||
+            ret == E_NOT_EXIST) {
             continue;
         }
         if (ret != E_OK) {
+            for (size_t j = 0; j < ssi_vec_.size(); j++) {
+                io_reader_->revert_ssi(ssi_vec_[j]);
+            }
+            ssi_vec_.clear();
             return ret;
         }
         size_t col_idx = ssi_vec_.size();
@@ -139,6 +144,7 @@ void QDSWithoutTimeGenerator::close() {
         io_reader_->revert_ssi(ssi);
     }
     ssi_vec_.clear();
+    tsblocks_.clear();
     if (qe_ != nullptr) {
         delete qe_;
         qe_ = nullptr;
diff --git a/cpp/test/reader/tree_view/tsfile_tree_query_by_row_test.cc 
b/cpp/test/reader/tree_view/tsfile_tree_query_by_row_test.cc
index 80bd974e..a686b899 100644
--- a/cpp/test/reader/tree_view/tsfile_tree_query_by_row_test.cc
+++ b/cpp/test/reader/tree_view/tsfile_tree_query_by_row_test.cc
@@ -16,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+#include <fcntl.h>
 #include <gtest/gtest.h>
 
 #include <chrono>
@@ -24,14 +25,114 @@
 #include "common/global.h"
 #include "common/record.h"
 #include "common/schema.h"
+#include "common/tablet.h"
 #include "file/write_file.h"
 #include "reader/tsfile_reader.h"
 #include "reader/tsfile_tree_reader.h"
 #include "writer/tsfile_tree_writer.h"
+#include "writer/tsfile_writer.h"
 
 using namespace storage;
 using namespace common;
 
+namespace {
+
+int write_multi_device_data_tablet(
+    const std::vector<std::pair<std::string, std::vector<std::string>>>&
+        devices_and_measurements,
+    const std::vector<TSDataType>& data_types, int row_count,
+    const std::string& file_path) {
+    TsFileWriter tsfile_writer;
+    int flags = O_WRONLY | O_CREAT | O_TRUNC;
+#ifdef _WIN32
+    flags |= O_BINARY;
+#endif
+    mode_t mode = 0666;
+    int ret = tsfile_writer.open(file_path, flags, mode);
+    if (ret != E_OK) {
+        return ret;
+    }
+    for (auto& device_pair : devices_and_measurements) {
+        const std::vector<std::string>& measurements = device_pair.second;
+        if (measurements.size() != data_types.size()) {
+            return E_INVALID_ARG;
+        }
+    }
+    for (auto& device_pair : devices_and_measurements) {
+        const std::string& device_id = device_pair.first;
+        const std::vector<std::string>& measurements = device_pair.second;
+        for (size_t i = 0; i < measurements.size(); i++) {
+            MeasurementSchema schema(measurements[i], data_types[i]);
+            ret = tsfile_writer.register_timeseries(device_id, schema);
+            if (ret != E_OK) {
+                return ret;
+            }
+        }
+    }
+    for (auto& device_pair : devices_and_measurements) {
+        const std::string& device_id = device_pair.first;
+        const std::vector<std::string>& measurements = device_pair.second;
+        auto schema_ptr = std::make_shared<std::vector<MeasurementSchema>>();
+        for (size_t i = 0; i < measurements.size(); i++) {
+            schema_ptr->emplace_back(measurements[i], data_types[i]);
+        }
+        Tablet tablet(device_id, schema_ptr, row_count);
+        for (int row = 0; row < row_count; row++) {
+            ret = tablet.add_timestamp(row, row);
+            if (ret != E_OK) {
+                return ret;
+            }
+            for (size_t col = 0; col < measurements.size(); col++) {
+                if ((static_cast<unsigned>(row) % 2) == (col % 2)) {
+                    continue;
+                }
+                switch (data_types[col]) {
+                    case BOOLEAN:
+                        ret = tablet.add_value(row, col, (row % 2 != 0));
+                        break;
+                    case INT32:
+                        ret = tablet.add_value(row, col,
+                                               static_cast<int32_t>(row));
+                        break;
+                    case INT64:
+                        ret = tablet.add_value(row, col,
+                                               static_cast<int64_t>(row));
+                        break;
+                    case FLOAT:
+                        ret =
+                            tablet.add_value(row, col, 
static_cast<float>(row));
+                        break;
+                    case DOUBLE:
+                        ret = tablet.add_value(row, col,
+                                               static_cast<double>(row));
+                        break;
+                    case STRING: {
+                        std::string val_str = "string" + std::to_string(row);
+                        ret = tablet.add_value(row, col, val_str.c_str());
+                        break;
+                    }
+                    default:
+                        return E_TYPE_NOT_MATCH;
+                }
+                if (ret != E_OK) {
+                    return ret;
+                }
+            }
+        }
+        ret = tsfile_writer.write_tablet(tablet);
+        if (ret != E_OK) {
+            return ret;
+        }
+    }
+    ret = tsfile_writer.flush();
+    if (ret != E_OK) {
+        return ret;
+    }
+    return tsfile_writer.close();
+}
+
+}  // namespace
+
 class TreeQueryByRowTest : public ::testing::Test {
    protected:
     void SetUp() override {
@@ -171,6 +272,49 @@ TEST_F(TreeQueryByRowTest, 
QueryByRow_SkipsMissingDeviceAndMeasurement) {
     reader.close();
 }
 
+TEST_F(TreeQueryByRowTest, QueryByRow_TabletMultiType_PartialPaths) {
+    std::string tablet_path = std::string("tree_query_by_row_tablet_") +
+                              generate_random_string(10) + ".tsfile";
+    remove(tablet_path.c_str());
+
+    std::vector<std::string> devices = {"root.db.d1"};
+    std::vector<std::string> measurement_names = {"bool_col",   "int32_col",
+                                                  "int64_col",  "float_col",
+                                                  "double_col", "string_col"};
+    std::vector<std::pair<std::string, std::vector<std::string>>>
+        devices_and_measurements = {{devices[0], measurement_names}};
+    std::vector<TSDataType> data_types = {BOOLEAN, INT32,  INT64,
+                                          FLOAT,   DOUBLE, STRING};
+    const int total_rows = 10;
+    ASSERT_EQ(E_OK, write_multi_device_data_tablet(devices_and_measurements,
+                                                   data_types, total_rows,
+                                                   tablet_path));
+
+    TsFileTreeReader reader;
+    ASSERT_EQ(E_OK, reader.open(tablet_path));
+
+    std::vector<std::string> q_devices = {devices[0], "d999"};
+    std::vector<std::string> q_meas = {measurement_names[0],
+                                       measurement_names[1], "ghost_m"};
+    ResultSet* result_set2 = nullptr;
+    ASSERT_EQ(E_OK, reader.queryByRow(q_devices, q_meas, 0, -1, result_set2));
+    ASSERT_NE(result_set2, nullptr);
+    auto meta2 = result_set2->get_metadata();
+    // Metadata includes the time column plus one entry per resolved series.
+    ASSERT_EQ(3u, meta2->get_column_count());
+
+    bool has_next = false;
+    int row_count = 0;
+    while (IS_SUCC(result_set2->next(has_next)) && has_next) {
+        row_count++;
+    }
+    EXPECT_EQ(row_count, total_rows);
+
+    reader.destroy_query_data_set(result_set2);
+    ASSERT_EQ(E_OK, reader.close());
+    remove(tablet_path.c_str());
+}
+
 // Device id with three dot-separated parts (e.g. root.sg1.FeederA) must 
resolve
 // to the same StringArrayDeviceID normalization as write path; queryByRow must
 // not return E_DEVICE_NOT_EXIST.

Reply via email to