This is an automated email from the ASF dual-hosted git repository.
yiguolei pushed a commit to branch branch-4.2
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-4.2 by this push:
new 21df1d0b5cb branch-4.2: [fix](be) Support TIMEV2 in topn_array #68845
(#69654)
21df1d0b5cb is described below
commit 21df1d0b5cb9fd5ea6084db1ae89d835a634b61e
Author: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Mon Nov 2 09:17:31 2026 +0800
branch-4.2: [fix](be) Support TIMEV2 in topn_array #68845 (#69654)
Cherry-picked from #68845
Co-authored-by: TengJianPing <[email protected]>
---
.../aggregate/aggregate_function_topn_array.cpp | 4 +-
be/test/exprs/aggregate/agg_topn_timev2_test.cpp | 117 +++++++++++++++++++++
.../agg_function/topn/topn_array_timev2.out | 64 +++++++++++
.../agg_function/topn/topn_array_timev2.groovy | 76 +++++++++++++
4 files changed, 259 insertions(+), 2 deletions(-)
diff --git a/be/src/exprs/aggregate/aggregate_function_topn_array.cpp
b/be/src/exprs/aggregate/aggregate_function_topn_array.cpp
index 08829a1db5c..96ee87ca7be 100644
--- a/be/src/exprs/aggregate/aggregate_function_topn_array.cpp
+++ b/be/src/exprs/aggregate/aggregate_function_topn_array.cpp
@@ -32,8 +32,8 @@ 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, TYPE_UUID>;
+ TYPE_DATEV2, TYPE_DATETIMEV2, TYPE_TIMEV2,
TYPE_TIMESTAMP_NS,
+ TYPE_TIMESTAMPTZ, TYPE_IPV4, TYPE_IPV6,
TYPE_UUID>;
AggregateFunctionPtr create_aggregate_function_topn_array(const std::string&
name,
const DataTypes&
argument_types,
diff --git a/be/test/exprs/aggregate/agg_topn_timev2_test.cpp
b/be/test/exprs/aggregate/agg_topn_timev2_test.cpp
new file mode 100644
index 00000000000..1d003dbb75c
--- /dev/null
+++ b/be/test/exprs/aggregate/agg_topn_timev2_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 "core/data_type/data_type_time.h"
+#include "core/value/time_value.h"
+#include "exprs/aggregate/agg_function_test.h"
+#include "exprs/aggregate/aggregate_function_simple_factory.h"
+
+namespace doris {
+
+struct AggregateFunctionTopNTimeV2Test : public AggregateFunctiontest {
+ void check_topn(const ColumnWithTypeAndName& values, int top_num, const
Field& expected_array,
+ bool expanded) {
+ SCOPED_TRACE(values.type->get_name());
+ SCOPED_TRACE(expanded);
+ SCOPED_TRACE(top_num);
+ Block block({values});
+ auto top_column = ColumnHelper::create_column_with_name<DataTypeInt32>(
+ std::vector<Int32>(values.column->size(), top_num));
+ block.insert(top_column);
+ DataTypes argument_types {values.type, top_column.type};
+ if (expanded) {
+ auto rate_column =
ColumnHelper::create_column_with_name<DataTypeInt32>(
+ std::vector<Int32>(values.column->size(), 100));
+ 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(values.type));
+ if (nullable) {
+ result_type = make_nullable(result_type);
+ }
+ auto function = AggregateFunctionSimpleFactory::instance().get(
+ "topn_array", 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("topn_array", nullable, argument_types, result_type);
+ execute(block, ColumnWithTypeAndName(std::move(expected_column),
result_type, "expected"));
+ }
+
+ static Field time_array(std::initializer_list<Float64> values) {
+ Array array;
+ for (auto value : values) {
+ array.push_back(Field::create_field<TYPE_TIMEV2>(value));
+ }
+ return Field::create_field<TYPE_ARRAY>(std::move(array));
+ }
+};
+
+TEST_F(AggregateFunctionTopNTimeV2Test, PrecisionAndLimits) {
+ const Float64 large = TimeValue::make_time(838, 59, 58, 0);
+ Float64 step = TimeValue::ONE_SECOND_MICROSECONDS;
+ for (UInt32 scale = 0; scale <= DataTypeTimeV2::MAX_SCALE; ++scale, step
/= 10) {
+ for (bool expanded : {false, true}) {
+ ColumnWithTypeAndName
values(ColumnHelper::create_column<DataTypeTimeV2>(
+ {large, large, large + step,
-step}),
+
std::make_shared<DataTypeTimeV2>(scale), "values");
+ check_topn(values, 1, time_array({large}), expanded);
+ check_topn(values, 5, time_array({large, large + step, -step}),
expanded);
+ }
+ }
+}
+
+TEST_F(AggregateFunctionTopNTimeV2Test, NegativeValuesAndZero) {
+ const Float64 minimum = TimeValue::make_time(838, 59, 59, 0, true);
+ for (bool expanded : {false, true}) {
+ ColumnWithTypeAndName values(
+ ColumnHelper::create_column<DataTypeTimeV2>({minimum,
-1000000, 0}),
+ std::make_shared<DataTypeTimeV2>(6), "values");
+ check_topn(values, 3, time_array({0, -1000000, minimum}), expanded);
+ }
+}
+
+TEST_F(AggregateFunctionTopNTimeV2Test, NullableValues) {
+ Float64 step = TimeValue::ONE_SECOND_MICROSECONDS;
+ for (UInt32 scale = 0; scale <= DataTypeTimeV2::MAX_SCALE; ++scale, step
/= 10) {
+ for (bool expanded : {false, true}) {
+ auto type = make_nullable(std::make_shared<DataTypeTimeV2>(scale));
+ ColumnWithTypeAndName
values(ColumnHelper::create_nullable_column<DataTypeTimeV2>(
+ {step, step, -step, 0}, {0,
0, 0, 1}),
+ type, "values");
+ check_topn(values, 2, time_array({step, -step}), expanded);
+
+ ColumnWithTypeAndName nulls(
+ ColumnHelper::create_nullable_column<DataTypeTimeV2>({0,
-step}, {1, 1}), type,
+ "values");
+ check_topn(nulls, 2, Field(), expanded);
+ }
+ }
+}
+
+} // namespace doris
diff --git
a/regression-test/data/nereids_function_p0/agg_function/topn/topn_array_timev2.out
b/regression-test/data/nereids_function_p0/agg_function/topn/topn_array_timev2.out
new file mode 100644
index 00000000000..22277553830
--- /dev/null
+++
b/regression-test/data/nereids_function_p0/agg_function/topn/topn_array_timev2.out
@@ -0,0 +1,64 @@
+-- This file is automatically generated. You should know what you did if you
want to edit this
+-- !reproduction --
+["02:00:00", "01:00:00"] ["02:00:00", "01:00:00"]
+
+-- !timev2_0 --
+["01:00:00"] ["01:00:00"] ["01:00:00", "-12:34:56"] ["01:00:00",
"-12:34:56"] ["01:00:00", "-12:34:56", "838:59:59", "27:00:01",
"02:00:01", "-838:59:59"] ["01:00:00", "-12:34:56", "838:59:59", "27:00:01",
"02:00:01", "-838:59:59"] 01:00:00
+
+-- !grouped_0 --
+1 ["01:00:00", "02:00:01"] ["01:00:00", "02:00:01"]
+2 ["-12:34:56", "838:59:59"] ["-12:34:56", "838:59:59"]
+3 \N \N
+
+-- !distinct_0 --
+["838:59:59", "27:00:01", "02:00:01", "01:00:00", "-12:34:56", "-838:59:59"]
["838:59:59", "27:00:01", "02:00:01", "01:00:00", "-12:34:56", "-838:59:59"]
+
+-- !state_0 --
+["01:00:00", "-12:34:56"] ["01:00:00", "-12:34:56"]
+
+-- !null_0 --
+\N \N
+
+-- !empty_0 --
+\N \N
+
+-- !timev2_3 --
+["01:00:00.123"] ["01:00:00.123"] ["01:00:00.123",
"-12:34:56.123"] ["01:00:00.123", "-12:34:56.123"] ["01:00:00.123",
"-12:34:56.123", "838:59:59.000", "27:00:00.654", "02:00:00.654",
"-838:59:59.000"] ["01:00:00.123", "-12:34:56.123", "838:59:59.000",
"27:00:00.654", "02:00:00.654", "-838:59:59.000"] 01:00:00.123
+
+-- !grouped_3 --
+1 ["01:00:00.123", "02:00:00.654"] ["01:00:00.123", "02:00:00.654"]
+2 ["-12:34:56.123", "838:59:59.000"] ["-12:34:56.123",
"838:59:59.000"]
+3 \N \N
+
+-- !distinct_3 --
+["838:59:59.000", "27:00:00.654", "02:00:00.654", "01:00:00.123",
"-12:34:56.123", "-838:59:59.000"] ["838:59:59.000", "27:00:00.654",
"02:00:00.654", "01:00:00.123", "-12:34:56.123", "-838:59:59.000"]
+
+-- !state_3 --
+["01:00:00.123", "-12:34:56.123"] ["01:00:00.123", "-12:34:56.123"]
+
+-- !null_3 --
+\N \N
+
+-- !empty_3 --
+\N \N
+
+-- !timev2_6 --
+["01:00:00.123456"] ["01:00:00.123456"] ["01:00:00.123456",
"-12:34:56.123456"] ["01:00:00.123456", "-12:34:56.123456"] ["01:00:00.123456",
"-12:34:56.123456", "838:59:59.000000", "27:00:00.654321", "02:00:00.654321",
"-838:59:59.000000"] ["01:00:00.123456", "-12:34:56.123456",
"838:59:59.000000", "27:00:00.654321", "02:00:00.654321", "-838:59:59.000000"]
01:00:00.123456
+
+-- !grouped_6 --
+1 ["01:00:00.123456", "02:00:00.654321"] ["01:00:00.123456",
"02:00:00.654321"]
+2 ["-12:34:56.123456", "838:59:59.000000"] ["-12:34:56.123456",
"838:59:59.000000"]
+3 \N \N
+
+-- !distinct_6 --
+["838:59:59.000000", "27:00:00.654321", "02:00:00.654321", "01:00:00.123456",
"-12:34:56.123456", "-838:59:59.000000"] ["838:59:59.000000",
"27:00:00.654321", "02:00:00.654321", "01:00:00.123456", "-12:34:56.123456",
"-838:59:59.000000"]
+
+-- !state_6 --
+["01:00:00.123456", "-12:34:56.123456"] ["01:00:00.123456",
"-12:34:56.123456"]
+
+-- !null_6 --
+\N \N
+
+-- !empty_6 --
+\N \N
+
diff --git
a/regression-test/suites/nereids_function_p0/agg_function/topn/topn_array_timev2.groovy
b/regression-test/suites/nereids_function_p0/agg_function/topn/topn_array_timev2.groovy
new file mode 100644
index 00000000000..3b5702d65e1
--- /dev/null
+++
b/regression-test/suites/nereids_function_p0/agg_function/topn/topn_array_timev2.groovy
@@ -0,0 +1,76 @@
+// 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_array_timev2") {
+ order_qt_reproduction """
+ SELECT topn_array(v, 2), topn_array(v, 2, 100) FROM (
+ SELECT CAST('01:00:00' AS TIME) v
+ UNION ALL SELECT CAST('02:00:00' AS TIME)
+ ) t
+ """
+
+ sql "DROP TABLE IF EXISTS test_topn_array_timev2"
+ sql """
+ CREATE TABLE test_topn_array_timev2 (
+ id INT,
+ g INT,
+ value_string STRING
+ ) DUPLICATE KEY(id)
+ DISTRIBUTED BY HASH(id) BUCKETS 3
+ PROPERTIES ("replication_num" = "1")
+ """
+ sql """
+ INSERT INTO test_topn_array_timev2 VALUES
+ (1, 1, '01:00:00.123456'), (2, 1, '01:00:00.123456'),
+ (3, 1, '02:00:00.654321'), (4, 2, '-12:34:56.123456'),
+ (5, 2, '-12:34:56.123456'), (6, 2, '27:00:00.654321'),
+ (7, 2, '838:59:59'), (8, 2, '-838:59:59'), (9, 1, NULL), (10, 3,
NULL)
+ """
+
+ [0, 3, 6].each { scale ->
+ "order_qt_timev2_${scale}" """
+ SELECT topn_array(v, 1), topn_array(v, 1, 100),
+ topn_array(v, 2), topn_array(v, 2, 100),
+ topn_array(v, 10), topn_array(v, 10, 100),
+ topn_array(v, 2)[1]
+ FROM (SELECT CAST(value_string AS TIME(${scale})) v FROM
test_topn_array_timev2) t
+ """
+ "order_qt_grouped_${scale}" """
+ SELECT g, topn_array(v, 2), topn_array(v, 2, 100)
+ FROM (SELECT g, CAST(value_string AS TIME(${scale})) v FROM
test_topn_array_timev2) t
+ GROUP BY g
+ """
+ "order_qt_distinct_${scale}" """
+ SELECT topn_array(DISTINCT v, 10), topn_array(DISTINCT v, 10, 100)
+ FROM (SELECT CAST(value_string AS TIME(${scale})) v FROM
test_topn_array_timev2) t
+ """
+ "order_qt_state_${scale}" """
+ SELECT topn_array_merge(topn_array_state(CAST(value_string AS
TIME(${scale})), 2)),
+ topn_array_merge(topn_array_state(CAST(value_string AS
TIME(${scale})), 2, 100))
+ FROM test_topn_array_timev2
+ """
+ "order_qt_null_${scale}" """
+ SELECT topn_array(CAST(NULL AS TIME(${scale})), 2),
+ topn_array(CAST(NULL AS TIME(${scale})), 2, 100)
+ """
+ "order_qt_empty_${scale}" """
+ SELECT topn_array(v, 2), topn_array(v, 2, 100)
+ FROM (SELECT CAST(value_string AS TIME(${scale})) v
+ FROM test_topn_array_timev2 WHERE id < 0) t
+ """
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]