github-actions[bot] commented on code in PR #67563:
URL: https://github.com/apache/doris/pull/67563#discussion_r4217163463


##########
be/test/exec/rowid_fetcher_test.cpp:
##########
@@ -256,4 +286,141 @@ TEST_F(RowIdStorageReaderTest, 
ExternalFetchPartitionSlotsPreserveHivePositionMa
     }
 }
 
+TEST_F(RowIdStorageReaderTest, SameSourceColumnSharesKey) {
+    // The bug case: one physical column projected twice must dedup onto one 
scan column.
+    const SlotDescriptor first = make_slot({});
+    const SlotDescriptor second = make_slot({});
+    EXPECT_EQ(key_of(first, 3), key_of(second, 3));
+}
+
+TEST_F(RowIdStorageReaderTest, ColumnIndexSeparatesKeys) {
+    const SlotDescriptor slot = make_slot({});
+    EXPECT_NE(key_of(slot, 3), key_of(slot, 4));
+}
+
+TEST_F(RowIdStorageReaderTest, ColumnNameSeparatesKeys) {
+    EXPECT_NE(key_of(make_slot({.col_name = "a"}), 0), 
key_of(make_slot({.col_name = "b"}), 0));
+}
+
+TEST_F(RowIdStorageReaderTest, UniqueIdSeparatesKeys) {
+    EXPECT_NE(key_of(make_slot({.col_unique_id = 1}), 0),
+              key_of(make_slot({.col_unique_id = 2}), 0));
+}
+
+TEST_F(RowIdStorageReaderTest, NameAndIndexBoundaryIsNotAmbiguous) {
+    // Without length prefixes, "a" + idx 12 and "a1" + idx 2 both flatten to 
"a12".
+    EXPECT_NE(key_of(make_slot({.col_name = "a"}), 12), 
key_of(make_slot({.col_name = "a1"}), 2));
+}
+
+TEST_F(RowIdStorageReaderTest, PathComponentBoundaryIsNotAmbiguous) {
+    // The concatenation hazard the length prefix exists for: ["a", "b"] and 
["a:b"] are
+    // different nested columns but share the naive ':'-joined spelling.
+    EXPECT_NE(key_of(make_slot({.column_paths = {"a", "b"}}), 0),
+              key_of(make_slot({.column_paths = {"a:b"}}), 0));
+}
+
+TEST_F(RowIdStorageReaderTest, EmptyPathIsNotTheSameAsNoPath) {
+    EXPECT_NE(key_of(make_slot({.column_paths = {}}), 0),
+              key_of(make_slot({.column_paths = {""}}), 0));
+}
+
+TEST_F(RowIdStorageReaderTest, PathOrderMatters) {
+    EXPECT_NE(key_of(make_slot({.column_paths = {"a", "b"}}), 0),
+              key_of(make_slot({.column_paths = {"b", "a"}}), 0));
+}
+
+TEST_F(RowIdStorageReaderTest, EqualPathsShareKey) {
+    EXPECT_EQ(key_of(make_slot({.column_paths = {"a", "b"}}), 0),
+              key_of(make_slot({.column_paths = {"a", "b"}}), 0));
+}
+
+TEST_F(RowIdStorageReaderTest, AccessPathSeparatesKeys) {
+    EXPECT_NE(key_of(make_slot({.access_paths = {data_path({"a"})}}), 0),
+              key_of(make_slot({.access_paths = {data_path({"b"})}}), 0));
+}
+
+TEST_F(RowIdStorageReaderTest, AbsentAccessPathIsNotAnEmptyOne) {
+    // The presence bit: an unset data_access_path must not collide with one 
that is set
+    // but carries no components.
+    EXPECT_NE(key_of(make_slot({.access_paths = {bare_path()}}), 0),
+              key_of(make_slot({.access_paths = {data_path({})}}), 0));
+}
+
+TEST_F(RowIdStorageReaderTest, AccessPathCountSeparatesKeys) {
+    EXPECT_NE(key_of(make_slot({.access_paths = {data_path({"a"})}}), 0),
+              key_of(make_slot({.access_paths = {data_path({"a"}), 
data_path({"b"})}}), 0));
+}
+
+// Runs every submitted task on the submitting thread. The point of these 
cases is which
+// status reaches the caller, not the threading, and inline execution keeps 
them
+// deterministic.
+class InlineScanScheduler : public ScannerScheduler {
+public:
+    Status start(int, int, int, int) override { return Status::OK(); }
+    void stop() override {}
+    Status submit_scan_task(SimplifiedScanTask scan_task) override {
+        scan_task.scan_func();
+        return Status::OK();
+    }
+    Status submit_scan_task(SimplifiedScanTask scan_task, const std::string&) 
override {
+        scan_task.scan_func();
+        return Status::OK();
+    }
+    void reset_thread_num(int, int, int) override {}
+    int get_queue_size() override { return 0; }
+    int get_active_threads() override { return 0; }
+    std::vector<int> thread_debug_info() override { return {}; }
+    Status schedule_scan_task(std::shared_ptr<ScannerContext>, 
std::shared_ptr<ScanTask>,
+                              std::unique_lock<std::mutex>&) override {
+        return Status::OK();
+    }
+};
+
+// submit_external_scan_tasks() signals completion from a Defer, so a worker 
that leaves
+// without publishing its status would still wake the waiter and the caller 
would report
+// success over a partially filled result block.
+class SubmitExternalScanTasksTest : public RowIdStorageReaderTest {
+protected:
+    static constexpr size_t kTaskCount = 3;
+
+    static Status run_tasks(const std::function<Status(size_t)>& run_task) {
+        InlineScanScheduler scheduler;
+        std::counting_semaphore<> semaphore {kTaskCount};
+        return RowIdStorageReader::submit_external_scan_tasks(

Review Comment:
   [P1] Move the private helper call into the friended fixture. 
`submit_external_scan_tasks` is private and `RowIdStorageReader` only friends 
`RowIdStorageReaderTest`. This call is in 
`SubmitExternalScanTasksTest::run_tasks`, a member of a derived fixture; C++ 
friendship is not inherited, so `rowid_fetcher_test.cpp` fails access checking. 
Put a forwarding `run_tasks` member in the friended base fixture or explicitly 
friend this fixture.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to