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

HappenLee 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 dbea64bcec9 [fix](be) Support Boolean in topn_weighted and topn_array 
(#68254)
dbea64bcec9 is described below

commit dbea64bcec932fdbd7aa43576953eae1a167b7c0
Author: HappenLee <[email protected]>
AuthorDate: Mon Sep 21 16:04:45 2026 +0800

    [fix](be) Support Boolean in topn_weighted and topn_array (#68254)
    
    ### What problem does this PR solve?
    
    Boolean input is declared by the FE overloads of `topn_weighted` and
    `topn_array`, but both BE factory type lists omit `TYPE_BOOLEAN`.
    Queries such as `SELECT topn_weighted(TRUE, 1, 2)` can therefore fail
    when BE creates the aggregate function.
    
    Add `TYPE_BOOLEAN` to both existing creator lists, covering both arities
    of each function. Reuse the existing numeric aggregation, NULL handling,
    serialization, merge and result insertion implementations. Preserve the
    existing FE signatures and `ARRAY<BOOLEAN>` result type; the final PR
    has no FE changes.
    
    Add BE unit tests for result type, ranking, limits, NULL values, ties,
    reset and serialization/merge paths. Add SQL regression coverage for
    literals, nullable columns and weights, grouped aggregation, all-NULL
    input and empty input. Expected output is generated by the regression
    runner.
    
    ### Release note
    
    `TOPN_WEIGHTED` and `TOPN_ARRAY` now execute on BOOLEAN inputs and
    preserve BOOLEAN array results.
    
    ### Check List (For Author)
    
    - Test:
    - ASAN BE and FE build: `./build.sh --be --fe -j48` passed, including FE
    Checkstyle.
    - BE unit tests: `./run-be-ut.sh --run -j48
    
--filter='AggregateFunctionTopNBooleanTest.*:AggTest.topn*:AggregateStateParametersTest.TopN*'`
    passed (8 tests).
    - Regression: generated `topn_boolean.out` using `-forceGenOut`,
    reviewed all output sections, then ran `./run-regression-test.sh --run
    -d nereids_function_p0/agg_function/topn -s topn,topn_boolean` (2 suites
    passed).
      - clang-format 16 and `build-support/check-build-hygiene.sh` passed.
    - clang-tidy was attempted for both production files and the new unit
    test. After correcting the local Clang resource path, it remains blocked
    by the pre-existing unmatched `NOLINTEND(readability-function-size)` in
    `be/src/core/types.h:576`; that unrelated header is unchanged.
    - Behavior changed: Yes. Boolean top-N array aggregates execute natively
    instead of failing BE function creation.
    - Does this need documentation: No.
---
 .../aggregate/aggregate_function_topn_array.cpp    |  10 +-
 .../aggregate/aggregate_function_topn_weighted.cpp |  10 +-
 be/test/exprs/aggregate/agg_topn_boolean_test.cpp  | 117 +++++++++++++++++++++
 .../agg_function/topn/topn_boolean.out             |  27 +++++
 .../agg_function/topn/topn_boolean.groovy          |  78 ++++++++++++++
 5 files changed, 234 insertions(+), 8 deletions(-)

diff --git a/be/src/exprs/aggregate/aggregate_function_topn_array.cpp 
b/be/src/exprs/aggregate/aggregate_function_topn_array.cpp
index 7f1ebf7b4c2..614a50711fe 100644
--- a/be/src/exprs/aggregate/aggregate_function_topn_array.cpp
+++ b/be/src/exprs/aggregate/aggregate_function_topn_array.cpp
@@ -27,10 +27,12 @@ using ImplArray = AggregateFunctionTopNImplArray<T, false>;
 template <PrimitiveType T>
 using ImplArrayWithDefault = AggregateFunctionTopNImplArray<T, true>;
 
-using topn_array_creator = creator_with_type_list<
-        TYPE_TINYINT, TYPE_SMALLINT, TYPE_INT, TYPE_BIGINT, TYPE_LARGEINT, 
TYPE_FLOAT, TYPE_DOUBLE,
-        TYPE_DECIMAL32, TYPE_DECIMAL64, TYPE_DECIMAL128I, TYPE_DECIMAL256, 
TYPE_VARCHAR,
-        TYPE_DATEV2, TYPE_DATETIMEV2, TYPE_TIMESTAMP_NS, TYPE_TIMESTAMPTZ, 
TYPE_IPV4, TYPE_IPV6>;
+using topn_array_creator =
+        creator_with_type_list<TYPE_BOOLEAN, TYPE_TINYINT, TYPE_SMALLINT, 
TYPE_INT, TYPE_BIGINT,
+                               TYPE_LARGEINT, TYPE_FLOAT, TYPE_DOUBLE, 
TYPE_DECIMAL32,
+                               TYPE_DECIMAL64, TYPE_DECIMAL128I, 
TYPE_DECIMAL256, TYPE_VARCHAR,
+                               TYPE_DATEV2, TYPE_DATETIMEV2, 
TYPE_TIMESTAMP_NS, TYPE_TIMESTAMPTZ,
+                               TYPE_IPV4, TYPE_IPV6>;
 
 AggregateFunctionPtr create_aggregate_function_topn_array(const std::string& 
name,
                                                           const DataTypes& 
argument_types,
diff --git a/be/src/exprs/aggregate/aggregate_function_topn_weighted.cpp 
b/be/src/exprs/aggregate/aggregate_function_topn_weighted.cpp
index dc955320d32..39f13689e3b 100644
--- a/be/src/exprs/aggregate/aggregate_function_topn_weighted.cpp
+++ b/be/src/exprs/aggregate/aggregate_function_topn_weighted.cpp
@@ -27,10 +27,12 @@ using ImplWeight = AggregateFunctionTopNImplWeight<T, 
false>;
 template <PrimitiveType T>
 using ImplWeightWithDefault = AggregateFunctionTopNImplWeight<T, true>;
 
-using topn_weighted_creator = creator_with_type_list<
-        TYPE_TINYINT, TYPE_SMALLINT, TYPE_INT, TYPE_BIGINT, TYPE_LARGEINT, 
TYPE_FLOAT, TYPE_DOUBLE,
-        TYPE_DECIMAL32, TYPE_DECIMAL64, TYPE_DECIMAL128I, TYPE_DECIMAL256, 
TYPE_VARCHAR,
-        TYPE_DATEV2, TYPE_DATETIMEV2, TYPE_TIMESTAMP_NS, TYPE_TIMESTAMPTZ, 
TYPE_IPV4, TYPE_IPV6>;
+using topn_weighted_creator =
+        creator_with_type_list<TYPE_BOOLEAN, TYPE_TINYINT, TYPE_SMALLINT, 
TYPE_INT, TYPE_BIGINT,
+                               TYPE_LARGEINT, TYPE_FLOAT, TYPE_DOUBLE, 
TYPE_DECIMAL32,
+                               TYPE_DECIMAL64, TYPE_DECIMAL128I, 
TYPE_DECIMAL256, TYPE_VARCHAR,
+                               TYPE_DATEV2, TYPE_DATETIMEV2, 
TYPE_TIMESTAMP_NS, TYPE_TIMESTAMPTZ,
+                               TYPE_IPV4, TYPE_IPV6>;
 
 AggregateFunctionPtr create_aggregate_function_topn_weighted(const 
std::string& name,
                                                              const DataTypes& 
argument_types,
diff --git a/be/test/exprs/aggregate/agg_topn_boolean_test.cpp 
b/be/test/exprs/aggregate/agg_topn_boolean_test.cpp
new file mode 100644
index 00000000000..ea811ac2f29
--- /dev/null
+++ b/be/test/exprs/aggregate/agg_topn_boolean_test.cpp
@@ -0,0 +1,117 @@
+// 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.
+
+#include <gtest/gtest.h>
+
+#include "agent/be_exec_version_manager.h"
+#include "core/data_type/data_type_array.h"
+#include "core/data_type/data_type_nullable.h"
+#include "core/data_type/data_type_number.h"
+#include "exprs/aggregate/agg_function_test.h"
+#include "exprs/aggregate/aggregate_function_simple_factory.h"
+
+namespace doris {
+
+struct AggregateFunctionTopNBooleanTest : public AggregateFunctiontest {
+    void check_topn(ColumnWithTypeAndName values, const std::vector<Int64>& 
weights, int top_num,
+                    const Field& expected_array, bool weighted, bool expanded) 
{
+        const std::string name = weighted ? "topn_weighted" : "topn_array";
+        SCOPED_TRACE(name + (expanded ? " with expansion rate" : " without 
expansion rate"));
+        SCOPED_TRACE(top_num);
+        Block block({values});
+        DataTypes argument_types {values.type};
+        if (weighted) {
+            auto weight_column = 
ColumnHelper::create_column_with_name<DataTypeInt64>(weights);
+            block.insert(weight_column);
+            argument_types.push_back(weight_column.type);
+        }
+        auto top_column = ColumnHelper::create_column_with_name<DataTypeInt32>(
+                std::vector<Int32>(values.column->size(), top_num));
+        block.insert(top_column);
+        argument_types.push_back(top_column.type);
+        if (expanded) {
+            auto rate_column = 
ColumnHelper::create_column_with_name<DataTypeInt32>(
+                    std::vector<Int32>(values.column->size(), 50));
+            block.insert(rate_column);
+            argument_types.push_back(rate_column.type);
+        }
+
+        const bool nullable = values.type->is_nullable();
+        DataTypePtr result_type =
+                
std::make_shared<DataTypeArray>(make_nullable(std::make_shared<DataTypeBool>()));
+        if (nullable) {
+            result_type = make_nullable(result_type);
+        }
+        auto function = AggregateFunctionSimpleFactory::instance().get(
+                name, argument_types, result_type, nullable,
+                BeExecVersionManager::get_newest_version());
+        ASSERT_NE(function, nullptr);
+        EXPECT_TRUE(function->get_return_type()->equals(*result_type));
+
+        auto expected_column = result_type->create_column();
+        expected_column->insert(expected_array);
+        create_agg(name, nullable, argument_types, result_type);
+        execute(block, ColumnWithTypeAndName(std::move(expected_column), 
result_type, "expected"));
+    }
+
+    static Field boolean_array(std::initializer_list<UInt8> values) {
+        Array array;
+        for (auto value : values) {
+            array.push_back(Field::create_field<TYPE_BOOLEAN>(value));
+        }
+        return Field::create_field<TYPE_ARRAY>(std::move(array));
+    }
+};
+
+TEST_F(AggregateFunctionTopNBooleanTest, ValuesAndLimits) {
+    for (bool weighted : {false, true}) {
+        for (bool expanded : {false, true}) {
+            auto values = 
ColumnHelper::create_column_with_name<DataTypeBool>({false, false, true});
+            check_topn(values, {1, 1, 5}, 1, boolean_array({weighted}), 
weighted, expanded);
+            for (int top_num : {2, 3}) {
+                check_topn(values, {1, 1, 5}, top_num, 
boolean_array({weighted, !weighted}),
+                           weighted, expanded);
+            }
+        }
+    }
+}
+
+TEST_F(AggregateFunctionTopNBooleanTest, NullableValues) {
+    for (bool weighted : {false, true}) {
+        for (bool expanded : {false, true}) {
+            auto values = 
ColumnHelper::create_nullable_column_with_name<DataTypeBool>(
+                    {false, false, true, true}, {0, 0, 0, 1});
+            check_topn(values, {1, 1, 5, 100}, 2, boolean_array({weighted, 
!weighted}), weighted,
+                       expanded);
+
+            auto nulls = 
ColumnHelper::create_nullable_column_with_name<DataTypeBool>({false, true},
+                                                                               
       {1, 1});
+            check_topn(nulls, {1, 5}, 2, Field(), weighted, expanded);
+        }
+    }
+}
+
+TEST_F(AggregateFunctionTopNBooleanTest, Ties) {
+    for (bool weighted : {false, true}) {
+        for (bool expanded : {false, true}) {
+            auto values = 
ColumnHelper::create_column_with_name<DataTypeBool>({false, true});
+            check_topn(values, {3, 3}, 2, boolean_array({true, false}), 
weighted, expanded);
+        }
+    }
+}
+
+} // namespace doris
diff --git 
a/regression-test/data/nereids_function_p0/agg_function/topn/topn_boolean.out 
b/regression-test/data/nereids_function_p0/agg_function/topn/topn_boolean.out
new file mode 100644
index 00000000000..a83bb17bdb2
--- /dev/null
+++ 
b/regression-test/data/nereids_function_p0/agg_function/topn/topn_boolean.out
@@ -0,0 +1,27 @@
+-- This file is automatically generated. You should know what you did if you 
want to edit this
+-- !literals --
+[1]    [0]     [1]     [0]
+
+-- !null_literals --
+\N     \N      \N      \N
+
+-- !weighted --
+[1]    [1]     [1, 0]  [1, 0]  [1, 0]  [1, 0]
+
+-- !array --
+[0]    [0]     [0, 1]  [0, 1]  [0, 1]  [0, 1]
+
+-- !grouped --
+\N     \N      \N      \N      \N
+false  [0]     [0]     [0]     [0]
+true   [1]     [1]     [1]     [1]
+
+-- !all_null --
+\N     \N      \N      \N
+
+-- !empty --
+\N     \N      \N      \N
+
+-- !ties --
+[1, 0] [1, 0]  [1, 0]  [1, 0]
+
diff --git 
a/regression-test/suites/nereids_function_p0/agg_function/topn/topn_boolean.groovy
 
b/regression-test/suites/nereids_function_p0/agg_function/topn/topn_boolean.groovy
new file mode 100644
index 00000000000..72b78245638
--- /dev/null
+++ 
b/regression-test/suites/nereids_function_p0/agg_function/topn/topn_boolean.groovy
@@ -0,0 +1,78 @@
+// 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.
+
+suite("topn_boolean") {
+    order_qt_literals """
+        SELECT topn_weighted(TRUE, 1, 2), topn_weighted(FALSE, 1, 2, 50),
+               topn_array(TRUE, 2), topn_array(FALSE, 2, 50)
+    """
+    order_qt_null_literals """
+        SELECT topn_weighted(CAST(NULL AS BOOLEAN), 1, 2),
+               topn_weighted(CAST(NULL AS BOOLEAN), 1, 2, 50),
+               topn_array(CAST(NULL AS BOOLEAN), 2),
+               topn_array(CAST(NULL AS BOOLEAN), 2, 50)
+    """
+
+    sql "DROP TABLE IF EXISTS test_topn_boolean"
+    sql """
+        CREATE TABLE test_topn_boolean (
+            id INT,
+            flag BOOLEAN,
+            weight BIGINT
+        ) DUPLICATE KEY(id)
+        DISTRIBUTED BY HASH(id) BUCKETS 4
+        PROPERTIES ("replication_num" = "1")
+    """
+    sql """
+        INSERT INTO test_topn_boolean VALUES
+        (1, FALSE, 1), (2, FALSE, 1), (3, TRUE, 5),
+        (4, NULL, 100), (5, TRUE, NULL)
+    """
+
+    order_qt_weighted """
+        SELECT topn_weighted(flag, weight, 1), topn_weighted(flag, weight, 1, 
50),
+               topn_weighted(flag, weight, 2), topn_weighted(flag, weight, 2, 
50),
+               topn_weighted(flag, weight, 3), topn_weighted(flag, weight, 3, 
50)
+        FROM test_topn_boolean
+    """
+    order_qt_array """
+        SELECT topn_array(flag, 1), topn_array(flag, 1, 50),
+               topn_array(flag, 2), topn_array(flag, 2, 50),
+               topn_array(flag, 3), topn_array(flag, 3, 50)
+        FROM test_topn_boolean WHERE weight IS NOT NULL
+    """
+    order_qt_grouped """
+        SELECT flag, topn_weighted(flag, weight, 2), topn_weighted(flag, 
weight, 2, 50),
+               topn_array(flag, 2), topn_array(flag, 2, 50)
+        FROM test_topn_boolean GROUP BY flag
+    """
+    order_qt_all_null """
+        SELECT topn_weighted(flag, weight, 2), topn_weighted(flag, weight, 2, 
50),
+               topn_array(flag, 2), topn_array(flag, 2, 50)
+        FROM test_topn_boolean WHERE flag IS NULL
+    """
+    order_qt_empty """
+        SELECT topn_weighted(flag, weight, 2), topn_weighted(flag, weight, 2, 
50),
+               topn_array(flag, 2), topn_array(flag, 2, 50)
+        FROM test_topn_boolean WHERE id < 0
+    """
+    order_qt_ties """
+        SELECT topn_weighted(flag, 1, 2), topn_weighted(flag, 1, 2, 50),
+               topn_array(flag, 2), topn_array(flag, 2, 50)
+        FROM test_topn_boolean WHERE id IN (1, 3)
+    """
+}


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

Reply via email to