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

yiguolei pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new e5da615f9e0 [refine](column) Remove pointer access from column element 
view (#64724)
e5da615f9e0 is described below

commit e5da615f9e0d7f0560a0e7e0941fe76ed7998d52
Author: Mryange <[email protected]>
AuthorDate: Thu Jun 25 09:57:55 2026 +0800

    [refine](column) Remove pointer access from column element view (#64724)
    
    ### What problem does this PR solve?
    
    ColumnElementView exposed ptr_at() only to adapt predicate set lookups
    that accepted raw void pointers. For string columns this required a
    mutable temporary StringRef inside the view, making the element access
    API harder to reason about.
    
    This change removes ColumnElementView::ptr_at() and the string staging
    field, updates in-list predicate evaluation to use
    get_element()/get_data() with HybridSetBase::find(data, size), and
    replaces the predicate selector macro with a small templated helper that
    accepts named lambdas.
    
    
    ### Release note
    
    None
    
    ### Check List (For Author)
    
    - Test <!-- At least one of them must be included. -->
        - [ ] Regression test
        - [ ] Unit Test
        - [ ] Manual test (add detailed scripts or steps below)
        - [ ] No need to test or manual test. Explain why:
    - [ ] This is a refactor/code format and no logic has been changed.
            - [ ] Previous test can cover this change.
            - [ ] No code files have been changed.
            - [ ] Other reason <!-- Add your reason?  -->
    
    - Behavior changed:
        - [ ] No.
        - [ ] Yes. <!-- Explain the behavior change -->
    
    - Does this need documentation?
        - [ ] No.
    - [ ] Yes. <!-- Add document PR link here. eg:
    https://github.com/apache/doris-website/pull/1214 -->
    
    ### Check List (For Reviewer who merge this PR)
    
    - [ ] Confirm the release note
    - [ ] Confirm test cases
    - [ ] Confirm document
    - [ ] Add branch pick label <!-- Add branch pick label that this PR
    should merge into -->
---
 be/src/core/column/column_execute_util.h        | 18 ++------------
 be/src/storage/predicate/column_predicate.h     | 32 +++++++++++++++----------
 be/src/storage/predicate/comparison_predicate.h | 28 ++++++++++++----------
 be/src/storage/predicate/in_list_predicate.h    | 30 +++++++++++++++--------
 be/src/storage/predicate/null_predicate.cpp     |  8 +++----
 5 files changed, 60 insertions(+), 56 deletions(-)

diff --git a/be/src/core/column/column_execute_util.h 
b/be/src/core/column/column_execute_util.h
index 49d4f67684f..211191e8cae 100644
--- a/be/src/core/column/column_execute_util.h
+++ b/be/src/core/column/column_execute_util.h
@@ -36,8 +36,7 @@ namespace doris {
 
 // Utility tools for convenient column execution
 
-// Per-row read view over a column.  The pointer returned by ptr_at on the
-// string specialization is valid only until the next ptr_at call.
+// Per-row read view over a column.
 namespace detail {
 
 template <PrimitiveType PType>
@@ -52,7 +51,6 @@ struct NumericElementView {
     ElementType get_element(size_t idx) const { return data[idx]; }
     const ElementType* get_data() const { return data.data(); }
     ElementType operator[](size_t idx) const { return data[idx]; }
-    const ElementType* ptr_at(size_t idx) const { return data.data() + idx; }
     size_t size() const { return data.size(); }
 };
 
@@ -60,17 +58,12 @@ struct StringElementView {
     using ColumnType = ColumnString;
     using ElementType = StringRef;
     const ColumnString& string_column;
-    mutable StringRef _cell {}; // staging for ptr_at
 
     StringElementView(const IColumn& column)
             : string_column(assert_cast<const ColumnString&>(column)) {}
 
     StringRef get_element(size_t idx) const { return 
string_column.get_data_at(idx); }
     StringRef operator[](size_t idx) const { return 
string_column.get_data_at(idx); }
-    const StringRef* ptr_at(size_t idx) const {
-        _cell = string_column.get_data_at(idx);
-        return &_cell;
-    }
     size_t size() const { return string_column.size(); }
 };
 
@@ -80,13 +73,6 @@ template <PrimitiveType PType>
 using ColumnElementView = std::conditional_t<is_string_type(PType), 
detail::StringElementView,
                                              
detail::NumericElementView<PType>>;
 
-template <typename T>
-concept ColumnElementSubscriptable = requires(const T& v, size_t i) {
-    typename T::ElementType;
-    { v[i] } -> std::convertible_to<typename T::ElementType>;
-    { v.size() } -> std::convertible_to<size_t>;
-};
-
 // ColumnView is used to handle the nullable and const properties of a column.
 // For example, a regular ColumnInt32 may appear in the following 4 cases:
 // 1. ColumnInt32
@@ -155,4 +141,4 @@ struct ColumnView {
 
     size_t size() const { return count; }
 };
-} // namespace doris
\ No newline at end of file
+} // namespace doris
diff --git a/be/src/storage/predicate/column_predicate.h 
b/be/src/storage/predicate/column_predicate.h
index 84d49ea4070..2bcc8359464 100644
--- a/be/src/storage/predicate/column_predicate.h
+++ b/be/src/storage/predicate/column_predicate.h
@@ -20,6 +20,7 @@
 #include <memory>
 #include <roaring/roaring.hh>
 
+#include "common/compiler_util.h"
 #include "common/exception.h"
 #include "core/column/column.h"
 #include "core/data_type/define_primitive_type.h"
@@ -181,20 +182,25 @@ struct PredicateTypeTraits {
     }
 };
 
-#define EVALUATE_BY_SELECTOR(EVALUATE_IMPL_WITH_NULL_MAP, 
EVALUATE_IMPL_WITHOUT_NULL_MAP) \
-    const bool is_dense_column = pred_col.size() == size;                      
           \
-    for (uint16_t i = 0; i < size; i++) {                                      
           \
-        uint16_t idx = is_dense_column ? i : sel[i];                           
           \
-        if constexpr (is_nullable) {                                           
           \
-            if (EVALUATE_IMPL_WITH_NULL_MAP(idx)) {                            
           \
-                sel[new_size++] = idx;                                         
           \
-            }                                                                  
           \
-        } else {                                                               
           \
-            if (EVALUATE_IMPL_WITHOUT_NULL_MAP(idx)) {                         
           \
-                sel[new_size++] = idx;                                         
           \
-            }                                                                  
           \
-        }                                                                      
           \
+template <bool is_nullable, typename PredColumn, typename WithNullFunc, 
typename WithoutNullFunc>
+inline ALWAYS_INLINE void evaluate_by_selector(const PredColumn& pred_col, 
uint16_t size,
+                                               uint16_t* sel, uint16_t& 
new_size,
+                                               WithNullFunc&& with_null_func,
+                                               WithoutNullFunc&& 
without_null_func) {
+    const bool is_dense_column = pred_col.size() == size;
+    for (uint16_t i = 0; i < size; i++) {
+        uint16_t idx = is_dense_column ? i : sel[i];
+        if constexpr (is_nullable) {
+            if (with_null_func(idx)) {
+                sel[new_size++] = idx;
+            }
+        } else {
+            if (without_null_func(idx)) {
+                sel[new_size++] = idx;
+            }
+        }
     }
+}
 
 class ColumnPredicate : public std::enable_shared_from_this<ColumnPredicate> {
 public:
diff --git a/be/src/storage/predicate/comparison_predicate.h 
b/be/src/storage/predicate/comparison_predicate.h
index 85de8abb0ff..d420e550ff5 100644
--- a/be/src/storage/predicate/comparison_predicate.h
+++ b/be/src/storage/predicate/comparison_predicate.h
@@ -630,12 +630,14 @@ private:
                     }
                 }
                 uint16_t new_size = 0;
-#define EVALUATE_WITH_NULL_IMPL(IDX) \
-    _opposite ^ (!null_map[IDX] && _operator(pred_col_data[IDX], dict_code))
-#define EVALUATE_WITHOUT_NULL_IMPL(IDX) _opposite ^ 
_operator(pred_col_data[IDX], dict_code)
-                EVALUATE_BY_SELECTOR(EVALUATE_WITH_NULL_IMPL, 
EVALUATE_WITHOUT_NULL_IMPL)
-#undef EVALUATE_WITH_NULL_IMPL
-#undef EVALUATE_WITHOUT_NULL_IMPL
+                auto with_null = [&](uint16_t idx) {
+                    return _opposite ^ (!null_map[idx] && 
_operator(pred_col_data[idx], dict_code));
+                };
+                auto without_null = [&](uint16_t idx) {
+                    return _opposite ^ _operator(pred_col_data[idx], 
dict_code);
+                };
+                evaluate_by_selector<is_nullable>(pred_col, size, sel, 
new_size, with_null,
+                                                  without_null);
 
                 return new_size;
             } else {
@@ -645,12 +647,14 @@ private:
         } else {
             uint16_t new_size = 0;
             ColumnElementView<Type> pred_col {*column};
-#define EVALUATE_WITH_NULL_IMPL(IDX) \
-    _opposite ^ (!null_map[IDX] && _operator(pred_col[IDX], _value))
-#define EVALUATE_WITHOUT_NULL_IMPL(IDX) _opposite ^ _operator(pred_col[IDX], 
_value)
-            EVALUATE_BY_SELECTOR(EVALUATE_WITH_NULL_IMPL, 
EVALUATE_WITHOUT_NULL_IMPL)
-#undef EVALUATE_WITH_NULL_IMPL
-#undef EVALUATE_WITHOUT_NULL_IMPL
+            auto with_null = [&](uint16_t idx) {
+                return _opposite ^ (!null_map[idx] && 
_operator(pred_col.get_element(idx), _value));
+            };
+            auto without_null = [&](uint16_t idx) {
+                return _opposite ^ _operator(pred_col.get_element(idx), 
_value);
+            };
+            evaluate_by_selector<is_nullable>(pred_col, size, sel, new_size, 
with_null,
+                                              without_null);
             return new_size;
         }
     }
diff --git a/be/src/storage/predicate/in_list_predicate.h 
b/be/src/storage/predicate/in_list_predicate.h
index 180a1b04139..47e1a9e9cd1 100644
--- a/be/src/storage/predicate/in_list_predicate.h
+++ b/be/src/storage/predicate/in_list_predicate.h
@@ -58,6 +58,7 @@ struct std::equal_to<doris::uint24_t> {
 };
 
 namespace doris {
+
 /**
  * Use HybridSetType can avoid virtual function call in the loop.
  * @tparam Type
@@ -536,15 +537,16 @@ private:
                 __builtin_unreachable();
             }
         } else {
-            // ptr_at safe: HybridSet::find consumes the pointer synchronously.
             ColumnElementView<Type> pred_col {*column};
-#define EVALUATE_WITH_NULL_IMPL(IDX) \
-    is_opposite ^ (!(*null_map)[IDX] && 
_operator(_values->find(pred_col.ptr_at(IDX)), false))
-#define EVALUATE_WITHOUT_NULL_IMPL(IDX) \
-    is_opposite ^ _operator(_values->find(pred_col.ptr_at(IDX)), false)
-            EVALUATE_BY_SELECTOR(EVALUATE_WITH_NULL_IMPL, 
EVALUATE_WITHOUT_NULL_IMPL)
-#undef EVALUATE_WITH_NULL_IMPL
-#undef EVALUATE_WITHOUT_NULL_IMPL
+            auto with_null = [&](uint16_t idx) {
+                return is_opposite ^
+                       (!(*null_map)[idx] && _operator(_find_value(pred_col, 
idx), false));
+            };
+            auto without_null = [&](uint16_t idx) {
+                return is_opposite ^ _operator(_find_value(pred_col, idx), 
false);
+            };
+            evaluate_by_selector<is_nullable>(pred_col, size, sel, new_size, 
with_null,
+                                              without_null);
         }
         return new_size;
     }
@@ -592,7 +594,6 @@ private:
                 __builtin_unreachable();
             }
         } else {
-            // ptr_at safe: HybridSet::find consumes the pointer synchronously.
             ColumnElementView<Type> view {*column};
             for (uint16_t i = 0; i < size; i++) {
                 if (is_and ^ flags[i]) {
@@ -607,7 +608,7 @@ private:
                         continue;
                     }
                 }
-                bool hit = _operator(_values->find(view.ptr_at(idx)), false);
+                bool hit = _operator(_find_value(view, idx), false);
                 if constexpr (!is_opposite) {
                     if (is_and ^ hit) {
                         flags[i] = !is_and;
@@ -630,6 +631,15 @@ private:
         }
     }
 
+    ALWAYS_INLINE bool _find_value(const ColumnElementView<Type>& pred_col, 
size_t idx) const {
+        if constexpr (is_string_type(Type)) {
+            const auto value = pred_col.get_element(idx);
+            return _values->find(value.data, value.size);
+        } else {
+            return _values->find(pred_col.get_data() + idx, sizeof(T));
+        }
+    }
+
     std::shared_ptr<HybridSetBase> _values;
     mutable std::map<std::pair<RowsetId, uint32_t>, std::vector<UInt8>>
             _segment_id_to_value_in_dict_flags;
diff --git a/be/src/storage/predicate/null_predicate.cpp 
b/be/src/storage/predicate/null_predicate.cpp
index f9c23117621..9973555109c 100644
--- a/be/src/storage/predicate/null_predicate.cpp
+++ b/be/src/storage/predicate/null_predicate.cpp
@@ -71,11 +71,9 @@ uint16_t NullPredicate::_evaluate_inner(const IColumn& 
column, uint16_t* sel, ui
         }
         auto& pred_col = nullable->get_null_map_data();
         constexpr bool is_nullable = true;
-#define EVALUATE_WITH_NULL_IMPL(IDX) pred_col[IDX] == _is_null
-#define EVALUATE_WITHOUT_NULL_IMPL(IDX) true
-        EVALUATE_BY_SELECTOR(EVALUATE_WITH_NULL_IMPL, 
EVALUATE_WITHOUT_NULL_IMPL)
-#undef EVALUATE_WITH_NULL_IMPL
-#undef EVALUATE_WITHOUT_NULL_IMPL
+        auto with_null = [&](uint16_t idx) { return pred_col[idx] == _is_null; 
};
+        auto without_null = [](uint16_t) { return true; };
+        evaluate_by_selector<is_nullable>(pred_col, size, sel, new_size, 
with_null, without_null);
         return new_size;
     } else {
         if (_is_null) return 0;


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

Reply via email to