This is an automated email from the ASF dual-hosted git repository.
csun5285 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 84eff3388bf [fix](function) Sum integers exactly in array_avg (#68632)
84eff3388bf is described below
commit 84eff3388bfa300494e727f23b8b331eac4a6129
Author: Chenyang Sun <[email protected]>
AuthorDate: Fri Oct 9 17:18:15 2026 +0800
[fix](function) Sum integers exactly in array_avg (#68632)
### What problem does this PR solve?
Issue Number: close #xxx
Related PR: #xxx
Problem Summary:
```sql
SELECT array_avg(array(9223372036854775807, 1, -9223372036854775807));
-- before: 0
-- after: 0.3333333333333333
```
### Release note
None
### Check List (For Author)
- Test <!-- At least one of them must be included. -->
- [ ] Regression test
- [ ] Unit Test
- [ ] Manual test (add detailed scripts or steps below)
- [ ] No need to test or manual test. Explain why:
- [ ] This is a refactor/code format and no logic has been changed.
- [ ] Previous test can cover this change.
- [ ] No code files have been changed.
- [ ] Other reason <!-- Add your reason? -->
- Behavior changed:
- [ ] No.
- [ ] Yes. <!-- Explain the behavior change -->
- Does this need documentation?
- [ ] No.
- [ ] Yes. <!-- Add document PR link here. eg:
https://github.com/apache/doris-website/pull/1214 -->
### Check List (For Reviewer who merge this PR)
- [ ] Confirm the release note
- [ ] Confirm test cases
- [ ] Confirm document
- [ ] Add branch pick label <!-- Add branch pick label that this PR
should merge into -->
Co-authored-by: Claude Opus 5.5 <[email protected]>
---
be/src/exprs/aggregate/aggregate_function_avg.cpp | 17 +-----
be/src/exprs/aggregate/aggregate_function_avg.h | 15 ++++++
.../function/array/function_array_aggregation.cpp | 3 +-
.../function/function_array_aggregation_test.cpp | 17 ++++++
.../data/doc/sql-manual/ArrayNullsafe.out | 2 +-
.../nereids_function_p0/scalar_function/Array1.out | 24 ++++-----
.../array_functions/test_array_avg_integer_sum.out | 21 ++++++++
.../test_array_avg_integer_sum.groovy | 60 ++++++++++++++++++++++
8 files changed, 130 insertions(+), 29 deletions(-)
diff --git a/be/src/exprs/aggregate/aggregate_function_avg.cpp
b/be/src/exprs/aggregate/aggregate_function_avg.cpp
index de5c15b529b..fa2e7860aae 100644
--- a/be/src/exprs/aggregate/aggregate_function_avg.cpp
+++ b/be/src/exprs/aggregate/aggregate_function_avg.cpp
@@ -27,25 +27,12 @@
namespace doris {
-constexpr PrimitiveType result_type(PrimitiveType T) {
- if (T == TYPE_LARGEINT || T == TYPE_BIGINT) {
- return TYPE_LARGEINT;
- } else if (is_int_or_bool(T)) {
- return TYPE_BIGINT;
- } else if (is_float_or_double(T) || is_time_type(T)) {
- return TYPE_DOUBLE;
- } else if (is_decimalv3(T) && T != TYPE_DECIMAL256) {
- return TYPE_DECIMAL128I;
- } else {
- return T;
- }
-}
-
// TODO: use result type got from FE plan
template <PrimitiveType T>
struct Avg {
static constexpr PrimitiveType ResultPType = T == TYPE_DECIMALV2 ? T :
TYPE_DOUBLE;
- using Function = AggregateFunctionAvg<T, ResultPType,
AggregateFunctionAvgData<result_type(T)>>;
+ using Function =
+ AggregateFunctionAvg<T, ResultPType,
AggregateFunctionAvgData<avg_sum_type(T)>>;
};
template <PrimitiveType T>
diff --git a/be/src/exprs/aggregate/aggregate_function_avg.h
b/be/src/exprs/aggregate/aggregate_function_avg.h
index 2ea1ba8c020..83eab79215e 100644
--- a/be/src/exprs/aggregate/aggregate_function_avg.h
+++ b/be/src/exprs/aggregate/aggregate_function_avg.h
@@ -52,6 +52,21 @@ class DataTypeNumber;
template <PrimitiveType T>
class ColumnVector;
+// avg() adds up the values in this type and divides only at the end, so
integers keep all digits.
+constexpr PrimitiveType avg_sum_type(PrimitiveType T) {
+ if (T == TYPE_LARGEINT || T == TYPE_BIGINT) {
+ return TYPE_LARGEINT;
+ } else if (is_int_or_bool(T)) {
+ return TYPE_BIGINT;
+ } else if (is_float_or_double(T) || is_time_type(T)) {
+ return TYPE_DOUBLE;
+ } else if (is_decimalv3(T) && T != TYPE_DECIMAL256) {
+ return TYPE_DECIMAL128I;
+ } else {
+ return T;
+ }
+}
+
template <PrimitiveType T>
struct AggregateFunctionAvgData {
using ResultType = typename PrimitiveTypeTraits<T>::CppType;
diff --git a/be/src/exprs/function/array/function_array_aggregation.cpp
b/be/src/exprs/function/array/function_array_aggregation.cpp
index d8cdddd7d1d..a3e8c0ebf01 100644
--- a/be/src/exprs/function/array/function_array_aggregation.cpp
+++ b/be/src/exprs/function/array/function_array_aggregation.cpp
@@ -90,7 +90,8 @@ struct AggregateFunctionTraits<AggregateOperation::AVERAGE> {
struct TypeTraits {
static constexpr PrimitiveType ResultType =
Element == TYPE_DECIMALV2 ? TYPE_DECIMALV2 : TYPE_DOUBLE;
- using AggregateDataType = AggregateFunctionAvgData<ResultType>;
+ // Add up the values in the same type as avg(). A double sum loses
digits of large integers.
+ using AggregateDataType =
AggregateFunctionAvgData<avg_sum_type(Element)>;
using Function = AggregateFunctionAvg<Element, ResultType,
AggregateDataType>;
static_assert(std::is_same_v<typename
PrimitiveTypeTraits<ResultType>::CppType,
typename Function::ResultType>,
diff --git a/be/test/exprs/function/function_array_aggregation_test.cpp
b/be/test/exprs/function/function_array_aggregation_test.cpp
index 9a99e482876..2427d053165 100644
--- a/be/test/exprs/function/function_array_aggregation_test.cpp
+++ b/be/test/exprs/function/function_array_aggregation_test.cpp
@@ -16,6 +16,7 @@
// under the License.
#include <cstddef>
+#include <limits>
#include <string>
#include <utility>
#include <vector>
@@ -336,6 +337,22 @@ TEST(VFunctionArrayAggregationTest,
TestArrayAverageNullable) {
func_name, data_set, PrimitiveType::TYPE_DOUBLE,
PrimitiveType::TYPE_DOUBLE, true));
}
+TEST(VFunctionArrayAggregationTest, TestArrayAverageLargeIntegers) {
+ const std::string func_name = "array_avg";
+ // The sum is 1. A double sum loses the 1 next to the large values and
gives 0.
+ std::vector<std::pair<std::vector<AnyValue<Int64>>, AnyValue<double>>>
bigint_data_set = {
+ {{std::numeric_limits<Int64>::max(), 1,
-std::numeric_limits<Int64>::max()}, 1.0 / 3},
+ };
+ static_cast<void>(check_function_array_wrapper<DataTypeInt64,
DataTypeFloat64>(
+ func_name, bigint_data_set, PrimitiveType::TYPE_BIGINT,
PrimitiveType::TYPE_DOUBLE));
+ std::vector<std::pair<std::vector<AnyValue<Int128>>, AnyValue<double>>>
largeint_data_set = {
+ {{std::numeric_limits<Int128>::max(), 1,
-std::numeric_limits<Int128>::max()}, 1.0 / 3},
+ };
+ static_cast<void>(check_function_array_wrapper<DataTypeInt128,
DataTypeFloat64>(
+ func_name, largeint_data_set, PrimitiveType::TYPE_LARGEINT,
+ PrimitiveType::TYPE_DOUBLE));
+}
+
TEST(VFunctionArrayAggregationTest, TestArrayProduct) {
const std::string func_name = "array_product";
IntDataSet data_set = {
diff --git a/regression-test/data/doc/sql-manual/ArrayNullsafe.out
b/regression-test/data/doc/sql-manual/ArrayNullsafe.out
index 64a056a2cdf..85431c5197e 100644
--- a/regression-test/data/doc/sql-manual/ArrayNullsafe.out
+++ b/regression-test/data/doc/sql-manual/ArrayNullsafe.out
@@ -879,7 +879,7 @@ false
\N
-- !sql_array_avg --
-1.7014118346046923e+38
+5.671372782015641e+37
3
2
\N
diff --git
a/regression-test/data/nereids_function_p0/scalar_function/Array1.out
b/regression-test/data/nereids_function_p0/scalar_function/Array1.out
index eb0b6863cb5..efd1e7c4961 100644
--- a/regression-test/data/nereids_function_p0/scalar_function/Array1.out
+++ b/regression-test/data/nereids_function_p0/scalar_function/Array1.out
@@ -123,8 +123,8 @@
\N
\N
\N
-0
-0
+-0.5
+-0.5
0
7.5
7.875
@@ -149,8 +149,8 @@
\N
\N
\N
-0
-0
+-0.5
+-0.5
0
7.5
7.875
@@ -172,10 +172,10 @@
\N
\N
\N
+-0.5
-9.055674363474186e+18
-9.223372036854776e+18
0
-0
3037000499.5
7.5
7.875
@@ -198,10 +198,10 @@
\N
\N
\N
+-0.5
-9.055674363474186e+18
-9.223372036854776e+18
0
-0
3037000499.5
7.5
7.875
@@ -25291,8 +25291,8 @@ true
\N
\N
\N
-0
-0
+-0.5
+-0.5
0
7.5
7.875
@@ -25317,8 +25317,8 @@ true
\N
\N
\N
-0
-0
+-0.5
+-0.5
0
7.5
7.875
@@ -25340,10 +25340,10 @@ true
\N
\N
\N
+-0.5
-9.055674363474186e+18
-9.223372036854776e+18
0
-0
3037000499.5
7.5
7.875
@@ -25366,10 +25366,10 @@ true
\N
\N
\N
+-0.5
-9.055674363474186e+18
-9.223372036854776e+18
0
-0
3037000499.5
7.5
7.875
diff --git
a/regression-test/data/query_p0/sql_functions/array_functions/test_array_avg_integer_sum.out
b/regression-test/data/query_p0/sql_functions/array_functions/test_array_avg_integer_sum.out
new file mode 100644
index 00000000000..7bcb966e22f
--- /dev/null
+++
b/regression-test/data/query_p0/sql_functions/array_functions/test_array_avg_integer_sum.out
@@ -0,0 +1,21 @@
+-- This file is automatically generated. You should know what you did if you
want to edit this
+-- !const --
+0.3333333333333333 0.3333333333333333
+
+-- !column --
+1 0.3333333333333333 0.3333333333333333
+2 0.3333333333333333 0.3333333333333333
+3 2 2.3333333333333335
+4 \N \N
+5 \N \N
+
+-- !same_as_avg_bigint --
+1 0.3333333333333333
+2 0.3333333333333333
+3 2
+
+-- !same_as_avg_largeint --
+1 0.3333333333333333
+2 0.3333333333333333
+3 2.3333333333333335
+
diff --git
a/regression-test/suites/query_p0/sql_functions/array_functions/test_array_avg_integer_sum.groovy
b/regression-test/suites/query_p0/sql_functions/array_functions/test_array_avg_integer_sum.groovy
new file mode 100644
index 00000000000..f746b31886a
--- /dev/null
+++
b/regression-test/suites/query_p0/sql_functions/array_functions/test_array_avg_integer_sum.groovy
@@ -0,0 +1,60 @@
+// 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("test_array_avg_integer_sum") {
+ // array_avg adds up integers in the same type as avg(), so the large
values cancel out
+ // and the average of the sum 1 is 1/3.
+ order_qt_const """
+ SELECT array_avg(array(9223372036854775807, 1, -9223372036854775807)),
+ array_avg(array(170141183460469231731687303715884105727, 1,
+ -170141183460469231731687303715884105727))
+ """
+
+ sql """ DROP TABLE IF EXISTS test_array_avg_integer_sum """
+ sql """
+ CREATE TABLE test_array_avg_integer_sum (
+ id INT,
+ b ARRAY<BIGINT>,
+ l ARRAY<LARGEINT>
+ ) DUPLICATE KEY(id)
+ DISTRIBUTED BY HASH(id) BUCKETS 1
+ PROPERTIES ("replication_num" = "1")
+ """
+ sql """
+ INSERT INTO test_array_avg_integer_sum VALUES
+ (1, array(9223372036854775807, 1, -9223372036854775807),
+ array(170141183460469231731687303715884105727, 1,
+ -170141183460469231731687303715884105727)),
+ (2, array(9223372036854775807, NULL, 1, -9223372036854775807),
+ array(170141183460469231731687303715884105727, NULL, 1,
+ -170141183460469231731687303715884105727)),
+ (3, array(1, 2, 3), array(1, 2, 4)),
+ (4, array(), array()),
+ (5, NULL, NULL)
+ """
+ order_qt_column """
+ SELECT id, array_avg(b), array_avg(l) FROM test_array_avg_integer_sum
+ """
+
+ // avg() over the same elements gives the same result.
+ order_qt_same_as_avg_bigint """
+ SELECT id, avg(x) FROM test_array_avg_integer_sum LATERAL VIEW
explode(b) t AS x GROUP BY id
+ """
+ order_qt_same_as_avg_largeint """
+ SELECT id, avg(x) FROM test_array_avg_integer_sum LATERAL VIEW
explode(l) t AS x GROUP BY id
+ """
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]