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

mrhhsg 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 f70306ce044 [Opt](bitmap) Optimize bitmap op count rewrites (#65483)
f70306ce044 is described below

commit f70306ce0449de8f591956ca95632bae8e5e85ff
Author: linrrarity <[email protected]>
AuthorDate: Mon Jul 27 16:03:34 2026 +0800

    [Opt](bitmap) Optimize bitmap op count rewrites (#65483)
    
    Problem Summary:
    
    ### Background
    
    `bitmap_count(bitmap_op(...))` currently materializes an intermediate
    bitmap before counting. For patterns such as
    `bitmap_count(bitmap_and(...))`, `bitmap_count(bitmap_or(...))`,
    `bitmap_count(bitmap_xor(...))`, and
    `bitmap_count(bitmap_and_not(...))`, Doris already has corresponding
    `bitmap_*_count` functions that can compute the cardinality directly.
    
    Also, `bitmap_and_count`, `bitmap_or_count`, `bitmap_xor_count`, and
    `bitmap_and_not_count` are semantically always not null, but their
    previous metadata could be marked nullable when bitmap arguments were
    nullable.
    
    ### Changes
    
    - Add Nereids expression rewrite:
      - `bitmap_count(bitmap_and(...))` -> `bitmap_and_count(...)`
      - `bitmap_count(bitmap_or(...))` -> `bitmap_or_count(...)`
      - `bitmap_count(bitmap_xor(...))` -> `bitmap_xor_count(...)`
    - `bitmap_count(bitmap_not(...))` / `bitmap_and_not(...)` ->
    `bitmap_and_not_count(...)`
    
    - Mark bitmap op count scalar functions as always not nullable in
    Nereids.
    
    - Add BE v2 implementations for bitmap op count return type inference:
      - `bitmap_and_count_v2`
      - `bitmap_or_count_v2`
      - `bitmap_xor_count_v2`
      - `bitmap_and_not_count_v2`
    
    - Add `new_version_bitmap_op_count` query option to select the v2 BE
    implementations.
    
    - Optimize binary bitmap count execution paths to avoid intermediate
    bitmap materialization.
    
    - Fix `BitmapValue::or_cardinality` for SET/SET input.
    
    - Merge `bitmap_and_not` / `bitmap_andnot` aliases into `bitmap_not`.
---
 be/src/core/value/bitmap_value.h                   |  61 ++++++++
 be/src/exprs/function/function.h                   |   1 +
 be/src/exprs/function/function_bitmap.cpp          | 101 +++----------
 be/src/exprs/function/function_bitmap_variadic.cpp | 166 +++++++++++++++++----
 be/src/exprs/function/simple_function_factory.h    |   5 +
 be/src/exprs/vectorized_fn_call.cpp                |   5 +-
 be/src/format_v2/expr/cast.cpp                     |   5 +-
 be/test/core/value/bitmap_value_test.cpp           |   5 +-
 be/test/exprs/function/function_bitmap_test.cpp    |  81 ++++++++--
 .../function/simple_function_factory_test.cpp      |  35 +++++
 .../doris/catalog/BuiltinScalarFunctions.java      |  10 +-
 .../nereids/load/NereidsStreamLoadPlanner.java     |   1 +
 .../rules/expression/ExpressionNormalization.java  |   4 +-
 .../rules/expression/ExpressionRuleType.java       |   3 +-
 .../rules/BitmapCountToBitmapOpCount.java          |  67 +++++++++
 .../expression/rules/FoldConstantRuleOnBE.java     |   1 +
 .../functions/scalar/BitmapAndCount.java           |   8 +-
 .../expressions/functions/scalar/BitmapAndNot.java |  73 ---------
 .../functions/scalar/BitmapAndNotAlias.java        |  73 ---------
 .../functions/scalar/BitmapAndNotCount.java        |   8 +-
 .../functions/scalar/BitmapAndNotCountAlias.java   |  78 ----------
 .../functions/scalar/BitmapOrCount.java            |   7 +-
 .../functions/scalar/BitmapXorCount.java           |   8 +-
 .../expressions/visitor/ScalarFunctionVisitor.java |  15 --
 .../main/java/org/apache/doris/qe/Coordinator.java |   3 +
 .../org/apache/doris/qe/CoordinatorContext.java    |   1 +
 .../org/apache/doris/qe/NereidsCoordinator.java    |   1 +
 .../java/org/apache/doris/qe/SessionVariable.java  |   1 +
 .../doris/cloud/catalog/CloudEnvFactoryTest.java   |  32 ++++
 .../rules/analysis/FunctionRegistryTest.java       |  21 +++
 .../rules/BitmapCountToBitmapOpCountTest.java      | 115 ++++++++++++++
 .../doris/qe/ShortCircuitQueryContextTest.java     |  33 ++++
 gensrc/thrift/PaloInternalService.thrift           |   1 +
 .../bitmap_functions/test_bitmap_function.out      |  18 +++
 .../bitmap_functions/test_bitmap_function.groovy   |  86 +++++++++++
 35 files changed, 736 insertions(+), 397 deletions(-)

diff --git a/be/src/core/value/bitmap_value.h b/be/src/core/value/bitmap_value.h
index f18a7eb8fd3..ae4249c5b19 100644
--- a/be/src/core/value/bitmap_value.h
+++ b/be/src/core/value/bitmap_value.h
@@ -2281,6 +2281,67 @@ public:
         return 0;
     }
 
+    uint64_t xor_cardinality(const BitmapValue& rhs) const {
+        switch (rhs._type) {
+        case EMPTY:
+            return cardinality();
+        case SINGLE:
+            switch (_type) {
+            case EMPTY:
+                return 1;
+            case SINGLE:
+                return 2 * (_sv != rhs._sv);
+            case BITMAP:
+                return cardinality() + 1 - 2 * _bitmap->contains(rhs._sv);
+            case SET:
+                return _set.size() + 1 - 2 * _set.contains(rhs._sv);
+            }
+            break;
+        case BITMAP:
+            switch (_type) {
+            case EMPTY:
+                return rhs.cardinality();
+            case SINGLE:
+                return rhs.cardinality() + 1 - 2 * rhs._bitmap->contains(_sv);
+            case BITMAP:
+                return _bitmap->xorCardinality(*rhs._bitmap);
+            case SET: {
+                uint64_t cardinality = rhs._bitmap->cardinality();
+                for (auto v : _set) {
+                    if (rhs._bitmap->contains(v)) {
+                        --cardinality;
+                    } else {
+                        ++cardinality;
+                    }
+                }
+                return cardinality;
+            }
+            }
+            break;
+        case SET:
+            switch (_type) {
+            case EMPTY:
+                return rhs.cardinality();
+            case SINGLE:
+                return rhs.cardinality() + 1 - 2 * rhs._set.contains(_sv);
+            case BITMAP: {
+                uint64_t cardinality = _bitmap->cardinality();
+                for (auto v : rhs._set) {
+                    if (_bitmap->contains(v)) {
+                        --cardinality;
+                    } else {
+                        ++cardinality;
+                    }
+                }
+                return cardinality;
+            }
+            case SET:
+                return _set.size() + rhs._set.size() - 2 * 
and_cardinality(rhs);
+            }
+        }
+        return 0;
+    }
+
     uint64_t andnot_cardinality(const BitmapValue& rhs) const {
         switch (rhs._type) {
         case EMPTY:
diff --git a/be/src/exprs/function/function.h b/be/src/exprs/function/function.h
index 13d4bfd6bb5..d26cab4d783 100644
--- a/be/src/exprs/function/function.h
+++ b/be/src/exprs/function/function.h
@@ -57,6 +57,7 @@ namespace doris {
 
 struct FunctionAttr {
     bool new_version_unix_timestamp {false};
+    bool new_version_bitmap_op_count {false};
 };
 
 #define RETURN_REAL_TYPE_FOR_DATEV2_FUNCTION(TYPE)                             
                \
diff --git a/be/src/exprs/function/function_bitmap.cpp 
b/be/src/exprs/function/function_bitmap.cpp
index 6213066e0e1..6ba5974cd41 100644
--- a/be/src/exprs/function/function_bitmap.cpp
+++ b/be/src/exprs/function/function_bitmap.cpp
@@ -582,52 +582,6 @@ struct BitmapNot {
     }
 };
 
-struct NameBitmapAndNot {
-    static constexpr auto name = "bitmap_and_not";
-};
-
-template <typename LeftDataType, typename RightDataType>
-struct BitmapAndNot {
-    using ResultDataType = DataTypeBitMap;
-    using T0 = typename LeftDataType::FieldType;
-    using T1 = typename RightDataType::FieldType;
-    using TData = std::vector<BitmapValue>;
-
-    static void vector_vector(const TData& lvec, const TData& rvec, TData& 
res) {
-        size_t size = lvec.size();
-        BitmapValue mid_data;
-        for (size_t i = 0; i < size; ++i) {
-            mid_data = lvec[i];
-            mid_data &= rvec[i];
-            res[i] = lvec[i];
-            res[i] -= mid_data;
-            mid_data.reset();
-        }
-    }
-    static void vector_scalar(const TData& lvec, const BitmapValue& rval, 
TData& res) {
-        size_t size = lvec.size();
-        BitmapValue mid_data;
-        for (size_t i = 0; i < size; ++i) {
-            mid_data = lvec[i];
-            mid_data &= rval;
-            res[i] = lvec[i];
-            res[i] -= mid_data;
-            mid_data.reset();
-        }
-    }
-    static void scalar_vector(const BitmapValue& lval, const TData& rvec, 
TData& res) {
-        size_t size = rvec.size();
-        BitmapValue mid_data;
-        for (size_t i = 0; i < size; ++i) {
-            mid_data = lval;
-            mid_data &= rvec[i];
-            res[i] = lval;
-            res[i] -= mid_data;
-            mid_data.reset();
-        }
-    }
-};
-
 struct NameBitmapAndNotCount {
     static constexpr auto name = "bitmap_and_not_count";
 };
@@ -642,32 +596,20 @@ struct BitmapAndNotCount {
 
     static void vector_vector(const TData& lvec, const TData& rvec, ResTData* 
res) {
         size_t size = lvec.size();
-        BitmapValue mid_data;
         for (size_t i = 0; i < size; ++i) {
-            mid_data = lvec[i];
-            mid_data &= rvec[i];
-            res[i] = lvec[i].andnot_cardinality(mid_data);
-            mid_data.reset();
+            res[i] = lvec[i].andnot_cardinality(rvec[i]);
         }
     }
     static void scalar_vector(const BitmapValue& lval, const TData& rvec, 
ResTData* res) {
         size_t size = rvec.size();
-        BitmapValue mid_data;
         for (size_t i = 0; i < size; ++i) {
-            mid_data = lval;
-            mid_data &= rvec[i];
-            res[i] = lval.andnot_cardinality(mid_data);
-            mid_data.reset();
+            res[i] = lval.andnot_cardinality(rvec[i]);
         }
     }
     static void vector_scalar(const TData& lvec, const BitmapValue& rval, 
ResTData* res) {
         size_t size = lvec.size();
-        BitmapValue mid_data;
         for (size_t i = 0; i < size; ++i) {
-            mid_data = lvec[i];
-            mid_data &= rval;
-            res[i] = lvec[i].andnot_cardinality(mid_data);
-            mid_data.reset();
+            res[i] = lvec[i].andnot_cardinality(rval);
         }
     }
 };
@@ -687,8 +629,10 @@ ColumnPtr handle_bitmap_op_count_null_value(ColumnPtr& 
src, const Block& block,
                                             const ColumnNumbers& args, 
uint32_t result,
                                             size_t input_rows_count) {
     MutableColumnPtr mutable_src = IColumn::mutate(std::move(src));
-    auto* nullable = assert_cast<ColumnNullable*>(mutable_src.get());
-    auto* src_not_nullable_mutable = &nullable->get_nested_column();
+    auto* src_not_nullable_mutable = mutable_src.get();
+    if (auto* nullable = check_and_get_column<ColumnNullable>(*mutable_src)) {
+        src_not_nullable_mutable = &nullable->get_nested_column();
+    }
     auto* __restrict count_data =
             
assert_cast<ColumnInt64*>(src_not_nullable_mutable)->get_data().data();
 
@@ -739,28 +683,32 @@ Status execute_bitmap_op_count_null_to_zero(
     return Status::OK();
 }
 
-template <typename FunctionName>
+template <typename FunctionName, bool NewVersion = false>
 class FunctionBitmapAndNotCount : public IFunction {
 public:
     using LeftDataType = DataTypeBitMap;
     using RightDataType = DataTypeBitMap;
     using ResultDataType = typename BitmapAndNotCount<LeftDataType, 
RightDataType>::ResultDataType;
 
-    static constexpr auto name = FunctionName::name;
+    static constexpr auto name = NewVersion ? "bitmap_and_not_count_v2" : 
FunctionName::name;
     static FunctionPtr create() { return 
std::make_shared<FunctionBitmapAndNotCount>(); }
     String get_name() const override { return name; }
     size_t get_number_of_arguments() const override { return 2; }
     DataTypePtr get_return_type_impl(const DataTypes& arguments) const 
override {
-        bool return_nullable = false;
-        // result is nullable only when any columns is nullable for 
bitmap_and_not_count
-        for (size_t i = 0; i < arguments.size(); ++i) {
-            if (arguments[i]->is_nullable()) {
-                return_nullable = true;
-                break;
+        if constexpr (NewVersion) {
+            return std::make_shared<ResultDataType>();
+        } else {
+            bool return_nullable = false;
+            // result is nullable only when any columns is nullable for 
bitmap_and_not_count
+            for (size_t i = 0; i < arguments.size(); ++i) {
+                if (arguments[i]->is_nullable()) {
+                    return_nullable = true;
+                    break;
+                }
             }
+            auto result_type = std::make_shared<ResultDataType>();
+            return return_nullable ? make_nullable(result_type) : result_type;
         }
-        auto result_type = std::make_shared<ResultDataType>();
-        return return_nullable ? make_nullable(result_type) : result_type;
     }
 
     bool use_default_implementation_for_nulls() const override {
@@ -1254,8 +1202,6 @@ using FunctionBitmapToBase64 = 
FunctionUnaryToType<BitmapToBase64, NameBitmapToB
 using FunctionBitmapFromBase64 = FunctionBitmapAlwaysNull<BitmapFromBase64>;
 using FunctionBitmapNot =
         FunctionBinaryToType<DataTypeBitMap, DataTypeBitMap, BitmapNot, 
NameBitmapNot>;
-using FunctionBitmapAndNot =
-        FunctionBinaryToType<DataTypeBitMap, DataTypeBitMap, BitmapAndNot, 
NameBitmapAndNot>;
 using FunctionBitmapContains =
         FunctionBinaryToType<DataTypeBitMap, DataTypeInt64, BitmapContains, 
NameBitmapContains>;
 using FunctionBitmapRemove =
@@ -1284,9 +1230,10 @@ void register_function_bitmap(SimpleFunctionFactory& 
factory) {
     factory.register_function<FunctionBitmapMax>();
     factory.register_function<FunctionBitmapToString>();
     factory.register_function<FunctionBitmapNot>();
-    factory.register_function<FunctionBitmapAndNot>();
-    factory.register_alias(NameBitmapAndNot::name, "bitmap_andnot");
+    factory.register_alias(NameBitmapNot::name, "bitmap_and_not");
+    factory.register_alias(NameBitmapNot::name, "bitmap_andnot");
     
factory.register_function<FunctionBitmapAndNotCount<NameBitmapAndNotCount>>();
+    factory.register_function<FunctionBitmapAndNotCount<NameBitmapAndNotCount, 
true>>();
     factory.register_alias(NameBitmapAndNotCount::name, "bitmap_andnot_count");
     factory.register_function<FunctionBitmapContains>();
     factory.register_function<FunctionBitmapRemove>();
diff --git a/be/src/exprs/function/function_bitmap_variadic.cpp 
b/be/src/exprs/function/function_bitmap_variadic.cpp
index 11cfcb9ef81..b9749c115d8 100644
--- a/be/src/exprs/function/function_bitmap_variadic.cpp
+++ b/be/src/exprs/function/function_bitmap_variadic.cpp
@@ -114,47 +114,117 @@ namespace doris {
         }                                                                      
                   \
     }
 
-#define BITMAP_FUNCTION_COUNT_VARIADIC(CLASS, FUNCTION_NAME, OP)               
                   \
+#define BITMAP_FUNCTION_COUNT_VARIADIC(CLASS, FUNCTION_NAME, OP, COUNT_OP)     
                   \
     struct CLASS {                                                             
                   \
+    public:                                                                    
                   \
         static constexpr auto name = #FUNCTION_NAME;                           
                   \
         using ResultDataType = DataTypeInt64;                                  
                   \
         using TData = std::vector<BitmapValue>;                                
                   \
         using ResTData = typename ColumnInt64::Container;                      
                   \
         static Status vector_vector(ColumnPtr argument_columns[], size_t 
col_size,                \
                                     size_t input_rows_count, ResTData& res, 
IColumn* res_nulls) { \
-            TData vals;                                                        
                   \
-            if (auto* nullable = 
check_and_get_column<ColumnNullable>(*argument_columns[0])) {    \
-                vals.resize(input_rows_count);                                 
                   \
-                BITMAP_OR_NULLABLE(nullable, input_rows_count, vals, =);       
                   \
-            } else {                                                           
                   \
-                vals = assert_cast<const 
ColumnBitmap*>(argument_columns[0].get())->get_data();   \
+            DCHECK_GE(col_size, 2);                                            
                   \
+            if (col_size == 2) {                                               
                   \
+                const auto lhs = 
make_bitmap_column_accessor(argument_columns[0]);                \
+                const auto rhs = 
make_bitmap_column_accessor(argument_columns[1]);                \
+                for (size_t row = 0; row < input_rows_count; ++row) {          
                   \
+                    const auto* lhs_value = lhs.is_null_at(row) ? nullptr : 
&lhs.get_value(row);  \
+                    const auto* rhs_value = rhs.is_null_at(row) ? nullptr : 
&rhs.get_value(row);  \
+                    if (!lhs_value || !rhs_value) {                            
                   \
+                        if constexpr (std::is_same_v<CLASS, BitmapOrCount>) {  
                   \
+                            const auto* value = lhs_value ? lhs_value : 
rhs_value;                \
+                            res[row] = value ? value->cardinality() : 0;       
                   \
+                        } else {                                               
                   \
+                            res[row] = 0;                                      
                   \
+                        }                                                      
                   \
+                    } else {                                                   
                   \
+                        res[row] = lhs_value->COUNT_OP(*rhs_value);            
                   \
+                    }                                                          
                   \
+                }                                                              
                   \
+                return Status::OK();                                           
                   \
             }                                                                  
                   \
-            for (size_t col = 1; col < col_size; ++col) {                      
                   \
-                if (auto* nullable =                                           
                   \
-                            
check_and_get_column<ColumnNullable>(*argument_columns[col])) {       \
-                    BITMAP_OR_NULLABLE(nullable, input_rows_count, vals, OP);  
                   \
-                } else {                                                       
                   \
-                    const auto& col_data =                                     
                   \
-                            assert_cast<const 
ColumnBitmap*>(argument_columns[col].get())         \
-                                    ->get_data();                              
                   \
-                    for (size_t row = 0; row < input_rows_count; ++row) {      
                   \
-                        vals[row] OP col_data[row];                            
                   \
+            TData vals(input_rows_count);                                      
                   \
+            const auto first_column = 
make_bitmap_column_accessor(argument_columns[0]);           \
+            for (size_t row = 0; row < input_rows_count; ++row) {              
                   \
+                if (!first_column.is_null_at(row)) {                           
                   \
+                    vals[row] = first_column.get_value(row);                   
                   \
+                }                                                              
                   \
+            }                                                                  
                   \
+            for (size_t col = 1; col + 1 < col_size; ++col) {                  
                   \
+                const auto column = 
make_bitmap_column_accessor(argument_columns[col]);           \
+                for (size_t row = 0; row < input_rows_count; ++row) {          
                   \
+                    if (!column.is_null_at(row)) {                             
                   \
+                        vals[row] OP column.get_value(row);                    
                   \
                     }                                                          
                   \
                 }                                                              
                   \
             }                                                                  
                   \
+            const auto last_column = 
make_bitmap_column_accessor(argument_columns[col_size - 1]); \
             for (size_t row = 0; row < input_rows_count; ++row) {              
                   \
-                res[row] = vals[row].cardinality();                            
                   \
+                const auto* lhs_value = &vals[row];                            
                   \
+                const auto* rhs_value =                                        
                   \
+                        last_column.is_null_at(row) ? nullptr : 
&last_column.get_value(row);      \
+                if (!rhs_value) {                                              
                   \
+                    if constexpr (std::is_same_v<CLASS, BitmapOrCount>) {      
                   \
+                        res[row] = lhs_value->cardinality();                   
                   \
+                    } else {                                                   
                   \
+                        res[row] = 0;                                          
                   \
+                    }                                                          
                   \
+                } else {                                                       
                   \
+                    res[row] = lhs_value->COUNT_OP(*rhs_value);                
                   \
+                }                                                              
                   \
             }                                                                  
                   \
             return Status::OK();                                               
                   \
+        }                                                                      
                   \
+                                                                               
                   \
+    private:                                                                   
                   \
+        struct BitmapColumnAccessor {                                          
                   \
+            const std::vector<BitmapValue>* values = nullptr;                  
                   \
+            const BitmapValue* const_value = nullptr;                          
                   \
+            const ColumnUInt8::value_type* null_map_data = nullptr;            
                   \
+            bool is_const = false;                                             
                   \
+            bool is_const_null = false;                                        
                   \
+                                                                               
                   \
+            bool is_null_at(size_t row) const {                                
                   \
+                return is_const ? is_const_null : (null_map_data && 
null_map_data[row]);          \
+            }                                                                  
                   \
+                                                                               
                   \
+            const BitmapValue& get_value(size_t row) const {                   
                   \
+                return is_const ? *const_value : (*values)[row];               
                   \
+            }                                                                  
                   \
+        };                                                                     
                   \
+                                                                               
                   \
+        static BitmapColumnAccessor make_bitmap_column_accessor(const 
ColumnPtr& column) {        \
+            BitmapColumnAccessor accessor;                                     
                   \
+            const auto& [data_column_ptr, is_const] = unpack_if_const(column); 
                   \
+            accessor.is_const = is_const;                                      
                   \
+            const IColumn* data_column = data_column_ptr.get();                
                   \
+                                                                               
                   \
+            if (const auto* nullable = 
check_and_get_column<ColumnNullable>(*data_column)) {      \
+                if (accessor.is_const) {                                       
                   \
+                    accessor.is_const_null = nullable->is_null_at(0);          
                   \
+                } else {                                                       
                   \
+                    accessor.null_map_data = 
nullable->get_null_map_data().data();                \
+                }                                                              
                   \
+                data_column = nullable->get_nested_column_ptr().get();         
                   \
+            }                                                                  
                   \
+                                                                               
                   \
+            const auto* bitmap_column = assert_cast<const 
ColumnBitmap*>(data_column);            \
+            if (accessor.is_const) {                                           
                   \
+                accessor.const_value = &bitmap_column->get_data()[0];          
                   \
+            } else {                                                           
                   \
+                accessor.values = &bitmap_column->get_data();                  
                   \
+            }                                                                  
                   \
+                                                                               
                   \
+            return accessor;                                                   
                   \
         }                                                                      
                   \
     }
 
 BITMAP_FUNCTION_VARIADIC(BitmapOr, bitmap_or, |=);
 BITMAP_FUNCTION_VARIADIC(BitmapAnd, bitmap_and, &=);
 BITMAP_FUNCTION_VARIADIC(BitmapXor, bitmap_xor, ^=);
-BITMAP_FUNCTION_COUNT_VARIADIC(BitmapOrCount, bitmap_or_count, |=);
-BITMAP_FUNCTION_COUNT_VARIADIC(BitmapAndCount, bitmap_and_count, &=);
-BITMAP_FUNCTION_COUNT_VARIADIC(BitmapXorCount, bitmap_xor_count, ^=);
+BITMAP_FUNCTION_COUNT_VARIADIC(BitmapOrCount, bitmap_or_count, |=, 
or_cardinality);
+BITMAP_FUNCTION_COUNT_VARIADIC(BitmapAndCount, bitmap_and_count, &=, 
and_cardinality);
+BITMAP_FUNCTION_COUNT_VARIADIC(BitmapXorCount, bitmap_xor_count, ^=, 
xor_cardinality);
 
 Status execute_bitmap_op_count_null_to_zero(
         FunctionContext* context, Block& block, const ColumnNumbers& 
arguments, uint32_t result,
@@ -162,12 +232,30 @@ Status execute_bitmap_op_count_null_to_zero(
         const std::function<Status(FunctionContext*, Block&, const 
ColumnNumbers&, size_t, size_t)>&
                 exec_impl_func);
 
-template <typename Impl>
+template <typename Impl, bool NewVersion = false>
 class FunctionBitMapVariadic : public IFunction {
+    static_assert(!NewVersion || (NewVersion && (std::is_same_v<Impl, 
BitmapOrCount> ||
+                                                 std::is_same_v<Impl, 
BitmapAndCount> ||
+                                                 std::is_same_v<Impl, 
BitmapXorCount>)));
+
 public:
-    static constexpr auto name = Impl::name;
+    static constexpr auto name = []() constexpr {
+        if constexpr (!NewVersion) {
+            return Impl::name;
+        } else if constexpr (std::is_same_v<Impl, BitmapOrCount>) {
+            return "bitmap_or_count_v2";
+        } else if constexpr (std::is_same_v<Impl, BitmapAndCount>) {
+            return "bitmap_and_count_v2";
+        } else if constexpr (std::is_same_v<Impl, BitmapXorCount>) {
+            return "bitmap_xor_count_v2";
+        } else {
+            return Impl::name;
+        }
+    }();
 
-    static FunctionPtr create() { return 
std::make_shared<FunctionBitMapVariadic>(); }
+    static FunctionPtr create() {
+        return std::make_shared<FunctionBitMapVariadic<Impl, NewVersion>>();
+    }
 
     String get_name() const override { return name; }
 
@@ -177,6 +265,9 @@ public:
 
     DataTypePtr get_return_type_impl(const DataTypes& arguments) const 
override {
         using ResultDataType = typename Impl::ResultDataType;
+        if constexpr (NewVersion) {
+            return std::make_shared<ResultDataType>();
+        }
         if (std::is_same_v<Impl, BitmapOr> || is_count()) {
             bool return_nullable = false;
             // result is nullable only when any columns is nullable for 
bitmap_or and bitmap_or_count
@@ -202,7 +293,8 @@ public:
 
     Status execute_impl(FunctionContext* context, Block& block, const 
ColumnNumbers& arguments,
                         uint32_t result, size_t input_rows_count) const 
override {
-        if (std::is_same_v<Impl, BitmapAndCount> || std::is_same_v<Impl, 
BitmapXorCount>) {
+        if constexpr (std::is_same_v<Impl, BitmapAndCount> ||
+                      std::is_same_v<Impl, BitmapXorCount>) {
             auto impl_func = [&](FunctionContext* context, Block& block,
                                  const ColumnNumbers& arguments, uint32_t 
result,
                                  size_t input_rows_count) {
@@ -219,12 +311,6 @@ public:
                                  const ColumnNumbers& arguments, uint32_t 
result,
                                  size_t input_rows_count) const {
         size_t argument_size = arguments.size();
-        std::vector<ColumnPtr> argument_columns(argument_size);
-
-        for (size_t i = 0; i < argument_size; ++i) {
-            argument_columns[i] =
-                    
block.get_by_position(arguments[i]).column->convert_to_full_column_if_const();
-        }
 
         using ResultDataType = typename Impl::ResultDataType; //DataTypeBitMap 
or DataTypeInt64
         using ColVecResult = 
std::conditional_t<is_complex_v<ResultDataType::PType>,
@@ -244,8 +330,18 @@ public:
         auto& vec_res = col_res->get_data();
         vec_res.resize(input_rows_count);
 
+        std::vector<ColumnPtr> argument_columns(argument_size);
+        for (size_t i = 0; i < argument_size; ++i) {
+            argument_columns[i] = block.get_by_position(arguments[i]).column;
+            if constexpr (!std::is_same_v<Impl, BitmapOrCount> &&
+                          !std::is_same_v<Impl, BitmapAndCount> &&
+                          !std::is_same_v<Impl, BitmapXorCount>) {
+                argument_columns[i] = 
argument_columns[i]->convert_to_full_column_if_const();
+            }
+        }
         RETURN_IF_ERROR(Impl::vector_vector(argument_columns.data(), 
argument_size,
                                             input_rows_count, vec_res, 
col_res_nulls.get()));
+
         if (!use_default_implementation_for_nulls() && 
result_info.type->is_nullable()) {
             block.replace_by_position(
                     result, ColumnNullable::create(std::move(col_res), 
std::move(col_res_nulls)));
@@ -268,6 +364,9 @@ using FunctionBitmapAnd = FunctionBitMapVariadic<BitmapAnd>;
 using FunctionBitmapOrCount = FunctionBitMapVariadic<BitmapOrCount>;
 using FunctionBitmapAndCount = FunctionBitMapVariadic<BitmapAndCount>;
 using FunctionBitmapXorCount = FunctionBitMapVariadic<BitmapXorCount>;
+using FunctionBitmapOrCountV2 = FunctionBitMapVariadic<BitmapOrCount, true>;
+using FunctionBitmapAndCountV2 = FunctionBitMapVariadic<BitmapAndCount, true>;
+using FunctionBitmapXorCountV2 = FunctionBitMapVariadic<BitmapXorCount, true>;
 
 void register_function_bitmap_variadic(SimpleFunctionFactory& factory) {
     factory.register_function<FunctionBitmapOr>();
@@ -276,5 +375,8 @@ void 
register_function_bitmap_variadic(SimpleFunctionFactory& factory) {
     factory.register_function<FunctionBitmapOrCount>();
     factory.register_function<FunctionBitmapAndCount>();
     factory.register_function<FunctionBitmapXorCount>();
+    factory.register_function<FunctionBitmapOrCountV2>();
+    factory.register_function<FunctionBitmapAndCountV2>();
+    factory.register_function<FunctionBitmapXorCountV2>();
 }
-} // namespace doris
\ No newline at end of file
+} // namespace doris
diff --git a/be/src/exprs/function/simple_function_factory.h 
b/be/src/exprs/function/simple_function_factory.h
index c0c3fc1ad60..1b7ac1d8c70 100644
--- a/be/src/exprs/function/simple_function_factory.h
+++ b/be/src/exprs/function/simple_function_factory.h
@@ -204,6 +204,11 @@ public:
             attr.new_version_unix_timestamp) {
             key_str += "_new";
         }
+        if (attr.new_version_bitmap_op_count &&
+            (key_str == "bitmap_and_count" || key_str == "bitmap_or_count" ||
+             key_str == "bitmap_xor_count" || key_str == 
"bitmap_and_not_count")) {
+            key_str += "_v2";
+        }
 
         temporary_function_update(be_version, key_str);
 
diff --git a/be/src/exprs/vectorized_fn_call.cpp 
b/be/src/exprs/vectorized_fn_call.cpp
index 56ba95cd755..0b78c49bb7e 100644
--- a/be/src/exprs/vectorized_fn_call.cpp
+++ b/be/src/exprs/vectorized_fn_call.cpp
@@ -216,7 +216,10 @@ Status VectorizedFnCall::prepare(RuntimeState* state, 
const RowDescriptor& desc,
         // get the function. won't prepare function.
         _function = SimpleFunctionFactory::instance().get_function(
                 _fn.name.function_name, argument_template, _data_type,
-                {.new_version_unix_timestamp = 
state->query_options().new_version_unix_timestamp},
+                {.new_version_unix_timestamp = 
state->query_options().new_version_unix_timestamp,
+                 .new_version_bitmap_op_count =
+                         
state->query_options().__isset.new_version_bitmap_op_count &&
+                         state->query_options().new_version_bitmap_op_count},
                 state->be_exec_version());
     }
     if (_function == nullptr) {
diff --git a/be/src/format_v2/expr/cast.cpp b/be/src/format_v2/expr/cast.cpp
index efeb9d851de..c1435732a9e 100644
--- a/be/src/format_v2/expr/cast.cpp
+++ b/be/src/format_v2/expr/cast.cpp
@@ -56,7 +56,10 @@ Status Cast::prepare(RuntimeState* state, const 
RowDescriptor& desc, VExprContex
     // get the function. won't prepare function.
     _function = SimpleFunctionFactory::instance().get_function(
             "CAST", argument_template, _data_type,
-            {.new_version_unix_timestamp = 
state->query_options().new_version_unix_timestamp},
+            {.new_version_unix_timestamp = 
state->query_options().new_version_unix_timestamp,
+             .new_version_bitmap_op_count =
+                     
state->query_options().__isset.new_version_bitmap_op_count &&
+                     state->query_options().new_version_bitmap_op_count},
             state->be_exec_version());
     if (_function == nullptr) {
         return Status::InternalError("Could not find function {} ", 
_expr_name);
diff --git a/be/test/core/value/bitmap_value_test.cpp 
b/be/test/core/value/bitmap_value_test.cpp
index b281d71a443..97cbdef56cb 100644
--- a/be/test/core/value/bitmap_value_test.cpp
+++ b/be/test/core/value/bitmap_value_test.cpp
@@ -448,6 +448,7 @@ void check_bitmap_value_operator(const BitmapValue& left, 
const BitmapValue& rig
     auto right_cardinality = right.cardinality();
     auto and_cardinality = left.and_cardinality(right);
     auto and_not_cardinality = left.andnot_cardinality(right);
+    auto xor_cardinality = left.xor_cardinality(right);
 
     std::cout << "left_cardinality: " << left_cardinality
               << ", right_cardinality: " << right_cardinality
@@ -475,7 +476,8 @@ void check_bitmap_value_operator(const BitmapValue& left, 
const BitmapValue& rig
 
     copy = left;
     copy ^= right;
-    EXPECT_EQ(copy.cardinality(), left_cardinality + right_cardinality - 
and_cardinality * 2);
+    EXPECT_EQ(xor_cardinality, left_cardinality + right_cardinality - 
and_cardinality * 2);
+    EXPECT_EQ(copy.cardinality(), xor_cardinality);
 }
 
 // '='
@@ -559,6 +561,7 @@ TEST(BitmapValueTest, operators) {
     check_bitmap_value_operator(left_empty, right_bitmap);
 
     check_bitmap_value_operator(left_single, right_emtpy);
+    check_bitmap_value_operator(left_single, left_single);
     check_bitmap_value_operator(left_single, right_single);
     check_bitmap_value_operator(left_single, right_set);
     check_bitmap_value_operator(left_single, right_bitmap);
diff --git a/be/test/exprs/function/function_bitmap_test.cpp 
b/be/test/exprs/function/function_bitmap_test.cpp
index 95813289427..aba66d453ba 100644
--- a/be/test/exprs/function/function_bitmap_test.cpp
+++ b/be/test/exprs/function/function_bitmap_test.cpp
@@ -346,9 +346,9 @@ TEST(function_bitmap_test, function_bitmap_and_count) {
     BitmapValue bitmap1({1, 2, 3});
     BitmapValue bitmap2({3, 4, 5});
     BitmapValue empty_bitmap;
-    DataSet data_set = {{{&bitmap1, &empty_bitmap}, (int64_t)0},
-                        {{&bitmap1, &bitmap1}, (int64_t)3},
-                        {{&bitmap1, &bitmap2}, (int64_t)1}};
+    DataSet data_set = {{{&bitmap1, &empty_bitmap}, (int64_t)0}, {{&bitmap1, 
&bitmap1}, (int64_t)3},
+                        {{&bitmap1, &bitmap2}, (int64_t)1},      {{Null(), 
&bitmap1}, (int64_t)0},
+                        {{&bitmap1, Null()}, (int64_t)0},        {{Null(), 
Null()}, (int64_t)0}};
 
     static_cast<void>(check_function<DataTypeInt64, true>(func_name, 
input_types, data_set));
 
@@ -377,12 +377,26 @@ TEST(function_bitmap_test, function_bitmap_or_count) {
     BitmapValue bitmap2({1, 2, 3, 4});
     BitmapValue bitmap3({2, 3});
     BitmapValue empty_bitmap;
-    DataSet data_set = {{{&bitmap1, &empty_bitmap}, (int64_t)3},
-                        {{&bitmap2, &bitmap3}, (int64_t)4},
-                        {{&bitmap1, &bitmap3}, (int64_t)3}};
+    DataSet data_set = {{{&bitmap1, &empty_bitmap}, (int64_t)3}, {{&bitmap2, 
&bitmap3}, (int64_t)4},
+                        {{&bitmap1, &bitmap3}, (int64_t)3},      {{Null(), 
&bitmap1}, (int64_t)3},
+                        {{&bitmap1, Null()}, (int64_t)3},        {{Null(), 
Null()}, (int64_t)0}};
 
     static_cast<void>(check_function<DataTypeInt64, true>(func_name, 
input_types, data_set));
 
+    {
+        const auto old_config = config::enable_set_in_bitmap_value;
+        config::enable_set_in_bitmap_value = true;
+        BitmapValue short_bitmap1({1, 2});
+        BitmapValue short_bitmap2({2, 3, 4, 5});
+        EXPECT_EQ(short_bitmap1.get_type_code(), BitmapTypeCode::SET);
+        EXPECT_EQ(short_bitmap2.get_type_code(), BitmapTypeCode::SET);
+
+        DataSet set_data_set = {{{&short_bitmap1, &short_bitmap2}, 
(int64_t)5}};
+        static_cast<void>(
+                check_function<DataTypeInt64, true>(func_name, input_types, 
set_data_set));
+        config::enable_set_in_bitmap_value = old_config;
+    }
+
     {
         InputTypeSet input_types = {PrimitiveType::TYPE_BITMAP, 
PrimitiveType::TYPE_BITMAP,
                                     PrimitiveType::TYPE_BITMAP};
@@ -411,9 +425,9 @@ TEST(function_bitmap_test, function_bitmap_xor_count) {
     BitmapValue bitmap3({2, 3});
     BitmapValue bitmap4({1, 2, 6});
     BitmapValue empty_bitmap;
-    DataSet data_set = {{{&bitmap1, &empty_bitmap}, (int64_t)3},
-                        {{&bitmap2, &bitmap3}, (int64_t)2},
-                        {{&bitmap1, &bitmap4}, (int64_t)2}};
+    DataSet data_set = {{{&bitmap1, &empty_bitmap}, (int64_t)3}, {{&bitmap2, 
&bitmap3}, (int64_t)2},
+                        {{&bitmap1, &bitmap4}, (int64_t)2},      {{Null(), 
&bitmap1}, (int64_t)0},
+                        {{&bitmap1, Null()}, (int64_t)0},        {{Null(), 
Null()}, (int64_t)0}};
 
     static_cast<void>(check_function<DataTypeInt64, true>(func_name, 
input_types, data_set));
 
@@ -443,13 +457,54 @@ TEST(function_bitmap_test, function_bitmap_and_not_count) 
{
     BitmapValue bitmap3({33, 5, std::numeric_limits<uint64_t>::max()});
     BitmapValue empty_bitmap;
 
-    DataSet data_set = {{{&bitmap1, &empty_bitmap}, (int64_t)3}, //1,2,3
-                        {{&bitmap2, Null()}, (int64_t)0},
-                        {{&bitmap2, &bitmap3}, (int64_t)3},  //0,3,4
-                        {{&bitmap1, &bitmap2}, (int64_t)2}}; //1,2
+    DataSet data_set = {
+            {{&bitmap1, &empty_bitmap}, (int64_t)3}, //1,2,3
+            {{Null(), &bitmap1}, (int64_t)0},        {{&bitmap2, Null()}, 
(int64_t)0},
+            {{Null(), Null()}, (int64_t)0},          {{&bitmap2, &bitmap3}, 
(int64_t)3}, //0,3,4
+            {{&bitmap1, &bitmap2}, (int64_t)2}};                               
          //1,2
 
     static_cast<void>(check_function<DataTypeInt64, true>(func_name, 
input_types, data_set));
 }
+
+TEST(function_bitmap_test, function_bitmap_op_count_v2_nullable_args) {
+    InputTypeSet input_types = {PrimitiveType::TYPE_BITMAP, 
PrimitiveType::TYPE_BITMAP};
+    BitmapValue bitmap1({1, 2, 3});
+    BitmapValue bitmap2({3, 4, 5});
+
+    {
+        DataSet data_set = {{{&bitmap1, &bitmap2}, (int64_t)1},
+                            {{Null(), &bitmap1}, (int64_t)0},
+                            {{&bitmap1, Null()}, (int64_t)0},
+                            {{Null(), Null()}, (int64_t)0}};
+        static_cast<void>(
+                check_function<DataTypeInt64, false>("bitmap_and_count_v2", 
input_types, data_set));
+    }
+    {
+        DataSet data_set = {{{&bitmap1, &bitmap2}, (int64_t)5},
+                            {{Null(), &bitmap1}, (int64_t)3},
+                            {{&bitmap1, Null()}, (int64_t)3},
+                            {{Null(), Null()}, (int64_t)0}};
+        static_cast<void>(
+                check_function<DataTypeInt64, false>("bitmap_or_count_v2", 
input_types, data_set));
+    }
+    {
+        DataSet data_set = {{{&bitmap1, &bitmap2}, (int64_t)4},
+                            {{Null(), &bitmap1}, (int64_t)0},
+                            {{&bitmap1, Null()}, (int64_t)0},
+                            {{Null(), Null()}, (int64_t)0}};
+        static_cast<void>(
+                check_function<DataTypeInt64, false>("bitmap_xor_count_v2", 
input_types, data_set));
+    }
+    {
+        DataSet data_set = {{{&bitmap1, &bitmap2}, (int64_t)2},
+                            {{Null(), &bitmap1}, (int64_t)0},
+                            {{&bitmap1, Null()}, (int64_t)0},
+                            {{Null(), Null()}, (int64_t)0}};
+        static_cast<void>(check_function<DataTypeInt64, 
false>("bitmap_and_not_count_v2",
+                                                               input_types, 
data_set));
+    }
+}
+
 TEST(function_bitmap_test, function_bitmap_and_not_count_alias) {
     std::string func_name = "bitmap_andnot_count";
     InputTypeSet input_types = {PrimitiveType::TYPE_BITMAP, 
PrimitiveType::TYPE_BITMAP};
diff --git a/be/test/exprs/function/simple_function_factory_test.cpp 
b/be/test/exprs/function/simple_function_factory_test.cpp
index 86f344a3f03..dc8dcdf8583 100644
--- a/be/test/exprs/function/simple_function_factory_test.cpp
+++ b/be/test/exprs/function/simple_function_factory_test.cpp
@@ -20,7 +20,12 @@
 #include <gtest/gtest.h>
 
 #include <memory>
+#include <string>
+#include <utility>
+#include <vector>
 
+#include "core/data_type/data_type_bitmap.h"
+#include "core/data_type/data_type_nullable.h"
 #include "core/data_type/data_type_number.h"
 
 namespace doris {
@@ -95,4 +100,34 @@ TEST_F(SimpleFunctionFactoryTest, test_return_all) {
     }
 }
 
+TEST_F(SimpleFunctionFactoryTest, test_bitmap_count_new_version_return_type) {
+    ColumnsWithTypeAndName arguments = {
+            {nullptr, make_nullable(std::make_shared<DataTypeBitMap>()), ""},
+            {nullptr, make_nullable(std::make_shared<DataTypeBitMap>()), ""}};
+    auto& factory = SimpleFunctionFactory::instance();
+
+    for (const auto& [function_name, new_function_name] :
+         std::vector<std::pair<std::string, std::string>> {
+                 {"bitmap_and_count", "bitmap_and_count_v2"},
+                 {"bitmap_or_count", "bitmap_or_count_v2"},
+                 {"bitmap_xor_count", "bitmap_xor_count_v2"},
+                 {"bitmap_and_not_count", "bitmap_and_not_count_v2"}}) {
+        auto old_builder = std::dynamic_pointer_cast<FunctionBuilderImpl>(
+                factory.function_creators.find(function_name)->second());
+        ASSERT_NE(old_builder, nullptr);
+        EXPECT_TRUE(old_builder->get_return_type(arguments)->is_nullable());
+
+        auto new_builder = std::dynamic_pointer_cast<FunctionBuilderImpl>(
+                factory.function_creators.find(new_function_name)->second());
+        ASSERT_NE(new_builder, nullptr);
+        EXPECT_FALSE(new_builder->get_return_type(arguments)->is_nullable());
+
+        auto new_func = SimpleFunctionFactory::instance().get_function(
+                function_name, arguments, std::make_shared<DataTypeInt64>(),
+                {.new_version_bitmap_op_count = true}, 
BeExecVersionManager::get_newest_version());
+        EXPECT_EQ(new_func->get_name(), new_function_name);
+        EXPECT_FALSE(new_func->get_return_type()->is_nullable());
+    }
+}
+
 } // namespace doris
\ No newline at end of file
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java
index 3b1171a376c..a1326326778 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java
@@ -103,10 +103,7 @@ import 
org.apache.doris.nereids.trees.expressions.functions.scalar.BitShiftRight
 import org.apache.doris.nereids.trees.expressions.functions.scalar.BitTest;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapAnd;
 import 
org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapAndCount;
-import 
org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapAndNot;
-import 
org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapAndNotAlias;
 import 
org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapAndNotCount;
-import 
org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapAndNotCountAlias;
 import 
org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapContains;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapCount;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapEmpty;
@@ -678,10 +675,7 @@ public class BuiltinScalarFunctions implements 
FunctionHelper {
             scalar(BitLength.class, "bit_length"),
             scalar(BitmapAnd.class, "bitmap_and"),
             scalar(BitmapAndCount.class, "bitmap_and_count"),
-            scalar(BitmapAndNot.class, "bitmap_and_not"),
-            scalar(BitmapAndNotAlias.class, "bitmap_andnot"),
-            scalar(BitmapAndNotCount.class, "bitmap_and_not_count"),
-            scalar(BitmapAndNotCountAlias.class, "bitmap_andnot_count"),
+            scalar(BitmapAndNotCount.class, "bitmap_and_not_count", 
"bitmap_andnot_count"),
             scalar(BitmapContains.class, "bitmap_contains"),
             scalar(BitmapCount.class, "bitmap_count"),
             scalar(BitmapEmpty.class, "bitmap_empty"),
@@ -694,7 +688,7 @@ public class BuiltinScalarFunctions implements 
FunctionHelper {
             scalar(BitmapHash64.class, "bitmap_hash64"),
             scalar(BitmapMax.class, "bitmap_max"),
             scalar(BitmapMin.class, "bitmap_min"),
-            scalar(BitmapNot.class, "bitmap_not"),
+            scalar(BitmapNot.class, "bitmap_not", "bitmap_and_not", 
"bitmap_andnot"),
             scalar(BitmapOr.class, "bitmap_or"),
             scalar(BitmapOrCount.class, "bitmap_or_count"),
             scalar(BitmapRemove.class, "bitmap_remove"),
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/load/NereidsStreamLoadPlanner.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/load/NereidsStreamLoadPlanner.java
index 6bc4a4974e9..ce581ad2010 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/load/NereidsStreamLoadPlanner.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/load/NereidsStreamLoadPlanner.java
@@ -323,6 +323,7 @@ public class NereidsStreamLoadPlanner {
         queryOptions.setEnableMemtableOnSinkNode(enableMemtableOnSinkNode);
         queryOptions.setNewVersionUnixTimestamp(true);
         queryOptions.setNewVersionPercentile(true);
+        queryOptions.setNewVersionBitmapOpCount(true);
         params.setQueryOptions(queryOptions);
         TQueryGlobals queryGlobals = new TQueryGlobals();
         
queryGlobals.setNowString(TimeUtils.getDatetimeFormatWithTimeZone().format(LocalDateTime.now()));
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionNormalization.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionNormalization.java
index c6b129e8c50..6155734100e 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionNormalization.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionNormalization.java
@@ -18,6 +18,7 @@
 package org.apache.doris.nereids.rules.expression;
 
 import org.apache.doris.nereids.rules.expression.check.CheckCast;
+import 
org.apache.doris.nereids.rules.expression.rules.BitmapCountToBitmapOpCount;
 import org.apache.doris.nereids.rules.expression.rules.ConcatWsMultiArrayToOne;
 import org.apache.doris.nereids.rules.expression.rules.ConvertAggStateCast;
 import org.apache.doris.nereids.rules.expression.rules.DigitalMaskingConvert;
@@ -76,7 +77,8 @@ public class ExpressionNormalization extends 
ExpressionRewrite {
                 MergeDateTrunc.INSTANCE,
                 NormalizeElementAt.INSTANCE,
                 CheckCast.INSTANCE,
-                SimplifyEqualBooleanLiteral.INSTANCE
+                SimplifyEqualBooleanLiteral.INSTANCE,
+                BitmapCountToBitmapOpCount.INSTANCE
             )
     );
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRuleType.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRuleType.java
index b2e44c81c16..a3409004ca7 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRuleType.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRuleType.java
@@ -69,7 +69,8 @@ public enum ExpressionRuleType {
     TIMESTAMP_TO_ADD_TIME,
     TOPN_TO_MAX,
     REWRITE_DEFAULT_EXPRESSION,
-    ADD_SESSION_VAR_GUARD;
+    ADD_SESSION_VAR_GUARD,
+    BITMAP_COUNT_TO_BITMAP_OP_COUNT;
     public int type() {
         return ordinal();
     }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/BitmapCountToBitmapOpCount.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/BitmapCountToBitmapOpCount.java
new file mode 100644
index 00000000000..8292d5cf62d
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/BitmapCountToBitmapOpCount.java
@@ -0,0 +1,67 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules.expression.rules;
+
+import org.apache.doris.nereids.rules.expression.ExpressionPatternMatcher;
+import org.apache.doris.nereids.rules.expression.ExpressionPatternRuleFactory;
+import org.apache.doris.nereids.rules.expression.ExpressionRuleType;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapAnd;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapAndCount;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapAndNotCount;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapCount;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapNot;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapOr;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapOrCount;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapXor;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapXorCount;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
+/** Rewrite bitmap_count(bitmap_op(...)) to corresponding bitmap_op_count 
function. */
+public class BitmapCountToBitmapOpCount implements 
ExpressionPatternRuleFactory {
+    public static final BitmapCountToBitmapOpCount INSTANCE = new 
BitmapCountToBitmapOpCount();
+
+    @Override
+    public List<ExpressionPatternMatcher<? extends Expression>> buildRules() {
+        return ImmutableList.of(
+                
matchesType(BitmapCount.class).then(BitmapCountToBitmapOpCount::rewrite)
+                        
.toRule(ExpressionRuleType.BITMAP_COUNT_TO_BITMAP_OP_COUNT)
+        );
+    }
+
+    private static Expression rewrite(BitmapCount bitmapCount) {
+        Expression child = bitmapCount.child(0);
+        if (child instanceof BitmapAnd) {
+            return new BitmapAndCount(child.child(0), child.child(1), 
varArgs(child));
+        } else if (child instanceof BitmapOr) {
+            return new BitmapOrCount(child.child(0), child.child(1), 
varArgs(child));
+        } else if (child instanceof BitmapXor) {
+            return new BitmapXorCount(child.child(0), child.child(1), 
varArgs(child));
+        } else if (child instanceof BitmapNot) {
+            return new BitmapAndNotCount(child.child(0), child.child(1));
+        }
+        return bitmapCount;
+    }
+
+    private static Expression[] varArgs(Expression expression) {
+        return expression.children().subList(2, 
expression.arity()).toArray(new Expression[0]);
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnBE.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnBE.java
index 50eee509628..3f6812405e8 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnBE.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnBE.java
@@ -322,6 +322,7 @@ public class FoldConstantRuleOnBE implements 
ExpressionPatternRuleFactory {
             
tQueryOptions.setEnableDecimal256(context.getSessionVariable().isEnableDecimal256());
             tQueryOptions.setNewVersionUnixTimestamp(true);
             tQueryOptions.setNewVersionPercentile(true);
+            tQueryOptions.setNewVersionBitmapOpCount(true);
             
tQueryOptions.setEnableStrictCast(SessionVariable.enableStrictCast());
 
             TFoldConstantParams tParams = new TFoldConstantParams(paramMap, 
queryGlobals);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/BitmapAndCount.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/BitmapAndCount.java
index 6266b02735f..70a62d3a41a 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/BitmapAndCount.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/BitmapAndCount.java
@@ -19,6 +19,7 @@ package 
org.apache.doris.nereids.trees.expressions.functions.scalar;
 
 import org.apache.doris.catalog.FunctionSignature;
 import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.functions.AlwaysNotNullable;
 import 
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
 import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.BigIntType;
@@ -34,7 +35,7 @@ import java.util.List;
  * ScalarFunction 'bitmap_and_count'. This class is generated by 
GenerateFunction.
  */
 public class BitmapAndCount extends ScalarFunction
-        implements ExplicitlyCastableSignature {
+        implements ExplicitlyCastableSignature, AlwaysNotNullable {
 
     public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
             
FunctionSignature.ret(BigIntType.INSTANCE).varArgs(BitmapType.INSTANCE, 
BitmapType.INSTANCE)
@@ -70,9 +71,4 @@ public class BitmapAndCount extends ScalarFunction
     public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
         return visitor.visitBitmapAndCount(this, context);
     }
-
-    @Override
-    public boolean nullable() {
-        return children().stream().anyMatch(Expression::nullable);
-    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/BitmapAndNot.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/BitmapAndNot.java
deleted file mode 100644
index 835b141027d..00000000000
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/BitmapAndNot.java
+++ /dev/null
@@ -1,73 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-package org.apache.doris.nereids.trees.expressions.functions.scalar;
-
-import org.apache.doris.catalog.FunctionSignature;
-import org.apache.doris.nereids.trees.expressions.Expression;
-import 
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
-import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
-import org.apache.doris.nereids.trees.expressions.shape.BinaryExpression;
-import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
-import org.apache.doris.nereids.types.BitmapType;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-
-import java.util.List;
-
-/**
- * ScalarFunction 'bitmap_and_not'. This class is generated by 
GenerateFunction.
- */
-public class BitmapAndNot extends ScalarFunction
-        implements BinaryExpression, ExplicitlyCastableSignature, 
PropagateNullable {
-
-    public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
-            
FunctionSignature.ret(BitmapType.INSTANCE).args(BitmapType.INSTANCE, 
BitmapType.INSTANCE)
-    );
-
-    /**
-     * constructor with 2 arguments.
-     */
-    public BitmapAndNot(Expression arg0, Expression arg1) {
-        super("bitmap_and_not", arg0, arg1);
-    }
-
-    /** constructor for withChildren and reuse signature */
-    private BitmapAndNot(ScalarFunctionParams functionParams) {
-        super(functionParams);
-    }
-
-    /**
-     * withChildren.
-     */
-    @Override
-    public BitmapAndNot withChildren(List<Expression> children) {
-        Preconditions.checkArgument(children.size() == 2);
-        return new BitmapAndNot(getFunctionParams(children));
-    }
-
-    @Override
-    public List<FunctionSignature> getSignatures() {
-        return SIGNATURES;
-    }
-
-    @Override
-    public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
-        return visitor.visitBitmapAndNot(this, context);
-    }
-}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/BitmapAndNotAlias.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/BitmapAndNotAlias.java
deleted file mode 100644
index 16045904184..00000000000
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/BitmapAndNotAlias.java
+++ /dev/null
@@ -1,73 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-package org.apache.doris.nereids.trees.expressions.functions.scalar;
-
-import org.apache.doris.catalog.FunctionSignature;
-import org.apache.doris.nereids.trees.expressions.Expression;
-import 
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
-import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
-import org.apache.doris.nereids.trees.expressions.shape.BinaryExpression;
-import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
-import org.apache.doris.nereids.types.BitmapType;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-
-import java.util.List;
-
-/**
- * ScalarFunction 'bitmap_and_not'. This class is generated by 
GenerateFunction.
- */
-public class BitmapAndNotAlias extends ScalarFunction
-        implements BinaryExpression, ExplicitlyCastableSignature, 
PropagateNullable {
-
-    public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
-            
FunctionSignature.ret(BitmapType.INSTANCE).args(BitmapType.INSTANCE, 
BitmapType.INSTANCE)
-    );
-
-    /**
-     * constructor with 2 arguments.
-     */
-    public BitmapAndNotAlias(Expression arg0, Expression arg1) {
-        super("bitmap_andnot", arg0, arg1);
-    }
-
-    /** constructor for withChildren and reuse signature */
-    private BitmapAndNotAlias(ScalarFunctionParams functionParams) {
-        super(functionParams);
-    }
-
-    /**
-     * withChildren.
-     */
-    @Override
-    public BitmapAndNotAlias withChildren(List<Expression> children) {
-        Preconditions.checkArgument(children.size() == 2);
-        return new BitmapAndNotAlias(getFunctionParams(children));
-    }
-
-    @Override
-    public List<FunctionSignature> getSignatures() {
-        return SIGNATURES;
-    }
-
-    @Override
-    public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
-        return visitor.visitBitmapAndNotAlias(this, context);
-    }
-}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/BitmapAndNotCount.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/BitmapAndNotCount.java
index 0976bc6fe05..ac00f957a18 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/BitmapAndNotCount.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/BitmapAndNotCount.java
@@ -19,6 +19,7 @@ package 
org.apache.doris.nereids.trees.expressions.functions.scalar;
 
 import org.apache.doris.catalog.FunctionSignature;
 import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.functions.AlwaysNotNullable;
 import 
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
 import org.apache.doris.nereids.trees.expressions.shape.BinaryExpression;
 import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
@@ -34,7 +35,7 @@ import java.util.List;
  * ScalarFunction 'bitmap_and_not_count'. This class is generated by 
GenerateFunction.
  */
 public class BitmapAndNotCount extends ScalarFunction
-        implements BinaryExpression, ExplicitlyCastableSignature {
+        implements BinaryExpression, ExplicitlyCastableSignature, 
AlwaysNotNullable {
 
     public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
             
FunctionSignature.ret(BigIntType.INSTANCE).args(BitmapType.INSTANCE, 
BitmapType.INSTANCE)
@@ -70,9 +71,4 @@ public class BitmapAndNotCount extends ScalarFunction
     public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
         return visitor.visitBitmapAndNotCount(this, context);
     }
-
-    @Override
-    public boolean nullable() {
-        return children().stream().anyMatch(Expression::nullable);
-    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/BitmapAndNotCountAlias.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/BitmapAndNotCountAlias.java
deleted file mode 100644
index 36205c847e2..00000000000
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/BitmapAndNotCountAlias.java
+++ /dev/null
@@ -1,78 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-package org.apache.doris.nereids.trees.expressions.functions.scalar;
-
-import org.apache.doris.catalog.FunctionSignature;
-import org.apache.doris.nereids.trees.expressions.Expression;
-import 
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
-import org.apache.doris.nereids.trees.expressions.shape.BinaryExpression;
-import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
-import org.apache.doris.nereids.types.BigIntType;
-import org.apache.doris.nereids.types.BitmapType;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-
-import java.util.List;
-
-/**
- * ScalarFunction 'bitmap_and_not_count'. This class is generated by 
GenerateFunction.
- */
-public class BitmapAndNotCountAlias extends ScalarFunction
-        implements BinaryExpression, ExplicitlyCastableSignature {
-
-    public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
-            
FunctionSignature.ret(BigIntType.INSTANCE).args(BitmapType.INSTANCE, 
BitmapType.INSTANCE)
-    );
-
-    /**
-     * constructor with 2 arguments.
-     */
-    public BitmapAndNotCountAlias(Expression arg0, Expression arg1) {
-        super("bitmap_andnot_count", arg0, arg1);
-    }
-
-    /** constructor for withChildren and reuse signature */
-    private BitmapAndNotCountAlias(ScalarFunctionParams functionParams) {
-        super(functionParams);
-    }
-
-    /**
-     * withChildren.
-     */
-    @Override
-    public BitmapAndNotCountAlias withChildren(List<Expression> children) {
-        Preconditions.checkArgument(children.size() == 2);
-        return new BitmapAndNotCountAlias(getFunctionParams(children));
-    }
-
-    @Override
-    public List<FunctionSignature> getSignatures() {
-        return SIGNATURES;
-    }
-
-    @Override
-    public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
-        return visitor.visitBitmapAndNotCountAlias(this, context);
-    }
-
-    @Override
-    public boolean nullable() {
-        return children().stream().anyMatch(Expression::nullable);
-    }
-}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/BitmapOrCount.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/BitmapOrCount.java
index 92c51db51ac..5165325d03f 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/BitmapOrCount.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/BitmapOrCount.java
@@ -19,6 +19,7 @@ package 
org.apache.doris.nereids.trees.expressions.functions.scalar;
 
 import org.apache.doris.catalog.FunctionSignature;
 import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.functions.AlwaysNotNullable;
 import 
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
 import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.BigIntType;
@@ -34,7 +35,7 @@ import java.util.List;
  * ScalarFunction 'bitmap_or_count'. This class is generated by 
GenerateFunction.
  */
 public class BitmapOrCount extends ScalarFunction
-        implements ExplicitlyCastableSignature {
+        implements ExplicitlyCastableSignature, AlwaysNotNullable {
 
     public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
             
FunctionSignature.ret(BigIntType.INSTANCE).varArgs(BitmapType.INSTANCE, 
BitmapType.INSTANCE)
@@ -70,8 +71,4 @@ public class BitmapOrCount extends ScalarFunction
     public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
         return visitor.visitBitmapOrCount(this, context);
     }
-
-    public boolean nullable() {
-        return children().stream().anyMatch(Expression::nullable);
-    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/BitmapXorCount.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/BitmapXorCount.java
index ff6742ebafc..a532aa87e9f 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/BitmapXorCount.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/BitmapXorCount.java
@@ -19,6 +19,7 @@ package 
org.apache.doris.nereids.trees.expressions.functions.scalar;
 
 import org.apache.doris.catalog.FunctionSignature;
 import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.functions.AlwaysNotNullable;
 import 
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
 import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.BigIntType;
@@ -34,7 +35,7 @@ import java.util.List;
  * ScalarFunction 'bitmap_xor_count'. This class is generated by 
GenerateFunction.
  */
 public class BitmapXorCount extends ScalarFunction
-        implements ExplicitlyCastableSignature {
+        implements ExplicitlyCastableSignature, AlwaysNotNullable {
 
     public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
             
FunctionSignature.ret(BigIntType.INSTANCE).varArgs(BitmapType.INSTANCE, 
BitmapType.INSTANCE)
@@ -70,9 +71,4 @@ public class BitmapXorCount extends ScalarFunction
     public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
         return visitor.visitBitmapXorCount(this, context);
     }
-
-    @Override
-    public boolean nullable() {
-        return children().stream().anyMatch(Expression::nullable);
-    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
index 7b1724ae085..6b73a00b854 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
@@ -113,10 +113,7 @@ import 
org.apache.doris.nereids.trees.expressions.functions.scalar.BitShiftRight
 import org.apache.doris.nereids.trees.expressions.functions.scalar.BitTest;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapAnd;
 import 
org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapAndCount;
-import 
org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapAndNot;
-import 
org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapAndNotAlias;
 import 
org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapAndNotCount;
-import 
org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapAndNotCountAlias;
 import 
org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapContains;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapCount;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapEmpty;
@@ -929,22 +926,10 @@ public interface ScalarFunctionVisitor<R, C> {
         return visitScalarFunction(bitmapAndCount, context);
     }
 
-    default R visitBitmapAndNot(BitmapAndNot bitmapAndNot, C context) {
-        return visitScalarFunction(bitmapAndNot, context);
-    }
-
     default R visitBitmapAndNotCount(BitmapAndNotCount bitmapAndNotCount, C 
context) {
         return visitScalarFunction(bitmapAndNotCount, context);
     }
 
-    default R visitBitmapAndNotAlias(BitmapAndNotAlias bitmapAndNotAlias, C 
context) {
-        return visitScalarFunction(bitmapAndNotAlias, context);
-    }
-
-    default R visitBitmapAndNotCountAlias(BitmapAndNotCountAlias 
bitmapAndNotCountAlias, C context) {
-        return visitScalarFunction(bitmapAndNotCountAlias, context);
-    }
-
     default R visitBitmapContains(BitmapContains bitmapContains, C context) {
         return visitScalarFunction(bitmapContains, context);
     }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/Coordinator.java 
b/fe/fe-core/src/main/java/org/apache/doris/qe/Coordinator.java
index 74e0128e8da..c8b8d6000df 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/Coordinator.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/Coordinator.java
@@ -402,6 +402,9 @@ public class Coordinator implements CoordInterface {
         this.queryGlobals.setTimeZone(timezone);
         this.queryGlobals.setLoadZeroTolerance(loadZeroTolerance);
         this.queryOptions.setBeExecVersion(Config.be_exec_version);
+        this.queryOptions.setNewVersionUnixTimestamp(true);
+        this.queryOptions.setNewVersionPercentile(true);
+        this.queryOptions.setNewVersionBitmapOpCount(true);
 
         List<Integer> fragmentIds = new ArrayList<>();
         for (PlanFragment fragment : fragments) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/qe/CoordinatorContext.java 
b/fe/fe-core/src/main/java/org/apache/doris/qe/CoordinatorContext.java
index 1caae547f06..f619d7f4917 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/CoordinatorContext.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/CoordinatorContext.java
@@ -310,6 +310,7 @@ public class CoordinatorContext {
         queryOptions.setBeExecVersion(Config.be_exec_version);
         queryOptions.setNewVersionUnixTimestamp(true);
         queryOptions.setNewVersionPercentile(true);
+        queryOptions.setNewVersionBitmapOpCount(true);
 
         TQueryGlobals queryGlobals = new TQueryGlobals();
         
queryGlobals.setNowString(TimeUtils.getDatetimeFormatWithTimeZone().format(LocalDateTime.now()));
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/qe/NereidsCoordinator.java 
b/fe/fe-core/src/main/java/org/apache/doris/qe/NereidsCoordinator.java
index 19c2eaec3ad..bc4c74335ca 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/NereidsCoordinator.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/NereidsCoordinator.java
@@ -504,6 +504,7 @@ public class NereidsCoordinator extends Coordinator {
         this.coordinatorContext.queryOptions.setDisableFileCache(true);
         this.coordinatorContext.queryOptions.setNewVersionUnixTimestamp(true);
         this.coordinatorContext.queryOptions.setNewVersionPercentile(true);
+        this.coordinatorContext.queryOptions.setNewVersionBitmapOpCount(true);
     }
 
     private void setForQuery() {
diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java 
b/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java
index df3fcbac6e0..ca2e3a6394f 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java
@@ -5866,6 +5866,7 @@ public class SessionVariable implements Serializable, 
Writable {
         tResult.setEnableInsertStrict(enableInsertStrict);
         tResult.setNewVersionUnixTimestamp(true); // once FE upgraded, always 
use new version
         tResult.setNewVersionPercentile(true);
+        tResult.setNewVersionBitmapOpCount(true);
 
         tResult.setHnswEfSearch(hnswEFSearch);
         tResult.setHnswCheckRelativeDistance(hnswCheckRelativeDistance);
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/cloud/catalog/CloudEnvFactoryTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/cloud/catalog/CloudEnvFactoryTest.java
index e1687ae21d1..c7af444c99c 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/cloud/catalog/CloudEnvFactoryTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/cloud/catalog/CloudEnvFactoryTest.java
@@ -17,16 +17,23 @@
 
 package org.apache.doris.cloud.catalog;
 
+import org.apache.doris.analysis.DescriptorTable;
 import org.apache.doris.catalog.Env;
 import org.apache.doris.catalog.EnvFactory;
 import org.apache.doris.cloud.datasource.CloudInternalCatalog;
+import org.apache.doris.cloud.qe.CloudCoordinator;
 import org.apache.doris.common.Config;
+import org.apache.doris.common.FeConstants;
 import org.apache.doris.common.util.PropertyAnalyzer;
+import org.apache.doris.qe.ConnectContext;
+import org.apache.doris.qe.Coordinator;
+import org.apache.doris.thrift.TUniqueId;
 
 import com.google.common.collect.Maps;
 import org.junit.Assert;
 import org.junit.Test;
 
+import java.util.Collections;
 import java.util.Map;
 
 public class CloudEnvFactoryTest {
@@ -51,4 +58,29 @@ public class CloudEnvFactoryTest {
         Assert.assertEquals("1", 
properties.get(PropertyAnalyzer.PROPERTIES_REPLICATION_NUM));
     }
 
+    @Test
+    public void testLegacyLoadCoordinatorSetsFunctionVersionOptions() {
+        boolean runningUnitTest = FeConstants.runningUnitTest;
+        FeConstants.runningUnitTest = true;
+        try {
+            ConnectContext context = new ConnectContext();
+            
context.getSessionVariable().setEnableNereidsDistributePlanner(false);
+            context.setThreadLocalInfo();
+            Coordinator coordinator = new CloudEnvFactory().createCoordinator(
+                    1L, new TUniqueId(1L, 1L), new DescriptorTable(),
+                    Collections.emptyList(), Collections.emptyList(), "UTC", 
false, false);
+
+            Assert.assertTrue(coordinator instanceof CloudCoordinator);
+            
Assert.assertTrue(coordinator.getQueryOptions().isSetNewVersionUnixTimestamp());
+            
Assert.assertTrue(coordinator.getQueryOptions().isNewVersionUnixTimestamp());
+            
Assert.assertTrue(coordinator.getQueryOptions().isSetNewVersionPercentile());
+            
Assert.assertTrue(coordinator.getQueryOptions().isNewVersionPercentile());
+            
Assert.assertTrue(coordinator.getQueryOptions().isSetNewVersionBitmapOpCount());
+            
Assert.assertTrue(coordinator.getQueryOptions().isNewVersionBitmapOpCount());
+        } finally {
+            ConnectContext.remove();
+            FeConstants.runningUnitTest = runningUnitTest;
+        }
+    }
+
 }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/FunctionRegistryTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/FunctionRegistryTest.java
index 0b3e4cb19f6..df7f4ca319e 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/FunctionRegistryTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/FunctionRegistryTest.java
@@ -21,16 +21,19 @@ import org.apache.doris.catalog.FunctionRegistry;
 import org.apache.doris.catalog.FunctionSignature;
 import org.apache.doris.nereids.exceptions.AnalysisException;
 import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.SlotReference;
 import org.apache.doris.nereids.trees.expressions.functions.BoundFunction;
 import 
org.apache.doris.nereids.trees.expressions.functions.BuiltinFunctionBuilder;
 import 
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
 import org.apache.doris.nereids.trees.expressions.functions.FunctionBuilder;
 import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapAndNotCount;
 import 
org.apache.doris.nereids.trees.expressions.functions.scalar.ScalarFunction;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Substring;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Year;
 import org.apache.doris.nereids.trees.expressions.literal.Literal;
 import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression;
+import org.apache.doris.nereids.types.BitmapType;
 import org.apache.doris.nereids.types.IntegerType;
 import org.apache.doris.nereids.util.MemoPatternMatchSupported;
 import org.apache.doris.nereids.util.MemoTestUtils;
@@ -87,6 +90,24 @@ public class FunctionRegistryTest implements 
MemoPatternMatchSupported {
                 );
     }
 
+    @Test
+    public void testBitmapAndNotCountAliasNotNullable() {
+        FunctionRegistry functionRegistry = new FunctionRegistry();
+        ImmutableList<Expression> arguments = ImmutableList.of(
+                new SlotReference("nullableBitmap1", BitmapType.INSTANCE, 
true),
+                new SlotReference("nullableBitmap2", BitmapType.INSTANCE, 
true));
+
+        FunctionBuilder aliasBuilder = 
functionRegistry.findFunctionBuilder("bitmap_andnot_count", arguments);
+        Expression aliasFunction = aliasBuilder.build("bitmap_andnot_count", 
arguments).first;
+        Assertions.assertInstanceOf(BitmapAndNotCount.class, aliasFunction);
+        Assertions.assertFalse(aliasFunction.nullable());
+
+        FunctionBuilder canonicalBuilder = 
functionRegistry.findFunctionBuilder("bitmap_and_not_count", arguments);
+        Expression canonicalFunction = 
canonicalBuilder.build("bitmap_and_not_count", arguments).first;
+        Assertions.assertInstanceOf(BitmapAndNotCount.class, 
canonicalFunction);
+        Assertions.assertFalse(canonicalFunction.nullable());
+    }
+
     @Test
     public void testOverrideArity() {
         // the substring function has 2 override functions:
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rules/BitmapCountToBitmapOpCountTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rules/BitmapCountToBitmapOpCountTest.java
new file mode 100644
index 00000000000..7275e9eedb7
--- /dev/null
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rules/BitmapCountToBitmapOpCountTest.java
@@ -0,0 +1,115 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules.expression.rules;
+
+import org.apache.doris.nereids.rules.expression.ExpressionRewriteTestHelper;
+import org.apache.doris.nereids.rules.expression.ExpressionRuleExecutor;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.SlotReference;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapAnd;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapAndCount;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapAndNotCount;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapCount;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapNot;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapOr;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapOrCount;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapXor;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapXorCount;
+import org.apache.doris.nereids.types.BitmapType;
+
+import com.google.common.collect.ImmutableList;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class BitmapCountToBitmapOpCountTest extends ExpressionRewriteTestHelper {
+
+    private final SlotReference bitmap1 = new SlotReference("bitmap1", 
BitmapType.INSTANCE, true);
+    private final SlotReference bitmap2 = new SlotReference("bitmap2", 
BitmapType.INSTANCE, true);
+    private final SlotReference bitmap3 = new SlotReference("bitmap3", 
BitmapType.INSTANCE, true);
+
+    @BeforeEach
+    void setUp() {
+        executor = new ExpressionRuleExecutor(ImmutableList.of(
+                bottomUp(BitmapCountToBitmapOpCount.INSTANCE)
+        ));
+    }
+
+    @Test
+    void testRewriteBitmapAnd() {
+        assertRewrite(
+                new BitmapCount(new BitmapAnd(bitmap1, bitmap2)),
+                new BitmapAndCount(bitmap1, bitmap2)
+        );
+    }
+
+    @Test
+    void testRewriteBitmapAndWithVarArgs() {
+        assertRewrite(
+                new BitmapCount(new BitmapAnd(bitmap1, bitmap2, bitmap3)),
+                new BitmapAndCount(bitmap1, bitmap2, bitmap3)
+        );
+    }
+
+    @Test
+    void testRewriteBitmapOr() {
+        assertRewrite(
+                new BitmapCount(new BitmapOr(bitmap1, bitmap2, bitmap3)),
+                new BitmapOrCount(bitmap1, bitmap2, bitmap3)
+        );
+    }
+
+    @Test
+    void testRewriteBitmapXor() {
+        assertRewrite(
+                new BitmapCount(new BitmapXor(bitmap1, bitmap2)),
+                new BitmapXorCount(bitmap1, bitmap2)
+        );
+    }
+
+    @Test
+    void testRewriteBitmapNot() {
+        assertRewrite(
+                new BitmapCount(new BitmapNot(bitmap1, bitmap2)),
+                new BitmapAndNotCount(bitmap1, bitmap2)
+        );
+    }
+
+    @Test
+    void testKeepPlainBitmapCount() {
+        assertRewrite(
+                new BitmapCount(bitmap1),
+                new BitmapCount(bitmap1)
+        );
+    }
+
+    @Test
+    void testBitmapOpCountNotNullableMetadata() {
+        Assertions.assertFalse(new BitmapAndCount(bitmap1, 
bitmap2).nullable());
+        Assertions.assertFalse(new BitmapOrCount(bitmap1, bitmap2).nullable());
+        Assertions.assertFalse(new BitmapXorCount(bitmap1, 
bitmap2).nullable());
+        Assertions.assertFalse(new BitmapAndNotCount(bitmap1, 
bitmap2).nullable());
+    }
+
+    @Test
+    void testRewriteToNotNullableBitmapOpCount() {
+        Expression rewrittenExpression = executor.rewrite(new BitmapCount(new 
BitmapAnd(bitmap1, bitmap2)), context);
+        Assertions.assertInstanceOf(BitmapAndCount.class, rewrittenExpression);
+        Assertions.assertFalse(rewrittenExpression.nullable());
+    }
+}
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/qe/ShortCircuitQueryContextTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/qe/ShortCircuitQueryContextTest.java
index 45e4927c403..e24a57ee465 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/qe/ShortCircuitQueryContextTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/qe/ShortCircuitQueryContextTest.java
@@ -17,12 +17,20 @@
 
 package org.apache.doris.qe;
 
+import org.apache.doris.analysis.DescriptorTable;
+import org.apache.doris.analysis.Queriable;
 import org.apache.doris.catalog.OlapTable;
+import org.apache.doris.planner.OlapScanNode;
+import org.apache.doris.planner.Planner;
+import org.apache.doris.thrift.TQueryOptions;
 
+import org.apache.thrift.TDeserializer;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 import org.mockito.Mockito;
 
+import java.util.Collections;
+
 public class ShortCircuitQueryContextTest {
     private OlapTable table(String name, int schemaVersion) {
         OlapTable table = Mockito.spy(new OlapTable());
@@ -55,4 +63,29 @@ public class ShortCircuitQueryContextTest {
 
         Assertions.assertFalse(context.isReusable(connectContext(0)));
     }
+
+    @Test
+    public void testSerializedQueryOptionsKeepBitmapOpCountVersion() throws 
Exception {
+        TQueryOptions queryOptions = new SessionVariable().toThrift();
+        Planner planner = Mockito.mock(Planner.class);
+        Mockito.when(planner.getQueryOptions()).thenReturn(queryOptions);
+        DescriptorTable descriptorTable = new DescriptorTable();
+        descriptorTable.createTupleDescriptor();
+        Mockito.when(planner.getDescTable()).thenReturn(descriptorTable);
+
+        OlapScanNode scanNode = Mockito.mock(OlapScanNode.class);
+        OlapTable table = table("tbl", 10);
+        
Mockito.when(scanNode.getPointQueryProjectList()).thenReturn(Collections.emptyList());
+        Mockito.when(scanNode.getOlapTable()).thenReturn(table);
+        Mockito.when(scanNode.getTableNameInPlan()).thenReturn("tbl");
+        
Mockito.when(planner.getScanNodes()).thenReturn(Collections.singletonList(scanNode));
+
+        ShortCircuitQueryContext context =
+                new ShortCircuitQueryContext(planner, 
Mockito.mock(Queriable.class));
+        TQueryOptions serializedQueryOptions = new TQueryOptions();
+        new TDeserializer().deserialize(serializedQueryOptions, 
context.serializedQueryOptions.toByteArray());
+
+        
Assertions.assertTrue(serializedQueryOptions.isSetNewVersionBitmapOpCount());
+        
Assertions.assertTrue(serializedQueryOptions.isNewVersionBitmapOpCount());
+    }
 }
diff --git a/gensrc/thrift/PaloInternalService.thrift 
b/gensrc/thrift/PaloInternalService.thrift
index 578ff2fca79..d15765ecf82 100644
--- a/gensrc/thrift/PaloInternalService.thrift
+++ b/gensrc/thrift/PaloInternalService.thrift
@@ -507,6 +507,7 @@ struct TQueryOptions {
   225: optional i64 runtime_filter_tree_publish_max_send_bytes = 268435456
 
   226: optional bool enable_prune_nested_column = false;
+  227: optional bool new_version_bitmap_op_count = false;
   // For cloud, to control if the content would be written into file cache
   // In write path, to control if the content would be written into file cache.
   // In read path, read from file cache or remote storage when execute query.
diff --git 
a/regression-test/data/query_p0/sql_functions/bitmap_functions/test_bitmap_function.out
 
b/regression-test/data/query_p0/sql_functions/bitmap_functions/test_bitmap_function.out
index 8fa306872e2..2df96803a0f 100644
--- 
a/regression-test/data/query_p0/sql_functions/bitmap_functions/test_bitmap_function.out
+++ 
b/regression-test/data/query_p0/sql_functions/bitmap_functions/test_bitmap_function.out
@@ -228,6 +228,9 @@ true
 -- !sql_bitmap_and_count6 --
 0
 
+-- !sql_bitmap_and_count_nulls --
+0      0       0
+
 -- !sql_bitmap_or_count1 --
 3
 
@@ -237,12 +240,21 @@ true
 -- !sql_bitmap_or_count3 --
 5
 
+-- !sql_bitmap_or_count_set_diff_length --
+5
+
 -- !sql_bitmap_or_count4 --
 6
 
 -- !sql_bitmap_or_count5 --
 6
 
+-- !sql_bitmap_or_count_nulls --
+3      3       0
+
+-- !sql_bitmap_or_count_nulls_multi --
+5
+
 -- !sql --
 2
 
@@ -276,6 +288,12 @@ true
 -- !sql_bitmap_xor_count6 --
 0
 
+-- !sql_bitmap_xor_count_nulls --
+0      0       0
+
+-- !sql_bitmap_count_rewrite_nullable --
+3      3       0       0       0       0
+
 -- !sql_bitmap_and_count7 --
 1      1
 2      1
diff --git 
a/regression-test/suites/query_p0/sql_functions/bitmap_functions/test_bitmap_function.groovy
 
b/regression-test/suites/query_p0/sql_functions/bitmap_functions/test_bitmap_function.groovy
index 2c6640a6515..540b396f37f 100644
--- 
a/regression-test/suites/query_p0/sql_functions/bitmap_functions/test_bitmap_function.groovy
+++ 
b/regression-test/suites/query_p0/sql_functions/bitmap_functions/test_bitmap_function.groovy
@@ -307,13 +307,17 @@ suite("test_bitmap_function") {
     qt_sql_bitmap_and_count4 """ select 
bitmap_and_count(bitmap_from_string('1,2,3'), bitmap_from_string('1,2'), 
bitmap_from_string('1,2,3,4,5')) """
     qt_sql_bitmap_and_count5 """ select 
bitmap_and_count(bitmap_from_string('1,2,3'), bitmap_from_string('1,2'), 
bitmap_from_string('1,2,3,4,5'),bitmap_empty()) """
     qt_sql_bitmap_and_count6 """ select 
bitmap_and_count(bitmap_from_string('1,2,3'), bitmap_from_string('1,2'), 
bitmap_from_string('1,2,3,4,5'), NULL) """
+    qt_sql_bitmap_and_count_nulls """ select bitmap_and_count(cast(NULL as 
bitmap), bitmap_from_string('1,2,3')), 
bitmap_and_count(bitmap_from_string('1,2,3'), cast(NULL as bitmap)), 
bitmap_and_count(cast(NULL as bitmap), cast(NULL as bitmap)) """
 
     // bitmap_or_count
     qt_sql_bitmap_or_count1 """ select 
bitmap_or_count(bitmap_from_string('1,2,3'),bitmap_empty()) """
     qt_sql_bitmap_or_count2 """ select 
bitmap_or_count(bitmap_from_string('1,2,3'),bitmap_from_string('1,2,3'))"""
     qt_sql_bitmap_or_count3 """ select 
bitmap_or_count(bitmap_from_string('1,2,3'),bitmap_from_string('3,4,5')) """
+    qt_sql_bitmap_or_count_set_diff_length """ select 
bitmap_or_count(bitmap_from_string('1,2'), bitmap_from_string('2,3,4,5')) """
     qt_sql_bitmap_or_count4 """ select 
bitmap_or_count(bitmap_from_string('1,2,3'), bitmap_from_string('3,4,5'), 
to_bitmap(100), bitmap_empty()) """
     qt_sql_bitmap_or_count5 """ select 
bitmap_or_count(bitmap_from_string('1,2,3'), bitmap_from_string('3,4,5'), 
to_bitmap(100), NULL) """
+    qt_sql_bitmap_or_count_nulls """ select bitmap_or_count(cast(NULL as 
bitmap), bitmap_from_string('1,2,3')), 
bitmap_or_count(bitmap_from_string('1,2,3'), cast(NULL as bitmap)), 
bitmap_or_count(cast(NULL as bitmap), cast(NULL as bitmap)) """
+    qt_sql_bitmap_or_count_nulls_multi """ select bitmap_or_count(cast(NULL as 
bitmap), bitmap_from_string('1,2,3'), bitmap_from_string('3,4,5'), cast(NULL as 
bitmap)) """
 
     // BITMAP_XOR
     qt_sql """ select 
bitmap_count(bitmap_xor(bitmap_from_string('2,3'),bitmap_from_string('1,2,3,4')))
 cnt """
@@ -329,6 +333,88 @@ suite("test_bitmap_function") {
     qt_sql_bitmap_xor_count4 """ select 
(bitmap_xor_count(bitmap_from_string('2,3'),bitmap_from_string('1,2,3,4'),bitmap_from_string('3,4,5')))
 """
     qt_sql_bitmap_xor_count5 """ select 
(bitmap_xor_count(bitmap_from_string('2,3'),bitmap_from_string('1,2,3,4'),bitmap_from_string('3,4,5'),bitmap_empty()))
 """
     qt_sql_bitmap_xor_count6 """ select 
(bitmap_xor_count(bitmap_from_string('2,3'),bitmap_from_string('1,2,3,4'),bitmap_from_string('3,4,5'),NULL))
 """
+    qt_sql_bitmap_xor_count_nulls """ select bitmap_xor_count(cast(NULL as 
bitmap), bitmap_from_string('1,2,3')), 
bitmap_xor_count(bitmap_from_string('1,2,3'), cast(NULL as bitmap)), 
bitmap_xor_count(cast(NULL as bitmap), cast(NULL as bitmap)) """
+    qt_sql_bitmap_count_rewrite_nullable """ select 
bitmap_count(bitmap_or(cast(NULL as bitmap), bitmap_from_string('1,2,3'))), 
bitmap_or_count(cast(NULL as bitmap), bitmap_from_string('1,2,3')), 
bitmap_count(bitmap_and(bitmap_from_string('1,2,3'), cast(NULL as bitmap))), 
bitmap_and_count(bitmap_from_string('1,2,3'), cast(NULL as bitmap)), 
bitmap_count(bitmap_xor(bitmap_from_string('1,2,3'), cast(NULL as bitmap))), 
bitmap_xor_count(bitmap_from_string('1,2,3'), cast(NULL as bitmap)) """
+
+    sql """ DROP TABLE IF EXISTS test_bitmap_op_count_short_circuit """
+    sql """
+        CREATE TABLE test_bitmap_op_count_short_circuit (
+            id BIGINT NOT NULL,
+            lhs BITMAP NOT NULL,
+            rhs BITMAP NOT NULL
+        ) ENGINE=OLAP
+        UNIQUE KEY(id)
+        DISTRIBUTED BY HASH(id) BUCKETS 1
+        PROPERTIES (
+            "replication_num" = "1",
+            "store_row_column" = "true",
+            "enable_unique_key_merge_on_write" = "true",
+            "light_schema_change" = "true"
+        )
+    """
+    sql """
+        INSERT INTO test_bitmap_op_count_short_circuit VALUES
+            (1, bitmap_from_string('1,2,3'), bitmap_from_string('3,4'))
+    """
+    sql "SET enable_nereids_planner=true"
+    sql "SET enable_short_circuit_query=true"
+    explain {
+        sql """
+            SELECT
+                bitmap_count(bitmap_and(lhs, rhs)),
+                bitmap_count(bitmap_or(lhs, rhs)),
+                bitmap_count(bitmap_xor(lhs, rhs)),
+                bitmap_count(bitmap_and_not(lhs, rhs))
+            FROM test_bitmap_op_count_short_circuit
+            WHERE id = 1
+        """
+        contains "SHORT-CIRCUIT"
+        contains "bitmap_and_count"
+        contains "bitmap_or_count"
+        contains "bitmap_xor_count"
+        contains "bitmap_and_not_count"
+    }
+    def shortCircuitResult = sql """
+        SELECT
+            bitmap_count(bitmap_and(lhs, rhs)),
+            bitmap_count(bitmap_or(lhs, rhs)),
+            bitmap_count(bitmap_xor(lhs, rhs)),
+            bitmap_count(bitmap_and_not(lhs, rhs))
+        FROM test_bitmap_op_count_short_circuit
+        WHERE id = 1
+    """
+    sql "SET enable_short_circuit_query=false"
+    def regularResult = sql """
+        SELECT
+            bitmap_count(bitmap_and(lhs, rhs)),
+            bitmap_count(bitmap_or(lhs, rhs)),
+            bitmap_count(bitmap_xor(lhs, rhs)),
+            bitmap_count(bitmap_and_not(lhs, rhs))
+        FROM test_bitmap_op_count_short_circuit
+        WHERE id = 1
+    """
+    check2_doris(shortCircuitResult, regularResult)
+
+    sql "SET enable_short_circuit_query=true"
+    def shortCircuitNullableResult = sql """
+        SELECT
+            bitmap_count(bitmap_and(lhs, CAST(NULL AS BITMAP))),
+            bitmap_count(bitmap_or(lhs, CAST(NULL AS BITMAP))),
+            bitmap_count(bitmap_xor(lhs, CAST(NULL AS BITMAP)))
+        FROM test_bitmap_op_count_short_circuit
+        WHERE id = 1
+    """
+    sql "SET enable_short_circuit_query=false"
+    def regularNullableResult = sql """
+        SELECT
+            bitmap_count(bitmap_and(lhs, CAST(NULL AS BITMAP))),
+            bitmap_count(bitmap_or(lhs, CAST(NULL AS BITMAP))),
+            bitmap_count(bitmap_xor(lhs, CAST(NULL AS BITMAP)))
+        FROM test_bitmap_op_count_short_circuit
+        WHERE id = 1
+    """
+    check2_doris(shortCircuitNullableResult, regularNullableResult)
+    sql "SET enable_short_circuit_query=true"
 
     // bitmap_and_count, bitmap_xor_count, bitmap_and_not_count of all 
nullable column
     sql """ DROP TABLE IF EXISTS test_bitmap1 """


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

Reply via email to