This is an automated email from the ASF dual-hosted git repository.
morrysnow pushed a commit to branch branch-3.1
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-3.1 by this push:
new e3440361b32 branch-3.1: [enhance](array) array_min/max support
array<string> #51145 (#52640)
e3440361b32 is described below
commit e3440361b324a1423cf4fa4bb0a19f862de35d32
Author: Sun Chenyang <[email protected]>
AuthorDate: Wed Jul 2 18:11:47 2025 +0800
branch-3.1: [enhance](array) array_min/max support array<string> #51145
(#52640)
pick from mater #51145
---
.../functions/array/function_array_aggregation.cpp | 59 +++++++++++-----
.../expressions/functions/scalar/ArrayAvg.java | 11 +++
.../expressions/functions/scalar/ArrayJoin.java | 11 +++
.../expressions/functions/scalar/ArrayProduct.java | 11 +++
.../expressions/functions/scalar/ArraySum.java | 11 +++
.../data/function_p0/test_array_agg.out | Bin 0 -> 338 bytes
.../data/variant_p0/test_array_function.out | Bin 0 -> 376 bytes
.../suites/function_p0/test_array_agg.groovy | 64 ++++++++++++++++++
.../suites/variant_p0/test_array_function.groovy | 74 +++++++++++++++++++++
9 files changed, 224 insertions(+), 17 deletions(-)
diff --git a/be/src/vec/functions/array/function_array_aggregation.cpp
b/be/src/vec/functions/array/function_array_aggregation.cpp
index 24d82f7894a..6879d68144c 100644
--- a/be/src/vec/functions/array/function_array_aggregation.cpp
+++ b/be/src/vec/functions/array/function_array_aggregation.cpp
@@ -228,7 +228,8 @@ struct ArrayAggregateImpl {
execute_type<Date>(res, type, data, offsets) ||
execute_type<DateTime>(res, type, data, offsets) ||
execute_type<DateV2>(res, type, data, offsets) ||
- execute_type<DateTimeV2>(res, type, data, offsets)) {
+ execute_type<DateTimeV2>(res, type, data, offsets) ||
+ execute_type<String>(res, type, data, offsets)) {
block.replace_by_position(result, std::move(res));
return Status::OK();
} else {
@@ -236,29 +237,22 @@ struct ArrayAggregateImpl {
}
}
- template <typename Element>
- static bool execute_type(ColumnPtr& res_ptr, const DataTypePtr& type,
const IColumn* data,
- const ColumnArray::Offsets64& offsets) {
- using ColVecType = ColumnVectorOrDecimal<Element>;
- using ResultType = ArrayAggregateResult<Element, operation,
enable_decimal256>;
- using ColVecResultType = ColumnVectorOrDecimal<ResultType>;
+ template <typename ColumnType, typename CreateColumnFunc>
+ static bool execute_type_impl(ColumnPtr& res_ptr, const DataTypePtr& type,
const IColumn* data,
+ const ColumnArray::Offsets64& offsets,
+ CreateColumnFunc create_column_func) {
using Function = AggregateFunction<AggregateFunctionImpl<operation,
enable_decimal256>>;
- const ColVecType* column =
+ const ColumnType* column =
data->is_nullable()
- ? check_and_get_column<ColVecType>(
+ ? check_and_get_column<ColumnType>(
static_cast<const
ColumnNullable*>(data)->get_nested_column())
- : check_and_get_column<ColVecType>(&*data);
+ : check_and_get_column<ColumnType>(&*data);
if (!column) {
return false;
}
- ColumnPtr res_column;
- if constexpr (IsDecimalNumber<Element>) {
- res_column = ColVecResultType::create(0, column->get_scale());
- } else {
- res_column = ColVecResultType::create();
- }
+ ColumnPtr res_column = create_column_func(column);
res_column = make_nullable(res_column);
static_cast<ColumnNullable&>(res_column->assume_mutable_ref()).reserve(offsets.size());
@@ -282,7 +276,38 @@ struct ArrayAggregateImpl {
}
res_ptr = std::move(res_column);
return true;
- };
+ }
+
+ template <typename Element>
+ static bool execute_type(ColumnPtr& res_ptr, const DataTypePtr& type,
const IColumn* data,
+ const ColumnArray::Offsets64& offsets) {
+ using ColVecType = ColumnVectorOrDecimal<Element>;
+ using ResultType = ArrayAggregateResult<Element, operation,
enable_decimal256>;
+ using ColVecResultType = ColumnVectorOrDecimal<ResultType>;
+
+ return execute_type_impl<ColVecType>(
+ res_ptr, type, data, offsets, [](const ColVecType* column) ->
ColumnPtr {
+ if constexpr (IsDecimalNumber<Element>) {
+ return ColVecResultType::create(0,
column->get_scale());
+ } else {
+ return ColVecResultType::create();
+ }
+ });
+ }
+
+ template <>
+ static bool execute_type<String>(ColumnPtr& res_ptr, const DataTypePtr&
type,
+ const IColumn* data, const
ColumnArray::Offsets64& offsets) {
+ if (operation == AggregateOperation::SUM || operation ==
AggregateOperation::PRODUCT ||
+ operation == AggregateOperation::AVERAGE) {
+ return false;
+ }
+ using ColumnType = ColumnString;
+
+ return execute_type_impl<ColumnType>(
+ res_ptr, type, data, offsets,
+ [](const ColumnType*) -> ColumnPtr { return
ColumnString::create(); });
+ }
};
struct NameArrayMin {
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayAvg.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayAvg.java
index e07351f2a5c..ee82c7c2221 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayAvg.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayAvg.java
@@ -18,6 +18,7 @@
package org.apache.doris.nereids.trees.expressions.functions.scalar;
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.functions.AlwaysNullable;
import
org.apache.doris.nereids.trees.expressions.functions.ComputePrecisionForArrayItemAgg;
@@ -27,6 +28,7 @@ import
org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.ArrayType;
import org.apache.doris.nereids.types.BigIntType;
import org.apache.doris.nereids.types.BooleanType;
+import org.apache.doris.nereids.types.DataType;
import org.apache.doris.nereids.types.DecimalV2Type;
import org.apache.doris.nereids.types.DecimalV3Type;
import org.apache.doris.nereids.types.DoubleType;
@@ -96,6 +98,15 @@ public class ArrayAvg extends ScalarFunction implements
ExplicitlyCastableSignat
// return signature;
// }
+ @Override
+ public void checkLegalityBeforeTypeCoercion() {
+ DataType argType = child().getDataType();
+ if (((ArrayType) argType).getItemType().isComplexType()) {
+ throw new AnalysisException(toSql() + " does not support type: "
+ + ((ArrayType)
argType).getItemType().toString());
+ }
+ }
+
/**
* withChildren.
*/
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayJoin.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayJoin.java
index 0da1ab78752..4185e74f755 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayJoin.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayJoin.java
@@ -18,11 +18,13 @@
package org.apache.doris.nereids.trees.expressions.functions.scalar;
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.functions.ExplicitlyCastableSignature;
import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.ArrayType;
+import org.apache.doris.nereids.types.DataType;
import org.apache.doris.nereids.types.StringType;
import org.apache.doris.nereids.types.VarcharType;
import org.apache.doris.nereids.types.coercion.AnyDataType;
@@ -60,6 +62,15 @@ public class ArrayJoin extends ScalarFunction
super("array_join", arg0, arg1, arg2);
}
+ @Override
+ public void checkLegalityBeforeTypeCoercion() {
+ DataType argType = child(0).getDataType();
+ if (((ArrayType) argType).getItemType().isComplexType()) {
+ throw new AnalysisException(toSql() + " does not support type: "
+ + ((ArrayType)
argType).getItemType().toString());
+ }
+ }
+
/**
* withChildren.
*/
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayProduct.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayProduct.java
index ecc4eaac5eb..ad9dda6c66d 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayProduct.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayProduct.java
@@ -18,6 +18,7 @@
package org.apache.doris.nereids.trees.expressions.functions.scalar;
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.functions.AlwaysNullable;
import
org.apache.doris.nereids.trees.expressions.functions.ComputePrecisionForArrayItemAgg;
@@ -27,6 +28,7 @@ import
org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.ArrayType;
import org.apache.doris.nereids.types.BigIntType;
import org.apache.doris.nereids.types.BooleanType;
+import org.apache.doris.nereids.types.DataType;
import org.apache.doris.nereids.types.DecimalV2Type;
import org.apache.doris.nereids.types.DecimalV3Type;
import org.apache.doris.nereids.types.DoubleType;
@@ -67,6 +69,15 @@ public class ArrayProduct extends ScalarFunction implements
ExplicitlyCastableSi
super("array_product", arg);
}
+ @Override
+ public void checkLegalityBeforeTypeCoercion() {
+ DataType argType = child().getDataType();
+ if (((ArrayType) argType).getItemType().isComplexType()) {
+ throw new AnalysisException(toSql() + " does not support type: "
+ + ((ArrayType)
argType).getItemType().toString());
+ }
+ }
+
/**
* withChildren.
*/
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArraySum.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArraySum.java
index 2a28a4d18bf..8ed41b2368f 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArraySum.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArraySum.java
@@ -18,6 +18,7 @@
package org.apache.doris.nereids.trees.expressions.functions.scalar;
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.functions.AlwaysNullable;
import
org.apache.doris.nereids.trees.expressions.functions.ComputePrecisionForArrayItemAgg;
@@ -27,6 +28,7 @@ import
org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.ArrayType;
import org.apache.doris.nereids.types.BigIntType;
import org.apache.doris.nereids.types.BooleanType;
+import org.apache.doris.nereids.types.DataType;
import org.apache.doris.nereids.types.DecimalV2Type;
import org.apache.doris.nereids.types.DecimalV3Type;
import org.apache.doris.nereids.types.DoubleType;
@@ -68,6 +70,15 @@ public class ArraySum extends ScalarFunction implements
ExplicitlyCastableSignat
super("array_sum", arg);
}
+ @Override
+ public void checkLegalityBeforeTypeCoercion() {
+ DataType argType = child().getDataType();
+ if (((ArrayType) argType).getItemType().isComplexType()) {
+ throw new AnalysisException(toSql() + " does not support type: "
+ + ((ArrayType)
argType).getItemType().toString());
+ }
+ }
+
/**
* withChildren.
*/
diff --git a/regression-test/data/function_p0/test_array_agg.out
b/regression-test/data/function_p0/test_array_agg.out
new file mode 100644
index 00000000000..4d0eff49821
Binary files /dev/null and
b/regression-test/data/function_p0/test_array_agg.out differ
diff --git a/regression-test/data/variant_p0/test_array_function.out
b/regression-test/data/variant_p0/test_array_function.out
new file mode 100644
index 00000000000..80815350a9a
Binary files /dev/null and
b/regression-test/data/variant_p0/test_array_function.out differ
diff --git a/regression-test/suites/function_p0/test_array_agg.groovy
b/regression-test/suites/function_p0/test_array_agg.groovy
new file mode 100644
index 00000000000..e89ea83be95
--- /dev/null
+++ b/regression-test/suites/function_p0/test_array_agg.groovy
@@ -0,0 +1,64 @@
+// 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_agg", "p0") {
+ sql """ set enable_nereids_planner=true;"""
+ sql """ set enable_fallback_to_original_planner=false;"""
+ def tableName = "array_agg_table"
+ sql """
+ drop table if exists ${tableName};
+ """
+
+ sql """ set enable_decimal256 = true """
+ sql """
+ CREATE TABLE IF NOT EXISTS ${tableName} (
+ `id` INT(11) null COMMENT "",
+ `a` array<INT> null COMMENT "",
+ `b` array<array<INT>> null COMMENT "",
+ `s` array<String> null COMMENT "",
+ `d` array<decimal(50,18)> null COMMENT ""
+ ) ENGINE=OLAP
+ DUPLICATE KEY(`id`)
+ DISTRIBUTED BY HASH(`id`) BUCKETS 1
+ PROPERTIES (
+ "replication_allocation" = "tag.location.default: 1",
+ "storage_format" = "V2"
+ );
+ """
+ sql """
+ insert into ${tableName} values
+ (1,[1,2,3],[[1],[1,2,3],[2]],["ab","123","114514"],[1.1,2.2,3.3]),
+ (2,[20],[[2]],["cd"],[3.3]),
+ (3,[100],[[1]],["efg"],[null,2.2,3.3]),
+ (4,null,[null],null,null),
+ (5,[null,2],[[2],null],[null,'c'],[1,null,3.3]);
+ """
+
+ qt_sql """
+ select array_min(a), array_min(s), array_max(a), array_max(s) from
${tableName} order by id;
+ """
+
+ qt_sql """
+ select array_join(a, ',', 'replaced'), array_join(s, ',', 'replaced')
from ${tableName} order by id;
+ """
+
+ qt_sql """ select array_sum(s) from ${tableName} order by id; """
+
+ qt_sql """ select array_avg(s) from ${tableName} order by id; """
+
+ qt_sql """ select array_product(s) from ${tableName} order by id; """
+}
diff --git a/regression-test/suites/variant_p0/test_array_function.groovy
b/regression-test/suites/variant_p0/test_array_function.groovy
new file mode 100644
index 00000000000..8fa2a513161
--- /dev/null
+++ b/regression-test/suites/variant_p0/test_array_function.groovy
@@ -0,0 +1,74 @@
+// 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_variant_array_function", "p0") {
+ sql """ set enable_nereids_planner=true;"""
+ sql """ set enable_fallback_to_original_planner=false;"""
+ def tableName = "test_variant_array_function"
+ sql """
+ drop table if exists ${tableName};
+ """
+
+ sql """
+ CREATE TABLE IF NOT EXISTS ${tableName} (
+ `id` INT(11) null COMMENT "",
+ `var` variant null
+ ) ENGINE=OLAP
+ DUPLICATE KEY(`id`)
+ DISTRIBUTED BY HASH(`id`) BUCKETS 1
+ PROPERTIES (
+ "replication_allocation" = "tag.location.default: 1",
+ "storage_format" = "V2"
+ );
+ """
+ sql """
+ insert into ${tableName} values
+ (1, '{"a":[1, 2,3],"b": ["a", "b", "c"], "c": [1.1, 2.2, 3.3]}')
+ """
+
+ sql """
+ insert into ${tableName} values
+ (2, '{"a":[1, 2,3],"b": ["1", "2", "3"], "c": [1.1, 2.2, 3.3]}')
+ """
+
+
+ qt_sql """
+ select array_min(cast(var['a'] as array<int>)), array_min(cast(var['b']
as array<string>)), array_max(cast(var['a'] as array<int>)),
array_max(cast(var['b'] as array<string>)) from ${tableName} order by id;
+ """
+
+ qt_sql """
+ select array_join(cast(var['a'] as array<int>), ',', 'replaced'),
array_join(cast(var['b'] as array<string>), ',', 'replaced'),
array_join(cast(var['c'] as array<double>), ',', 'replaced') from ${tableName}
order by id;
+ """
+
+ qt_sql """
+ select array_sum(cast(var['a'] as array<int>)),
array_sum(cast(var['c'] as array<double>)) from ${tableName} order by id;
+ """
+
+ qt_sql """
+ select array_avg(cast(var['a'] as array<int>)),
array_avg(cast(var['c'] as array<double>)) from ${tableName} order by id;
+ """
+
+ qt_sql """
+ select array_product(cast(var['a'] as array<int>)),
array_product(cast(var['c'] as array<double>)) from ${tableName} order by id;
+ """
+
+ qt_sql """ select array_sum(cast(var['b'] as array<string>)) from
${tableName} order by id; """
+
+ qt_sql """ select array_avg(cast(var['b'] as array<string>)) from
${tableName} order by id; """
+
+ qt_sql """ select array_product(cast(var['b'] as array<string>)) from
${tableName} order by id; """
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]